playwright-java – skill Lập trình cho agent AI
Khởi tạo, viết, debug và nâng cấp test E2E Playwright cấp doanh nghiệp bằng Java, dùng Page Object Model, JUnit 5, báo cáo Allure và chạy song song.
Cài skill playwright-java bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/playwright-java-5f9bd.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /playwright-java – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/playwright-java-5f9bd.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $playwright-java – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/playwright-java-5f9bd.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /playwright-java – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/playwright-java-5f9bd.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /playwright-java – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
Supporting material
The bundled files are [configuration](config.md), [page objects](page-objects.md), [assertions](assertions.md), [fixtures](fixtures.md), [BaseTest.java](BaseTest.java) and [BasePage.java](BasePage.java). Copy/adapt them into the target project with their dependencies; src/test/resources/junit-platform.properties below is a project file to create, not a bundled file.
Playwright Java – Advanced Test Automation
Overview
This skill supplies Playwright Java test patterns requiring project-specific compilation and execution.
It enforces the Page Object Model (POM), strict locator strategies, per-thread Playwright ownership for parallel
execution, and full Allure reporting integration. Targets Java 17+ and Playwright 1.44+.
Supporting reference files are available for deeper topics:
| Topic | File |
|-------|------|
| Maven POM, ConfigReader, Docker/CI setup | config.md |
| Component pattern, dropdowns, uploads, waits | page-objects.md |
| Full assertion API, soft assertions, visual testing | assertions.md |
| Fixtures, test data factory, auth state, retry | fixtures.md |
| Drop-in base class templates | BaseTest.java, BasePage.java |
---
When to Use This Skill
- Use when scaffolding a new Playwright Java project from scratch
- Use when writing Page Object classes or JUnit 5 test classes
- Use when the user asks about cross-browser testing, parallel execution, or Allure reports
- Use when fixing flaky tests or replacing
Thread.sleep()with proper waits - Use when setting up Playwright in CI/CD pipelines (GitHub Actions, Jenkins, Docker)
- Use when combining API calls and UI assertions in a single test (hybrid testing)
- Use when the user mentions "POM pattern", "BrowserContext", "Playwright fixtures", or "traces"
---
How It Works
Step 1: Decide the Approach
Use this matrix to pick the right pattern before writing any code:
| User Request | Approach |
|---|---|
| New project from scratch | Full scaffold — see config.md |
| Single feature test | POM page class + JUnit5 test class |
| API + UI hybrid | APIRequestContext alongside Page |
| Cross-browser | @MethodSource parameterized over browser names |
| Flaky test fix | Replace sleep with waitFor / waitForResponse |
| CI integration | playwright install --with-deps in pipeline |
| Parallel execution | junit-platform.properties + ThreadLocal |
| Rich reporting | Allure + Playwright trace + video recording |
---
Step 2: Scaffold the Project Structure
Always use this layout when creating a new project:
src/
├── test/
│ ├── java/com/company/tests/
│ │ ├── base/
│ │ │ ├── BaseTest.java ← BaseTest.java
│ │ │ └── BasePage.java ← BasePage.java
│ │ ├── pages/
│ │ │ └── LoginPage.java
│ │ ├── tests/
│ │ │ └── LoginTest.java
│ │ ├── utils/
│ │ │ ├── TestDataFactory.java
│ │ │ └── WaitUtils.java
│ │ └── config/
│ │ └── ConfigReader.java
│ └── resources/
│ ├── test.properties
│ ├── junit-platform.properties
│ └── testdata/users.json
pom.xml---
Step 3: Set Up Thread-Safe BaseTest
Use the bundled BaseTest.java, with the matching ConfigReader from config.md; it registers resources before fallible tracing/page creation and removes thread-local values during teardown.
---
Step 4: Build Page Object Classes
public class LoginPage extends BasePage {
// Declare ALL locators as fields — never inline in action methods
private final Locator emailInput;
private final Locator passwordInput;
private final Locator loginButton;
private final Locator errorMessage;
public LoginPage(Page page) {
super(page);
emailInput = page.getByLabel("Email address");
passwordInput = page.getByLabel("Password");
loginButton = page.getByRole(AriaRole.BUTTON,
new Page.GetByRoleOptions().setName("Sign in"));
errorMessage = page.getByTestId("login-error");
}
@Override protected String getUrl() { return "/login"; }
// Navigation methods return the next Page Object — enables fluent chaining
public DashboardPage loginAs(String email, String password) {
fill(emailInput, email);
fill(passwordInput, password);
clickAndWaitForNav(loginButton, "**/dashboard");
return new DashboardPage(page);
}
public LoginPage loginExpectingError(String email, String password) {
fill(emailInput, email);
fill(passwordInput, password);
loginButton.click();
errorMessage.waitFor();
return this;
}
public String getErrorMessage() { return errorMessage.textContent(); }
}---
Step 5: Write Tests with Allure Annotations
class LoginTest extends BaseTest {
private LoginPage loginPage;
@BeforeEach
void openLoginPage() {
loginPage = new LoginPage(page());
loginPage.navigate();
}
@Test
@Severity(SeverityLevel.BLOCKER)
@DisplayName("Valid credentials redirect to dashboard")
void shouldLoginWithValidCredentials() {
User user = TestDataFactory.getDefaultUser();
DashboardPage dash = loginPage.loginAs(user.email(), user.password());
assertThat(page()).hasURL(Pattern.compile(".*/dashboard"));
assertThat(dash.getWelcomeBanner()).containsText("Welcome, " + user.firstName());
}
@Test
void shouldShowErrorOnInvalidCredentials() {
loginPage.loginExpectingError("[email protected]", "wrongpass");
SoftAssertions softly = new SoftAssertions();
softly.assertThat(loginPage.getErrorMessage()).contains("Invalid email or password");
assertThat(page()).hasURL(Pattern.compile(".*/login"));
softly.assertAll();
}
@ParameterizedTest
@MethodSource("provideInvalidCredentials")
void shouldRejectInvalidCredentials(String email, String password, String expectedError) {
loginPage.loginExpectingError(email, password);
org.assertj.core.api.Assertions.assertThat(loginPage.getErrorMessage()).contains(expectedError);
}
static Stream<Arguments> provideInvalidCredentials() {
return Stream.of(
Arguments.of("", "password123", "Email is required"),
Arguments.of("[email protected]", "", "Password is required"),
Arguments.of("notanemail", "pass", "Invalid email format")
);
}
}---
Examples
Example 1: API + UI Hybrid Test
@Test
void shouldDisplayNewlyCreatedOrder() {
// Arrange via API — faster than navigating through UI
APIRequestContext api = page().context().request();
APIResponse response = api.post("/api/orders",
RequestOptions.create()
.setHeader("Authorization", "Bearer " + authToken)
.setData(Map.of("productId", "SKU-001", "quantity", 2)));
assertThat(response).isOK();
String orderId = new JsonParser().parse(response.text())
.getAsJsonObject().get("id").getAsString();
OrdersPage orders = new OrdersPage(page());
orders.navigate();
assertThat(orders.getOrderRowById(orderId)).isVisible();
}Example 2: Network Mocking
@Test
void shouldHandleApiFailureGracefully() {
page().route("**/api/products", route -> route.fulfill(
new Route.FulfillOptions()
.setStatus(503)
.setBody("{\"error\":\"Service Unavailable\"}")
.setContentType("application/json")));
ProductsPage products = new ProductsPage(page());
products.navigate();
assertThat(products.getErrorBanner())
.hasText("We're having trouble loading products. Please try again.");
}Example 3: Cross-Browser Execution
Run separate Maven processes/jobs with -Dbrowser=chromium, firefox and webkit. Do not set a process-global system property inside a parameterized test: setup already launched the browser and parallel tests race on that property. Give each job a unique artifact name.
Example 4: Parallel Execution Config
# src/test/resources/junit-platform.properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4Example 5: GitHub Actions CI Pipeline
- name: Install Playwright browsers
run: mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="install --with-deps"
- name: Run tests
run: mvn test -Dbrowser=${{ matrix.browser }} -Dheadless=true
- name: Upload traces on failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-traces-${{ matrix.browser }}
path: target/traces/
- name: Upload Allure results
uses: actions/upload-artifact@v4
if: always()
with:
name: allure-results-${{ matrix.browser }}
path: target/allure-results/… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- poka-yoke – Chống lỗi cho code, cấu hình và quy trình: làm cho hành động sai trở nên không thể hoặc…
- polars – Thư viện DataFrame theo biểu thức cho Python và Rust. Dùng cho phân tích bảng dạng eager…
- policy-as-code – Triển khai policy as code với OPA, Sentinel và Kyverno. Tự động hóa thực thi chính sách…
- policy-library – Sổ đăng ký chính sách: tên, phiên bản, danh mục, chủ sở hữu và người phê duyệt, phạm vi…
- power-user-cultivation – Khi người dùng muốn tìm và nuôi dưỡng developer advocate, xây dựng chương trình…
- pre-release-review – Chạy rà soát chỉ đọc trước khi phát hành để kiểm tra mức sẵn sàng triển khai, migration…
- privacy-mask – Che, làm mờ, ẩn danh và kiểm duyệt thông tin nhạy cảm (PII) trong ảnh chụp màn hình và…
- probation-tracker – Sổ theo dõi thử việc: nhân viên, ngày bắt đầu và kết thúc, điểm đánh giá ở mốc 30, 60 và…