過去,End-to-End (E2E)測試是以Selenium為主,最近幾年逐漸被Playwright取代。Playwright支援Node.js、Python、Java跟.Net

當我們已經完成了我們的功能之後,我們可以利用Playwright錄腳本,未來修改程式時,就可以利用這個錄好的腳本迅速的測試我們的系統:

首先,安裝Playwright套件,點擊extensions,輸入playwright:

image.png

選擇「Playwright Test for VS Code」,點選「Install」:

image.png

點擊「Testing」,可以看到我們先前產生的測試,也可以看到下方的Playwright工具:

image.png

先啟動我們的網頁:

image.png

我們來測試完整的新增、修改、刪除。首先,為避免有意外的狀況,錄腳本時,最好就是以最乾淨的狀況,也就是從登入開始,一直到登出。另外,產品也是以新增、修改、刪除的順序進行,讓資料回到測試前的狀況。

點選「Record new」。

image.png

<aside> 📢

要注意,腳本裡會有我們輸入的帳號、密碼,如果我們使用的是權限比較高的測試帳號,要小心帳號密碼外洩,要把帳號、密碼儲存在.env裡

</aside>

錄製結束後,這是錄製好的腳本:

<aside> 💡

電子郵件、密碼先以XXXX代替。

</aside>

import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
  await page.goto('<http://localhost:3000/>');
  await page.getByRole('button', { name: '登入' }).click();
  await page.getByRole('textbox', { name: '電子郵件' }).click();
  await page.getByRole('textbox', { name: '電子郵件' }).fill('');
  await expect(page.getByText('用戶登入')).toBeVisible();
  await page.getByRole('textbox', { name: '電子郵件' }).click();
  await page.getByRole('textbox', { name: '電子郵件' }).fill('XXXX');
  await page.getByRole('textbox', { name: '密碼' }).click();
  await page.getByRole('textbox', { name: '密碼' }).fill('XXXX');
  await page.locator('form').getByRole('button', { name: '登入' }).click();
  await page.getByRole('banner').getByRole('button', { name: '產品管理' }).click();
  await page.getByRole('button', { name: 'add' }).click();
  await page.getByRole('textbox', { name: '產品名稱' }).click();
  await page.getByRole('textbox', { name: '產品名稱' }).fill('#test product#');
  await page.getByRole('spinbutton', { name: '價格' }).click();
  await page.getByRole('spinbutton', { name: '價格' }).fill('12000');
  await page.getByRole('button', { name: '新增' }).click();
  await expect(page.getByLabel('product list')).toContainText('#test product#');
  await expect(page.getByLabel('product list')).toContainText('NT$ 12000');
  await page.locator('li:nth-child(54) > .MuiListItemSecondaryAction-root > .MuiButtonBase-root.MuiIconButton-root.MuiIconButton-edgeEnd.MuiIconButton-sizeMedium.css-1hnclpu-MuiButtonBase-root-MuiIconButton-root').click();
  await page.getByRole('textbox', { name: '產品名稱' }).click();
  await page.getByRole('textbox', { name: '產品名稱' }).fill('#test product 2#');
  await page.getByRole('spinbutton', { name: '價格' }).click();
  await page.getByRole('spinbutton', { name: '價格' }).press('ArrowLeft');
  await page.getByRole('spinbutton', { name: '價格' }).press('ArrowLeft');
  await page.getByRole('spinbutton', { name: '價格' }).press('ArrowLeft');
  await page.getByRole('spinbutton', { name: '價格' }).fill('13000');
  await page.getByRole('button', { name: '儲存' }).click();
  await expect(page.getByLabel('product list')).toContainText('#test product 2#');
  await expect(page.getByLabel('product list')).toContainText('NT$ 13000');
  await page.locator('li:nth-child(54) > .MuiListItemSecondaryAction-root > .MuiButtonBase-root.MuiIconButton-root.MuiIconButton-edgeEnd.MuiIconButton-sizeMedium.css-wcomb0-MuiButtonBase-root-MuiIconButton-root').click();
  await page.getByRole('button', { name: '登出' }).click();
});

點選測試腳本旁的「Run Test」