원클릭으로
create-e2e-test
Create end-to-end tests using Playwright with page objects and fixtures following project conventions
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Create end-to-end tests using Playwright with page objects and fixtures following project conventions
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Expert-level design amplification for creating bold, distinctive, and memorable visual experiences. Use for enhancing typography, color, layout, and motion to achieve a strong visual impact while maintaining usability and coherence.
Manages Agent Platform serving endpoints. Use when you need to create, list, describe, update, or delete serving endpoints for model deployment on Agent Platform. Also use when troubleshooting endpoint permission, quota, or resource busy errors. Don't use for deploying models to endpoints or for running model evaluations.
Manages custom Agent resources on Gemini Enterprise Agent Platform. Use when the user wants to programmatically create, configure, list, update, or delete stateful, server-managed Agent resources (including mounting files, skills, and tools) before executing conversations.
Expert in building immersive scroll-driven experiences - parallax storytelling, scroll animations, interactive narratives, and cinematic web experiences. Like NY Times interactives, Apple product pages, and award-winning web experiences.
Create commit messages following Conventional Commit conventions. Use when committing code changes, writing commit messages, or formatting git history. Follows conventional commits with-specific issue references.
When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions "SEO audit," "technical SEO," "why am I not ranking," "SEO issues," "on-page SEO," "meta tags review," or "SEO health check." For building pages at scale to target keywords, see programmatic-seo. For adding structured data, see schema-markup.
| name | create-e2e-test |
| description | Create end-to-end tests using Playwright with page objects and fixtures following project conventions |
| user-invocable | true |
Create end-to-end tests for the user flow described below.
First, analyze the User Flow to identify:
Before writing code, explore relevant existing files:
apps/e2e-tests/
├── pages/ # Page Objects - check for reusable pages
├── fixtures/ # Base fixtures (auth.fixtures.ts)
└── tests/
└── [feature]/ # Existing test patterns
├── [feature].fixtures.ts
└── [feature].spec.ts
Key files to reference:
apps/e2e-tests/fixtures/auth.fixtures.ts - Authentication fixturesapps/e2e-tests/pages/SiteCreationPage.ts - Page object pattern exampleapps/e2e-tests/tests/site-creation/site-creation.fixtures.ts - Fixture composition exampleFor each page/screen in the flow, create or update a page object in apps/e2e-tests/pages/:
Page Object Pattern:
import { expect, type Page } from "@playwright/test";
export class FeaturePage {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
// Navigation
async goto(): Promise<void> {
await this.page.goto("/route-path");
}
// Assertions (prefix with expect*)
async expectStepVisible(): Promise<void> {
await expect(this.page.getByRole("heading", { name: "Step Title" })).toBeVisible();
}
// User Actions (verb-based names)
async clickButton(): Promise<void> {
await this.page.getByRole("button", { name: "Button Text" }).click();
}
async fillInput(value: string): Promise<void> {
await this.page.getByLabel("Input Label").fill(value);
}
async selectOption(value: string): Promise<void> {
await this.page.getByRole("radio", { name: value }).check({ force: true });
await this.submit();
}
// Private helpers
private async submit(): Promise<void> {
await this.page.getByRole("button", { name: /Valider|Suivant/ }).click();
}
}
Selector Priority (accessibility-first):
getByRole() - buttons, links, headings, textboxesgetByLabel() - form inputs with labelsgetByText() - visible text contentlocator() - CSS selectors (last resort)Create apps/e2e-tests/tests/[feature]/[feature].fixtures.ts:
import { test as authTest } from "../../fixtures/auth.fixtures";
import { FeaturePage } from "../../pages/FeaturePage";
type FeatureFixtures = {
featurePage: FeaturePage;
};
export const test = authTest.extend<FeatureFixtures>({
featurePage: async ({ authenticatedPage }, use) => {
const featurePage = new FeaturePage(authenticatedPage);
await use(featurePage);
},
});
export { expect } from "@playwright/test";
If authentication is NOT needed, extend from base Playwright test instead:
import { test as base, expect } from "@playwright/test";
Create apps/e2e-tests/tests/[feature]/[feature].spec.ts:
import { test } from "./[feature].fixtures";
test.describe("Feature Name", () => {
test("describes what the user can do", async ({ featurePage }) => {
// Navigate to starting point
await featurePage.goto();
// Step 1: Action + optional assertion
await featurePage.expectStepVisible();
await featurePage.clickStart();
// Step 2: Another action
await featurePage.fillInput("value");
await featurePage.submit();
// Final assertions
await featurePage.expectSuccessMessage();
});
});
Test Naming: Use descriptive names that explain what the user can do:
"allows authenticated user to create a new project""shows error when required field is empty""redirects to login when not authenticated"# Start the e2e stack (if not already running)
docker compose --env-file .env.e2e -f docker-compose.e2e.yml up -d
# Run specific test file
pnpm --filter e2e-tests test:e2e tests/[feature]/[feature].spec.ts
# Run with browser visible (for debugging)
pnpm --filter e2e-tests test:headed tests/[feature]/[feature].spec.ts
# Type check
pnpm --filter e2e-tests typecheck
Before completing, ensure you have created/updated:
apps/e2e-tests/pages/[PageName].tsapps/e2e-tests/tests/[feature]/[feature].fixtures.tsapps/e2e-tests/tests/[feature]/[feature].spec.tspnpm --filter e2e-tests test:e2e tests/[feature]/pnpm --filter e2e-tests typecheckimport type { SiteNature, FricheActivity } from "shared";
import { getLabelForSiteNature } from "shared";
// Wait for element to appear
await this.page.getByRole("option").first().waitFor({ state: "visible", timeout: 10000 });
// Wait for navigation
await expect(this.page).toHaveURL("/expected-path");
async fillAutocomplete(searchText: string): Promise<void> {
const input = this.page.getByRole("searchbox", { name: /Label/i });
await input.pressSequentially(searchText, { delay: 50 });
const firstOption = this.page.getByRole("option").first();
await firstOption.waitFor({ state: "visible", timeout: 10000 });
await firstOption.click();
}
async expectDataInList(expectedData: [label: string, value: string][]): Promise<void> {
for (const [label, value] of expectedData) {
await expect(
this.page.locator("dl").filter({ hasText: label }).locator("dt")
).toHaveText(value);
}
}
$ARGUMENTS