Claude Code और Playwright से production-ready E2E testing
Claude Code और Playwright से E2E, mobile screenshots, auth state, Trace Viewer, selectors और CI retries सेट करें.
Claude Code से सिर्फ “Playwright tests जोड़ दो” कहना production quality के लिए काफी नहीं है। ऐसा करने पर tests एक बार pass हो सकते हैं, पर वे CSS class पर depend करते हैं, हर test में login UI चलाते हैं, mobile screenshot नहीं रखते और CI fail होने पर Trace Viewer से कारण समझना मुश्किल हो जाता है।
इस guide में Claude Code को code generator नहीं, test-design partner की तरह इस्तेमाल किया गया है। E2E का मतलब End to End है: browser में user journey को शुरू से अंत तक चलाकर देखना। Playwright से हम revenue CTAs, authenticated pages, mobile layout, code blocks, Trace Viewer, CI retries और flaky tests को practical तरीके से संभालेंगे।
Official references के लिए Claude Code overview, Claude Code common workflows, और Playwright docs के Locators, Authentication, Screenshots, Trace Viewer, Retries, CI देखें। ClaudeCodeLab पर related reading: testing strategy, CI/CD setup, और responsive design।
कौन से flows E2E में रखें
E2E tests real browser खोलते हैं, इसलिए वे unit tests से slow होते हैं। हर चीज E2E में डालने के बजाय उन flows को चुनें जहाँ browser-level proof जरूरी है।
| Use case | क्या protect करता है | Playwright proof |
|---|---|---|
| Article से products page | Reader /products/ तक पहुँचता है | CTA link, URL, mobile tap |
| Signed-in dashboard | Authenticated user protected page खोलता है | storageState, redirect, permission |
| Code article layout | Code blocks और tables mobile width नहीं तोड़ते | Mobile screenshot, no overflow, trace |
flowchart LR
A["Revenue या signup path"] --> B["Playwright E2E"]
C["Mobile layout risk"] --> B
D["Pure validation"] --> E["Unit tests"]
F["API या component boundary"] --> G["Integration tests"]
Content site में भी यह practical है। अगर mobile पर CTA छिप जाए, long code line page को चौड़ा कर दे, या paid-user page CI में कभी test न हो, तो bug छोटा दिखता है लेकिन conversion और trust पर असर डालता है।
Claude Code को clear prompt दें
Claude Code codebase पढ़ सकता है, पर quality rules अपने आप तय नहीं करेगा। Prompt में routes, selector policy, command और allowed files साफ लिखें।
Existing Astro site पढ़कर Playwright E2E tests जोड़ें।
Goals:
- `/hi/blog/claude-code-playwright-testing/` से `/products/` और `/training/` reachable हैं
- 390px mobile width पर article, tables और code blocks horizontal overflow नहीं करते
- Authenticated tests में हर बार UI login न करें; `storageState` use करें
- CI में retries 2 और trace `on-first-retry` रखें
Constraints:
- `page.waitForTimeout()` use न करें
- CSS class chains के बजाय role, label, text या test id prefer करें
- केवल `playwright.config.ts` और `tests/e2e/**` बदलें
- `npx playwright test` चलाएँ और failures Trace Viewer से explain करें
Review करते समय देखें कि failure explainable है या नहीं, selector user intent से जुड़ा है या नहीं, और test data repeatable है या नहीं।
Copy-paste setup
cd site
npm i -D @playwright/test
npx playwright install
mkdir tests/e2e
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
const baseURL = process.env.BASE_URL ?? 'http://127.0.0.1:4321';
const hasAuth = Boolean(process.env.TEST_EMAIL && process.env.TEST_PASSWORD);
const authFile = 'playwright/.auth/user.json';
export default defineConfig({
testDir: './tests/e2e',
timeout: 30_000,
expect: { timeout: 5_000 },
fullyParallel: true,
forbidOnly: Boolean(process.env.CI),
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 2 : undefined,
reporter: process.env.CI ? [['html'], ['github']] : 'html',
use: {
baseURL,
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
...(process.env.PLAYWRIGHT_WEB_SERVER === '1'
? {
webServer: {
command: 'npm run preview -- --host 127.0.0.1 --port 4321',
url: baseURL,
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
}
: {}),
projects: [
...(hasAuth
? [
{
name: 'setup',
testMatch: /.*\.setup\.ts/,
},
]
: []),
{
name: 'desktop-chrome',
use: {
...devices['Desktop Chrome'],
storageState: hasAuth ? authFile : undefined,
},
dependencies: hasAuth ? ['setup'] : [],
},
{
name: 'mobile-safari',
use: {
...devices['iPhone 13'],
storageState: hasAuth ? authFile : undefined,
},
dependencies: hasAuth ? ['setup'] : [],
},
],
});
Local run में retries off रखें ताकि problem जल्दी दिखे। CI में retries useful हैं, पर तभी जब trace, screenshot और HTML report save हों।
Authentication state save करें
हर test में UI login चलाना slow और fragile है। Playwright का storageState login के बाद browser state save करता है और बाकी tests उसे reuse करते हैं। playwright/.auth में sensitive cookies हो सकती हैं, इसलिए इसे git में commit न करें।
// tests/e2e/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
import fs from 'node:fs';
import path from 'node:path';
const authFile = path.resolve('playwright/.auth/user.json');
const email = process.env.TEST_EMAIL;
const password = process.env.TEST_PASSWORD;
setup('save signed-in browser state', async ({ page }) => {
setup.skip(!email || !password, 'Set TEST_EMAIL and TEST_PASSWORD to record auth state.');
await page.goto('/login');
await page.getByLabel(/email|メール|e-mail/i).fill(email!);
await page.getByLabel(/password|パスワード/i).fill(password!);
await page.getByRole('button', { name: /log in|sign in|ログイン/i }).click();
await expect(page).toHaveURL(/dashboard|account|admin/);
await expect(page.locator('body')).toBeVisible();
fs.mkdirSync(path.dirname(authFile), { recursive: true });
await page.context().storageState({ path: authFile });
});
Claude Code से कहें कि login behavior tests और authenticated feature tests अलग रखे। इससे login button बदलने पर पूरी E2E suite नहीं टूटेगी।
Mobile screenshot और code block QA
Technical articles में long code lines, tables और images mobile layout तोड़ सकते हैं। यह spec CTA, screenshot और horizontal overflow तीनों check करता है।
// tests/e2e/article-quality.spec.ts
import { test, expect } from '@playwright/test';
const articlePath = process.env.ARTICLE_PATH ?? '/hi/blog/claude-code-playwright-testing/';
test.describe('article quality checks', () => {
test('article has monetization CTAs', async ({ page }) => {
await page.goto(articlePath);
await expect(page.getByRole('heading', { level: 1 })).toContainText(/Playwright|E2E|Claude Code/i);
await expect(page.locator('a[href="/products/"], a[href="/products"]').first()).toBeVisible();
await expect(page.locator('a[href="/training/"], a[href="/training"]').first()).toBeVisible();
});
test('mobile layout has no horizontal overflow', async ({ page }, testInfo) => {
await page.setViewportSize({ width: 390, height: 844 });
await page.goto(articlePath);
await expect(page.locator('main, article').first()).toBeVisible();
const overflow = await page.evaluate(() => ({
viewport: window.innerWidth,
documentWidth: document.documentElement.scrollWidth,
offenders: Array.from(document.querySelectorAll('pre, table, img, iframe, .prose'))
.filter((node) => {
const rect = node.getBoundingClientRect();
return rect.left < -1 || rect.right > window.innerWidth + 1;
})
.map((node) => {
const rect = node.getBoundingClientRect();
return `${node.tagName.toLowerCase()} ${Math.round(rect.left)}-${Math.round(rect.right)}`;
}),
}));
expect(overflow.documentWidth, JSON.stringify(overflow)).toBeLessThanOrEqual(overflow.viewport + 2);
expect(overflow.offenders).toEqual([]);
await page.screenshot({ path: testInfo.outputPath('article-mobile.png'), fullPage: true });
});
test('code examples are present and copyable', async ({ page }) => {
await page.goto(articlePath);
const blocks = page.locator('pre code');
await expect(blocks.first()).toBeVisible();
expect(await blocks.count()).toBeGreaterThanOrEqual(3);
await expect(blocks.nth(0)).toContainText(/playwright|defineConfig|test/i);
});
});
Screenshot human review के लिए है; overflow assertion CI gate के लिए है।
Revenue और training CTAs protect करें
// tests/e2e/revenue-flows.spec.ts
import { test, expect } from '@playwright/test';
const articlePath = process.env.ARTICLE_PATH ?? '/hi/blog/claude-code-playwright-testing/';
test.describe('revenue and learning flows', () => {
test('reader can move from article to products', async ({ page }) => {
await page.goto(articlePath);
await page.locator('a[href="/products/"], a[href="/products"]').first().click();
await expect(page).toHaveURL(/\/products\/?$/);
await expect(page.locator('main').first()).toBeVisible();
});
test('training CTA is reachable on mobile', async ({ page }) => {
await page.setViewportSize({ width: 390, height: 844 });
await page.goto(articlePath);
await page.locator('a[href="/training/"], a[href="/training"]').first().click();
await expect(page).toHaveURL(/\/training\/?$/);
await expect(page.locator('main').first()).toBeVisible();
});
test('main navigation can open the blog index', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('navigation').first()).toBeVisible();
await page.getByRole('link', { name: /blog|記事|articles/i }).first().click();
await expect(page).toHaveURL(/blog/);
});
});
Multilingual site में CTA text बदल सकता है। Critical actions के लिए stable href या data-testid अच्छा contract देता है।
Flaky tests कम करने वाले selectors
| Priority | Selector | Example | Why |
|---|---|---|---|
| High | Role + name | page.getByRole('button', { name: /save/i }) | User और accessibility view के करीब |
| High | Label | page.getByLabel(/email/i) | Form semantics भी check होते हैं |
| Medium | Text | page.getByText(/Start trial/) | साफ है, पर copy changes से टूट सकता है |
| Medium | Test id | page.getByTestId('checkout-submit') | Stable business action के लिए अच्छा |
| Low | CSS structure | .card:nth-child(3) | Layout बदलते ही टूटता है |
page.waitForTimeout() avoid करें। toBeVisible(), toHaveURL() और toContainText() जैसी web-first assertions real condition का इंतजार करती हैं।
Trace Viewer से failure समझें
npx playwright test --trace on
npx playwright show-report
npx playwright show-trace test-results/path-to-trace/trace.zip
Failure Claude Code को भेजते समय test name, trace में दिखी screen state और expected user behavior दें। इससे वह blind timeout नहीं बढ़ाएगा, बल्कि selector, data setup या UI issue पर काम करेगा।
CI example
# .github/workflows/playwright.yml
name: Playwright E2E
on:
pull_request:
push:
branches: [main]
jobs:
e2e:
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: site
env:
BASE_URL: http://127.0.0.1:4321
PLAYWRIGHT_WEB_SERVER: "1"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: site/package-lock.json
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run build
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: site/playwright-report
retention-days: 7
Retry flaky test को ठीक नहीं करता; वह बस classify करके evidence छोड़ता है। HTML report और trace zip जरूर देखें।
Common pitfalls
पहली गलती है हर चीज E2E में डालना। Calculations, validation और permission edge cases को unit या integration tests में रखें।
दूसरी गलती auth state commit करना है। Limited test user use करें और playwright/.auth को git से बाहर रखें।
तीसरी गलती retry से instability छिपाना है। अगर test retry पर ही pass होता है, तो वह अभी भी risk है।
चौथी गलती Claude Code को बहुत बड़ा scope देना है। पहले failing test जोड़ें, trace देखें, फिर smallest product fix करें।
Self-serve implementation के लिए ClaudeCodeLab products templates से शुरू करें। Team rollout के लिए training review rules, CI policy और onboarding align करने में मदद करता है।
मैंने इस workflow को local ClaudeCodeLab-style article page पर आजमाया: 390px screenshot, code block overflow, /products/ और /training/ CTA navigation, और CI retry config। पहले useful failures Playwright में नहीं थे; वे long code lines और ambiguous link names थे। इन्हें ठीक करने के बाद Trace Viewer अगली Claude Code prompt के लिए solid evidence बन गया।
मुफ़्त PDF: Claude Code cheatsheet
Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.
हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.
लेखक के बारे में
Masa
Claude Code workflow और team adoption पर काम करने वाला engineer.
संबंधित लेख
Claude Code Permission Receipt Pattern: scope, proof और rollback लिखना
Claude Code के लिए permission receipt: allowed actions, approval boundary, verification commands, rollback note और revenue CTA checks।
Claude Code और Codex के लिए सुरक्षित Agent Harness: permissions, verification और rollback
Claude Code और Codex agents के लिए सुरक्षित harness: permissions, plan, verification और rollback.
Claude Code Subagents गाइड: article और code work को सुरक्षित तरीके से delegate करें
Claude Code subagents से article और code work बांटें: delegation rules, prompts, pitfalls, checklist और examples.