Skip to main content

從 Protractor 遷移

遷移原則

Cheat Sheet

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 測試文件都有明確的 testexpect 函式匯入
  2. 測試函式標記為 async
  3. Playwright 測試給定一個 page 作為其參數之一。這是 Playwright 測試中許多有用的 fixtures之一。
  4. 幾乎所有的 Playwright 呼叫都以 await 為前綴
  5. 使用 page.locator() 建立定位器是少數同步的方法之一。

Polyfilling waitForAngular

Playwright Test 有內建的自動等待,這使得 protractor 的waitForAngular在一般情況下不再需要。

然而,它可能在某些邊緣情況下派上用場。以下是如何在 Playwright Test 中填補 waitForAngular 函式:

  1. 確保你在 package.json 中安裝了 protractor

  2. Polyfill function

    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 usage

    const page = await context.newPage();
    await page.goto('https://example.org');
    await waitForAngular(page);

Playwright Test 超能力

一旦你使用 Playwright 測試,你會獲得很多!

  • 完整的零配置 TypeScript 支援
  • 所有網頁引擎(Chrome、Firefox、Safari)上,於任何流行的作業系統(Windows、macOS、Ubuntu)上執行測試
  • 完整支援多個來源,(i)frames分頁和上下文
  • 在多個瀏覽器中平行執行測試
  • 內建測試 artifact collection

你還會獲得所有這些 ✨ 很棒的工具 ✨,這些工具與 Playwright Test 一起捆綁提供:

延伸閱讀

了解更多關於 Playwright 測試執行器: