使用 Playwright 進行自動化端對端測試
1. 概述
端到端測試是決定軟體產品整體工作的重要因素之一。它有助於發現在單元和整合測試階段可能被忽視的問題,並有助於確定軟體是否按預期工作。
執行可能包括多個使用者步驟和旅程的端到端測試是乏味的。因此,一種可行的方法是進行端到端測試案例的自動化測試。
在本文中,我們將學習如何使用 Playwright 和 TypeScript 自動化端對端測試。
2.什麼是劇作家端對端測驗?
Playwright 端對端測試是幫助開發人員和測試人員模擬真實使用者與網站互動的過程。借助 Playwright,我們可以自動執行一些任務,例如點擊按鈕、填寫表單以及瀏覽頁面以檢查一切是否如預期運作。它適用於 Chrome、Firefox、Safari 和 Edge 等流行瀏覽器。
3.劇作家端到端測試的先決條件
若要使用 Playwright ,請安裝**NodeJS 版本 18 或更高版本**以及 TypeScript。有兩種安裝 Playwright 的方法:
- 使用命令列
- 使用 VS 程式碼
不過,在本文中,我們將使用 VS Code 安裝 Playwright。
- 從 VS Code 市場安裝 Playwright 後,讓我們打開命令面板並執行命令
Install Playwright:
- 讓我們安裝所需的瀏覽器。然後我們點選確定:
- 安裝完成後,我們將得到package.json檔案中包含相依性的資料夾結構:
4. 如何與Playwright進行端對端測試?
端到端測試涵蓋最終用戶理想遵循的用例。讓我們考慮一下用於編寫端到端測試的LambdaTest eCommerce Playground網站。
我們將**使用 LambdaTest 這樣的基於雲端的測試平台來實現端到端測試的更高可擴展性和可靠性**。 LambdaTest是一個由 AI 驅動的測試執行平台,可使用 Playwright 在 3000 多個真實瀏覽器和作業系統上提供自動化測試。
4.1.測試場景1
- 在 LambdaTest eCommerce Playground 網站上註冊新用戶。
- 執行斷言以檢查使用者是否已成功註冊。
4.2.測試場景2
- 執行斷言以檢查使用者是否已登入。
- 在主頁上搜尋產品。
- 選擇產品並將其添加到購物車。
- 執行斷言以檢查是否將正確的產品添加到購物車。
4.3.測試配置
讓我們建立一個固定文件,該文件將透過覆蓋storageState 固定裝置對每個工作人員進行一次身份驗證。我們可以使用testInfo.parallelIndex來區分工人。
此外,我們可以使用相同的固定檔案來設定 LambdaTest 功能。現在,我們建立一個名為 base 的新資料夾和一個新檔案page-object-model-fixture.ts 。
第一個區塊包含來自其他專案目錄的 npm 套件和檔案的導入語句。我們將導入expect 、 chromium和test作為baseTest變量,並使用dotenv來取得環境變數。然後我們直接在fixture檔案中聲明頁面物件類別實例並進行測試。
下一個區塊涉及新增 LambdaTest 功能:
const modifyCapabilities = (configName, testName) => {
let config = configName.split("@lambdatest")[0];
let [browserName, browserVersion, platform] = config.split(":");
capabilities.browserName = browserName;
capabilities.browserVersion = browserVersion;
capabilities["LT:Options"]["platform"] =
platform || capabilities["LT:Options"]["platform"];
capabilities["LT:Options"]["name"] = testName;
};
我們可以使用LambdaTest 功能產生器輕鬆產生這些功能。下一行將透過自訂和建立專案名稱來使用 LambdaTest 功能。專案名稱最好是瀏覽器、瀏覽器版本和平台名稱組合,可以使用chrome:latest:macOS Sonoma@lambdatest 格式:
projects: [
{
name: "chrome:latest:macOS Sonoma@lambdatest",
use: {
viewport: {
width: 1920,
height: 1080,
},
},
},
{
name: "chrome:latest:Windows 10@lambdatest",
use: {
viewport: {
width: 1280,
height: 720,
},
},
},
下一個程式碼區塊被分成兩個部分。在第一部分中,聲明了testPages常數變量,並將其分配給baseTest擴展了最初在固定文件中聲明的頁面類型以及workerStorageState :
const testPages = baseTest.extend<pages, { workerStorageState: string; }>({
page: async ({}, use, testInfo) => {
if (testInfo.project.name.match(/lambdatest/)) {
modifyCapabilities(testInfo.project.name, `${testInfo.title}`);
const browser =
await chromium.connect(
`wss://cdp.lambdatest.com/playwright?capabilities=
${encodeURIComponent(JSON.stringify(capabilities))}`
);
const context = await browser.newContext(testInfo.project.use);
const ltPage = await context.newPage();
await use(ltPage);
const testStatus = {
action: "setTestStatus",
arguments: {
status: testInfo.status,
remark: getErrorMessage(testInfo, ["error", "message"]),
},
};
await ltPage.evaluate(() => {},
`lambdatest_action: ${JSON.stringify(testStatus)}`
);
await ltPage.close();
await context.close();
await browser.close();
} else {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
await use(page);
}
},
homePage: async ({ page }, use) => {
await use(new HomePage(page));
},
registrationPage: async ({ page }, use) => {
await use(new RegistrationPage(page));
},
});
在該區塊的第二部分中,設定了workerStorageState ,其中每個平行工作執行緒都經過一次身份驗證。所有測試都使用工作人員執行的相同身份驗證狀態:
storageState: ({ workerStorageState }, use) =>
use(workerStorageState),
workerStorageState: [
async ({ browser }, use) => {
const id = test.info().parallelIndex;
const fileName = path.resolve(
test.info().project.outputDir,
`.auth/${id}.json`
);
},
],
每個工作人員將使用工作人員範圍的固定裝置進行一次身份驗證。我們需要透過取消儲存狀態來確保在乾淨的環境中進行身份驗證:
const page = await browser.newPage({ storageState: undefined });
接下來應該在固定文件中更新身份驗證過程。它包括用戶註冊步驟,如測試場景 1 所述。
4.4.實施:測試場景1
首先,我們將建立兩頁物件類別來保存與每個頁面元素互動的定位器和函數。讓我們在測試資料夾中建立一個名為 pageobjects 的新資料夾。第一頁物件類別將用於主頁:
import { Page, Locator } from "@playwright/test";
import { SearchResultPage } from "./search-result-page";
export class HomePage {
readonly myAccountLink: Locator;
readonly registerLink: Locator;
readonly searchProductField: Locator;
readonly searchBtn: Locator;
readonly logoutLink: Locator;
readonly page: Page;
constructor(page: Page) {
this.page = page;
this.myAccountLink = page.getByRole("button", { name: " My account" });
this.registerLink = page.getByRole("link", { name: "Register" });
this.logoutLink = page.getByRole("link", { name: " Logout" });
this.searchProductField = page.getByPlaceholder("Search For Products");
this.searchBtn = page.getByRole("button", { name: "Search" });
}
async hoverMyAccountLink(): Promise<void> {
await this.myAccountLink.hover({ force: true });
}
async navigateToRegistrationPage(): Promise<void> {
await this.hoverMyAccountLink();
await this.registerLink.click();
}
}
在主頁上,我們首先需要將滑鼠懸停在「我的帳戶」連結上以開啟下拉式選單,然後點擊註冊連結以開啟註冊頁面:
在 Chrome 的「DevTools」視窗中,「我的帳號」WebElement 角色是a button.因此,讓我們使用以下程式碼找到此連結:
this.myAccountLink = page.getByRole("button", { name: " My account" });
讓我們將滑鼠懸停在MyAccount Link上以開啟下拉清單進行查看,然後點擊註冊連結:
async hoverMyAccountLink(): Promise<void> {
await this.myAccountLink.hover({ force: true });
}
必須找到註冊連結並點擊才能開啟註冊頁面。我們可以注意到 Chrome DevTools 中的registerLink定位器;此 WebElement 的作用是連結:
以下函數將滑鼠懸停在MyAccountLink上,當下拉清單開啟時,它將找到並點擊registerLink :
async navigateToRegistrationPage(): Promise<void> {
await this.hoverMyAccountLink();
await this.registerLink.click();
}
讓我們為註冊頁面建立第二頁物件類,它將包含用於執行互動的所有欄位和函數:
async registerUser(
firstName: string,
lastName: string,
email: string,
telephoneNumber: string,
password: string
): Promise<MyAccountPage> {
await this.firstNameField.fill(firstName);
await this.lastNameField.fill(lastName);
await this.emailField.fill(email);
await this.telephoneField.fill(telephoneNumber);
await this.passwordField.fill(password);
await this.confirmPassword.fill(password);
await this.agreePolicy.click();
await this.continueBtn.click();
return new MyAccountPage(this.page);
}
我們可以使用getByLabel()函數來定位字段,然後建立registerUser()函數來互動並完成註冊。
讓我們為標頭斷言建立 my-account-page.ts 並更新註冊場景的固定檔案。我們將使用navigateToRegistrationPage()存取註冊頁面並聲明註冊帳戶標題。然後,我們將使用來自register-user-data.json資料從RegistrationPage類別呼叫registerUser() 。
註冊後,我們會斷言檢查頁面標題「您的帳戶已建立! 「在我的帳戶頁面上可見。
4.5.實作:測試場景2
我們將在第二個測試場景中新增產品並驗證購物車詳細資訊是否顯示正確的值。
第一個斷言檢查MyAccountLink是否已登入。
現在,我們將使用主頁中的搜尋框來搜尋產品。
我們將透過在搜尋框中輸入值並點擊搜尋按鈕來搜尋iPhone 。 *searchForProduct()*函數將幫助我們搜尋產品並傳回SearchResultPage:
const searchResultPage = await homePage.searchForProduct("iPhone");
await searchResultPage.addProductToCart();
搜尋結果將顯示在earchResultP s上age. *addProductToCart()*函數會將滑鼠停留在搜尋結果中檢索到的頁面上的第一個產品上。當滑鼠懸停在產品上時,它將單擊“添加到購物車”按鈕。
將出現一個通知彈出窗口,顯示確認文字:
await expect(searchResultPage.successMessage).toContainText(
"Success: You have added iPhone to your shopping cart!"
);
const shoppingCart = await searchResultPage.viewCart();
要確認購物車中包含產品,請先在彈出視窗中斷言確認文本,然後點擊viewCart按鈕導航到購物車頁面。
一個斷言最終驗證購物車中的產品名稱iPhone確認了搜尋到的產品的添加:
await expect(shoppingCart.productName).toContainText("iPhone");
4.6.測試執行
以下命令將在本機電腦上的 Google Chrome 瀏覽器上執行測試:
$ npx playwright test --project=\"Google Chrome\"
以下命令將在 LambdaTest 雲端網格上的 macOS Sonoma 上的最新 Google Chrome 版本上執行測試:
$ npx playwright test --project=\"chrome:latest:macOS Sonoma@lambdatest\"
讓我們更新package.json檔案中腳本區塊中的對應命令:
"scripts": {
"test_local": "npx playwright test --project=\"Google Chrome\"",
"test_cloud": "npx playwright test --project=\"chrome:latest:macOS Sonoma@lambdatest\""
}
因此,如果我們想在本地運行測試,請執行命令:
$ npm run test_local
要在 LambdaTest 雲端網格上執行測試,我們可以執行以下命令:
$ npm run test_cloud
測試執行後,我們可以在 LambdaTest Web Automation Dashboard 和建置詳細資訊視窗中查看測試結果:
建立詳細資訊畫面提供平台、瀏覽器名稱及其各自版本、影片、日誌、執行的命令以及執行測試所需的時間等資訊。
5. 結論
Playwright 是一個輕量級且易於使用的測試自動化框架。開發人員和測試人員可以使用多種程式語言輕鬆配置它。
將 Playwright 與 TypeScript 結合使用更加靈活和簡單,因為我們不必編寫太多的樣板程式碼來進行配置和設定。我們需要執行一個簡單的安裝命令,然後立即開始編寫測試。
本文中使用的源代碼可在 GitHub 上取得。