Protractor to Playwright

JavaScript pattern

Protractor to Playwright.

Basic Sample

See: https://playwright.dev/docs/protractor

BEFORE
describe('angularjs homepage todo list', function () {
  it('should add a todo', function () {
    browser.get('https://angularjs.org');

    element(by.model(module.sample)).sendKeys('first test');
    element(by.model('todoList.todoText')).sendKeys('first test');
    element(by.css('[value="add"]')).click();

    var 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();
    var completedAmount = element.all(by.css('.done-true'));
    expect(completedAmount.count()).toEqual(2);
  });
});
AFTER
import { test, expect } from '@playwright/test';

test.describe('angularjs homepage todo list', function () {
  test('should add a todo', async function ({ page }) {
    await page.goto('https://angularjs.org');

    await page.locator(`[ng-model="${module.sample}"]`).fill('first test');
    await page.locator(`[ng-model="${'todoList.todoText'}"]`).fill('first test');
    await page.locator('[value="add"]').click();

    var todoList = page.locator(`[ng-repeat="${'todo in todoList.todos'}"]`);
    await expect(todoList).toHaveCount(3);
    await expect(todoList.nth(2)).toHaveText('first test');

    // You wrote your first test, cross it off the list
    await todoList.nth(2).locator('input').click();
    var completedAmount = page.locator('.done-true');
    await expect(completedAmount).toHaveCount(2);
  });
});

Handle Async

BEFORE
var wait = function () {
  var EC = protractor.ExpectedConditions;
  browser.wait(EC.presenceOf($('#someId')));
  browser.wait(EC.presenceOf($('#hello')), 1000);
};

var two = () => {
  browser.wait(EC.presenceOf($('#someId')));
};

// Already sync
var three = async () => {
  await browser.wait(EC.presenceOf($('#someId')));
};
AFTER
import { test, expect } from '@playwright/test';

var wait = async function () {
  await page.locator('#someId').waitFor({ state: 'attached' });
  await page.locator('#hello').waitFor({ state: 'attached', timeout: 1000 });
};

var two = async () => {
  await page.locator('#someId').waitFor({ state: 'attached' });
};

// Already sync
var three = async () => {
  await page.locator('#someId').waitFor({ state: 'attached' });
};

Avoid deleting code

BEFORE
async function attributeNotToMatch(selector, attr, text, { timeout } = {}) {
  let actual = '';

  return browser.wait(
    async () => {
      actual = await attribute(selector, attr, { timeout });
      return !doMatch(actual, text);
    },
    utils.getTimeout(timeout),
    formatError({
      selector,
      method: 'attributeNotToMatch',
      actual,
      expected: `not to match "${text}"`,
    }),
  );
}
AFTER
import { test, expect } from '@playwright/test';

async function attributeNotToMatch(selector, attr, text, { timeout } = {}) {
  let actual = '';

  return page.waitForFunction(
    async () => {
      actual = await attribute(selector, attr, { timeout });
      return !doMatch(actual, text);
    },
    { timeout: utils.getTimeout(timeout) },
  );
}

Does not modify unrelated files

JAVASCRIPT
function () {
    todoList.get(2).element(by.css('input')).click();
}