From 36d31f3727a1924ecdd3b8bb9347efd40fa7f1eb Mon Sep 17 00:00:00 2001 From: Stanley SERVICAL <32981008+stanlee974@users.noreply.github.com> Date: Sat, 5 Aug 2023 01:33:16 +0200 Subject: [PATCH] feat: add mechanism for reusable scenarios, #198 --- .gitignore | 4 + .../docs/03-wordings/03-reusable-scenarios.md | 71 ++++++++++ .../03-wordings/03-reusable-scenarios.md | 71 ++++++++++ packages/runner-commons/src/index.ts | 2 +- .../runner/formatter/uuv-custom-formatter.ts | 113 --------------- .../src/step-definition-generator/common.ts | 27 +++- .../generate-playbook-step-definitions.ts | 129 ++++++++++++++++++ .../generate-step-definitions.ts | 3 + .../.cypress-cucumber-preprocessorrc.json | 3 +- packages/runner-cypress/cypress.config.ts | 3 +- .../e2e/playbook/example1.playbooked.feature | 5 + .../e2e/playbook/example2.playbooked.feature | 9 ++ .../template/template.playbook.feature | 9 ++ .../template/template2.playbook.feature | 5 + .../generate-playbook-step-definitions.ts | 19 +++ packages/runner-cypress/package.json | 1 + .../cypress/_playbook-engine.ts | 17 +++ .../cypress/base-check-engine.ts | 2 +- packages/runner-cypress/src/lib/uuv-cli.ts | 28 ++-- .../.cypress-cucumber-preprocessorrc.json | 3 +- .../target-config/cypress.config.ts | 3 +- packages/runner-playwright/cucumber.cjs | 3 +- .../e2e/playbook/example1.playbooked.feature | 6 + .../e2e/playbook/example2.playbooked.feature | 10 ++ .../template/template.playbook.feature | 10 ++ .../template/template2.playbook.feature | 6 + .../generate-playbook-step-definitions.ts | 19 +++ packages/runner-playwright/package.json | 1 + .../playwright/_playbook-engine.ts | 16 +++ .../playwright/base-check-engine.ts | 2 +- packages/runner-playwright/src/lib/uuv-cli.ts | 9 ++ .../target-config/cucumber.cjs | 3 +- 32 files changed, 480 insertions(+), 132 deletions(-) create mode 100644 packages/docs/docs/03-wordings/03-reusable-scenarios.md create mode 100644 packages/docs/i18n/fr/docusaurus-plugin-content-docs/current/03-wordings/03-reusable-scenarios.md delete mode 100644 packages/runner-commons/src/runner/formatter/uuv-custom-formatter.ts create mode 100644 packages/runner-commons/src/step-definition-generator/generate-playbook-step-definitions.ts create mode 100644 packages/runner-cypress/e2e/playbook/example1.playbooked.feature create mode 100644 packages/runner-cypress/e2e/playbook/example2.playbooked.feature create mode 100644 packages/runner-cypress/e2e/playbook/template/template.playbook.feature create mode 100644 packages/runner-cypress/e2e/playbook/template/template2.playbook.feature create mode 100644 packages/runner-cypress/generate-playbook-step-definitions.ts create mode 100644 packages/runner-cypress/src/cucumber/step_definitions/cypress/_playbook-engine.ts create mode 100644 packages/runner-playwright/e2e/playbook/example1.playbooked.feature create mode 100644 packages/runner-playwright/e2e/playbook/example2.playbooked.feature create mode 100644 packages/runner-playwright/e2e/playbook/template/template.playbook.feature create mode 100644 packages/runner-playwright/e2e/playbook/template/template2.playbook.feature create mode 100644 packages/runner-playwright/generate-playbook-step-definitions.ts create mode 100644 packages/runner-playwright/src/cucumber/step_definitions/playwright/_playbook-engine.ts diff --git a/.gitignore b/.gitignore index 8b6ad09c2..68ec75ad6 100644 --- a/.gitignore +++ b/.gitignore @@ -43,12 +43,16 @@ testem.log Thumbs.db *.iml packages/runner-cypress/cypress/screenshots/ +packages/runner-cypress/generated +packages/runner-cypress/e2e/generated packages/docs/docs/03-wordings/01-generated-wording-description/ packages/runner-playwright/src/cucumber/step_definitions/playwright/generated/ packages/runner-playwright/reports/ packages/runner-playwright/tests/.features-gen +packages/runner-playwright/generated +packages/runner-playwright/e2e/generated packages/docs/i18n/fr/docusaurus-plugin-content-docs/current/03-wordings/01-generated-wording-description/ packages/docs/static/assistant/uuv-assistant-resources.bundle.js packages/docs/static/assistant/index.html diff --git a/packages/docs/docs/03-wordings/03-reusable-scenarios.md b/packages/docs/docs/03-wordings/03-reusable-scenarios.md new file mode 100644 index 000000000..d05dbce9f --- /dev/null +++ b/packages/docs/docs/03-wordings/03-reusable-scenarios.md @@ -0,0 +1,71 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Reusable scenarios + +:::caution +**Only available for developers** + +Reusable scenarios cannot be used in conjunction with each other +::: + +## Create file with extension .playbook.feature +File with this extension contains reusable scenarios. + +```gherkin title='uuv/e2e/playbook/template.playbook.feature' +@Ignore //Only used with playwright +Feature: Template + + Scenario: I go to town list + When I visit path "https://e2e-test-quest.github.io/weather-app/" + And Within a button named "Get started" + And I click + + Scenario: I select douala + When I visit path "https://e2e-test-quest.github.io/weather-app/" + And Within a button named "Get started" + And I click + And I reset context + And Within a list named "Available Towns" + And Within a list item named "Douala" + And I click + And I reset context +``` + +## Create a file with extension .playbooked.feature +Files with this extension contains scenarios using reusable scenarios. + +```gherkin title='uuv/e2e/playbook/weatherApp.playbooked.feature' +@Ignore //Only used with playwright +Feature: Feature using reusable scenarios + + Scenario: vital check on first page + Given I go to town list + Then I should see a title named "Nothing to display" + + Scenario: vital check on second page + Given I select douala + Then Within the element with aria-label "Weather of Douala" + And I should see a title named "Douala" + And I should see an element with content "min: 10.8 °c" +``` + +## Launch script to generate executable feature +this script replace playbook scenarios name by playbook scenarios steps. + + + + +```shell +npx uuv playbook +``` + + + + +```shell +yarn uuv playbook +``` + + + diff --git a/packages/docs/i18n/fr/docusaurus-plugin-content-docs/current/03-wordings/03-reusable-scenarios.md b/packages/docs/i18n/fr/docusaurus-plugin-content-docs/current/03-wordings/03-reusable-scenarios.md new file mode 100644 index 000000000..728d31c2d --- /dev/null +++ b/packages/docs/i18n/fr/docusaurus-plugin-content-docs/current/03-wordings/03-reusable-scenarios.md @@ -0,0 +1,71 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Scénarios réutilisables + +:::caution +**Disponible seulement pour les développeurs** + +Les scénarios réutilisables ne peuvent être utilisés entre eux. +::: + +## Créer un fichier avec l'extension .playbook.feature +Les fichiers avec cette extension contiennent des scénarios réutilisables + +```gherkin title='uuv/e2e/playbook/template.playbook.feature' +@Ignore //Seulement utile avec playwright + #language: fr +Fonctionnalité: Template + + Scénario: j'aille à la liste des villes + Lorsque je visite l'Url "https://e2e-test-quest.github.io/weather-app/" + Et je vais à l'intérieur de bouton nommé "Get started" + Et je clique + + Scénario: je sélectionne douala + Lorsque je visite l'Url "https://e2e-test-quest.github.io/weather-app/" + Et je vais à l'intérieur de bouton nommé "Get started" + Et je clique + Et je reinitialise le contexte + Et je vais à l'intérieur de liste nommée "Available Towns" + Et je vais à l'intérieur de élément de liste nommé "Douala" + Et je clique + Et je reinitialise le contexte +``` + +## Créer un fichier avec l'extension .playbooked.feature +Les fichiers avec cet extension contiennent des scénarios utilisant les scénarios réutilisables + +```gherkin title='uuv/e2e/playbook/weatherApp.playbooked.feature' +@Ignore //Seulement utile avec playwright + #language: fr + Fonctionnalité: Fonctionnalité utilisant les scénarios réutilisables + Scénario: vérification vital de la première page + Etant donné que j'aille à la liste des villes + Alors je dois voir un titre nommé "Nothing to display" + Scénario: vérification vital de la seconde page + Etant donné que je sélectionne douala + Lorsque je vais à l'intérieur de l'élément ayant pour aria-label "Weather of Douala" + Alors je dois voir un titre nommé "Douala" + Et je dois voir un élément qui contient "min: 10.8 °c" +``` + +## Lancement du script de génération de feature éxecutable +Ce script remplace les noms de scénarios des playbooks par les étapes de scénarios des playbooks. + + + + +```shell +npx uuv playbook +``` + + + + +```shell +yarn uuv playbook +``` + + + diff --git a/packages/runner-commons/src/index.ts b/packages/runner-commons/src/index.ts index afc62b887..c2793576a 100644 --- a/packages/runner-commons/src/index.ts +++ b/packages/runner-commons/src/index.ts @@ -1,8 +1,8 @@ export * from "./step-definition-generator/common"; export * from "./step-definition-generator/generate-step-definitions"; export * from "./step-definition-generator/generate-step-definitions-documentation"; +export * from "./step-definition-generator/generate-playbook-step-definitions"; export * from "./runner/step-definitions/_constant"; export * from "./runner/step-definitions/_i-context"; -export * from "./runner/formatter/uuv-custom-formatter"; import key from "./assets/i18n/template.json"; export { key }; diff --git a/packages/runner-commons/src/runner/formatter/uuv-custom-formatter.ts b/packages/runner-commons/src/runner/formatter/uuv-custom-formatter.ts deleted file mode 100644 index f1bd76476..000000000 --- a/packages/runner-commons/src/runner/formatter/uuv-custom-formatter.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { Formatter } from "cucumber-json-report-formatter"; - -// FIXME remove this class when the PR https://github.com/vrymar/cucumber-json-report-formatter/pull/20 will be merged -export class UuvCustomFormatter extends Formatter { - constructor() { - super(); - } - override async parseCucumberJson(sourceFile, outputFile) { - console.info(`Start formatting file '${sourceFile}' into '${outputFile}'`); - const report = await this.helper.readFileIntoJson(sourceFile); - const gherkinDocumentJson = this.helper.getJsonFromArray(report, "gherkinDocument"); - const cucumberReport = []; - gherkinDocumentJson.forEach(gherkinJson => { - let gherkinDocument; - try { - gherkinDocument = JSON.parse(gherkinJson).gherkinDocument; - } catch (err) { - console.error("Error parsing JSON string.", err); - } - const feature = gherkinDocument.feature; - const featureChildren = feature.children; - const scenariosJson = []; - const background = {}; - featureChildren.forEach(featureChild => { - if (featureChild.rule) { - featureChild.rule.steps = []; - featureChild.rule.children.forEach(ruleChildren => { - this.buildAndAddScenario(ruleChildren, report, background, feature, scenariosJson, featureChild.rule); - }); - } else { - this.buildAndAddScenario(featureChild, report, background, feature, scenariosJson, undefined); - } - }); - const rootJson = { - comments: this.getComments(gherkinDocument.comments), - description: gherkinDocument.feature.description, - elements: scenariosJson, - id: feature.name, - keyword: feature.keyword, - line: feature.location.line, - name: feature.name, - uri: gherkinDocument.uri, - tags: this.getTags(gherkinDocument.feature.tags) - }; - // @ts-ignore - cucumberReport.push(rootJson); - }); - await this.validateReportSchema(report); - const reportString = JSON.stringify(cucumberReport); - console.info(`Finished formatting file '${sourceFile}'`); - this.helper.writeFile(outputFile, reportString); - } - - private buildAndAddScenario(child, report: string[], background: {}, feature, scenariosJson: any[], rule) { - let steps = []; - let stepJson = {}; - // Background - if (child.scenario === undefined) { - child.background.steps.forEach(step => { - stepJson = this.createStepJson(step, report, 0); - // @ts-ignore - steps.push(stepJson); - }); - background = this.createScenarioJson(feature, child.background, steps, "background"); - // eslint-disable-next-line brace-style - } - // Normal Scenario - else if (!child.scenario.keyword.includes("Outline")) { - child.scenario.steps.forEach(step => { - stepJson = this.createStepJson(step, report, 0); - // @ts-ignore - steps.push(stepJson); - }); - const scenario = this.createScenarioJson(feature, child.scenario, steps, "scenario"); - if (rule) { - scenario.id = `${feature.name};${rule.name};${scenario.name}`; - } - if (Object.keys(background).length !== 0 && background !== undefined) { - // @ts-ignore - scenariosJson.push(background); - } - // @ts-ignore - scenariosJson.push(scenario); - } - // Scenario Outline - else if (child.scenario.examples[0].tableBody !== undefined) { - const numberOfExecutions = child.scenario.examples[0].tableBody.length; - const numberOfStepsEachExecution = child.scenario.steps.length; - let scenarioIndex = 0; - while (scenarioIndex < numberOfExecutions) { - let currentStep = 0; - steps = []; - while (currentStep < numberOfStepsEachExecution) { - stepJson = this.createStepJson(child.scenario.steps[currentStep], report, scenarioIndex); - currentStep++; - // @ts-ignore - steps.push(stepJson); - } - const scenario = this.createScenarioJson(feature, child.scenario, steps, "scenario", scenarioIndex); - if (rule) { - scenario.id = `${feature.name};${rule.name};${scenario.name}`; - } - if (Object.keys(background).length !== 0 && background !== undefined) { - // @ts-ignore - scenariosJson.push(background); - } - // @ts-ignore - scenariosJson.push(scenario); - scenarioIndex++; - } - } - } -} diff --git a/packages/runner-commons/src/step-definition-generator/common.ts b/packages/runner-commons/src/step-definition-generator/common.ts index 4bcfa5b95..c2afa7eaf 100644 --- a/packages/runner-commons/src/step-definition-generator/common.ts +++ b/packages/runner-commons/src/step-definition-generator/common.ts @@ -14,6 +14,7 @@ */ import fs from "fs"; +import glob from "glob"; export { fs }; @@ -43,7 +44,14 @@ export enum TEST_RUNNER_ENUM { export enum STEP_DEFINITION_FILE_NAME { BASE = "base-check-engine", - BY_ROLE = "based-role-check-engine" + BY_ROLE = "based-role-check-engine", + BY_SCENARIO_TEMPLATE = "_playbook-engine", +} + +export enum UUV_ENVELOPE { + PLAYBOOK = "playbook.feature", + PLAYBOOKED = "playbooked.feature", + PLAYBOOKED_GEN = "playbooked.generated.feature", } export enum KEY_PRESS { @@ -98,4 +106,21 @@ export class Common { `[WRITE] ${generatedFile} written successfully` ); } + + static getFileList(dirName) { + let files : string[] = []; + const items = fs.readdirSync(dirName, { withFileTypes: true }); + for (const item of items) { + if (item.isDirectory()) { + files = [ + ...files, + ...(Common.getFileList(`${dirName}/${item.name}`)), + ]; + } else { + files.push(`${dirName}/${item.name}`); + } + } + + return files; + } } diff --git a/packages/runner-commons/src/step-definition-generator/generate-playbook-step-definitions.ts b/packages/runner-commons/src/step-definition-generator/generate-playbook-step-definitions.ts new file mode 100644 index 000000000..922ab855d --- /dev/null +++ b/packages/runner-commons/src/step-definition-generator/generate-playbook-step-definitions.ts @@ -0,0 +1,129 @@ +/** + * Software Name : UUV + * + * SPDX-FileCopyrightText: Copyright (c) 2022-2023 Orange + * SPDX-License-Identifier: MIT + * + * This software is distributed under the MIT License, + * the text of which is available at https://spdx.org/licenses/MIT.html + * or see the "LICENSE" file for more details. + * + * Authors: NJAKO MOLOM Louis Fredice & SERVICAL Stanley + * Software description: Make test writing fast, understandable by any human + * understanding English or French. + */ + +import { Common, fs, GenerateFileProcessing, STEP_DEFINITION_FILE_NAME, TEST_RUNNER_ENUM, UUV_ENVELOPE } from "./common"; +import chalk from "chalk"; + +export class PlaybookStepDefinition extends GenerateFileProcessing { + override generatedDir = ""; + UUV_FOLDER = `${this.baseDir}/e2e`; + SCENARIO_REGEXP = RegExp("(Scenario: |Scénario: |Scenario : |Scénario : |Scenario:|Scénario:|Scenario :|Scénario :)(.+)"); + + constructor(baseDir: string, runner: TEST_RUNNER_ENUM, stepDefinitionFileName: STEP_DEFINITION_FILE_NAME) { + super(baseDir, runner, stepDefinitionFileName); + } + + runGenerate() { + this.generatedDir = `${this.UUV_FOLDER}/generated`; + const generatedStepDefinitionDir = `${this.UUV_FOLDER}/../generated/`; + const generatedFile = `${generatedStepDefinitionDir}_playbook-step-definitions.ts`; + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + Common.cleanFolderIfExists(this.generatedDir); + Common.buildDirIfNotExists(this.generatedDir); + Common.cleanFolderIfExists(generatedStepDefinitionDir); + Common.buildDirIfNotExists(generatedStepDefinitionDir); + this.generateWordingFiles(generatedFile); + } + + computeWordingFile(data: string, wordingFile: string): string { + data = + "/*******************************\n" + + "NE PAS MODIFIER, FICHIER GENERE\n" + + "*******************************/\n\n" + + data; + const foundPlaybookedFile = this.initializeGeneratedPlaybookedFile(); + Common.getFileList(this.UUV_FOLDER).forEach(file => { + // chaque template + if (file.includes(UUV_ENVELOPE.PLAYBOOK.toString())) { + const templateFile = fs.readFileSync(file); + // récupère noms scénario + const scenarioRow = templateFile.toString().split(this.SCENARIO_REGEXP); + if (scenarioRow) { + // chaque scénario + scenarioRow.forEach((value, index) => { + if (value.includes("Scenario") || value.includes("Scénario")) { + if (index + 1 <= scenarioRow.length) { + const scenarioName = scenarioRow[index + 1]; + const scenarioSteps = scenarioRow[index + 2]; + if (foundPlaybookedFile) { + this.generatePlaybookedFile(scenarioName, scenarioSteps); + } + // construit la phrase cucumber + data += `Given("${scenarioName}", function() { + return; + }); +`; + } + } + }); + } + } + }); + return data; + } + + generateWordingFiles( + generatedFile: string + ): void { + const wordingFile = `${__dirname}/uuv/template-config.json`; + const definitionSteps = fs.readFileSync( + this.stepDefinitionFile!, + { encoding: "utf8" }); + const updatedData = this.computeWordingFile(definitionSteps, wordingFile); + Common.writeWordingFile(generatedFile, updatedData); + } + + private generatePlaybookedFile(wording, steps): void { + const stepsToCopy = ` + ##### Start playbook "Given ${wording}" +${steps} + ##### End playbook + + `; + Common.getFileList(this.UUV_FOLDER).forEach(file => { + if (file.includes(UUV_ENVELOPE.PLAYBOOKED.toString())) { + const fileNamePath = file.split("/"); + const fileName = fileNamePath[fileNamePath.length - 1]; + const generatedPlaybookedFile = fs.readFileSync(`${this.generatedDir}/_${fileName.replace(UUV_ENVELOPE.PLAYBOOKED.toString(), UUV_ENVELOPE.PLAYBOOKED_GEN.toString())}`).toString(); + const generatedPlaybookedFileUpdated = generatedPlaybookedFile.replaceAll(RegExp(`Given ${wording}$`, "gm"), stepsToCopy); + const consumerFileNameTab = file.split("."); + let generatedFeatureName = consumerFileNameTab[consumerFileNameTab.length - 3].concat(`.${UUV_ENVELOPE.PLAYBOOKED_GEN.toString()}`); + const generatedFeaturePathSplitByDir = generatedFeatureName.split("/"); + if (generatedFeaturePathSplitByDir.length > 1) { + generatedFeatureName = generatedFeaturePathSplitByDir[generatedFeaturePathSplitByDir.length - 1]; + } + Common.writeWordingFile(this.generatedDir + "/_" + generatedFeatureName, generatedPlaybookedFileUpdated); + } + }); + } + + private initializeGeneratedPlaybookedFile(): boolean { + let foundPlaybook = false; + Common.getFileList(this.UUV_FOLDER).forEach(file => { + if (file.includes(UUV_ENVELOPE.PLAYBOOKED.toString())) { + foundPlaybook = true; + const fileContent = fs.readFileSync(file).toString(); + const fileNamePath = file.split("/"); + const fileName = fileNamePath[fileNamePath.length - 1]; + Common.writeWordingFile(this.generatedDir + "/_" + fileName.replace(UUV_ENVELOPE.PLAYBOOKED.toString(), UUV_ENVELOPE.PLAYBOOKED_GEN.toString()), fileContent); + } + }); + if (!foundPlaybook) { + console.error(chalk.red("no playbook found at path ./e2e")); + } + return foundPlaybook; + } +} diff --git a/packages/runner-commons/src/step-definition-generator/generate-step-definitions.ts b/packages/runner-commons/src/step-definition-generator/generate-step-definitions.ts index 8c63aefed..f42bb6a74 100644 --- a/packages/runner-commons/src/step-definition-generator/generate-step-definitions.ts +++ b/packages/runner-commons/src/step-definition-generator/generate-step-definitions.ts @@ -16,6 +16,7 @@ import { BaseStepDefinition } from "./generate-base-step-definitions"; import { BasedRoleStepDefinition } from "./generate-based-role-step-definitions"; import { STEP_DEFINITION_FILE_NAME, TEST_RUNNER_ENUM } from "./common"; +import { PlaybookStepDefinition } from "./generate-playbook-step-definitions"; export function generateStepDefinitionForRunner(baseDir: string, runner: TEST_RUNNER_ENUM) { @@ -23,4 +24,6 @@ export function generateStepDefinitionForRunner(baseDir: string, runner: TEST_RU cypressBaseStepDefinition.runGenerate(); const cypressBasedRoleStepDefinition: BasedRoleStepDefinition = new BasedRoleStepDefinition(baseDir, runner, STEP_DEFINITION_FILE_NAME.BY_ROLE); cypressBasedRoleStepDefinition.runGenerate(); + const cypressPlaybookStepDefinition: PlaybookStepDefinition = new PlaybookStepDefinition(baseDir, runner, STEP_DEFINITION_FILE_NAME.BY_SCENARIO_TEMPLATE); + cypressPlaybookStepDefinition.runGenerate(); } diff --git a/packages/runner-cypress/.cypress-cucumber-preprocessorrc.json b/packages/runner-cypress/.cypress-cucumber-preprocessorrc.json index 28a3a40f0..3e2022440 100644 --- a/packages/runner-cypress/.cypress-cucumber-preprocessorrc.json +++ b/packages/runner-cypress/.cypress-cucumber-preprocessorrc.json @@ -1,6 +1,7 @@ { "stepDefinitions": [ "src/cucumber/step_definitions/cypress/generated/**/*.{js,ts}", - "src/cucumber/step_definitions/cypress/unsafe/*.{js,ts}" + "src/cucumber/step_definitions/cypress/unsafe/*.{js,ts}", + "generated/*.{js,ts}" ] } diff --git a/packages/runner-cypress/cypress.config.ts b/packages/runner-cypress/cypress.config.ts index 0590ebe20..d6a9ed6cc 100644 --- a/packages/runner-cypress/cypress.config.ts +++ b/packages/runner-cypress/cypress.config.ts @@ -6,7 +6,8 @@ export default defineConfig({ video: true, e2e: { baseUrl: "https://e2e-test-quest.github.io/simple-webapp", - specPattern: "e2e/**/*.{cy.ts,feature}", + specPattern: ["e2e/**/*.cy.ts", "e2e/**/*.feature"], + excludeSpecPattern: ["e2e/**/*.playbook.feature", "e2e/**/*.playbooked.feature"], supportFile: false, setupNodeEvents, viewportWidth: 1536, diff --git a/packages/runner-cypress/e2e/playbook/example1.playbooked.feature b/packages/runner-cypress/e2e/playbook/example1.playbooked.feature new file mode 100644 index 000000000..3bed37d47 --- /dev/null +++ b/packages/runner-cypress/e2e/playbook/example1.playbooked.feature @@ -0,0 +1,5 @@ +Feature: Accessibility Step Definition + + Scenario: key.then.a11y.check.default + Given je me connecte3 + Then I should not see an element with aria-label "[NOT] flegend" diff --git a/packages/runner-cypress/e2e/playbook/example2.playbooked.feature b/packages/runner-cypress/e2e/playbook/example2.playbooked.feature new file mode 100644 index 000000000..00127c2ea --- /dev/null +++ b/packages/runner-cypress/e2e/playbook/example2.playbooked.feature @@ -0,0 +1,9 @@ +Feature: Accessibility Step Definition + + Scenario: key.then.a11y.check.default + Given je me connecte + Then I should not see an element with aria-label "[NOT] flegend" + + Scenario: key.then.a11y.check.default + Given je me connecte2 + Then I should not see an element with aria-label "[NOT] flegend" diff --git a/packages/runner-cypress/e2e/playbook/template/template.playbook.feature b/packages/runner-cypress/e2e/playbook/template/template.playbook.feature new file mode 100644 index 000000000..6df99ae3f --- /dev/null +++ b/packages/runner-cypress/e2e/playbook/template/template.playbook.feature @@ -0,0 +1,9 @@ +Feature: Template + + Scenario: je me connecte + When I visit path "https://e2e-test-quest.github.io/simple-webapp/?template1" + Then I should see an element with aria-label "flegend" + + Scenario: je me connecte3 + When I visit path "https://e2e-test-quest.github.io/simple-webapp/?template3" + Then I should see an element with aria-label "flegend" diff --git a/packages/runner-cypress/e2e/playbook/template/template2.playbook.feature b/packages/runner-cypress/e2e/playbook/template/template2.playbook.feature new file mode 100644 index 000000000..f7293521e --- /dev/null +++ b/packages/runner-cypress/e2e/playbook/template/template2.playbook.feature @@ -0,0 +1,5 @@ +Feature: Template + + Scenario: je me connecte2 + When I visit path "https://e2e-test-quest.github.io/simple-webapp/?template2" + Then I should see an element with aria-label "flegend" diff --git a/packages/runner-cypress/generate-playbook-step-definitions.ts b/packages/runner-cypress/generate-playbook-step-definitions.ts new file mode 100644 index 000000000..ec1e837a1 --- /dev/null +++ b/packages/runner-cypress/generate-playbook-step-definitions.ts @@ -0,0 +1,19 @@ +/** +* Software Name : UUV +* +* SPDX-FileCopyrightText: Copyright (c) 2022-2023 Orange +* SPDX-License-Identifier: MIT +* +* This software is distributed under the MIT License, +* the text of which is available at https://spdx.org/licenses/MIT.html +* or see the "LICENSE" file for more details. +* +* Authors: NJAKO MOLOM Louis Fredice & SERVICAL Stanley +* Software description: Make test writing fast, understandable by any human +* understanding English or French. +*/ + +import { STEP_DEFINITION_FILE_NAME, TEST_RUNNER_ENUM, PlaybookStepDefinition } from "@uuv/runner-commons"; + +const playbookStepDefinition: PlaybookStepDefinition = new PlaybookStepDefinition(__dirname, TEST_RUNNER_ENUM.CYPRESS, STEP_DEFINITION_FILE_NAME.BY_SCENARIO_TEMPLATE); +playbookStepDefinition.runGenerate(); diff --git a/packages/runner-cypress/package.json b/packages/runner-cypress/package.json index 69e312fdc..a8d98871e 100644 --- a/packages/runner-cypress/package.json +++ b/packages/runner-cypress/package.json @@ -35,6 +35,7 @@ "scripts": { "generate:step-definitions": "ts-node generate-step-definitions.ts", "generate:step-definitions-documentation": "ts-node generate-step-definitions-documentation.ts", + "generate:playbook-step-definitions": "ts-node generate-playbook-step-definitions.ts", "package": "npm pack --pack-destination=\"../../dist/packages\"", "postinstall": "node postinstall.js", "test:run": "node test.js --run", diff --git a/packages/runner-cypress/src/cucumber/step_definitions/cypress/_playbook-engine.ts b/packages/runner-cypress/src/cucumber/step_definitions/cypress/_playbook-engine.ts new file mode 100644 index 000000000..66aa219a1 --- /dev/null +++ b/packages/runner-cypress/src/cucumber/step_definitions/cypress/_playbook-engine.ts @@ -0,0 +1,17 @@ +/** + * Software Name : UUV + * + * SPDX-FileCopyrightText: Copyright (c) 2022-2023 Orange + * SPDX-License-Identifier: MIT + * + * This software is distributed under the MIT License, + * the text of which is available at https://spdx.org/licenses/MIT.html + * or see the "LICENSE" file for more details. + * + * Authors: NJAKO MOLOM Louis Fredice & SERVICAL Stanley + * Software description: Make test writing fast, understandable by any human + * understanding English or French. + */ + +import { defineStep as Given } from "@badeball/cypress-cucumber-preprocessor"; + diff --git a/packages/runner-cypress/src/cucumber/step_definitions/cypress/base-check-engine.ts b/packages/runner-cypress/src/cucumber/step_definitions/cypress/base-check-engine.ts index e96ea28c0..1f3dda239 100644 --- a/packages/runner-cypress/src/cucumber/step_definitions/cypress/base-check-engine.ts +++ b/packages/runner-cypress/src/cucumber/step_definitions/cypress/base-check-engine.ts @@ -13,7 +13,7 @@ * understanding English or French. */ -import { DataTable, Given, Then, When } from "@badeball/cypress-cucumber-preprocessor"; +import { DataTable, Given, Then, When, defineStep as UuvTemplate } from "@badeball/cypress-cucumber-preprocessor"; import { Context } from "./_context"; import "../../../cypress/commands"; import { Method } from "cypress/types/net-stubbing"; diff --git a/packages/runner-cypress/src/lib/uuv-cli.ts b/packages/runner-cypress/src/lib/uuv-cli.ts index 31fd170fb..0a8a7e187 100644 --- a/packages/runner-cypress/src/lib/uuv-cli.ts +++ b/packages/runner-cypress/src/lib/uuv-cli.ts @@ -25,6 +25,7 @@ import fs from "fs"; import cypress from "cypress"; import { UuvCustomFormatter } from "../cucumber/uuv-custom-formatter"; +import { PlaybookStepDefinition, STEP_DEFINITION_FILE_NAME, TEST_RUNNER_ENUM } from "@uuv/runner-commons"; export async function main() { const JSON_REPORT_DIR = "./uuv/reports/e2e/json"; @@ -37,15 +38,19 @@ export async function main() { const argv = minimist(process.argv.slice(2)); const command = findTargetCommand(argv); console.info(chalk.blueBright(`Executing UUV command ${command}...`)); - switch (command) { - case "open": - await openCypress(argv); - break; - case "e2e": - await runE2ETests(argv); - break; - default: - console.error(chalk.red("Unknown command")); + + switch (command) { + case "open": + await openCypress(argv); + break; + case "e2e": + await runE2ETests(argv); + break; + case "playbook": + await runPlaybook(); + break; + default: + console.error(chalk.red("Unknown command")); process.exit(1); } console.info(`UUV command ${command} executed`); @@ -97,6 +102,11 @@ export async function main() { }); } + async function runPlaybook(): Promise { + const playbookStepDefinition: PlaybookStepDefinition = new PlaybookStepDefinition(__dirname + "/../..", TEST_RUNNER_ENUM.CYPRESS, STEP_DEFINITION_FILE_NAME.BY_SCENARIO_TEMPLATE); + playbookStepDefinition.runGenerate(); + } + async function formatCucumberMessageFile() { // Creating needed dirs if (!fs.existsSync(JSON_REPORT_DIR)) { diff --git a/packages/runner-cypress/target-config/.cypress-cucumber-preprocessorrc.json b/packages/runner-cypress/target-config/.cypress-cucumber-preprocessorrc.json index 7ffa6d8de..93e53e052 100644 --- a/packages/runner-cypress/target-config/.cypress-cucumber-preprocessorrc.json +++ b/packages/runner-cypress/target-config/.cypress-cucumber-preprocessorrc.json @@ -1,7 +1,8 @@ { "stepDefinitions": [ "cucumber/step_definitions/**/*.{js,ts}", - "../node_modules/@uuv/cypress/dist/cucumber/step_definitions/cypress/{generated,unsafe}/**/*.{js,ts}" + "../node_modules/@uuv/cypress/dist/cucumber/step_definitions/cypress/{generated,unsafe}/**/*.{js,ts}", + "uuv/generated/*.{js,ts}" ], "messages": { "enabled": true diff --git a/packages/runner-cypress/target-config/cypress.config.ts b/packages/runner-cypress/target-config/cypress.config.ts index d19999192..dd2ff4d2c 100644 --- a/packages/runner-cypress/target-config/cypress.config.ts +++ b/packages/runner-cypress/target-config/cypress.config.ts @@ -8,7 +8,8 @@ export default defineConfig({ screenshotsFolder: "reports/screenshots", e2e: { baseUrl: "http://localhost:4200", - specPattern: "e2e/**/*.{cy.ts,feature}", + specPattern: ["e2e/**/*.cy.ts", "e2e/**/*.feature"], + excludeSpecPattern: ["e2e/**/*.playbook.feature", "e2e/**/*.playbooked.feature"], supportFile: false, setupNodeEvents, viewportWidth: 1536, diff --git a/packages/runner-playwright/cucumber.cjs b/packages/runner-playwright/cucumber.cjs index ea49ddde1..09cd87ec2 100644 --- a/packages/runner-playwright/cucumber.cjs +++ b/packages/runner-playwright/cucumber.cjs @@ -1,10 +1,11 @@ module.exports = { default: { - paths: [ 'e2e/*.feature' ], + paths: [ 'e2e/**/*.feature'], require: [ 'src/cucumber/step_definitions/playwright/**/*.{ts,js}' ], publishQuiet: true, format: ['html:report/playwright/cucumber-report.html', 'message:report/cucumber-messages.ndjson', 'html:cucumber-report.html'], compiler: 'ts:ts-node/register', requireModule: ['ts-node/register'], + tags: 'not @Ignore' }, }; diff --git a/packages/runner-playwright/e2e/playbook/example1.playbooked.feature b/packages/runner-playwright/e2e/playbook/example1.playbooked.feature new file mode 100644 index 000000000..78a7cdcf6 --- /dev/null +++ b/packages/runner-playwright/e2e/playbook/example1.playbooked.feature @@ -0,0 +1,6 @@ +@Ignore +Feature: Accessibility Step Definition + + Scenario: key.then.a11y.check.default + Given je me connecte3 + Then I should not see an element with aria-label "[NOT] flegend" diff --git a/packages/runner-playwright/e2e/playbook/example2.playbooked.feature b/packages/runner-playwright/e2e/playbook/example2.playbooked.feature new file mode 100644 index 000000000..248f42500 --- /dev/null +++ b/packages/runner-playwright/e2e/playbook/example2.playbooked.feature @@ -0,0 +1,10 @@ +@Ignore +Feature: Accessibility Step Definition + + Scenario: key.then.a11y.check.default + Given je me connecte + Then I should not see an element with aria-label "[NOT] flegend" + + Scenario: key.then.a11y.check.default + Given je me connecte2 + Then I should not see an element with aria-label "[NOT] flegend" diff --git a/packages/runner-playwright/e2e/playbook/template/template.playbook.feature b/packages/runner-playwright/e2e/playbook/template/template.playbook.feature new file mode 100644 index 000000000..bc45ae11b --- /dev/null +++ b/packages/runner-playwright/e2e/playbook/template/template.playbook.feature @@ -0,0 +1,10 @@ +@Ignore +Feature: Template + + Scenario: je me connecte + When I visit path "https://e2e-test-quest.github.io/simple-webapp/?template1" + Then I should see an element with aria-label "flegend" + + Scenario: je me connecte3 + When I visit path "https://e2e-test-quest.github.io/simple-webapp/?template3" + Then I should see an element with aria-label "flegend" diff --git a/packages/runner-playwright/e2e/playbook/template/template2.playbook.feature b/packages/runner-playwright/e2e/playbook/template/template2.playbook.feature new file mode 100644 index 000000000..34ff5b629 --- /dev/null +++ b/packages/runner-playwright/e2e/playbook/template/template2.playbook.feature @@ -0,0 +1,6 @@ +@Ignore +Feature: Template + + Scenario: je me connecte2 + When I visit path "https://e2e-test-quest.github.io/simple-webapp/?template2" + Then I should see an element with aria-label "flegend" diff --git a/packages/runner-playwright/generate-playbook-step-definitions.ts b/packages/runner-playwright/generate-playbook-step-definitions.ts new file mode 100644 index 000000000..1a889235b --- /dev/null +++ b/packages/runner-playwright/generate-playbook-step-definitions.ts @@ -0,0 +1,19 @@ +/** +* Software Name : UUV +* +* SPDX-FileCopyrightText: Copyright (c) 2022-2023 Orange +* SPDX-License-Identifier: MIT +* +* This software is distributed under the MIT License, +* the text of which is available at https://spdx.org/licenses/MIT.html +* or see the "LICENSE" file for more details. +* +* Authors: NJAKO MOLOM Louis Fredice & SERVICAL Stanley +* Software description: Make test writing fast, understandable by any human +* understanding English or French. +*/ + +import { STEP_DEFINITION_FILE_NAME, TEST_RUNNER_ENUM, PlaybookStepDefinition } from "@uuv/runner-commons"; + +const playbookStepDefinition: PlaybookStepDefinition = new PlaybookStepDefinition(__dirname, TEST_RUNNER_ENUM.PLAYWRIGHT, STEP_DEFINITION_FILE_NAME.BY_SCENARIO_TEMPLATE); +playbookStepDefinition.runGenerate(); diff --git a/packages/runner-playwright/package.json b/packages/runner-playwright/package.json index b91a1d5bb..d7b42b945 100644 --- a/packages/runner-playwright/package.json +++ b/packages/runner-playwright/package.json @@ -34,6 +34,7 @@ ], "scripts": { "generate:step-definitions": "ts-node generate-step-definitions.ts", + "generate:playbook-step-definitions": "ts-node generate-playbook-step-definitions.ts", "package": "npm pack --pack-destination=\"../../dist/packages\"", "postinstall": "node postinstall.js", "serverTest:run": "ts-node playwright/run-test-app.ts 9002", diff --git a/packages/runner-playwright/src/cucumber/step_definitions/playwright/_playbook-engine.ts b/packages/runner-playwright/src/cucumber/step_definitions/playwright/_playbook-engine.ts new file mode 100644 index 000000000..0bf552786 --- /dev/null +++ b/packages/runner-playwright/src/cucumber/step_definitions/playwright/_playbook-engine.ts @@ -0,0 +1,16 @@ +/** + * Software Name : UUV + * + * SPDX-FileCopyrightText: Copyright (c) 2022-2023 Orange + * SPDX-License-Identifier: MIT + * + * This software is distributed under the MIT License, + * the text of which is available at https://spdx.org/licenses/MIT.html + * or see the "LICENSE" file for more details. + * + * Authors: NJAKO MOLOM Louis Fredice & SERVICAL Stanley + * Software description: Make test writing fast, understandable by any human + * understanding English or French. + */ + +import { Given } from "@cucumber/cucumber"; diff --git a/packages/runner-playwright/src/cucumber/step_definitions/playwright/base-check-engine.ts b/packages/runner-playwright/src/cucumber/step_definitions/playwright/base-check-engine.ts index 9b9cf53ae..164742c8d 100644 --- a/packages/runner-playwright/src/cucumber/step_definitions/playwright/base-check-engine.ts +++ b/packages/runner-playwright/src/cucumber/step_definitions/playwright/base-check-engine.ts @@ -14,7 +14,7 @@ */ import { DEFAULT_TIMEOUT, fs, key, KEY_PRESS } from "@uuv/runner-commons"; -import { checkA11y, configureAxe, injectAxe } from "axe-playwright"; +import { checkA11y, injectAxe } from "axe-playwright"; import { Locator } from "playwright"; import { devices, expect } from "@playwright/test"; import { Page } from "playwright"; diff --git a/packages/runner-playwright/src/lib/uuv-cli.ts b/packages/runner-playwright/src/lib/uuv-cli.ts index c0a5cac0e..f8642a265 100644 --- a/packages/runner-playwright/src/lib/uuv-cli.ts +++ b/packages/runner-playwright/src/lib/uuv-cli.ts @@ -21,6 +21,7 @@ import figlet from "figlet"; import minimist from "minimist"; import { run } from "./runner-playwright"; import fs from "fs"; +import { PlaybookStepDefinition, STEP_DEFINITION_FILE_NAME, TEST_RUNNER_ENUM } from "@uuv/runner-commons"; export async function main() { const PROJECT_DIR = "uuv"; @@ -37,6 +38,9 @@ export async function main() { case "e2e": await runE2ETests(argv); break; + case "playbook": + await runPlaybook(); + break; default: console.error(chalk.red("Unknown command")); process.exit(1); @@ -79,6 +83,11 @@ export async function main() { }); } + async function runPlaybook(): Promise { + const playbookStepDefinition: PlaybookStepDefinition = new PlaybookStepDefinition(__dirname + "/../..", TEST_RUNNER_ENUM.PLAYWRIGHT, STEP_DEFINITION_FILE_NAME.BY_SCENARIO_TEMPLATE); + playbookStepDefinition.runGenerate(); + } + function findTargetCommand(argv: any) { if (argv._.length < 1) { console.error(chalk.red("No command specified")); diff --git a/packages/runner-playwright/target-config/cucumber.cjs b/packages/runner-playwright/target-config/cucumber.cjs index e498637fb..5dd065709 100644 --- a/packages/runner-playwright/target-config/cucumber.cjs +++ b/packages/runner-playwright/target-config/cucumber.cjs @@ -8,6 +8,7 @@ module.exports = { publishQuiet: true, requireModule: [ 'ts-node/register' - ] + ], + tags: 'not @Ignore' }, };