| name | web-testing |
| description | Playwright automation, Chrome DevTools debugging, and browser interaction testing. Use for E2E/unit tests, capturing screenshots, inspecting network/console logs, or validating user flows in web applications. |
| license | Complete terms in LICENSE.txt |
Web Application Testing & Debugging
Comprehensive toolkit for testing and debugging web applications using Playwright automation and Chrome DevTools.
Skill Paths
- Workspace skills:
.github/skills/
- Global skills:
C:/Users/LOQ/.agents/skills/
Activation Conditions
Playwright Testing:
- Testing frontend functionality in a real browser
- Verifying UI behavior and interactions
- Debugging web application issues
- Capturing screenshots for documentation or debugging
- Inspecting browser console logs
- Validating form submissions and user flows
- Checking responsive design across viewports
Chrome DevTools Debugging:
- Interacting with web pages through automated controls
- Taking screenshots, and analyzing network traffic
- Navigating pages, clicking elements, filling forms, handling dialogs
- Emulating network conditions or devices
- Running JavaScript in page context, capturing console messages
- Performance profiling and identifying bottlenecks
Part 1: Playwright Testing
Core Capabilities
Browser Automation
import { test, expect, Page, Browser } from '@playwright/test';
await page.goto('https://example.com');
await page.waitForLoadState('networkidle');
await page.click('#submit-button');
await page.click('text=Continue');
await page.fill('#email', 'user@example.com');
await page.fill('#password', 'securepassword');
await page.selectOption('#country', 'United States');
page.on('dialog', async dialog => {
await dialog.accept();
});
User Flow Testing
test('complete checkout flow', async ({ page }) => {
await page.goto('/products');
await page.click('text=Add to Cart');
await page.goto('/cart');
await expect(page.locator('.cart-item')).toHaveCount(1);
await page.click('text=Checkout');
await page.fill('#email', 'test@example.com');
await page.fill('#shipping-address', '123 Main St');
await page.click('text=Place Order');
await expect(page.locator('.success-message')).toBeVisible();
});
Form Validation Testing
test('form validation', async ({ page }) => {
await page.goto('/register');
await page.click('text=Submit');
await expect(page.locator('.error-email')).toBeVisible();
await expect(page.locator('.error-password')).toBeVisible();
await page.fill('#email', 'valid@example.com');
await page.fill('#password', 'securePass123!');
await page.click('text=Submit');
await expect(page.locator('.error-email')).not.toBeVisible();
await expect(page.locator('.success-message')).toBeVisible();
});
Responsive Testing
test.describe('Responsive Design', () => {
const viewports = [
{ name: 'Mobile', width: 375, height: 667 },
{ name: 'Tablet', width: 768, height: 1024 },
{ name: 'Desktop', width: 1280, height: 720 },
];
viewports.forEach(({ name, width, height }) => {
test(`layout on ${name} (${width}x${height})`, async ({ page }) => {
await page.setViewportSize({ width, height });
await page.goto('/');
const nav = page.locator('nav');
await expect(nav).toBeVisible();
if (width < 768) {
await expect(page.locator('.mobile-menu-toggle')).toBeVisible();
} {
(page.())..();
}
page.({
: ,
: ,
});
});
});
});
Console & Network Inspection
test('console errors and warnings', async ({ page, context }) => {
const errors: string[] = [];
page.on('console', msg => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
await page.goto('/');
expect(errors).toEqual([]);
});
test('network requests monitoring', async ({ page }) => {
const requests: string[] = [];
page.on('request', request => {
requests.push(request.url());
});
await page.goto('/');
const apiRequests = requests.filter(url => url.includes('/api/'));
expect(apiRequests.length).toBeGreaterThan(0);
: [] = [];
page.(, {
(response.() === ) {
failedResponses.(response.());
}
});
page.();
(failedResponses).([]);
});
Accessibility Testing
test('basic accessibility checks', async ({ page }) => {
const headings = await page.locator('h1, h2, h3').all();
expect(headings[0]).toHaveText('Main Heading');
const imagesWithoutAlt = await page.locator('img:not([alt])').count();
expect(imagesWithoutAlt).toBe(0);
const inputs = await page.locator('input, select, textarea').all();
for (const input of inputs) {
const hasLabel = await input.evaluate(el => {
return el.labels.length > 0 || el.getAttribute('aria-label');
});
expect(hasLabel).toBeTruthy();
}
await page.keyboard.press();
focusedElement = page.( .?.);
([, , ]).(focusedElement);
});
Visual Regression Testing
import { compareScreenshots } from './visual-utils';
test('visual regression - home page', async ({ page }) => {
await page.goto('/');
await page.waitForLoadState('networkidle');
await page.waitForTimeout(1000);
const screenshot = await page.screenshot({
fullPage: true,
});
const diff = await compareScreenshots(screenshot, 'baseline/home.png');
expect(diff.pixelDifference).toBeLessThan(100);
});
Part 2: Chrome DevTools Integration
Tool Categories
Navigation & Page Management
await chrome.newPage();
await chrome.navigatePage('https://example.com');
await chrome.navigatePage({ action: 'reload' });
await chrome.navigatePage({ action: 'back' });
await chrome.navigatePage({ action: 'forward' });
const pages = await chrome.listPages();
await chrome.selectPage(pages[0].id);
await chrome.closePage('page-id-here');
await chrome.waitFor('Welcome to the site');
Input & Interaction
const snapshot = await chrome.takeSnapshot();
const submitButton = snapshot.elements.find(el => el.text === 'Submit');
await chrome.click(submitButton.uid);
await chrome.fill(inputUid, 'value@example.com');
await chrome.fillForm([
{ uid: emailInputUid, value: 'test@example.com' },
{ uid: passwordInputUid, value: 'password123' },
{ uid: nameInputUid, value: 'John Doe' },
]);
await chrome.hover(buttonUid);
await chrome.pressKey('Enter');
await chrome.pressKey('Control+C');
await chrome.drag(sourceUid, targetUid);
await chrome.handleDialog('accept');
chrome.();
Debugging & Inspection
const snapshot = await chrome.takeSnapshot();
const screenshot = await chrome.takeScreenshot();
const messages = await chrome.listConsoleMessages();
const errors = await chrome.listConsoleMessages('error');
const warnings = await chrome.listConsoleMessages('warning');
const message = await chrome.getConsoleMessage(messageId);
const result = await chrome.evaluateScript('document.title');
const userInfo = await chrome.evaluateScript(`
JSON.parse(localStorage.getItem('user'))
`);
const requests = await chrome.listNetworkRequests();
const failedRequests = requests.filter(req =>
req.status >= 400 || req.status ===
);
requestDetails = chrome.(requestId);
Emulation & Performance
await chrome.resizePage({ width: 375, height: 667 });
await chrome.emulate({
network: 'offline'
});
await chrome.emulate({
geolocation: { lat: 40.7128, lon: -74.0060 }
});
await chrome.performanceStartTrace({ reload: true });
await chrome.waitFor('Page loaded');
const trace = await chrome.performanceStopTrace();
const insights = await chrome.performanceAnalyzeInsight();
console.log('LCP:', insights.largestContentfulPaint);
console.log('CLS:', insights.cumulativeLayoutShift);
Common Debugging Patterns
Pattern A: Identifying Elements (Snapshot-First)
Always prefer snapshot over screenshot for finding elements:
const snapshot = await chrome.takeSnapshot();
const element = snapshot.elements.find(el => el.text === 'Continue');
await chrome.click(element.uid);
Pattern B: Troubleshooting Errors
When a page is failing, check both console and network:
const errors = await chrome.listConsoleMessages('error');
console.log('JavaScript Errors:', errors);
const requests = await chrome.listNetworkRequests();
const failed = requests.filter(r => r.status >= 400);
console.log('Failed Requests:', failed);
const apiResponse = await chrome.evaluateScript(`
window.lastApiResponse
`);
console.log('Last API Response:', apiResponse);
Pattern C: Performance Profiling
Identify why a page is slow:
await chrome.performanceStartTrace({ reload: true, autoStop: true });
const timeout = 10000;
await new Promise(resolve => setTimeout(resolve, timeout));
const insights = await chrome.performanceAnalyzeInsight();
console.log('Performance Issues:', insights.issues);
console.log('LCP:', insights.largestContentfulPaint);
console.log('CLS:', insights.cumulativeLayoutShift);
console.log('FID:', insights.firstInputDelay);
if (insights.largestContentfulPaint > 2500) {
console.warn('LCP is slow - consider optimizing images and CSS');
}
if (insights.cumulativeLayoutShift > 0.1) {
console.warn();
}
Workflow Examples
Testing Login Flow
await chrome.navigatePage('https://example.com/login');
const snapshot = await chrome.takeSnapshot();
const emailInput = snapshot.elements.find(el => el.attributes.id === 'email');
await chrome.fill(emailInput.uid, 'user@example.com');
const passwordInput = snapshot.elements.find(el => el.attributes.type === 'password');
await chrome.fill(passwordInput.uid, 'password123');
const submitButton = snapshot.elements.find(el => el.text === 'Sign In');
await chrome.click(submitButton.uid);
await chrome.waitFor('Dashboard');
await chrome.();
Debugging API Issues
await chrome.navigatePage('https://example.com/data-page');
const apiCalls = [];
chrome.on('networkRequest', (request) => {
if (request.url.includes('/api/')) {
apiCalls.push({
url: request.url,
method: request.method,
});
}
});
await chrome.click(submitButtonUid);
console.log('API Calls:', apiCalls);
const responseData = await chrome.evaluateScript(`
window.lastApiResponse
`);
console.log('Response Data:', responseData);
Part 3: Testing Best Practices
Test Structure
test.describe('User Authentication', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
});
test('successful login with valid credentials', async ({ page }) => {
await test.step('Enter credentials', async () => {
await page.fill('#email', 'valid@example.com');
await page.fill('#password', 'correct-password');
});
await test.step('Submit form', async () => {
await page.click('text=Login');
});
await test.step('Verify redirected to dashboard', async () => {
await expect(page).toHaveURL('/dashboard');
});
});
test('shows error for invalid credentials', async ({ page }) => {
await page.fill('#email', 'invalid@example.com');
await page.(, );
page.();
(page.()).();
(page).();
});
});
Page Object Model
export class LoginPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.page.fill('#email', email);
await this.page.fill('#password', password);
await this.page.click('text=Login');
}
async getErrorMessage() {
return await this.page.locator('.error-message').textContent();
}
assertVisible() {
expect(this.page.()).();
}
}
(, ({ page }) => {
loginPage = (page);
loginPage.();
loginPage.(, );
(page).();
});
Parallel Testing
export default defineConfig({
workers: process.env.CI ? 2 : 4,
projects: [
{
name: 'chromium',
use: { browserName: 'chromium' },
},
{
name: 'firefox',
use: { browserName: 'firefox' },
},
{
name: 'webkit',
use: { browserName: 'webkit' },
},
],
});
Part 4: Debugging Toolset
Quick Reference
| Task | Playwright | Chrome DevTools |
|---|
| Browser Automation | Yes | Yes |
| Page Navigation | page.goto() | navigate_page() |
| Click Elements | page.click() | click(uid) |
| Fill Forms | page.fill() | fill(uid, value) |
| Screenshots | page.screenshot() | take_screenshot() |
| Console Logs | page.on('console') | list_console_messages() |
| Network Requests | page.on('request') | list_network_requests() |
| JavaScript Eval | page.evaluate() | evaluate_script() |
| Viewport Resize | page.setViewportSize() | resize_page() |
| Performance | Trace API | performance_* tools |
| Device Emulation | deviceDescriptor | emulate() |
Common Debugging Commands
npx playwright test
npx playwright test --ui
npx playwright test --headed
npx playwright test tests/login.spec.ts --debug
npx playwright codegen https://example.com
Testing Checklist
Functionality
Responsive Design
Cross-Browser
Accessibility
Performance
Error Handling
References & Resources
Documentation
- Playwright Selectors — All selector types with decision tree and priority order
- Test Patterns — Page Object Model, fixtures, auth reuse, API mocking, and accessibility patterns
Scripts
- Test Scaffold — PowerShell Playwright test file generator for e2e, visual, and accessibility tests
Examples
Related Skills