Playwright Test
Neben seiner Funktion als Browser-Automatisierungswerkzeug verfügt Playwright außerdem über einvollständiges Test-Framework —— Playwright Test。
Playwright Test hilft uns, Testfälle zu organisieren, Berichte zu generieren, parallel auszuführen, bei Fehlern erneut zu versuchen, und ist von Haus aus voll funktionsfähig.
- Playwright Test ist einintegriertes Test-Framework, ohne zusätzliche Abhängigkeiten.
- Die Konfigurationsdatei kannTimeout, Wiederholungen, Berichte, Browser-Projekteusw. festlegen.
- Testfälle unterstützenGruppierung, Hooks, datengetriebene Tests。
- und bietenparallele Ausführung, HTML-Berichte, Wiederholungen bei Fehlernund weitere fortgeschrittene Funktionen.
Überblick über das Test-Framework
- Integriertes Test-Framework: enthält einen integrierten Test-Runner, Jest oder Mocha müssen nicht separat installiert werden.
- Integrierte Assertion-Bibliothek: unterstützt
expectAssertions. - Testisolierung: Jeder
testläuft standardmäßig in einem neuen Browser-Kontext, unabhängig voneinander. - Umfangreiche Funktionen: parallele Ausführung, Wiederholungen, Screenshots, Aufzeichnung, HTML-Berichte, usw.
Installationsmethode:
npm init playwright@latest
Projektstruktur automatisch generieren, einschließlich Konfigurationsdateiplaywright.config.js。
1. Details zur Konfigurationsdatei
Playwright Test verwendetplaywright.config.js(oder.ts) als Einstiegspunkt für die Konfiguration.
// playwright.config.js
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests', // 测试目录
timeout: 30 * 1000, // 单个测试超时时间
retries: 2, // 失败重试次数
reporter: [['html'], ['list']], // 测试报告类型
use: {
headless: true, // 是否无头模式
screenshot: 'only-on-failure', // 失败时截图
video: 'retain-on-failure', // 失败时保留视频
baseURL: 'https://example.com', // 基础 URL
},
projects: [
{ name: 'Chromium', use: { browserName: 'chromium' } },
{ name: 'Firefox', use: { browserName: 'firefox' } },
{ name: 'WebKit', use: { browserName: 'webkit' } },
],
});
2. Struktur des Testskripts
Playwright Test-Skripte enthalten normalerweise:
1. Testbibliothek importieren
import { test, expect } from '@playwright/test';
2. Testfälle schreiben
test('示例测试', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveTitle('Example Domain');
});
3. Gruppierung und Hooks
- Verwenden Sie
describezum Organisieren von Tests - Verwenden Sie
beforeEach/afterEachfür Setup und Teardown
Schreiben von Testfällen
1. test()Funktionsverwendung
test('页面标题验证', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveTitle(/Playwright/);
});
2. describe()Gruppierung
test.describe('用户登录模块', () => {
test('输入正确账号密码', async ({ page }) => {
// 登录逻辑...
});
test('输入错误密码', async ({ page }) => {
// 验证错误提示...
});
});
3. Test-Hooks
test.describe('购物车模块', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://example.com/cart');
});
test.afterEach(async ({ page }) => {
await page.screenshot({ path: 'cart.png' });
});
test('添加商品', async ({ page }) => {
await page.click('#add-item');
await expect(page.locator('#cart-count')).toHaveText('1');
});
});
4. Testdatenvorbereitung
Unterstützt parametrisierte Tests:
const users = [
{ name: 'admin', password: '123456' },
{ name: 'guest', password: 'guest' },
];
for (const user of users) {
test(`用户 ${user.name} 登录`, async ({ page }) => {
await page.goto('https://example.com/login');
await page.fill('#username', user.name);
await page.fill('#password', user.password);
await page.click('#submit');
await expect(page.locator('.welcome')).toBeVisible();
});
}
Ausführung und Berichterstattung
1. Testausführungsbefehle
npx playwright test # 运行全部测试 npx playwright test login.spec.js # 运行单个文件 npx playwright test -g "登录" # 运行指定用例
2. Paralleles Testen
Playwright standardmäßigführt Dateien parallel aus, oder du kannst die Anzahl der Worker in der Konfigurationsdatei angeben:
npx playwright test --workers=4
3. Testberichterstellung
Nach der AusführungHTML-Bericht generieren:
npx playwright show-report
4. Wiederholungsmechanismus bei Fehlschlägen
In der Konfigurationsdateiplaywright.config.jsfestlegen:
retries: 2
Wenn ein Test fehlschlägt, wird er automatisch wiederholt, geeignet für den Umgang mit sporadischen Fehlern.
- Playwright Test ist einintegriertes Test-Framework, keine zusätzlichen Abhängigkeiten erforderlich.
- Die Konfigurationsdatei kannTimeout, Wiederholungen, Berichte, Browser-Projekteusw. festlegen.
- Testfälle unterstützenGruppierung, Hooks, datengetriebene Tests。
- und bietenparallele Ausführung, HTML-Berichte, Wiederholungen bei Fehlernund weitere fortgeschrittene Funktionen.
Beispiel für eine vollständige Testsuite
1. Projektstruktur
playwright-demo/ ├─ playwright.config.ts # 全局配置(多项目、多浏览器、报告、重试…) ├─ package.json ├─ tests/ │ ├─ auth.setup.ts # 一次性登录,生成 storageState │ ├─ smoke/ │ │ └─ home.spec.ts # 冒烟用例:标题/URL/截图对比 │ └─ e2e/ │ └─ cart.spec.ts # 端到端:添加购物车、断言、附件、步骤 ├─ fixtures/ │ ├─ pages.ts # 页面对象(PO) │ └─ test.extend.ts # 自定义 fixtures └─ snapshots/ # 视觉基线(自动生成)
2. Konfigurationsdatei (playwright.config.ts)
Beispiel
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30_000,
retries: 2,
workers: 4,
reporter: [['html', { outputFolder: 'report' }], ['list']],
forbidOnly: !!process.env.CI,
// Einheitliche Standardverwendung (kann auf Projekt- oder Testebene überschrieben werden)
Verwenden Sie: {
baseURL: 'https://demo.playwright.dev',
headless: true,
screenshot: 'only-on-failure',
video: 'retain-on-failure',
trace: 'retain-on-failure',
viewport: { width: 1366, height: 900 },
locale: 'zh-CN',
},
// Mehrere Projekte: verschiedene Browser/Geräte/Login-Zustände
projects: [
{ name: 'Chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'Firefox', use: { ...devices['Desktop Firefox'] } },
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 7'], headless: wahr },
},
// Projekt mit Login-Zustand (storageState wiederverwenden)
{
name: 'Chromium Logged-in',
use: { storageState: 'storageState.json' },
dependencies: ['setup'], // Hängt von einem Setup-Projekt ab, um den Login-Zustand zu generieren
},
// Setup-Projekt: wird einmal ausgeführt, um storageState zu generieren
{
name: 'setup',
testMatch: /auth\.setup\.ts/,
},
],
});
Wichtige Punkte:Projekte ermöglichen, dass dieselbe Testsuite in verschiedenen Browsern/Konfigurationen ausgeführt wird; use kann auf globaler/Projekt-/Testebene überschrieben werden; Berichte und Wiederholungsversuche werden zentral in der Konfiguration verwaltet.
3. Fixtures und Page Objects
fixtures/test.extend.ts (benutzerdefinierte Fixtures + Kapselung gemeinsamer Schritte)
Beispiel
import { test as base } from '@playwright/test';
import { HomePage, CartPage } from './pages';
type MyFixtures = {
home: HomePage;
cart: CartPage;
};
export const test = base.extend<MyFixtures>({
home: async ({ page }, use) => {
const home = new HomePage(page);
await use(home);
},
cart: async ({ page }, use) => {
const cart = new CartPage(page);
await use(cart);
},
});
export { expect } from '@playwright/test';
Fügen Sie benutzerdefinierte Fixtures basierend auf test.extend() hinzu, sodass sich home- und cart-Instanzen in jedem Testfall direkt injizieren lassen.
fixtures/pages.ts (Page Objects)
Beispiel
import { Page, expect } from '@playwright/test';
export class HomePage {
constructor(private page: Page) {}
async goto() { await this.page.goto('/'); }
get tryTodoLink() { return this.page.getByRole('link', { name: /ToDo MVC/i }); }
}
export class CartPage {
constructor(private page: Page) {}
async goto() { await this.page.goto('/e2e'); } // Angenommen, eine e2e-Beispielseite existiert
get addFirstItem() { return this.page.getByRole('button', { name: /Add .* #1/i }); }
get cartCount() { return this.page.locator('[data-test=cart-count]'); }
async addOne() { await this.addFirstItem.click(); }
async expectCount(n: number) { await expect(this.cartCount).toHaveText(String(n)); }
}
4. Vorab-Anmeldung (storageState einmal generieren)
tests/auth.setup.ts (läuft nur im Projekt "setup")
Beispiel
import { test, expect } from '@playwright/test';
test('create storageState', async ({ page }) => {
await page.goto('https://demo.playwright.dev/todomvc');
// ...Ersetzen Sie durch Ihren Login-Ablauf...
// Angenommen, die Anmeldung ist erfolgreich
await expect(page).toHaveURL(/todomvc/);
await page.context().storageState({ path: 'storageState.json' });
});
5. Smoke-Tests (Titel/URL/Visueller Vergleich)
tests/smoke/home.spec.ts
Beispiel
test.describe('Smoke - Home', () => {
test('title & url & visual snapshot', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveTitle(/Playwright/);
await expect(page).toHaveURL(/playwright\.dev/);
// Visuelle Regression (Basislinie automatisch generieren/vergleichen)
await expect(page).toHaveScreenshot(); // Der erste Durchlauf erzeugt eine Basislinie
});
});
Für den visuellen Vergleich wird empfohlen, toHaveScreenshot zu verwenden (bevorzugt gegenüber dem manuellen Ansatz mit page.screenshot() + toMatchSnapshot).
6. End-to-End-Tests (Schritte, Anhänge, Assertions)
tests/e2e/cart.spec.ts
Beispiel
test.describe.configure({ mode: 'parallel' });
test.describe('E2E - Warenkorb', () => {
test.beforeEach(async ({ home }) => {
await test.step('Zur Startseite gehen', async () => {
await home.goto();
});
});
test('Produkt zum Warenkorb hinzufügen (mit Anhang und Assertion)', async ({ page, cart }) => {
await test.step('Zur Warenkorbseite gehen und Produkt hinzufügen', async () => {
await cart.goto();
await cart.addOne();
await cart.expectCount(1);
});
await test.step('Debug-Informationen zum Bericht hinzufügen', async () => {
await test.info().attach('state.json', {
contentType: 'application/json',
body: Buffer.from(JSON.stringify({ ts: Date.now(), note: 'nach dem Hinzufügen' })),
});
});
// Screenshot auf Elementebene
await test.step('Element-Screenshot', async () => {
const badge = page.locator('[data-test=cart-count]');
await expect(badge).toBeVisible();
await expect(badge).toHaveScreenshot(); // Element-Snapshot
});
});
});
Verwenden Sie test.step, um Schritte hierarchisch aufzuzeichnen, und verwenden Sie test.info().attach(), um Debug-Daten/Screenshots zur einfacheren Fehlersuche an den Bericht anzuhängen; im Parallelmodus kann describe.configure({ mode: 'parallel' }) verwendet werden.
7. Ausführung und Berichterstattung
Gängige Befehle:
npx playwright test # 运行全部 npx playwright test tests/e2e # 运行目录 npx playwright test -g "Cart" # 按标题过滤 npx playwright test --project="Chromium" # 指定项目 npx playwright show-report # 打开HTML报告 npx playwright test --update-snapshots # 更新视觉基线 npx playwright test --debug # 调试模式(Inspector)
Informationen zur CLI-Filterung, Projektauswahl, Berichtsanzeige, Snapshot-Aktualisierungen usw. finden Sie in der offiziellen CLI-/Reporting-/Snapshot-Dokumentation.
Kurzreferenz für häufig verwendete zugehörige APIs (Playwright Test)
1. Tests und Gruppierung
| API | Zweck |
|---|---|
test(name, fn) |
Tests definieren |
test.describe(title, fn) |
Gruppierung |
test.describe.configure({ mode }) |
parallel / serial |
test.beforeAll/afterAll |
Before-/After-Hooks auf Gruppenebene |
test.beforeEach/afterEach |
Before-/After-Hooks für Testfälle |
test.skip/only/fixme/slow/fail |
Testfälle markieren/steuern |
2. Fixtures und Konfiguration
| API | Zweck |
|---|---|
test.extend<Fixtures>(defs) |
Benutzerdefinierte Fixtures erweitern |
test.use(options) |
Überschreibung auf TestebeneuseOptionen (wie z. B.storageState、viewport、localeusw.) |
defineConfig({...}) |
Eintrag in der Konfigurationsdatei (testDir、retries、workers、reporter…) |
projects |
Ausführung von Multi-Projekt-/Multi-Browser-/verschiedenen Konfigurationen |
use: { baseURL, trace, video, screenshot, viewport, locale, timezoneId, storageState } |
Laufzeitumgebung und Aufnahmestrategie |
Details zu Fixtures / Verwendung / Konfigurationsoptionen und Projekten finden Sie in der offiziellen Dokumentation "Fixtures / Use options / Configuration / Projects". (Playwright)
3. Assertions (expect)
| API | Zweck | |
|---|---|---|
expect(value).toBe / toEqual / toContain ... |
Allgemeine Assertions | |
expect(locator).toHaveText/Value/Attribute |
Webspezifische Assertions (mit intelligentem Warten) | |
expect(locator).toBeVisible/Hidden/Enabled/Disabled/Checked |
Zustands-Assertions | |
expect(page).toHaveTitle/URL |
Seiten-Assertions | |
| `expect(page/locator).toHaveScreenshot([name | options])` | Visueller Snapshot-Vergleich (empfohlen) |
Empfohlene Vorgehensweisen für Assertions und visuelle Snapshots finden Sie in der Dokumentation zu Assertions und Snapshots.(Playwright)
4. Schritte und Anhänge
| API | Zweck | |
|---|---|---|
test.step(name, fn) |
Tests in Schritte unterteilen (Visualisierung im Bericht) | |
| `test.info().attach(name, { path | body, contentType })` | Dateien/Daten an Tests oder Schritte anhängen (im Bericht angezeigt) |
Anhänge können auch auf Schritt-Ebene angewendet werden (siehe TestStep / TestStepInfo).(Playwright)
5. Berichterstellung und CLI
| Befehl/Konfiguration | Zweck |
|---|---|
reporter: [['html', { outputFolder }], ['list']] |
Berichtskonfiguration |
npx playwright test --project="Chromium" |
Projekt zum Ausführen auswählen |
-g "keyword" / --grep / --grep-invert |
Testfälle filtern |
--update-snapshots |
Visuelle Baselines aktualisieren |
npx playwright show-report |
Bericht öffnen |
Weitere ErweiterungenSiehe die offizielle Dokumentation für die vollständigen CLI- und Reporter-Optionen.(Playwright)