跳到主要内容

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

const 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();
const 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', () => {
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,
});

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

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

  1. 每个 Playwright Test 文件都需要显式导入 testexpect 函数
  2. 测试函数标记为 async
  3. Playwright Test 接收 page 作为参数之一。这是 Playwright Test 中众多实用 fixture 之一。
  4. 几乎所有 Playwright 调用都需要加上 await 前缀
  5. 使用 page.locator() 创建定位器是少数同步方法之一。

实现 waitForAngular 的 polyfill

Playwright Test 内置了自动等待机制,因此在大多数情况下不再需要 protractor 的 waitForAngular 功能。

但在某些边缘情况下,这个功能可能仍然有用。以下是在 Playwright Test 中实现 waitForAngular polyfill 的方法:

  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)上运行 所有浏览器引擎(Chrome、Firefox、Safari)的测试
  • 全面支持多源站、(i)frames标签页和上下文
  • 支持跨多浏览器并行运行测试
  • 内置测试产物收集功能

你还将获得这些 ✨ 超棒工具 ✨(它们已内置在 Playwright Test 中):

延伸阅读

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