跳到主要內容

從 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 中眾多 實用的 fixture 之一。
  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 執行器