File: protractor.md | Updated: 11/18/2025
On this page
Migration Principles
No need for "webdriver-manager" / Selenium.
Protractor’s ElementFinder ⇄ Playwright Test Locator
Protractor’s waitForAngular
⇄ Playwright Test auto-waiting
Don’t forget to await in Playwright Test
Cheat Sheet
| Protractor | Playwright Test |
| --- | --- |
| element(by.buttonText('...')) | page.locator('button, input[type="button"], input[type="submit"] >> text="..."') |
| element(by.css('...')) | page.locator('...') |
| element(by.cssContainingText('..1..', '..2..')) | page.locator('..1.. >> text=..2..') |
| element(by.id('...')) | page.locator('#...') |
| element(by.model('...')) | page.locator('[ng-model="..."]') |
| element(by.repeater('...')) | page.locator('[ng-repeat="..."]') |
| element(by.xpath('...')) | page.locator('xpath=...') |
| element.all | page.locator |
| browser.get(url) | await page.goto(url) |
| browser.getCurrentUrl() | page.url() |
Example
Protractor:
describe('angularjs homepage todo list', function() { it('should add a todo', function() { browser.get('https://angularjs.org'); element(by.model('todoList.todoText')).sendKeys('first test'); element(by.css('[value="add"]')).click(); const todoList = element.all(by.repeater('todo in todoList.todos')); expect(todoList.count()).toEqual(3); expect(todoList.get(2).getText()).toEqual('first test'); // You wrote your first test, cross it off the list todoList.get(2).element(by.css('input')).click(); const completedAmount = element.all(by.css('.done-true')); expect(completedAmount.count()).toEqual(2); });});
Line-by-line migration to Playwright Test:
const { test, expect } = require('@playwright/test'); // 1test.describe('angularjs homepage todo list', () => { test('should add a todo', async ({ page }) => { // 2, 3 await page.goto('https://angularjs.org'); // 4 await page.locator('[ng-model="todoList.todoText"]').fill('first test'); await page.locator('[value="add"]').click(); const todoList = page.locator('[ng-repeat="todo in todoList.todos"]'); // 5 await expect(todoList).toHaveCount(3); await expect(todoList.nth(2)).toHaveText('first test', { useInnerText: true, }); // You wrote your first test, cross it off the list await todoList.nth(2).getByRole('textbox').click(); const completedAmount = page.locator('.done-true'); await expect(completedAmount).toHaveCount(2); });});
Migration highlights (see inline comments in the Playwright Test code snippet):
test and expect functionsasyncpage as one of its parameters. This is one of the many useful fixtures
in Playwright Test.awaitPolyfilling waitForAngular
Playwright Test has built-in auto-waiting
that makes protractor's waitForAngular
unneeded in general case.
However, it might come handy in some edge cases. Here's how to polyfill waitForAngular function in Playwright Test:
Make sure you have protractor installed in your package.json
Polyfill function
async function waitForAngular(page) { const clientSideScripts = require('protractor/built/clientsidescripts.js'); async function executeScriptAsync(page, script, ...scriptArgs) { await page.evaluate(` new Promise((resolve, reject) => { const callback = (errMessage) => { if (errMessage) reject(new Error(errMessage)); else resolve(); }; (function() {${script}}).apply(null, [...${JSON.stringify(scriptArgs)}, callback]); }) `); } await executeScriptAsync(page, clientSideScripts.waitForAngular, '');}
If you don't want to keep a version protractor around, you can also use this simpler approach using this function (only works for Angular 2+):
async function waitForAngular(page) { await page.evaluate(async () => { // @ts-expect-error if (window.getAllAngularTestabilities) { // @ts-expect-error await Promise.all(window.getAllAngularTestabilities().map(whenStable)); // @ts-expect-error async function whenStable(testability) { return new Promise(res => testability.whenStable(res)); } } });}
Polyfill usage
const page = await context.newPage();await page.goto('https://example.org');await waitForAngular(page);
Playwright Test Super Powers
Once you're on Playwright Test, you get a lot!
Full zero-configuration TypeScript support
Run tests across all web engines (Chrome, Firefox, Safari) on any popular operating system (Windows, macOS, Ubuntu)
Full support for multiple origins, (i)frames , tabs and contexts
Run tests in parallel across multiple browsers
Built-in test artifact collection
You also get all these ✨ awesome tools ✨ that come bundled with Playwright Test:
Playwright Tracing for post-mortem debugging
Further Reading
Learn more about Playwright Test runner: