Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

198 i want to reuse scenario steps in other scenarios to simplify my written tests #209

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions packages/assistant/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ Make test writing fast, understandable by any human understanding English or Fre
<img src="https://img.shields.io/badge/available%20on%20npm-grey?logo=npm" alt="npm"/>
</a>
<a href="https://www.npmjs.com/package/@uuv/assistant">
<img src="https://img.shields.io/npm/dt/%40uuv%2assistant" alt="downloads"/>
</a>
<a href="https://www.npmjs.com/package/@uuv/assistant">
<img src="https://img.shields.io/badge/using-react-00DCFF?logo=react" alt="npm"/>
</a>
<a href="https://jestjs.io/fr/">
Expand Down
71 changes: 71 additions & 0 deletions packages/docs/docs/03-wordings/03-reusable-scenarios.md
Original file line number Diff line number Diff line change
@@ -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.

<Tabs>
<TabItem value="Npm" label="Npm">

```shell
npx uuv playbook
```

</TabItem>
<TabItem value="Yarn" label="Yarn">

```shell
yarn uuv playbook
```

</TabItem>
</Tabs>
Original file line number Diff line number Diff line change
@@ -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.

<Tabs>
<TabItem value="Npm" label="Npm">

```shell
npx uuv playbook
```

</TabItem>
<TabItem value="Yarn" label="Yarn">

```shell
yarn uuv playbook
```

</TabItem>
</Tabs>
3 changes: 3 additions & 0 deletions packages/runner-commons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Make test writing fast, understandable by any human understanding English or Fre
<img src="https://img.shields.io/badge/available%20on%20npm-grey?logo=npm" alt="npm"/>
</a>
<a href="https://www.npmjs.com/package/@uuv/commons">
<img src="https://img.shields.io/npm/dt/%40uuv%2Fcommons" alt="downloads"/>
</a>
<a href="https://www.npmjs.com/package/@uuv/commons">
<img src="https://img.shields.io/badge/accessibility-yes-green" alt="accessibility"/>
</a>
<a href="https://jestjs.io/fr/">
Expand Down
1 change: 1 addition & 0 deletions packages/runner-commons/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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";
import key from "./assets/i18n/template.json";
Expand Down
27 changes: 26 additions & 1 deletion packages/runner-commons/src/step-definition-generator/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/

import fs from "fs";
import glob from "glob";

export { fs };

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
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) {
const cypressBaseStepDefinition: BaseStepDefinition = new BaseStepDefinition(baseDir, runner, STEP_DEFINITION_FILE_NAME.BASE);
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();
}
Original file line number Diff line number Diff line change
@@ -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}"
]
}
3 changes: 3 additions & 0 deletions packages/runner-cypress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Make test writing fast, understandable by any human understanding English or Fre
<a href="https://www.npmjs.com/package/@uuv/cypress">
<img src="https://img.shields.io/badge/available%20on%20npm-grey?logo=npm" alt="npm"/>
</a>
<a href="https://www.npmjs.com/package/@uuv/cypress">
<img src="https://img.shields.io/npm/dt/%40uuv%2Fcypress" alt="downloads"/>
</a>
<a href="https://www.cypress.io/">
<img src="https://img.shields.io/badge/tested with-cypress-04C38E?logo=cypress" alt="cypress"/>
</a>
Expand Down
Loading