跳到主要内容

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

// 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);
});
});

逐行迁移到 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);
});
});

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

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

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 支持
  • 所有 Web 引擎 (Chrome, Firefox, Safari) 和 任何流行的操作系统 (Windows, macOS, Ubuntu) 上运行测试
  • 完全支持多源,(i)frames标签页和上下文
  • 跨多个浏览器并行运行测试
  • 内置测试工件收集

你还可以获得所有这些 ✨ 强大的工具 ✨,它们与 Playwright Test 捆绑在一起

延伸阅读

了解更多关于 Playwright Test 运行器