跳至主要内容

从 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 中众多 有用夹具 之一。
  4. 几乎所有 Playwright 调用都以 await 为前缀
  5. 使用 page.locator() 创建定位器是为数不多的同步方法之一。

填充 waitForAngular

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

你还可以获得与 Playwright Test 捆绑在一起的这些 ✨ 绝佳工具 ✨

进一步阅读

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