Migrating from Protractor | Playwright (original) (raw)

Migration Principles

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'); // 1

test.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):

  1. Each Playwright Test file has explicit import of the test and expect functions
  2. Test function is marked with async
  3. Playwright Test is given a page as one of its parameters. This is one of the many useful fixtures in Playwright Test.
  4. Almost all Playwright calls are prefixed with await
  5. Locator creation with page.locator() is one of the few methods that is sync.

Polyfilling 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:

  1. Make sure you have protractor installed in your package.json
  2. 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));  
      }  
    }  
  });  
}  
  1. 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!

You also get all these ✨ awesome tools ✨ that come bundled with Playwright Test:

Further Reading

Learn more about Playwright Test runner: