跳转到主要内容

从 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() 创建定位器是少数同步方法之一。

waitForAngular 添加垫片 (Polyfilling)

Playwright Test 内置了自动等待功能,这使得在一般情况下不再需要 Protractor 的 waitForAngular

然而,在某些边缘情况下它可能仍然有用。以下是在 Playwright Test 中为 waitForAngular 函数添加垫片的方法

  1. 确保您的 package.json 中已安装 protractor

  2. 垫片函数

    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. 垫片用法

    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)帧选项卡和上下文
  • 跨多个浏览器并行运行测试
  • 内置测试工件收集

您还将获得所有这些随 Playwright Test 捆绑的 ✨ 强大工具 ✨

进一步阅读

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