/*******************************
NE PAS MODIFIER, FICHIER GENERE
*******************************/

/**
 * 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.
 */

import { DataTable, Given, Then, When } from "@badeball/cypress-cucumber-preprocessor";
import { Context } from "../_context";
import "../../../../cypress/commands";
import { Method } from "cypress/types/net-stubbing";

import {
    assertTextContent,
    click,
    findWithRoleAndName,
    findWithRoleAndNameAndContent,
    findWithRoleAndNameAndContentDisable,
    findWithRoleAndNameAndContentEnable,
    findWithRoleAndNameFocused,
    notFoundWithRoleAndName,
    withinRoleAndName
} from "../core-engine";
import { A11yReferenceEnum } from "@uuv/a11y";
import { expectTableToHaveContent, pressKey, removeHeaderSeparatorLine } from "./../_.common";

/**
 * 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://
 * */
When(`je visite l'Url {string}`, function(siteUrl: string) {
  if (siteUrl.match("^http:\\/\\/|https:\\/\\/")) {
    cy.visit(`${siteUrl}`);
  } else {
    cy.visit(`${Cypress.config().baseUrl}${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>.
 * */
When(`je clique`, function() {
    if (haveKeyBoardFocused()) {
        cy.focused().click();
    } else {
        cy.uuvCheckContextWithinFocusedElement().then(context => {
            context.withinFocusedElement!.click();
        });
    }
});

/**
 * Déclenche un click sur un élément avec le rôle et le nom donnés
 * */
When(`je clique sur l'élément avec le rôle {string} et le nom {string}`, function(role: string, name: string) {
  click(role, name);
});

/**
 * 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>.
 * */
When(`je saisie le(s) mot(s) {string}`, function(textToType: string) {
    type(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>.
 * */
When(`j'entre la valeur {string}`, function(textToType: string) {
    type(textToType);
});

/**
 * Répète la touche le nombre de fois spécifié en utilisant | comme ceci : num|{key}
 * */
When(`j'appuie {int} fois sur {string}`, function(nbTimes: number, key: string) {
  for (let i = 1; i <= nbTimes; i++) {
    pressKey(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>.
 * */
When(`j'appuie sur {string}`, function(key: string) {
  pressKey(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>
 * */
When(`je vais au précédent élément au clavier`, function() {
  pressKey("{reverseTab}");
});

/**
 * 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>
 * */
When(`je vais au prochain élément au clavier`, function() {
  pressKey("{tab}");
});

////////////////////////////////////////////
// Context ACTIONS
////////////////////////////////////////////

/**
 * 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)
 * */
Given(`je redimensionne la fenêtre à la vue {string}`, function(viewportPreset: string) {
  cy.viewport(viewportPreset as Cypress.ViewportPreset);
});

/**
 * Configure les dimensions de la fenêtre à la largeur et la longueur spécifiées
 * */
Given(
 `je redimensionne la fenêtre avec une largeur de {int} px et une longueur de {int} px`,
 function(width: number, height: number) {
   cy.viewport(width, 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>
 * */
Given(
 `je commence une navigation au clavier depuis le haut de la page`,
 function() {
     cy.get("body").last().realClick({ x: 0.5, y: 0.5 });
 }
);

/**
 * 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
 * */
When(`je positionne le timeout à {int} secondes`, function(newTimeout: number) {
  cy.uuvPatchContext({
    timeout: newTimeout
  });
});

/**
 * key.when.withinElement.description
 * */
When(`je vais à l'intérieur de l'élément ayant pour rôle {string} et pour nom {string}`, function(role: string, name: string) {
  withinRoleAndName(role, name);
});

/**
 * 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
 * */
When(`je vais à l'intérieur de l'élément ayant pour aria-label {string}`, function(expectedAriaLabel: string) {
  const foundedElement = cy.uuvFindByLabelText(expectedAriaLabel, {})
   .uuvFoundedElement()
   .should("exist");

  cy.uuvPatchContext({
    withinFocusedElement: foundedElement
  });
});

/**
 * key.when.withinElement.description
 * */
When(`je vais à l'intérieur de l'élément ayant pour testId {string}`, function(testId: string) {
  const foundedElement = cy.uuvFindByTestId(testId)
   .uuvFoundedElement()
   .should("exist");

  cy.uuvPatchContext({
    withinFocusedElement: foundedElement
  });
});

/**
 * 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
 * */
When(`je vais à l'intérieur de l'élément ayant pour sélecteur {string}`, function(selector: string) {
  const foundedElement = cy.uuvGetContext().then(context => {
    const parentElement = context.withinFocusedElement;
    if (parentElement) {
      // console.log("parentElement: ", parentElement);
      return parentElement.should("exist").within(() => {
        cy.get(selector).as("foundedChildElement");
      });
    }
    cy.wrap(null).as("foundedChildElement");
    return cy.get(selector);
  }).uuvFoundedElement()
   .should("exist");

  cy.uuvPatchContext({
    withinFocusedElement: foundedElement
  });
});

/**
 * Supprime l'élément sélectionné et le timeout du contexte
 * */
When(`je reinitialise le contexte`, function() {
    cy.wrap(new Context()).as("context");
    if (haveKeyBoardFocused()) {
        cy.focused().blur();
    } else {
        cy.window().trigger("blur");
    }
});

/**
 * 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>
 * */
When(
 `je simule une requête {} sur l'url {string} nommée {string} avec le contenu suivant {}`,
 function(verb: Method, uri: string, name: string, body: any) {
   cy
    .intercept(verb, uri, {
      body: body
    })
    .as(name);
 }
);

/**
 * Simule une réponse d'API avec un code http spécifique
 * */
When(
 `je simule une requête {} sur l'url {string} nommée {string} avec le code http {int}`,
 function(verb: Method, uri: string, name: string, statusCode: number) {
   cy
    .intercept(verb, uri, {
      statusCode: statusCode
    })
    .as(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
 * */
When(
 `je simule une requête {} sur l'url {string} nommée {string} avec le fichier suivant {}`,
 function(verb: Method, uri: string, name: string, fixture: any) {
   cy
    .intercept(verb, uri, {
      fixture: fixture
    })
    .as(name);
 }
);

////////////////////////////////////////////
// INTERCEPTION
////////////////////////////////////////////
/**
 * 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>
 * */
When(
 `je saisie le(s) header(s) pour l'Uri {string} et la methode {string}`,
 function(url: string, method: string, headersToSet: DataTable) {
   cy.intercept(method as Method, url, (req) => {
     req.headers = {
       ...req.headers,
       ...headersToSet.rowsHash()
     };
     req.continue();
   });
 }
);

/**
 * Positionne un ou plusieurs headers à la requête http indiquée
 * */
When(`je saisie le(s) header(s) pour l'Uri {string}`, function(url: string, headersToSet: DataTable) {
  cy.intercept(url, (req) => {
    req.headers = {
      ...req.headers,
      ...headersToSet.rowsHash()
    };
    req.continue();
  });
});

////////////////////////////////////////////
// VALIDATION
////////////////////////////////////////////

/**
 * Vérifie que la page courante a le bon titre
 * */
Then(`je dois voir le titre de page {string}`, function(pageTitle: string) {
    cy.title().should("eq", pageTitle);
});

/**
 * Vérifie qu'un élément Html existe avec le contenu spécifié
 * */
Then(`je dois voir un élément qui contient {string}`, function(textContent: string) {
  cy.uuvFindByText(textContent, {})
   .uuvFoundedElement()
   .should("exist");
});

/**
 * Vérifie qu'un élément Html n'existe pas avec le contenu spécifié
 * */
Then(`je ne dois pas voir un élément qui contient {string}`, function(textContent: string) {
  cy.uuvFindByText(textContent, {})
   .should("not.exist");
});

/**
 * Vérifie qu'un élément Html existe avec l'attribut data-testid spécifié
 * */
Then(`je dois voir un élément ayant pour testId {string}`, function(testId: string) {
  cy.uuvFindByTestId(testId)
   .uuvFoundedElement()
   .should("exist");
});

/**
 * Vérifie qu'un élément Html n'existe pas avec l'attribut data-testid spécifié
 * */
Then(`je ne dois pas voir un élément ayant pour testId {string}`, function(testId: string) {
  cy.uuvFindByTestId(testId)
   .should("not.exist");
});

/**
 * 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
 * */
Then(`je dois voir un élément avec le rôle {string} et le nom {string}`, function(role: string, name: string) {
  findWithRoleAndName(role, name);
});

/**
 * 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
 * */
Then(
 `je ne dois pas voir un élément avec le rôle {string} et le nom {string}`,
  function(role: string, name: string) {
   notFoundWithRoleAndName(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
 * */
Then(
 `je dois voir un élément avec le rôle {string} et le nom {string} et pour contenu {string}`,
  function(expectedRole: string, name: string, expectedTextContent: string) {
   findWithRoleAndNameAndContent(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>
 * */
Then(
 `l'élément avec le rôle {string} et le nom {string} doit avoir le focus clavier`,
  function(expectedRole: string, name: string) {
    findWithRoleAndNameFocused(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>
 * */
Then(
 `l'élément avec le sélecteur {string} doit avoir le focus clavier`,
 function(selector: string) {
   cy.get(selector).then(foundElement => {
     cy.focused().then(focusedElement => {
       expect(foundElement?.get(0)).eq(focusedElement?.get(0));
     });
   });
 }
);

/**
 * 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
 * */
Then(
 `je dois voir un élément avec le rôle {string} et le nom {string} et pour contenu {string} inactif`,
  function(expectedRole: string, name: string, expectedTextContent: string) {
   findWithRoleAndNameAndContentDisable(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
 * */
Then(
 `je dois voir un élément avec le rôle {string} et le nom {string} et pour contenu {string} actif`,
  function(expectedRole: string, name: string, expectedTextContent: string) {
   findWithRoleAndNameAndContentEnable(expectedRole, name, expectedTextContent);
 }
);

/**
 * Vérifie qu'un élément Html existe avec l'attribut aria-label spécifié
 * */
Then(`je dois voir un élément ayant pour aria-label {string}`, function(expectedAriaLabel: string) {
  cy.uuvFindByLabelText(expectedAriaLabel, {})
   .uuvFoundedElement()
   .should("exist");
});

/**
 * Vérifie qu'un élément Html n'existe pas avec l'attribut aria-label spécifié
 * */
Then(`je ne dois pas voir un élément ayant pour aria-label {string}`, function(expectedAriaLabel: string) {
  cy.uuvFindByLabelText(expectedAriaLabel, {})
    .should("not.exist");
});

/**
 * Vérifie qu'un élément Html existe avec l'attribut aria-label et le contenu spécifiés
 * */
Then(
 `je dois voir un élément ayant pour aria-label {string} et pour contenu {string}`,
  function(expectedAriaLabel: string, expectedTextContent: string) {
   cy.uuvFindByLabelText(expectedAriaLabel, {})
    .uuvFoundedElement()
    .should("exist")
    .then((response) => {
      assert.equal(response.length, 1);
      assertTextContent(response, expectedTextContent);
    });
 }
);

/**
 * 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>
 * */
When(`le précédent élément avec le focus clavier doit avoir le role {string} et le nom {string}`, function(expectedRole: string, name: string) {
    pressKey("{reverseTab}");
    findWithRoleAndNameFocused(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>
 * */
When(`le prochain élément avec le focus clavier doit avoir le role {string} et le nom {string}`, function(expectedRole: string, name: string) {
    pressKey("{tab}");
    findWithRoleAndNameFocused(expectedRole, name);
});

/**
 * Vérifie qu'un bouchon nommé ait bien été consommé
 * */
Then(`je dois consommer le bouchon nommé {string}`, function(name: string) {
  cy.wait([`@${name}`]);
});

/**
 * key.when.click.withContext.description
 * */
Then(`j'attends {int} ms`, function(ms: number) {
  cy.wait(ms);
});

/**
 * 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```
 * */
Then(
 `je dois voir une liste nommée {string} et contenant`,
  function(expectedListName: string, expectedElementsOfList: DataTable) {
   cy.uuvFindByRole("list", { name: expectedListName })
    .uuvFoundedElement()
    .should("exist")
    .within(() => {
      return cy.findAllByRole("listitem", {}).then((listitem) => {
        const foundedElement: any[] = [];
        for (let i = 0; i < listitem.length; i++) {
          foundedElement.push([listitem[i].textContent]);
        }
        assert.equal(listitem.length, expectedElementsOfList.raw().length);
        assert.deepEqual(
         foundedElement,
         expectedElementsOfList.raw(),
         `expected [${foundedElement}] to be [${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```
 * */
Then(
    `je dois voir une grille nommée {string} et contenant`,
    function(expectedListName: string, pExpectedElementsOfList: DataTable) {
        const expectedElementsOfList = removeHeaderSeparatorLine(pExpectedElementsOfList);
        cy.uuvFindByRole("grid", { name: expectedListName })
            .uuvFoundedElement()
            .should("exist")
            .within(() => {
                expectTableToHaveContent(expectedElementsOfList, "gridcell");
            });
    }
);

/**
 * 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```
 * */
Then(
    `je dois voir une grille arborescente nommée {string} et contenant`,
    function(expectedListName: string, pExpectedElementsOfList: DataTable) {
        const expectedElementsOfList = removeHeaderSeparatorLine(pExpectedElementsOfList);
        cy.uuvFindByRole("treegrid", { name: expectedListName })
            .uuvFoundedElement()
            .should("exist")
            .within(() => {
                expectTableToHaveContent(expectedElementsOfList, "gridcell");
            });
    }
);


/**
 * 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```
 * */
Then(
    `je dois voir un tableau nommé {string} et contenant`,
    function(expectedListName: string, pExpectedElementsOfList: DataTable) {
        const expectedElementsOfList = removeHeaderSeparatorLine(pExpectedElementsOfList);
        cy.uuvFindByRole("table", { name: expectedListName })
            .uuvFoundedElement()
            .should("exist")
            .within(() => {
                expectTableToHaveContent(expectedElementsOfList, "cell");
            });
    }
);

/**
 * Vérifie des attributs Html de l'élément sélectionné
 * */
Then(
 `je dois voir les attributs avec valeurs suivantes`,
  function(expectedAttributeList: DataTable) {
   cy.uuvCheckContextWithinFocusedElement().then((context) => {
     const elementToSelect = context.withinFocusedElement!;
     for (const currentIndex in expectedAttributeList.raw()) {
       const attributeName = expectedAttributeList.raw()[currentIndex][0];
       const attributeValue = expectedAttributeList.raw()[currentIndex][1];
       elementToSelect.then((response) => {
         assert.equal(response[0].getAttribute(attributeName), attributeValue);
       });
     }
   });
 }
);

/**
 * Vérifie qu'un élément Html existe avec le sélecteur spécifié
 * */
Then(`je dois voir un élément ayant pour sélecteur {string}`, function(selector: string) {
  cy.get(selector).should("exist");
});

/**
 * 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)
 * */
Then(
 `je ne dois pas avoir de problèmes d'accessibilité axe-core`,
  function() {
    cy.injectUvvA11y();
    cy.checkUvvA11y({
      reference: A11yReferenceEnum.WCAG_WEB
    });
 });

/**
 * 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
 * */
Then(
 `je ne dois pas avoir de problèmes d'accessibilité axe-core de niveau critique`,
  function() {
   cy.injectUvvA11y();
   cy.checkUvvA11y({
      reference: A11yReferenceEnum.WCAG_WEB,
      runnerOptions: {
        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'
 * */
Then(
 `je ne dois pas avoir de problèmes d'accessibilité axe-core avec l(es) impact(s) {}`,
  function(impacts: any) {
   cy.injectUvvA11y();
   cy.checkUvvA11y({
      reference: A11yReferenceEnum.WCAG_WEB,
      runnerOptions: {
        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)
 * */
Then(
 `je ne dois pas avoir de problèmes d'accessibilité axe-core avec le(s) standard(s) {}`,
  function(tags: any) {
   cy.injectUvvA11y();
   cy.checkUvvA11y({
      reference: A11yReferenceEnum.WCAG_WEB,
      runnerOptions: {
        runOnly: {
          type: "tag",
          values: [tags]
        }
      }
   });
 });

/**
 * 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)
 * */
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 {}`,
  function(context: any, option: any) {
   cy.injectAxe();
   cy.fixture(context).then(context => {
     cy.fixture(option).then(option => {
       cy.checkA11y(context, option);
     });
   });
 });

/**
 * 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)
 * */
Then(
 `je ne dois pas avoir de problèmes d'accessibilité axe-core avec le fichier json suivant d'option {}`,
  function(option: any) {
   cy.injectUvvA11y();
   cy.fixture(option).then(data => {
    cy.checkUvvA11y({
      reference: A11yReferenceEnum.WCAG_WEB,
      runnerOptions: data
    });
   });
 });


/**
 * Vérifie sur la page courante qu'il n'y a aucune [erreur de conformité d'accessibilité](https://accessibilite.numerique.gouv.fr/methode/criteres-et-tests) avec un des référentiels : WCAG-WEB, RGAA et une des versions 4.1
 * */
Then(
 `je ne dois pas avoir de problèmes d'accessibilité rgaa`,
  function() {
   cy.injectUvvA11y();
   cy.checkUvvA11y({
    reference: A11yReferenceEnum.RGAA
   });
 });

Then(
 `je dois avoir les résultats suivants selon le référentiel rgaa`,
  function(expectedResult: string) {
   cy.injectUvvA11y();
   cy.checkUvvA11y({
    reference: A11yReferenceEnum.RGAA,
    expectedResult: {
      value: JSON.parse(expectedResult)
    }
   });
 });

Then(
 `je dois avoir les résultats partiels suivants selon le référentiel rgaa`,
  function(expectedResult: string) {
   cy.injectUvvA11y();
   cy.checkUvvA11y({
    reference: A11yReferenceEnum.RGAA,
    expectedResult: {
      value: JSON.parse(expectedResult),
      isContainsMode: true
    }
   });
});

function haveKeyBoardFocused() {
  return Cypress.$(":focus").length > 0;
}

function type(textToType: string) {
  cy.uuvCheckContextWithinFocusedElement(true).then((context) => {
    if (context.withinFocusedElement) {
      context.withinFocusedElement!.type(textToType);
    } else if (haveKeyBoardFocused()) {
      cy.focused().type(textToType);
    }
  });
}
