Protractor的isDisplayed等价Selenium写法及NoSuchElementError问题
Ah, I see the issue here! Let's break down why your Selenium code is throwing that NoSuchElementError and how to fix it to match Protractor's behavior.
The Root Cause
Your Protractor code works seamlessly because Protractor has built-in asynchronous handling and automatic waits for elements to be present before executing actions (thanks to its ElementFinder abstraction and the eventually Chai-as-Promised syntax).
But raw Selenium doesn't have this safety net. When you run driver.findElement(By.id('button')), it doesn't wait around for the element to load—it immediately throws an error if the element isn't found right that second. Your test is trying to check visibility before the element even exists in the DOM!
Solutions
Here are the most reliable ways to replicate Protractor's expected behavior in Selenium:
Use Explicit Waits (Recommended)
Explicit waits let you define a specific condition (like an element being visible) and wait up to a set timeout for that condition to be met. This is the most flexible and maintainable approach for stable tests.For Node.js Selenium (using the official
selenium-webdriverpackage):const { By, until } = require('selenium-webdriver'); // Wait up to 5 seconds for the element to be both present and visible const button = await driver.wait(until.elementIsVisible(driver.findElement(By.id('button'))), 5000); // Now safely assert the element is displayed expect(await button.isDisplayed()).to.be.true;If you want to separate checking element existence and visibility:
// First wait for the element to exist in the DOM const button = await driver.wait(until.elementLocated(By.id('button')), 5000); // Then verify it's visible to the user expect(await button.isDisplayed()).to.be.true;Use Implicit Waits (Quick Fix, Less Flexible)
You can set a global implicit wait that applies to allfindElementandfindElementsoperations. This tells Selenium to wait a specified number of milliseconds for an element to appear before throwing an error.// Set this once at the start of your test suite (not per test) await driver.manage().setTimeouts({ implicit: 5000 }); // Now your original code will wait up to 5 seconds for the element to exist expect(await driver.findElement(By.id('button')).isDisplayed()).to.be.true;⚠️ Important: Avoid mixing implicit and explicit waits—this can lead to unpredictable wait times and flaky tests.
Use Chai-as-Promised with Waits (Protractor-Style Syntax)
If you prefer theeventuallysyntax from Protractor, you can combine Chai-as-Promised with explicit waits to keep that familiar pattern:const { By, until } = require('selenium-webdriver'); const chai = require('chai'); const chaiAsPromised = require('chai-as-promised'); chai.use(chaiAsPromised); const expect = chai.expect; // Wait for the element to exist, then assert visibility expect(driver.wait(until.elementLocated(By.id('button')), 5000)).to.eventually.exist; expect(driver.findElement(By.id('button')).isDisplayed()).to.eventually.be.true;
Key Takeaway
Raw Selenium doesn't have Protractor's automatic waiting behavior. Explicit waits are the best practice here—they make your tests more stable, easier to debug, and give you granular control over wait conditions for different elements.
内容的提问来源于stack exchange,提问作者sininen

