通过selenium-webdriver.Builder创建浏览器时,如何正确定义Protractor的$?
Hey there! Let's break down why you're hitting this issue and how to get Protractor's handy $ selector working smoothly with your Selenium WebDriver setup.
Why This Happens
Protractor's $ and $$ are custom wrapper functions built on top of Selenium WebDriver—they’re designed to work within Protractor’s test framework environment. When you directly use require('selenium-webdriver').Builder to spin up a browser instance, you’re operating in a raw Selenium context. Protractor’s global utilities like $ aren’t automatically loaded or linked to your driver, which is why you see those "undefined" or "not a function" errors.
Solution 1: Link Your Selenium Driver to Protractor
If you want to keep using Protractor’s $, you need to explicitly bind your Selenium driver to Protractor’s browser object. Here’s a step-by-step implementation:
const { Builder } = require('selenium-webdriver'); const protractor = require('protractor'); async function setupTest() { // Create your raw Selenium driver instance const driver = new Builder().forBrowser('chrome').build(); // Bind the driver to Protractor's browser object protractor.browser.driver = driver; // If testing a non-Angular app, disable Angular synchronization (critical!) await protractor.browser.waitForAngularEnabled(false); // Expose $ and $$ globally to match Protractor's standard setup global.$ = protractor.$; global.$$ = protractor.$$; // Now you can use $ just like in a regular Protractor test await $('input#username').sendKeys('test-user'); } // Clean up after the test setupTest().finally(() => protractor.browser.quit());
Note: Protractor’s $ returns a promise-like ElementFinder, so always use await with it (especially since Protractor’s old control flow is deprecated in newer versions).
Solution 2: Use Native Selenium Locators (No Protractor Dependency)
If you don’t need Protractor’s extra Angular-focused features, you can stick to raw Selenium methods that work natively with your driver. This skips any Protractor-specific setup entirely:
const { Builder, By } = require('selenium-webdriver'); async function runTest() { const driver = new Builder().forBrowser('chrome').build(); try { await driver.get('https://your-app-url.com'); // Equivalent to Protractor's $: use By.css for CSS selectors const usernameInput = await driver.findElement(By.css('input#username')); await usernameInput.sendKeys('test-user'); // Equivalent to Protractor's $$: find multiple elements const allButtons = await driver.findElements(By.css('button')); console.log(`Found ${allButtons.length} buttons on the page`); } finally { await driver.quit(); } } runTest();
You can even wrap these into your own $/$$ functions to mimic Protractor’s syntax if you prefer:
const { By } = require('selenium-webdriver'); let driver; // Your initialized Selenium driver instance async function $(selector) { return await driver.findElement(By.css(selector)); } async function $$(selector) { return await driver.findElements(By.css(selector)); } // Usage example: await $('input#username').sendKeys('test-user');
Why You Might Have Seen "$ is not a function"
If you tried configuring Protractor before but hit this error, it’s probably due to one of these issues:
- You didn’t properly bind your Selenium driver to Protractor’s
browserobject. - You forgot to handle the asynchronous nature of Protractor’s
$(e.g., missingawaitin an async function). - You’re testing a non-Angular app and didn’t disable Protractor’s automatic Angular synchronization, causing timing conflicts.
内容的提问来源于stack exchange,提问作者Jesus is Lord

