Skip to main content

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

// 你寫下第一個測試,將它從清單中勾選
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,
});

// 你寫下第一個測試,將它從清單中勾選
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 提供 Polyfill

Playwright Test 內建自動等待,一般情況下不需要 Protractor 的 waitForAngular

不過在某些邊界情境時仍可能有用。以下是在 Playwright Test 中為 waitForAngular 提供 polyfill 的方式:

  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 支援
  • 在所有主流瀏覽器引擎(Chrome、Firefox、Safari)與常見作業系統(Windows、macOS、Ubuntu)上執行測試
  • 完整支援多來源、(i)frame分頁與情境(contexts)
  • 在多個瀏覽器間並行執行測試
  • 內建測試產物收集

此外還有這些 ✨ 超好用工具 ✨ 與 Playwright Test 一起提供:

延伸閱讀

深入了解 Playwright Test 測試執行器: