Skip to main content
playwright Playwright for end-to-end testing, browser automation, and web scraping. Use when user mentions "playwright", "e2e testing", "end to end test", "browser testing", "browser automation", "web scraping", "headless browser", "cross-browser testing", "page.goto", "locator", or automating browser interactions.
Ir a la instalación Skills Marketplace Descubre y explora habilidades de IA creadas por la comunidad.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Copiar promptMostrar detalles del prompt Un comando directo omite el prompt de revisión. Revisa el origen antes de ejecutarlo.
npx skills add https://github.com/1Mangesh1/dev-skills-collection --skill playwrightEl comando permanece en una sola línea. Desplázate horizontalmente para revisarlo antes de copiarlo.
¿Prefieres una copia local? Descarga los archivos que SkillsMP tiene disponibles ahora.
Descargar Zip Descargando... Más de este repositorio REST API design patterns, structure, and best practices. Use when user asks to "design a REST API", "create API endpoints", "write OpenAPI spec", "design API routes", "add pagination to API", "version an API", "create API schema", "design webhook endpoints", "structure API responses", "implement HATEOAS", "design API errors", "API versioning", "API deprecation", "rate limiting design", or mentions REST API design, endpoint naming, HTTP methods, status codes, API best practices, request/response design, or API documentation.
Caching strategies and implementation patterns. Use when user asks to "add caching", "cache API responses", "set up CDN caching", "configure HTTP caching", "implement memoization", "cache database queries", "set cache headers", "invalidate cache", "design cache layer", "reduce API latency", "cache warming", "cache busting", "distributed caching", "Redis caching", "edge caching", or mentions caching strategies, cache invalidation, TTL, cache-aside, write-through, write-behind, CDN, browser caching, or memoization.
CI/CD pipeline design, setup, and optimization. Use when user asks to "set up CI/CD", "create a pipeline", "configure Jenkins", "set up GitLab CI", "create CircleCI config", "automate deployments", "create build pipeline", "set up continuous deployment", "configure pipeline stages", "add pipeline caching", "pipeline security", "secret management", "artifact management", "GitHub Actions workflow", "deployment strategies", "canary deployment", or mentions CI/CD pipelines, continuous integration, continuous deployment, build automation, deployment pipelines, or pipeline optimization.
Ocupaciones relacionadas SOC
Basado en la clasificación ocupacional SOC
name playwright description Playwright for end-to-end testing, browser automation, and web scraping. Use when user mentions "playwright", "e2e testing", "end to end test", "browser testing", "browser automation", "web scraping", "headless browser", "cross-browser testing", "page.goto", "locator", or automating browser interactions.
Playwright
Setup
npm init playwright@latest
npx playwright install
npx playwright install chromium
Configuration
import { defineConfig, devices } from '@playwright/test' ;
export default defineConfig ({
testDir : './tests' ,
fullyParallel : true ,
forbidOnly : !!process.env .CI ,
retries : process.env .CI ? 2 : 0 ,
workers : process.env .CI ? 1 : undefined ,
reporter : [[ ], [ ]],
: {
: ,
: ,
: ,
: ,
},
: [
{ : , : { ...devices[ ] } },
{ : , : { ...devices[ ] } },
{ : , : { ...devices[ ] } },
{ : , : { ...devices[ ] } },
],
: {
: ,
: ,
: !process. . ,
},
});
'html'
'list'
use
baseURL
'http://localhost:3000'
trace
'on-first-retry'
screenshot
'only-on-failure'
video
'retain-on-failure'
projects
name
'chromium'
use
'Desktop Chrome'
name
'firefox'
use
'Desktop Firefox'
name
'webkit'
use
'Desktop Safari'
name
'mobile-chrome'
use
'Pixel 5'
webServer
command
'npm run dev'
url
'http://localhost:3000'
reuseExistingServer
env
CI
Writing Tests import { test, expect } from '@playwright/test' ;
test.describe ('Feature Name' , () => {
test.beforeEach (async ({ page }) => {
await page.goto ('/' );
});
test ('should do something specific' , async ({ page }) => {
await page.getByRole ('button' , { name : 'Submit' }).click ();
await expect (page.getByText ('Success' )).toBeVisible ();
});
});
Playwright auto-waits for elements to be visible, stable, enabled, and receiving events before performing actions. Assertions auto-retry until the timeout (default 5s).
Locators Prefer role-based and user-facing locators over CSS selectors.
page.getByRole ('button' , { name : 'Sign In' })
page.getByRole ('heading' , { name : 'Dashboard' , level : 2 })
page.getByRole ('textbox' , { name : 'Email' })
page.getByRole ('checkbox' , { name : 'Remember me' })
page.getByText ('Welcome back' )
page.getByLabel ('Email address' )
page.getByPlaceholder ('Enter your email' )
page.getByTestId ('submit-button' )
page.locator ('.nav-item.active' )
page.locator ('xpath=//div[@class="container"]//span' )
page.getByRole ('listitem' ).filter ({ hasText : 'Product A' })
page.getByRole ('listitem' ).filter ({ has : page.getByRole ('button' , { name : 'Buy' }) })
page.locator ('.card' ).nth (2 )
page.locator ('.card' ).first ()
Actions
await page.getByRole ('button' , { name : 'Submit' }).click ();
await page.getByRole ('button' ).dblclick ();
await page.getByRole ('button' ).click ({ button : 'right' });
await page.getByLabel ('Email' ).fill ('user@example.com' );
await page.getByLabel ('Name' ).pressSequentially ('John' , { delay : 50 });
await page.getByLabel ('Name' ).clear ();
await page.keyboard .press ('Enter' );
await page.keyboard .press ('Control+A' );
await page.getByLabel ('Country' ).selectOption ('us' );
await page.getByLabel ('Country' ).selectOption ({ label : 'United States' });
await page.getByRole ('checkbox' , { name : 'Agree' }).check ();
await page.getByRole ('checkbox' , { name : 'Agree' }).uncheck ();
await page.getByText ('Menu' ).hover ();
await page.getByLabel ('Email' ).focus ();
await page.getByTestId ('source' ).dragTo (page.getByTestId ('target' ));
Assertions await expect (page.getByText ('Welcome' )).toBeVisible ();
await expect (page.getByText ('Loading' )).toBeHidden ();
await expect (page.getByRole ('heading' )).toHaveText ('Dashboard' );
await expect (page.getByRole ('heading' )).toHaveText (/dashboard/i );
await expect (page.getByRole ('status' )).toContainText ('3 items' );
await expect (page.getByLabel ('Email' )).toHaveValue ('user@example.com' );
await expect (page).toHaveURL ('/dashboard' );
await expect (page).toHaveTitle ('My App - Dashboard' );
await expect (page.getByRole ('button' )).toBeEnabled ();
await expect (page.getByRole ('checkbox' )).toBeChecked ();
await expect (page.getByRole ('listitem' )).toHaveCount (5 );
await expect (page.getByTestId ('card' )).toHaveClass (/highlighted/ );
await expect (page.getByTestId ('card' )).toHaveAttribute ('data-status' , 'active' );
await expect (page.getByText ('Error' )).not .toBeVisible ();
await expect.soft (page.getByText ('Title' )).toHaveText ('Expected' );
Page Navigation and Waiting await page.goto ('https://example.com' );
await page.goto ('/relative-path' );
await page.goBack ();
await page.reload ();
await page.waitForURL ('**/dashboard' );
await page.waitForSelector ('.dynamic-content' , { state : 'visible' });
await page.waitForSelector ('.spinner' , { state : 'detached' });
const response = await page.waitForResponse (
resp => resp.url ().includes ('/api/users' ) && resp.status () === 200
);
await page.waitForLoadState ('networkidle' );
await page.waitForFunction (() => document .title .includes ('Ready' ));
await page.getByText ('Loaded' ).click ({ timeout : 10000 });
Network Interception
await page.route ('**/api/users' , async route => {
await route.fulfill ({
status : 200 ,
contentType : 'application/json' ,
body : JSON .stringify ([{ id : 1 , name : 'Alice' }]),
});
});
await page.route ('**/api/settings' , async route => {
const response = await route.fetch ();
const json = await response.json ();
json.featureFlag = true ;
await route.fulfill ({ response, json });
});
await page.route ('**/*.{png,jpg,jpeg,gif,svg}' , route => route.abort ());
await page.route ('**/api/submit' , async route => {
const postData = route.request ().postDataJSON ();
expect (postData.email ).toBe ('user@example.com' );
await route.continue ();
});
await page.routeFromHAR ('tests/data/api.har' , { update : true });
await page.routeFromHAR ('tests/data/api.har' );
Authentication Save login state once, reuse across all tests:
import { test as setup } from '@playwright/test' ;
const authFile = 'playwright/.auth/user.json' ;
setup ('authenticate' , async ({ page }) => {
await page.goto ('/login' );
await page.getByLabel ('Email' ).fill ('user@example.com' );
await page.getByLabel ('Password' ).fill ('password123' );
await page.getByRole ('button' , { name : 'Sign In' }).click ();
await page.waitForURL ('/dashboard' );
await page.context ().storageState ({ path : authFile });
});
{ name : 'setup' , testMatch : /.*\.setup\.ts/ },
{
name : 'chromium' ,
dependencies : ['setup' ],
use : { ...devices['Desktop Chrome' ], storageState : 'playwright/.auth/user.json' },
},
Add playwright/.auth/ to .gitignore.
Multiple Pages, Tabs, and Popups const newPage = await page.context ().newPage ();
await newPage.goto ('/another-page' );
const popupPromise = page.waitForEvent ('popup' );
await page.getByRole ('button' , { name : 'Sign in with Google' }).click ();
const popup = await popupPromise;
await popup.waitForLoadState ();
const context1 = await browser.newContext ();
const context2 = await browser.newContext ();
const page1 = await context1.newPage ();
const page2 = await context2.newPage ();
Screenshots and Video await page.screenshot ({ path : 'screenshots/home.png' });
await page.screenshot ({ path : 'full.png' , fullPage : true });
await page.getByTestId ('chart' ).screenshot ({ path : 'chart.png' });
Configure globally in playwright.config.ts under use: screenshot: 'only-on-failure', video: 'retain-on-failure'.
Visual Regression Testing await expect (page).toHaveScreenshot ();
await expect (page).toHaveScreenshot ('homepage.png' );
await expect (page).toHaveScreenshot ({ maxDiffPixels : 100 });
await expect (page.getByTestId ('header' )).toHaveScreenshot ('header.png' );
Update baselines with npx playwright test --update-snapshots. Baselines are stored alongside the test file in a -snapshots/ directory. Commit them to version control.
Parallel Execution and Sharding
export default defineConfig ({
fullyParallel : true ,
workers : 4 ,
});
test.describe .configure ({ mode : 'serial' });
Shard across CI machines: npx playwright test --shard=1/3, --shard=2/3, --shard=3/3.
Debugging npx playwright test --headed
npx playwright test --debug
npx playwright codegen https://example.com
npx playwright show-trace trace.zip
npx playwright test --grep "login"
npx playwright test tests/login.spec.ts
Use await page.pause() inside a test to pause execution and open Inspector.
Trace viewer shows a timeline of actions, DOM snapshots at each step, network requests, and console logs. Enable with trace: 'on-first-retry' in config or record manually:
await page.context ().tracing .start ({ screenshots : true , snapshots : true });
await page.context ().tracing .stop ({ path : 'trace.zip' });
Page Object Model
import { type Locator , type Page , expect } from '@playwright/test' ;
export class LoginPage {
readonly emailInput : Locator ;
readonly passwordInput : Locator ;
readonly submitButton : Locator ;
constructor (private page : Page ) {
this .emailInput = page.getByLabel ('Email' );
this .passwordInput = page.getByLabel ('Password' );
this .submitButton = page.getByRole ('button' , { name : 'Sign In' });
}
async goto ( ) { await this .page .goto ('/login' ); }
async login (email : string , password : string ) {
await this .emailInput .fill (email);
await this .passwordInput .fill (password);
await this .submitButton .click ();
}
}
test ('successful login' , async ({ page }) => {
const loginPage = new LoginPage (page);
await loginPage.goto ();
await loginPage.login ('user@example.com' , 'password123' );
await expect (page).toHaveURL ('/dashboard' );
});
CI/CD Integration
GitHub Actions
name: Playwright Tests
on: [push , pull_request ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with: { name: playwright-report , path: playwright-report/ , retention-days: 30 }
Sharded CI jobs:
test:
strategy:
matrix:
shard: [1 /4 , 2 /4 , 3 /4 , 4 /4 ]
steps:
- run: npx playwright test --shard=${{ matrix.shard }}
Docker FROM mcr.microsoft.com/playwright:v1.48.0-noble
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx playwright test
Common Patterns
File Upload and Download await page.getByLabel ('Upload' ).setInputFiles ('tests/fixtures/doc.pdf' );
await page.getByLabel ('Upload' ).setInputFiles (['a.png' , 'b.png' ]);
await page.getByLabel ('Upload' ).setInputFiles ([]);
const downloadPromise = page.waitForEvent ('download' );
await page.getByRole ('link' , { name : 'Download Report' }).click ();
const download = await downloadPromise;
await download.saveAs ('downloads/' + download.suggestedFilename ());
Iframe Handling const frame = page.frameLocator ('#my-iframe' );
await frame.getByRole ('button' , { name : 'Click me' }).click ();
await expect (frame.getByText ('Done' )).toBeVisible ();
Dialog Handling page.on ('dialog' , dialog => dialog.accept ());
page.on ('dialog' , dialog => dialog.dismiss ());
page.once ('dialog' , async dialog => {
expect (dialog.message ()).toBe ('Are you sure?' );
await dialog.accept ();
});
await page.getByRole ('button' , { name : 'Delete' }).click ();
Waiting for API Before Asserting const responsePromise = page.waitForResponse ('**/api/save' );
await page.getByRole ('button' , { name : 'Save' }).click ();
const response = await responsePromise;
expect (response.status ()).toBe (200 );
await expect (page.getByText ('Saved' )).toBeVisible ();
Form Validation Testing test ('validates required fields' , async ({ page }) => {
await page.goto ('/contact' );
await page.getByRole ('button' , { name : 'Submit' }).click ();
await expect (page.getByText ('Email is required' )).toBeVisible ();
await page.getByLabel ('Email' ).fill ('invalid' );
await expect (page.getByText ('Invalid email format' )).toBeVisible ();
await page.getByLabel ('Email' ).fill ('user@example.com' );
await page.getByLabel ('Message' ).fill ('Hello' );
await page.getByRole ('button' , { name : 'Submit' }).click ();
await expect (page.getByText ('Message sent' )).toBeVisible ();
});