playwright/docs/src/protractor-js.md
2023-10-06 15:08:51 +02:00

6.4 KiB
Raw Blame History

id title
protractor Migrating from Protractor

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 [method: 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));
          }
        }
      });
    }
    
  3. 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:

Further Reading

Learn more about Playwright Test runner: