Skip to main content

从 Protractor 迁移

迁移原则

备忘单

ProtractorPlaywright 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.allpage.locator
browser.get(url)await page.goto(url)
browser.getCurrentUrl()page.url()

示例

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();

var todoList = element.all(by.repeater('todo in todoList.todos'));
expect(todoList.count()).toEqual(3);
expect(todoList.get(2).getText()).toEqual('first test');

// 你写了第一个测试,把它从列表中划掉
todoList.get(2).element(by.css('input')).click();
var completedAmount = element.all(by.css('.done-true'));
expect(completedAmount.count()).toEqual(2);
});
});

逐行迁移到 Playwright Test:

const { test, expect } = require('@playwright/test'); // 1

test.describe('angularjs homepage todo list', function() {
test('should add a todo', async function({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();

var 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,
});

// 你写了第一个测试,把它从列表中划掉
await todoList.nth(2).getByRole('textbox').click();
var completedAmount = page.locator('.done-true');
await expect(completedAmount).toHaveCount(2);
});
}

迁移亮点(参见 Playwright Test 代码片段中的内联注释):

  1. 每个 Playwright Test 文件都有 testexpect 函数的显式导入
  2. 测试函数标记为 async
  3. Playwright Test 被赋予一个 page 作为其参数之一。这是 Playwright Test 中众多 有用的 fixtures 之一。
  4. 几乎所有 Playwright 调用都以 await 为前缀
  5. 使用 page.locator(selector[, options]) 创建定位器是为数不多的同步方法之一。

Polyfilling waitForAngular

Playwright Test 具有内置的 自动等待,这使得 protractor 的 waitForAngular 在一般情况下是不需要的。

但是,在某些边缘情况下它可能会派上用场。以下是在 Playwright Test 中 polyfill waitForAngular 函数的方法:

  1. 确保在 package.json 中安装了 protractor

  2. Polyfill 函数

    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, '');
    }

    如果您不想保留 protractor 版本,也可以使用此函数使用此更简单的方法(仅适用于 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 用法

    const page = await context.newPage();
    await page.goto('https://example.org');
    await waitForAngular(page);

Playwright Test 超能力

一旦您使用 Playwright Test,您将获得很多!

  • 完全零配置的 TypeScript 支持
  • 任何流行的操作系统(Windows、macOS、Ubuntu)上的 所有 Web 引擎(Chrome、Firefox、Safari)上运行测试
  • 完全支持多个来源、(i)frames选项卡和上下文
  • 在多个浏览器中并行运行测试
  • 内置测试工件收集:视频录制截图playwright 跟踪

您还可以获得所有这些与 Playwright Test 捆绑在一起的 ✨ 很棒的工具 ✨:

进一步阅读

了解有关 Playwright Test 运行器的更多信息: