web-dev-qa-db-fra.com

cypress.io: contient () n'attend pas l'élément

Nous écrivons des tests d'interface utilisateur avec cyprès, ce qui est généralement assez simple à utiliser. Mais encore et encore, je tombe sur un problème d'attente fastidieux.

Le scénario est assez simple. L'utilisateur clique sur le bouton de recherche. Il sélectionne ensuite l'un des éléments avec un certain texte. Voici le code:

cy.get('#search-button').click();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();

Le troisième événement de clic échoue, car déjà cy.contains('Test item 1') n'attend pas le rendu de la page et de l'élément. D'après ce que je peux voir dans les étapes de test, il clique simplement au milieu de la page, ce qui ne fait essentiellement rien. Donc, toutes les étapes suivantes échouent bien sûr.

Cependant, si j'ajoute une wait() entre les appels comme ceci:

cy.get('#search-button').click();
cy.wait(2000);
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();    

La page s'affiche correctement, Test item 1 Apparaît, est cliqué et toutes les étapes suivantes réussissent.

Selon meilleures pratiques l'appel wait() ne devrait pas être nécessaire et devrait donc être évité. Qu'est-ce que je fais mal ici?

10
Ash

tl; dr

Donnez un délai plus long pour contains:

cy.get('#search-button').click();
cy.contains('Test item 1', { timeout: 4000 }).click();
cy.get('#cheapest-offer-button').click();  

Explication

Comme beaucoup de commandes Cypress, contains ont un second argument qui accepte un objet option. Vous pouvez passer le nombre de millisecondes que la commande doit attendre dans la clé timeout comme ceci:

.contains('Stuff', { timeout: 5000 }) // Timeout after 5 secs

De cette façon, la commande se comportera comme si vous aviez ajouté un wait avant, mais si la commande a réussi, elle n'attendra pas tout le temps comme le fait wait.

Le documents officiels de Cypress sur les délais d'attente explique cette technique: comment cela fonctionne, comment cela doit être fait et comment il affecte les assertions chaînées.

Si la raison pour laquelle vous ne pouvez pas cliquer sur l'élément est la visibilité, vous pouvez essayer .click({ force: true }), bien que cela ne devrait être qu'un dernier recours car il peut masquer de vrais bogues.

3
totymedli

Il semble que ce soit un problème courant https://github.com/cypress-io/cypress/issues/695 .

La solution est de forcer Cypress à attendre toutes les opérations asynchrones comme dans les frameworks basés sur le webdriver Selenium. C'est beaucoup plus rapide que cy.wait () Implémentez la méthode:

function waitForBrowser() { 
   cy.window().then(win => {
      return new Cypress.Promise(resolve => win['requestIdleCallback'](resolve));
   });
}

Et utilisez-le comme ceci:

cy.get('#search-button').click();
waitForBrowser();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();

Si vous utilisez Angular , mieux vaut utiliser waitForAngular au lieu de waitForBrowser

function waitForAngular() {
  return cy.window().then(win => {
      return new Cypress.Promise((resolve, reject) => {
        let testabilities = win['getAllAngularTestabilities']();
        if (!testabilities) {
            return reject(new Error('No testabilities. Check Angular API'));
        }
        let count = testabilities.length;
        testabilities.forEach(testability => testability.whenStable(() => {
            count--;
            if (count !== 0) return;
            resolve();
        }));
      });
  });
}
0
EvgenyV

J'ai eu le même problème en essayant d'atteindre une portée avec une certaine valeur. Je l'ai corrigé en fournissant un chemin d'accès plus spécifique à la plage au lieu d'obtenir tous les éléments de la plage dans la page.

cy.get('span').contains('Round ID') //not working
cy.get('.details span').contains('Round ID') //worked

Vous pouvez donc essayer d'être plus précis lors de l'obtention d'éléments du type que vous souhaitez cibler. Une autre option est d'attendre () ...

0
Kostadin Terziev