web-dev-qa-db-fra.com

Comment exécuter ensuite un élément puis un autre dans le rapporteur

Ce code suivant se comporte de manière aléatoire de temps en temps, il fonctionne correctement et génère parfois une erreur comme celle-ci Stale Element Reference Exception 

ce que je veux est que je veux obtenir ce ci-dessous exécuté en premier

element(by.id('FiltItemTransDocNo')).sendKeys(grno);

après que je veux que cela soit exécuté ci-dessous

element.all(by.name('chkGrd')).first().click();

j'ai essayé de cette façon, mais cela ne semble pas fonctionner

element(by.id('FiltItemTransDocNo')).sendKeys(grno).then(function(el){
     element.all(by.name('chkGrd')).first().click();
});

aide-moi avec ça

j'ai joint l'image J'envoie les clés au champ Purchase Rquisition et je suis arrivé avec un résultat qui ne montrera qu'un résultat et je veux cliquer et si je mets une condition de visibilité, il sera toujours true alors je mènerai au même problème  enter image description here

7
Rao

Une note rapide sur sendKeys et e1

Une note rapide indiquant que sendKeys ne retourne pas un WebElement ou un ElementFinder. Cela signifie que e1 dans l'exemple ci-dessus est probablement indéfini.

Éléments obsolètes et changement du DOM

Note rapide sur les hypothèses: La réponse suppose que l'envoi de texte à un filtre modifierait le nombre de lignes ou le nombre d'éléments à l'écran. S'il y a le même nombre d'éléments à l'écran après l'envoi du texte, cela ne fonctionnera pas. Je voudrais regarder le commentaire de Florent ci-dessous sur l'erreur de référence obsolète.

Les éléments obsolètes se produisent généralement lorsque le DOM a changé. Si vous utilisez une directive structurelle dans Angular, le DOM changera si vous utilisez * ngFor ou * ngIf. Mon hypothèse est qu'après avoir filtré l'élément, vous obtenez les éléments dans le DOM pendant ou avant que celui-ci change réellement en fonction de votre filtre. Cela entraînerait un élément Web référencé périmé. Dans mon exemple ci-dessous, j'utilise async/wait avec le flux de contrôle désactivé.

Attente explicite pendant le filtrage

Vous pouvez définir explicitement une veille afin que le DOM se mette à jour avant de passer un appel afin de cliquer sur le premier élément. Cela pourrait conduire à des tests potentiellement instables, car le délai d'attente est inconnu en fonction de l'environnement dans lequel vous vous lancerez.

it('should do something', async () => {
  const filterItem = element(by.id('FiltItemTransDocNo'));
  await filterItem.sendKeys(grno);
  await browser.sleep(1000);  // or some other waits
  await element.all(by.name('chkGrd')).first().click();
});

Comparer les lignes pour element.all

Vous pouvez également vérifier la quantité d'éléments element.all que vous avez avant et après le clic et passer à autre chose lorsque les éléments sont mis à jour.

it('should do something', async () => {
  const filterItem = element(by.id('FiltItemTransDocNo'));
  const table = element.all(by.name('chkGrd'));
  const length = await table.count();

  await filterItem.sendKeys(grno);

  // After the filter keys are sent, check to see if the current table
  // count is not equal to the `table.count()`.
  let updated = false;
  await browser.wait(async () => {
    updated = length !== await table.count();
    return updated;
  }, 5000);

  // So if we use the entire 5 seconds and the count has not changed,
  // we should probably fail before clicking on stuff.
  expect(updated).toBeTruthy();

  // now we can click on the next element.
  await element.all(by.name('chkGrd')).first().click();
});

Pourquoi appeler length !== await table.count() fonctionne? En effet, la table représente une promesse d'obtenir l'élément Web. Lorsque vous appelez la méthode count, elle exécute l'action en résolvant d'abord l'élément Web. Cela pourrait potentiellement être différent selon que le DOM change. Nous comparons ensuite le nombre actuel au précédent.

Assurez-vous que vous utilisez async/wait

Dans votre fichier de configuration, vous devrez spécifier que vous êtes en dehors du flux de contrôle:

exports.config = {
    // In this case, I plan to use a Selenium standalone server
    // at http://127.0.0.1:4444/wd/hub. You could also use other 
    // methods like direct connect or starting it up with 'local'.
    seleniumAddress: 'http://127.0.0.1:4444/wd/hub',

    // Required flag to tell Protractor you do not want to use the
    // control flow. This means that you will have to either chain
    // your promises or async / await your actions. Historically
    // jasminewd node module would resolve promises for you. This
    // package will no longer be used in future releases since the
    // control flow is deprecated.
    Selenium_PROMISE_MANAGER: false,

    // The rest of your config...
}

J'espère que cela pourra aider.

6
cnishina

il existe plusieurs solutions pour la référence des éléments périmés.

Premier:

    let filterItem = element(by.id('FiltItemTransDocNo'));
    browser.wait(ExpectedConditions.visibilityOf(filterItem), 5000, 'Element is not visible.');
    filterItem.sendKeys('some random text');

    let elementToClick = element.all(by.name('chkGrd')).first();
    browser.wait(ExpectedConditions.elementToBeClickable(elementToClick), 5000, 'Element is not clickable.');
    elementToClick.click();

Vous pouvez aussi les chaîner:

browser.wait(ExpectedConditions.visibilityOf(filterItem), 5000, 'Element is not visible.').then( () => {
                filterItem.sendKeys('some random text');

                browser.wait(ExpectedConditions.elementToBeClickable(elementToClick), 5000, 'Element is not clickable.').then( () => {
                    elementToClick.click();
                });
            });

Ou deuxième façon, pour actualiser l'élément en cas d'erreur:

let filterItem = element(by.id('FiltItemTransDocNo'));

            try {
                filterItem.sendKeys('some random text');
            } catch (e) {
                if (e instanceof StaleElementReferenceError) {
                    filterItem = element(by.id('FiltItemTransDocNo'));
                    filterItem.sendKeys('text');
                }
            }
2
Infern0

Comme je l'ai expliqué dans une réponse à une autre question , Protractor et les outils qu'il utilise changent pour utiliser les promesses JavaScript natives, dans l'espoir que tout le monde migrera son code vers un style de code totalement asynchrone. Malheureusement, cela ne facilite pas les choses car vous ne pouvez pas mélanger l'ancien code de style avec le nouveau style. Pour commencer, assurez-vous que votre suite entière est écrite en style async et que vous avez défini Selenium_PROMISE_MANAGER: false dans votre configuration.

Que se passe-t-il en réponse à la sendKeys? Si cela déclenche un appel AJAX et que la réponse à cet appel modifie le DOM, vous devrez probablement faire ce que @cnishina suggère et interroger le DOM pour attendre le changement d'atterrissage. Si, toutefois, seuls les changements Angular côté client se produisent, alors ce code devrait fonctionner:

it('should do something', async () => {
  await element(by.id('FiltItemTransDocNo')).sendKeys(grno);
  await element.all(by.name('chkGrd')).first().click();
});

Les deux appels element se synchronisent avec Angular pour s'assurer que les mises à jour de Angular sont terminées avant que les localisateurs ne fonctionnent, vous devriez donc être OK pour Angular. 

2
Old Pro