@uuv/playwright
Version:
A solution to facilitate the writing and execution of E2E tests understandable by any human being using cucumber(BDD) and playwright
643 lines (642 loc) • 41.8 kB
JavaScript
;
/*******************************
NE PAS MODIFIER, FICHIER GENERE
*******************************/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Software Name : UUV
*
* SPDX-License-Identifier: MIT
*
* This software is distributed under the MIT License,
* 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.
*/
const runner_commons_1 = require("@uuv/runner-commons");
const axe_playwright_1 = require("axe-playwright");
const test_1 = require("@playwright/test");
const core_engine_1 = require("../core-engine");
const world_1 = require("../../../preprocessor/run/world");
const path_1 = __importDefault(require("path"));
/**
* Configure les dimensions de la fenêtre avec à un des préréglages définit par le moteur d'exécution à savoir pour Cypress: [lien](https://docs.cypress.io/api/commands/viewport#Preset) et pour Playwright: [lien](https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/deviceDescriptorsSource.json)
* */
(0, world_1.Given)(`je redimensionne la fenêtre à la vue {string}`, async function (viewportPreset) {
await this.page.setViewportSize(test_1.devices[viewportPreset].viewport);
});
/**
* Configure les dimensions de la fenêtre à la largeur et la longueur spécifiées
* */
(0, world_1.Given)(`je redimensionne la fenêtre avec une largeur de {int} px et une longueur de {int} px`, async function (width, height) {
await this.page.setViewportSize({ width: width, height: height });
});
/**
* Démarre une session de navigation au clavier à partir du haut de la page<br/><a target='_blank' href='https://github.com/e2e-test-quest/uuv/blob/main/example/fr-keyboard.feature'>Exemples</a>
* */
(0, world_1.Given)(`je commence une navigation au clavier depuis le haut de la page`, async function () {
await this.page.mouse.click(0.5, 0.5);
});
/**
* Navigue vers l'Uri passé en paramètre (url complète étant constituée de la BASE_URL + Uri) ou navigue vers l'Url si ça commence par http:// ou https://
* */
(0, world_1.Given)(`je visite l'Url {string}`, async function (siteUrl) {
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
await this.page.goto(`${siteUrl}`);
});
/**
* Déclenche un click sur l'élément sélectionné.<br/>Assurez vous d'avoir effectué une sélection d'élément avant avec les phrases <strong>Je vais à l'intérieur...</strong>.
* */
(0, world_1.When)(`je clique`, async function () {
const keyBoardFocusTargetObj = keyBoardFocusTarget(this);
if ((await keyBoardFocusTargetObj.count()) === 1) {
await keyBoardFocusTargetObj.click({ timeout: runner_commons_1.DEFAULT_TIMEOUT });
}
else {
await (0, core_engine_1.getPageOrElement)(this).then((element) => element.click({ timeout: runner_commons_1.DEFAULT_TIMEOUT }));
}
});
/**
* Déclenche un click sur un élément avec le rôle et le nom donnés
* */
(0, world_1.When)(`je clique sur l'élément avec le rôle {string} et le nom {string}`, async function (role, name) {
await (0, core_engine_1.click)(this, role, name);
});
// TODO : permet de gérer les label accessibles donc pas que les aria : https://playwright.dev/docs/api/class-locator#locator-get-by-label
/**
* Sélectionne l'élément dont l'aria-label est spécifié <br />⚠ pensez à déselectionner l'élement avec <b>[je reinitialise le contexte](#je-reinitialise-le-contexte)</b> si vous n'agissez plus dessus
* */
(0, world_1.When)(`je vais à l'intérieur de l'élément ayant pour aria-label {string}`, async function (expectedAriaLabel) {
const sanitizedExpectedAriaLabel = encodeURIComponent(expectedAriaLabel).replaceAll("%20", " ");
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const locator = element.getByLabel(sanitizedExpectedAriaLabel, { exact: true });
await (0, test_1.expect)(locator).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await locator.focus({ timeout: 10000 });
});
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT, new core_engine_1.SelectedElementCookie(core_engine_1.FILTER_TYPE.ARIA_LABEL, sanitizedExpectedAriaLabel));
});
/**
* Supprime l'élément sélectionné et le timeout du contexte
* */
(0, world_1.When)(`je reinitialise le contexte`, async function () {
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.TIMEOUT);
const keyBoardFocusTargetObj = keyBoardFocusTarget(this);
if ((await keyBoardFocusTargetObj.count()) === 1) {
await keyBoardFocusTargetObj.blur();
}
});
/**
* Sélectionne l'élément dont le sélecteur est spécifié <br />⚠ pensez à déselectionner l'élement avec <b>[je reinitialise le contexte](#je-reinitialise-le-contexte)</b> si vous n'agissez plus dessus
* */
(0, world_1.When)(`je vais à l'intérieur de l'élément ayant pour sélecteur {string}`, async function (selector) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const locator = element.locator(selector);
await (0, test_1.expect)(locator).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await locator.focus({ timeout: 10000 });
});
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT, new core_engine_1.SelectedElementCookie(core_engine_1.FILTER_TYPE.SELECTOR, selector));
});
/**
* Saisie de la phrase passée en paramètre (utile par exemple pour remplir un champ de formulaire).<br/>Assurez vous d'avoir effectué une sélection d'élément avant avec les phrases <strong>je vais à l'intérieur...</strong>.
* */
(0, world_1.When)(`je saisie le(s) mot(s) {string}`, async function (textToType) {
await type(this, textToType);
});
/**
* Saisit de la phrase passée en paramètre (utile par exemple pour remplir un champ de formulaire).<br/>Assurez vous d'avoir effectué une sélection d'élément avant avec les phrases <strong>je vais à l'intérieur...</strong>.
* */
(0, world_1.When)(`j'entre la valeur {string}`, async function (textToType) {
await type(this, textToType);
});
/**
* Saisie de la phrase passée en paramètre dans une cellule d'une grille ag-Grid (utile par exemple pour remplir une cellule dans une grille).<br/>Assurez vous d'avoir effectué une sélection d'élément avant avec les phrases <strong>je vais à l'intérieur...</strong>.
* */
(0, world_1.When)(`je saisie le(s) mot(s) {string} dans la cellule aggrid à la ligne {int} et la colonne nommée {string}`, async function (textToType, lineNumber, columnName) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
// Confirm the element is a grid or treegrid
const elementRole = await element.getAttribute("role");
(0, test_1.expect)(["grid", "treegrid"], { message: "Focus element doesn't have grid/treegrid role" }).toContain(elementRole);
// Retrieve column index
const columnElement = await element.getByRole("columnheader", { name: columnName, exact: true });
const colIndex = Number(await columnElement.getAttribute("aria-colindex")) - 1;
// Double click on the cell
const rows = await element.getByRole("row", { exact: true }).all();
const cellElement = (await rows[lineNumber].getByRole("gridcell", { exact: true }).all())[colIndex];
await cellElement.dblclick();
// Type text in the cell
await this.page.locator("[aria-label=\"Input Editor\"]").type(textToType);
});
});
/**
* Sélectionne l'option passée en paramètre (utile par exemple pour remplir un champ le liste déroulante).<br/>Assurez vous d'avoir effectué une sélection d'élément avant avec les phrases <strong>je vais à l'intérieur de la liste déroulante nommée 'maListeDeroulante'</strong>.
* */
(0, world_1.When)(`je sélectionne la valeur {string}`, async function (valueToSet) {
const keyBoardFocusTargetObj = keyBoardFocusTarget(this);
if ((await keyBoardFocusTargetObj.count()) === 1) {
await keyBoardFocusTargetObj.selectOption({ label: valueToSet });
}
else {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
// console.debug(element);
await element.focus({ timeout: 10000 });
await element.selectOption({ label: valueToSet });
});
}
});
/**
* Check that the current page have the following partial [result](https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/) based on RGAA standard
* */
(0, world_1.When)(`je dois voir une liste déroulante nommée {string} avec la valeur {string}`, async function (name, expectedValue) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const byRole = await element.getByRole("combobox", { name: name, exact: true });
await (0, test_1.expect)(byRole).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await (0, test_1.expect)(byRole.getByRole("option", { name: expectedValue, selected: true, exact: true }))
.toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
});
});
/**
* Check that the current page have the following partial [result](https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests/) based on RGAA standard
* */
(0, world_1.When)(`je sélectionne la valeur {string} dans la liste déroulante nommée {string}`, async function (valueToSet, name) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const byRole = await element.getByRole("combobox", { name: name, exact: true });
await (0, test_1.expect)(byRole).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await byRole.selectOption({ label: valueToSet });
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
});
});
/**
* Répète la touche le nombre de fois spécifié en utilisant | comme ceci : num|{key}
* */
(0, world_1.When)(`j'appuie {int} fois sur {string}`, async function (nbTimes, key) {
for (let i = 1; i <= nbTimes; i++) {
await pressKey(this, key);
}
});
/**
* Simule un appui sur la touche spécifiée : <table><thead><tr><th>Touche</th><th>Description</th></tr></thead><tbody><tr><td>{tab}</td><td>Tabulation</td></tr><tr><td>{reverseTab}</td><td>Tabulation arrière</td></tr><tr><td>{down}</td><td>Flèche du bas</td></tr><tr><td>{right}</td><td>Flèche de droite</td></tr><tr><td>{left}</td><td>Flèche de gauche</td></tr><tr><td>{up}</td><td>Flèche du haut</td></tr></tbody></table>.<br/>Assurez vous d'avoir effectué une sélection d'élément avant avec les phrases <strong>Je vais à l'intérieur...</strong>.
* */
(0, world_1.When)(`j'appuie sur {string}`, async function (key) {
await pressKey(this, key);
});
/**
* se déplace au précédent élément HTML atteignable avec la tabulation retour<br/><a target='_blank' href='https://github.com/e2e-test-quest/uuv/blob/main/example/fr-keyboard.feature'>Exemples</a>
* */
(0, world_1.When)(`je vais au précédent élément au clavier`, async function () {
await this.page.keyboard.press("ShiftLeft+Tab");
});
/**
* se déplace au prochain élément HTML atteignable avec la tabulation<br/><a target='_blank' href='https://github.com/e2e-test-quest/uuv/blob/main/example/fr-keyboard.feature'>Exemples</a>
* */
(0, world_1.When)(`je vais au prochain élément au clavier`, async function () {
await this.page.keyboard.press("Tab");
});
/**
* Positionne le timeout (en milliseconde) pour la recherche des éléments dans le dom <br />⚠ pensez à déselectionner l'élement avec <b>[je reinitialise le contexte](#je-reinitialise-le-contexte)</b> si vous n'agissez plus dessus
* */
(0, world_1.When)(`je positionne le timeout à {int} secondes`, async function (newTimeout) {
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.TIMEOUT, new core_engine_1.TimeoutCookie("timeout", newTimeout));
});
/**
* Sélectionne l'élément dont le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types) et le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) sont spécifiés <br />⚠ pensez à déselectionner l'élement avec <b>[je reinitialise le contexte](#je-reinitialise-le-contexte)</b> si vous n'agissez plus dessus
* */
(0, world_1.When)(`je vais à l'intérieur de l'élément ayant pour rôle {string} et pour nom {string}`, async function (role, name) {
await (0, core_engine_1.withinRoleAndName)(this, role, name);
});
/**
* Sélectionne l'élément dont l'attribut data-testId est spécifié <br />⚠ pensez à déselectionner l'élement avec <b>[je reinitialise le contexte](#je-reinitialise-le-contexte)</b> si vous n'agissez plus dessus
* */
(0, world_1.When)(`je vais à l'intérieur de l'élément ayant pour testId {string}`, async function (testId) {
testId = encodeURIComponent(testId);
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const locator = element.getByTestId(testId);
await (0, test_1.expect)(locator).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await locator.focus({ timeout: 10000 });
});
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT, new core_engine_1.SelectedElementCookie(core_engine_1.FILTER_TYPE.TEST_ID, testId));
});
/**
* Simule une réponse d'API avec un contenu spécifique. <i>Si vous utilisez Playwright comme moteur d'exécution, les attributs <b>méthode de requête</b> et <b>nom</b> ne sont pas utilisés.</i>
* */
(0, world_1.When)(`je simule une requête {} sur l'url {string} nommée {string} avec le contenu suivant {}`, async function (verb, url, name, body) {
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.MOCK_URL, new core_engine_1.MockCookie(name, url, verb));
await this.page.route(url, async (route) => {
await route.fulfill({ body });
await afterMock(this, url, verb, name);
});
});
/**
* Simule une réponse d'API avec un code http spécifique
* */
(0, world_1.When)(`je simule une requête {} sur l'url {string} nommée {string} avec le code http {int}`, async function (verb, url, name, statusCode) {
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.MOCK_URL, new core_engine_1.MockCookie(name, url, verb));
await this.page.route(url, async (route) => {
await route.fulfill({ status: statusCode });
await afterMock(this, url, verb, name);
});
});
/**
* Simule une réponse d'API avec un fichier spécifique ayant pour extension .json, .js, .coffee, .html, .txt, .csv, .png, .jpg, .jpeg, .gif, .tif, .tiff, .zip
* */
(0, world_1.When)(`je simule une requête {} sur l'url {string} nommée {string} avec le fichier suivant {}`, async function (verb, url, name, fixture) {
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.MOCK_URL, new core_engine_1.MockCookie(name, url, verb));
const data = runner_commons_1.fs.readFileSync(path_1.default.join(getConfigDir(), `playwright/fixtures/${fixture}`), "utf8");
await this.page.route(url, async (route) => {
await route.fulfill({ body: data });
await afterMock(this, url, verb, name);
});
});
/**
* Vérifie qu'un élément Html existe avec le sélecteur spécifié
* */
(0, world_1.Then)(`je dois voir un élément ayant pour sélecteur {string}`, async function (selector) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => (0, test_1.expect)(element.locator(selector)).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) }));
});
/**
* Positionne un ou plusieurs headers à la requête http indiquée et uniquement pour la méthode Http (GET / POST / etc...) passée en paramètre. <i>Si le moteur d'exécution est playwright, la <b>méthode</b> n'est pas gérée.</i>
* */
(0, world_1.When)(`je saisie le(s) header(s) pour l'Uri {string} et la methode {string}`, async function (url, method, headersToSet) {
await this.page.route(url, async (route) => {
const headers = route.request().headers();
await route.continue({ headers: { ...headers, ...headersToSet.rowsHash() } });
});
});
/**
* Positionne un ou plusieurs headers à la requête http indiquée
* */
(0, world_1.When)(`je saisie le(s) header(s) pour l'Uri {string}`, async function (url, headersToSet) {
await this.page.route(url, async (route) => {
const headers = route.request().headers();
await route.continue({ headers: { ...headers, ...headersToSet.rowsHash() } });
});
});
/**
* Vérifie que la page courante a le bon titre
* */
(0, world_1.Then)(`je dois voir le titre de page {string}`, async function (pageTitle) {
await (0, test_1.expect)(this.page).toHaveTitle(pageTitle);
});
/**
* Vérifie qu'un élément Html existe avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types) et le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) spécifiés
* */
(0, world_1.Then)(`je dois voir un élément avec le rôle {string} et le nom {string}`, async function (role, name) {
await (0, core_engine_1.findWithRoleAndName)(this, role, name);
});
/**
* Vérifie qu'un élément Html existe avec le contenu spécifié
* */
(0, world_1.Then)(`je dois voir un élément qui contient {string}`, async function (textContent) {
// TODO partie pris de faire en exactitude. A voir si on doit faire 2 phrases https://playwright.dev/docs/api/class-locator#locator-get-by-text
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => (0, test_1.expect)(element.getByText(textContent, { exact: true })).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) }));
});
/**
* Vérifie qu'un élément Html n'existe pas avec le contenu spécifié
* */
(0, world_1.Then)(`je ne dois pas voir un élément qui contient {string}`, async function (textContent) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => (0, test_1.expect)(element.getByText(textContent, { exact: true })).toHaveCount(0, { timeout: await (0, core_engine_1.getTimeout)(this) }));
});
/**
* Vérifie qu'un élément Html existe avec l'attribut data-testid spécifié
* */
(0, world_1.Then)(`je dois voir un élément ayant pour testId {string}`, async function (testId) {
testId = encodeURIComponent(testId);
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => (0, test_1.expect)(element.getByTestId(testId, { exact: true })).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) }));
});
/**
* Vérifie qu'un élément Html n'existe pas avec l'attribut data-testid spécifié
* */
(0, world_1.Then)(`je ne dois pas voir un élément ayant pour testId {string}`, async function (testId) {
testId = encodeURIComponent(testId);
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => (0, test_1.expect)(element.getByTestId(testId, { exact: true })).toHaveCount(0, { timeout: await (0, core_engine_1.getTimeout)(this) }));
});
/**
* Vérifie sur la page courante qu'il n'y a aucune erreur d'accessibilité [axe-core](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md)
* */
(0, world_1.Then)(`je ne dois pas avoir de problèmes d'accessibilité axe-core`, async function () {
await (0, axe_playwright_1.injectAxe)(this.page);
await (0, axe_playwright_1.checkA11y)(this.page);
});
/**
* Vérifie sur la page courante qu'il n'y a aucune erreur d'accessibilité [axe-core](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md) [avec l'option](https://github.com/dequelabs/axe-core/blob/HEAD/doc/API.md#options-parameter)
* */
(0, world_1.Then)(`je ne dois pas avoir de problèmes d'accessibilité axe-core avec le fichier json suivant d'option {}`, async function (option) {
await (0, axe_playwright_1.injectAxe)(this.page);
const optionFile = await runner_commons_1.fs.readFileSync(path_1.default.join(getConfigDir(), `playwright/fixtures/${option}`));
const optionJson = JSON.parse(optionFile.toString());
await (0, axe_playwright_1.checkA11y)(this.page, undefined, {
axeOptions: optionJson
});
});
function getConfigDir() {
// eslint-disable-next-line dot-notation
return process.env["CONFIG_DIR"] ? process.env["CONFIG_DIR"] : "";
}
/**
* Vérifie sur la page courante qu'il n'y a aucune erreur d'accessibilité [axe-core](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md) [avec l'option](https://github.com/dequelabs/axe-core/blob/HEAD/doc/API.md#options-parameter) sur le [contexte donné](https://github.com/dequelabs/axe-core/blob/HEAD/doc/API.md#context-parameter)
* */
(0, world_1.Then)(`je ne dois pas avoir de problèmes d'accessibilité axe-core sur le fichier json suivant de contexte {} et avec le fichier json suivant d'option {}`, async function (context, option) {
await (0, axe_playwright_1.injectAxe)(this.page);
const contextFile = await runner_commons_1.fs.readFileSync(path_1.default.join(getConfigDir(), `playwright/fixtures/${context}`));
const optionFile = await runner_commons_1.fs.readFileSync(path_1.default.join(getConfigDir(), `playwright/fixtures/${option}`));
const optionJson = JSON.parse(optionFile.toString());
await (0, axe_playwright_1.checkA11y)(this.page, JSON.parse(contextFile.toString()), {
axeOptions: optionJson
});
});
/**
* Vérifie sur la page courante qu'il n'y a aucune erreur d'accessibilité [axe-core](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md) de niveau critique
* */
(0, world_1.Then)(`je ne dois pas avoir de problèmes d'accessibilité axe-core de niveau critique`, async function () {
await (0, axe_playwright_1.injectAxe)(this.page);
await (0, axe_playwright_1.checkA11y)(this.page, undefined, {
includedImpacts: ["critical"]
});
});
/**
* Vérifie sur la page courante qu'il n'y a aucune erreur d'accessibilité [axe-core](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md)avec un ou plusieurs impacts parmi : 'minor','moderate','serious','critical'
* */
(0, world_1.Then)(`je ne dois pas avoir de problèmes d'accessibilité axe-core avec l(es) impact(s) {}`, async function (impacts) {
await (0, axe_playwright_1.injectAxe)(this.page);
await (0, axe_playwright_1.checkA11y)(this.page, undefined, {
includedImpacts: [impacts]
});
});
/**
* Vérifie sur la page courante qu'il n'y a aucune erreur d'accessibilité [axe-core](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md) [avec le ou les standards d'accessibilité](https://github.com/dequelabs/axe-core/blob/HEAD/doc/API.md#axe-core-tags)
* */
(0, world_1.Then)(`je ne dois pas avoir de problèmes d'accessibilité axe-core avec le(s) standard(s) {}`, async function (tags) {
await (0, axe_playwright_1.injectAxe)(this.page);
await (0, axe_playwright_1.checkA11y)(this.page, undefined, {
axeOptions: {
runOnly: {
type: "tag",
values: [tags]
}
}
});
});
/**
* Vérifie qu'un élément Html n'existe pas avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types) et le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) spécifiés
* */
(0, world_1.Then)(`je ne dois pas voir un élément avec le rôle {string} et le nom {string}`, async function (role, name) {
await (0, core_engine_1.notFoundWithRoleAndName)(this, role, name);
});
/**
* Vérifie qu'un élément Html existe avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types), le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) et le contenu spécifiés
* */
(0, world_1.Then)(`je dois voir un élément avec le rôle {string} et le nom {string} et pour contenu {string}`, async function (expectedRole, name, expectedTextContent) {
await (0, core_engine_1.findWithRoleAndNameAndContent)(this, expectedRole, name, expectedTextContent);
});
/**
* Vérifie que l'élément Html avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types) et le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) est focus<br/><a target='_blank' href='https://github.com/e2e-test-quest/uuv/blob/main/example/fr-keyboard.feature'>Exemples</a>
* */
(0, world_1.Then)(`l'élément avec le rôle {string} et le nom {string} doit avoir le focus clavier`, async function (expectedRole, name) {
await (0, core_engine_1.findWithRoleAndNameFocused)(this, expectedRole, name);
});
/**
* Vérifie que l'élément Html avec le sélecteur est focus<br/><a target='_blank' href='https://github.com/e2e-test-quest/uuv/blob/main/example/fr-keyboard.feature'>Exemples</a>
* */
(0, world_1.Then)(`l'élément avec le sélecteur {string} doit avoir le focus clavier`, async function (selector) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const locator = element.locator(selector);
await locator.focus({ timeout: 10000 });
await (0, test_1.expect)(locator).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await (0, test_1.expect)(locator).toBeFocused();
});
});
/**
* Vérifie qu'un élément Html existe avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types), le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) et le contenu spécifiés, et avec l'attribut disabled à true
* */
(0, world_1.Then)(`je dois voir un élément avec le rôle {string} et le nom {string} et pour contenu {string} désactivé`, async function (expectedRole, name, expectedTextContent) {
await (0, core_engine_1.findWithRoleAndNameAndContentDisabled)(this, expectedRole, name, expectedTextContent);
});
/**
* Vérifie qu'un élément Html existe avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types), le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) et le contenu spécifiés et avec l'attribut disabled à false
* */
(0, world_1.Then)(`je dois voir un élément avec le rôle {string} et le nom {string} et pour contenu {string} activé`, async function (expectedRole, name, expectedTextContent) {
await (0, core_engine_1.findWithRoleAndNameAndContentEnabled)(this, expectedRole, name, expectedTextContent);
});
/**
* Vérifie qu'un élément Html existe avec l'attribut aria-label spécifié
* */
(0, world_1.Then)(`je dois voir un élément ayant pour aria-label {string}`, async function (expectedAriaLabel) {
expectedAriaLabel = encodeURIComponent(expectedAriaLabel);
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => (0, test_1.expect)(element.getByLabel(expectedAriaLabel, { exact: true })).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) }));
});
/**
* Vérifie qu'un élément Html n'existe pas avec l'attribut aria-label spécifié
* */
(0, world_1.Then)(`je ne dois pas voir un élément ayant pour aria-label {string}`, async function (expectedAriaLabel) {
expectedAriaLabel = encodeURIComponent(expectedAriaLabel);
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => (0, test_1.expect)(element.getByLabel(expectedAriaLabel, { exact: true })).toHaveCount(0, { timeout: await (0, core_engine_1.getTimeout)(this) }));
});
/**
* Vérifie qu'un élément Html existe avec l'attribut aria-label et le contenu spécifiés
* */
(0, world_1.Then)(`je dois voir un élément ayant pour aria-label {string} et pour contenu {string}`, async function (expectedAriaLabel, expectedTextContent) {
expectedAriaLabel = encodeURIComponent(expectedAriaLabel);
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const byLabel = element.getByLabel(expectedAriaLabel, { exact: true });
await (0, test_1.expect)(byLabel).toHaveCount(1, { timeout: await (0, core_engine_1.getTimeout)(this) });
await (0, test_1.expect)(byLabel.filter({ hasText: expectedTextContent })).toHaveCount(1);
});
});
/**
* Se déplace au précédent élément HTML atteignable avec la tabulation et vérifie que l'élément Html avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types) et le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) a le focus clavier<br/><a target='_blank' href='https://github.com/e2e-test-quest/uuv/blob/main/example/fr-keyboard.feature'>Exemples</a>
* */
(0, world_1.When)(`le précédent élément avec le focus clavier doit avoir le role {string} et le nom {string}`, async function (expectedRole, name) {
await this.page.keyboard.press("ShiftLeft+Tab");
await (0, core_engine_1.findWithRoleAndNameFocused)(this, expectedRole, name);
});
/**
* "Se déplace au prochain élément HTML atteignable avec la tabulation et vérifie que l'élément Html avec le [rôle accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles#aria_role_types) et le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) a le focus clavier<br/><a target='_blank' href='https://github.com/e2e-test-quest/uuv/blob/main/example/fr-keyboard.feature'>Exemples</a>
* */
(0, world_1.When)(`le prochain élément avec le focus clavier doit avoir le role {string} et le nom {string}`, async function (expectedRole, name) {
await this.page.keyboard.press("Tab");
await (0, core_engine_1.findWithRoleAndNameFocused)(this, expectedRole, name);
});
/**
* Vérifie qu'un bouchon nommé ait bien été consommé
* */
(0, world_1.Then)(`je dois consommer le bouchon nommé {string}`, async function (name) {
const cookie = await (0, core_engine_1.getCookie)(this, core_engine_1.COOKIE_NAME.MOCK_URL);
(0, test_1.expect)(() => {
if (!cookie.isValid()) {
throw new Error(`Mock ${name} must be defined before use this sentence`);
}
}).not.toThrow();
await test_1.expect.poll(async () => {
const cookie = await (0, core_engine_1.getCookie)(this, core_engine_1.COOKIE_NAME.MOCK_URL);
const mockUrls = JSON.parse(cookie.value);
const mockUrl = mockUrls.find(mock => mock.name === name);
if (mockUrl) {
return mockUrl?.isConsumed;
}
return false;
}).toBeDefined();
});
/**
* Attends un nombre de millisecondes. <b>Attention:</b> Utiliser cette phrase <b>en production</b> peut rendre votre <b>test <i>flaky</i></b>.
* */
(0, world_1.Then)(`j'attends {int} ms`, async function (ms) {
await this.page.waitForTimeout(ms);
});
/**
* Vérifie des attributs Html de l'élément sélectionné
* */
(0, world_1.Then)(`je dois voir les attributs avec valeurs suivantes`, async function (expectedAttributeList) {
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
// console.debug("expectedAttributeList.raw(),", expectedAttributeList.raw())
for (const expectedAttribute of expectedAttributeList.raw()) {
const attributeName = expectedAttribute[0];
const attributeValue = expectedAttribute[1];
// await showAttributesInLocator(element);
await (0, test_1.expect)(element).toHaveAttribute(attributeName, attributeValue);
}
});
});
/**
* Vérifie qu'il existe une liste avec le nom et les éléments de liste spécifiés.<br/> <u>Exemple</u>\n```gherkin\nAlors je dois voir une liste nommée "test-list" et contenant\n| Premier élément |\n| Deuxième élément |\n| Troisième élément |\n```
* */
(0, world_1.Then)(`je dois voir une liste nommée {string} et contenant`, async function (expectedListName, expectedElementsOfList) {
await (0, core_engine_1.withinRoleAndName)(this, "list", expectedListName);
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
const listitem = await element.getByRole("listitem", { exact: true }).all();
const foundedElement = [];
for (const element of listitem) {
const textContent = await element.textContent();
foundedElement.push([textContent]);
}
await (0, test_1.expect)(foundedElement.length).toBeGreaterThan(0);
// console.debug(`expected [${expectedElementsOfList.raw()}] to be [${foundedElement}]`);
await (0, test_1.expect)(listitem.length).toEqual(expectedElementsOfList.raw().length);
await (0, test_1.expect)(foundedElement).toEqual(expectedElementsOfList.raw());
});
});
/**
* Vérifie qu'il existe une grille (grid) avec le nom et les éléments spécifiés.<br/> <u>Exemple</u>\n```gherkin\nQuand je visite l'Url "https://e2e-test-quest.github.io/simple-webapp/grid.html"\nAlors je dois voir une liste nommée "HTML Grid Example" et contenant\n| Make | Model | Price |\n| ------------ | ------- | ------ |\n| Toyota | Celica | 35000 |\n| Ford | Mondeo | 32000 |\n| Porsche | Boxster | 72000 |\n| BMW | M50 | 60000 |\n| Aston Martin | DBX | 190000 |\n```
* */
(0, world_1.Then)(`je dois voir une grille nommée {string} et contenant`, async function (expectedListName, pExpectedElementsOfList) {
const expectedElementsOfList = removeHeaderSeparatorLine(pExpectedElementsOfList);
await (0, core_engine_1.findWithRoleAndName)(this, "grid", expectedListName);
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT, new core_engine_1.SelectedElementCookie(core_engine_1.FILTER_TYPE.SELECTOR, `role=grid[name="${expectedListName}"]`));
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
await expectTableToHaveContent(element, expectedElementsOfList, "gridcell");
});
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
});
/**
* Vérifie qu'il existe une grille arborescente (treegrid) avec le nom et les éléments spécifiés.<br/> <u>Exemple</u>\n```gherkin\nQuand je visite l'Url "https://e2e-test-quest.github.io/simple-webapp/treegrid.html"\nAlors je dois voir une liste nommée "HTML Treegrid Example" et contenant\n| Make | Model | Price |\n| ------------ | ------- | ------ |\n| Toyota | Celica | 35000 |\n| Ford | Mondeo | 32000 |\n| Porsche | Boxster | 72000 |\n| BMW | M50 | 60000 |\n| Aston Martin | DBX | 190000 |\n```
* */
(0, world_1.Then)(`je dois voir une grille arborescente nommée {string} et contenant`, async function (expectedListName, pExpectedElementsOfList) {
const expectedElementsOfList = removeHeaderSeparatorLine(pExpectedElementsOfList);
await (0, core_engine_1.findWithRoleAndName)(this, "treegrid", expectedListName);
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT, new core_engine_1.SelectedElementCookie(core_engine_1.FILTER_TYPE.SELECTOR, `role=treegrid[name="${expectedListName}"]`));
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
await expectTableToHaveContent(element, expectedElementsOfList, "gridcell");
});
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
});
/**
* Vérifie qu'il existe un tableau (table) avec le nom et les éléments spécifiés.<br/> <u>Exemple</u>\n```gherkin\nQuand je visite l'Url "https://e2e-test-quest.github.io/simple-webapp/table.html"\nAlors je dois voir un tableau nommée "HTML Table Example" et contenant\n| Company | Contact | Country |\n| ----------------------------- | ---------------- | ------- |\n| Alfreds Futterkiste | Maria Anders | Germany |\n| Centro comercial Moctezuma | Francisco Chang | Mexico |\n| Ernst Handel | Roland Mendel | Austria |\n| Island Trading | Helen Bennett | UK |\n| Laughing Bacchus Winecellars | Yoshi Tannamuri | Canada |\n| Magazzini Alimentari Riuniti | Giovanni Rovelli | Italy |\n```
* */
(0, world_1.Then)(`je dois voir un tableau nommé {string} et contenant`, async function (expectedListName, pExpectedElementsOfList) {
const expectedElementsOfList = removeHeaderSeparatorLine(pExpectedElementsOfList);
await (0, core_engine_1.findWithRoleAndName)(this, "table", expectedListName);
await (0, core_engine_1.addCookie)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT, new core_engine_1.SelectedElementCookie(core_engine_1.FILTER_TYPE.SELECTOR, `role=table[name="${expectedListName}"]`));
await (0, core_engine_1.getPageOrElement)(this).then(async (element) => {
await expectTableToHaveContent(element, expectedElementsOfList, "cell");
});
await (0, core_engine_1.deleteCookieByName)(this, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
});
/**
* Vérifie l'existence d'un élément Html ayant le rôle `heading`, le [nom accessible](https://russmaxdesign.github.io/html-elements-names/) et le niveau spécifiés
* */
(0, world_1.Then)(`je dois voir un titre nommé {string} avec le niveau {int}`, async function (name, level) {
await (0, core_engine_1.findWithRoleAndName)(this, "heading", name, { level });
});
function removeHeaderSeparatorLine(pExpectedElementsOfList) {
const expectedElementsOfList = pExpectedElementsOfList.raw();
if (expectedElementsOfList.length > 1) {
expectedElementsOfList.splice(1, 1);
}
return expectedElementsOfList;
}
async function expectTableToHaveContent(element, expectedElementsOfList, pCellAccessibleRole) {
const rows = await element.getByRole("row", { exact: true }).all();
return await Promise.all(rows.map(async (row, rowNumber) => {
const cellAccessibleRole = rowNumber === 0 ? "columnheader" : pCellAccessibleRole;
const cellsElement = await row.getByRole(cellAccessibleRole, { exact: true }).all();
let cellNumber = 0;
return await Promise.all(cellsElement.map((cell) => {
const expectedValue = expectedElementsOfList[rowNumber][cellNumber];
cellNumber++;
return (0, test_1.expect)(cell, { message: `${cellAccessibleRole} at index [${rowNumber + 1}, ${cellNumber}] should be ${expectedValue}` }).toHaveAccessibleName(expectedValue);
}));
}));
}
async function pressKey(world, key) {
switch (key) {
case runner_commons_1.KEY_PRESS.TAB:
await world.page.keyboard.press("Tab");
break;
case runner_commons_1.KEY_PRESS.REVERSE_TAB:
await world.page.keyboard.press("ShiftLeft+Tab");
break;
case runner_commons_1.KEY_PRESS.UP:
await world.page.keyboard.press("ArrowUp");
break;
case runner_commons_1.KEY_PRESS.DOWN:
await world.page.keyboard.press("ArrowDown");
break;
case runner_commons_1.KEY_PRESS.LEFT:
await world.page.keyboard.press("ArrowLeft");
break;
case runner_commons_1.KEY_PRESS.RIGHT:
await world.page.keyboard.press("ArrowRight");
break;
default:
console.error("the command" + key + " is unrecognized.");
break;
}
await (0, core_engine_1.deleteCookieByName)(world, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT);
await (0, core_engine_1.addCookie)(world, core_engine_1.COOKIE_NAME.SELECTED_ELEMENT, new core_engine_1.SelectedElementCookie(core_engine_1.FILTER_TYPE.SELECTOR_PARENT, "*:focus"));
}
function keyBoardFocusTarget(world) {
return world.page.locator(":focus");
}
async function setMockAsConsumed(name, mock, world) {
const newMockCookie = new core_engine_1.MockCookie(name, mock.url, mock.verb);
newMockCookie.isConsumed = true;
await (0, core_engine_1.addCookie)(world, core_engine_1.COOKIE_NAME.MOCK_URL, newMockCookie);
}
async function afterMock(world, url, verb, name) {
await world.page.waitForResponse(url);
const cookie = await (0, core_engine_1.getCookie)(world, core_engine_1.COOKIE_NAME.MOCK_URL);
const mockCookie = JSON.parse(cookie.value);
for (const mock of mockCookie) {
if (mock.name === name && mock.verb === verb && mock.url === url) {
await setMockAsConsumed(name, mock, world);
}
}
}
async function type(world, textToType) {
const keyBoardFocusTargetObj = keyBoardFocusTarget(world);
if ((await keyBoardFocusTargetObj.count()) === 1) {
await keyBoardFocusTargetObj.type(textToType);
}
else {
await (0, core_engine_1.getPageOrElement)(world).then(async (element) => {
// console.debug(element);
await element.focus({ timeout: 10000 });
await element.type(textToType);
});
}
}