We've recently rolled out Playwright 2025 features in our team and accumulated a good deal of experience. Sharing it here as a reference, hoping it helps others tackling similar challenges.
Quick Start
Let's start by looking at the basic implementation:
javascript
import { test, expect } from "@playwright/test";
import { render, screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test("button click", async ({ page }) => {
await page.goto("/buttons");
await page.getByRole("button", { name: "提交" }).click();
await expect(page.getByText("提交成功")).toBeVisible();
});
This snippet illustrates the fundamental usage. In real projects you'll also need to account for error handling and edge cases.
Advanced Usage
Building on this foundation, we can further optimize:
javascript
import { test, expect } from "@playwright/test";
import { render, screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test("form submission", async ({ page }) => {
await page.goto("/form");
await page.getByLabel("邮箱").fill("test@example.com");
await page.getByLabel("密码").fill("password123");
await page.getByRole("button", { name: "登录" }).click();
await expect(page).toHaveURL("/dashboard");
});
This approach improves both the testability and scalability of the code.
Case Studies
Here is a complete example:
javascript
import { test, expect } from "@playwright/test";
import { render, screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
test.describe("Shopping cart", () => {
test("add item to cart", async ({ page }) => {
await page.goto("/products");
await page
.getByTestId("product-1")
.getByRole("button", { name: "加入购物车" })
.click();
await expect(page.getByTestId("cart-count")).toHaveText("1");
});
});
Pay attention to edge-case handling—this is crucial in production environments.
Common Pitfalls
1. Avoid hard-coded waits (waitForTimeout)
→ Use waitForSelector, waitForResponse instead
2. Use page.getByRole instead of page.locator
→ Better accessibility semantics and more stable
3. Isolate test data
→ Each test should create/clean up its own data
4. Parallelize test execution
→ worker: 4; fullyParallel: true in playwright.config.ts
Summary
- Always verify compatibility before using in production
- In team collaboration, conventions and documentation matter more than the technology itself
- Stay up-to-date with community trends; technical solutions require continuous iteration