使用Protractor时遭遇Stale Element Reference错误的技术求助
Hey there, let's break down why you're hitting that stale element reference error and how to fix it!
The Root Cause
When you first grab the full list of links with element.all(by.xpath('linkname')).then(function(ann){...}), you're storing references to those specific DOM elements. But when you click the "back" button, the modal's content gets re-rendered—meaning those original link elements are no longer attached to the page document. When your loop tries to access ann[i] the second time, it's pointing to an element that doesn't exist anymore, hence the error.
Solution: Re-locate Elements on Each Loop Iteration
Instead of caching the entire list of links upfront, you should re-fetch the link you need every time before clicking it. This ensures you're always interacting with the current, active DOM elements.
Here's a revised version of your code, using async/await for cleaner readability (Protractor supports this in newer versions):
this.new = async function () { // Open the modal and switch context await element(by.xpath('')).click(); await browser.sleep(5000); await browser.switchTo().defaultContent(); // Get total number of links once const linkCount = await element.all(by.xpath('linkname')).count(); for (let i = 0; i < linkCount; i++) { // Re-fetch the i-th link each iteration to avoid stale references const currentLink = element.all(by.xpath('linkname')).get(i); await currentLink.click(); // Wait for detail content, then navigate back await browser.sleep(2000); await element(by.id("back")).click(); await browser.sleep(2000); } };
Bonus: Replace Fixed Sleeps with Explicit Waits
browser.sleep() is flaky because it waits a fixed time regardless of when elements are actually ready. For more reliable tests, use Protractor's ExpectedConditions to wait for elements to be interactable:
const EC = protractor.ExpectedConditions; this.new = async function () { await element(by.xpath('')).click(); // Wait for links to become visible instead of fixed sleep await browser.wait(EC.visibilityOf(element(by.xpath('linkname'))), 5000); await browser.switchTo().defaultContent(); const linkCount = await element.all(by.xpath('linkname')).count(); for (let i = 0; i < linkCount; i++) { const currentLink = element.all(by.xpath('linkname')).get(i); await browser.wait(EC.elementToBeClickable(currentLink), 5000); await currentLink.click(); const backButton = element(by.id("back")); await browser.wait(EC.elementToBeClickable(backButton), 5000); await backButton.click(); } };
This way, your test waits exactly as long as needed for elements to be ready, making it more stable across different environments.
内容的提问来源于stack exchange,提问作者Sneh

