소스 정보
- 저장소
- tomevault-io/skills-registry
- 최근 소스 활동
- 2026년 4월 28일 22:53
- 감지된 SKILL.md 언어
- 영어
- 스타
- 0
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tomevault-io/skills-registry --skill debugging-troubleshooting명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | debugging-troubleshooting |
| description | > Use when this capability is needed. |
Comprehensive guide to debugging Playwright tests — using Playwright Inspector, debug mode, trace viewer, video analysis, and systematic troubleshooting techniques.
# Run a specific test with the inspector
npx playwright test tests/checkout.spec.ts --debug
# Run all tests in debug mode
npx playwright test --debug
# Debug a specific test by title
npx playwright test -g "should complete checkout" --debug
test('debug this test with inspector', async ({ page }) => {
await page.goto('/products');
// Add page.pause() to stop execution and open inspector
await page.pause();
// Inspector opens here - you can:
// 1. Step through actions one at a time
// 2. Inspect the page's DOM
// 3. Try selectors in the Locator tab
// 4. View the action log
// 5. Resume or step over
await page.getByRole('button', { name: 'Add to Cart' }).click();
// Add another pause to inspect state after the click
await page.pause();
await expect(page.getByRole('alert')).toBeVisible();
});
// TIP 1: Use PWDEBUG environment variable
// PWDEBUG=1 npx playwright test
// This auto-opens inspector for ALL tests
// TIP 2: Use console mode in inspector
// PWDEBUG=console npx playwright test
// Opens browser DevTools console with Playwright helpers
// TIP 3: Pick locators interactively
// In the Inspector, click "Pick locator" then click any element
// on the page to get the recommended selector
# Run tests in headed mode (see the browser)
npx playwright test --headed
# Slow down actions for visual debugging
npx playwright test --headed --slow-mo=500
# Combine with specific test
npx playwright test tests/login.spec.ts --headed --slow-mo=1000
// playwright.config.ts - Debug-friendly config
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// Slow down actions by 200ms (useful for visual debugging)
launchOptions: {
slowMo: process.env.SLOW_MO ? parseInt(process.env.SLOW_MO) : 0,
},
// Keep browser open after test failure
headless: process.env.HEADED ? false : true,
},
});
// Temporarily focus on one test for debugging
test.only('debug: should add item to cart', async ({ page }) => {
// Set a longer timeout while debugging
test.setTimeout(0); // No timeout during debugging
await page.goto('/products');
// Log page URL for verification
console.log('Current URL:', page.url());
// Take a screenshot at a specific point
await page.screenshot({ path: 'debug-screenshot.png' });
await page.getByRole('button', { name: 'Add to Cart' }).click();
// Check what's on the page
const content = await page.textContent('body');
console.log('Page contains:', content?.substring(0, 500));
});
// IMPORTANT: Remove test.only before committing!
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// ✅ Recommended: Record trace on first retry
trace: 'on-first-retry',
// Other options:
// trace: 'on' - Always record (slower, more storage)
// trace: 'off' - Never record
// trace: 'retain-on-failure' - Keep only for failures
},
});
# Open the trace viewer with a trace file
npx playwright show-trace test-results/checkout-should-complete/trace.zip
# Open trace from HTML report
npx playwright show-report
# Then click on a failed test → "Traces" tab
// The trace viewer provides:
// 1. Timeline - Visual timeline of all test actions
// 2. Actions - Each step with before/after screenshots
// 3. Metadata - Test name, duration, status
// 4. Source - The test source code with current line highlighted
// 5. Network - All network requests and responses
// 6. Console - Browser console output
// 7. DOM - Snapshot of DOM at each step
// 8. Call - Detailed info about each Playwright call
// You can:
// - Click any action to see the page state
// - Filter network requests
// - Search the DOM snapshot
// - View request/response bodies
test('trace specific operations', async ({ page, context }) => {
// Start tracing for a specific section
await context.tracing.start({ screenshots: true, snapshots: true });
await page.goto('/checkout');
await page.getByLabel('Email').fill('user@example.com');
await page.getByRole('button', { name: 'Place Order' }).click();
// Stop and save trace
await context.tracing.stop({ path: 'traces/checkout-trace.zip' });
});
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// ✅ Record video only on failure (recommended)
video: 'on-first-retry',
// Video size configuration
video: {
mode: 'on-first-retry',
size: { width: 1280, height: 720 },
},
},
});
test('video will be saved on failure', async ({ page }, testInfo) => {
await page.goto('/products');
await page.getByRole('button', { name: 'Add to Cart' }).click();
// After test completes, video is available at:
// test-results/<test-name>/video.webm
// You can also access video path programmatically
const video = page.video();
if (video) {
const path = await video.path();
console.log('Video saved at:', path);
// Attach video to test report
await testInfo.attach('test-video', {
path: path,
contentType: 'video/webm',
});
}
});
// Use VIDEO when:
// - You need to see the full visual flow
// - Animations or transitions are involved
// - You want to share with non-technical stakeholders
// - CI/CD failure investigation
// Use TRACE when:
// - You need to inspect DOM state at each step
// - You need network request/response details
// - You need console output
// - You need step-by-step debugging
// - Trace is more detailed but larger files
// ✅ Best practice: Use both on first retry
// video: 'on-first-retry',
// trace: 'on-first-retry',
test('debug with screenshots', async ({ page }, testInfo) => {
await page.goto('/checkout');
// Capture state at key points
await page.screenshot({
path: 'debug/step-1-page-loaded.png',
fullPage: true,
});
await page.getByLabel('Email').fill('user@example.com');
// Capture after form fill
await page.screenshot({
path: 'debug/step-2-form-filled.png',
});
await page.getByRole('button', { name: 'Submit' }).click();
// Capture result
await page.screenshot({
path: 'debug/step-3-after-submit.png',
fullPage: true,
});
// Attach to report for easy access
await testInfo.attach('after-submit', {
body: await page.screenshot(),
contentType: 'image/png',
});
});
test('capture specific element state', async ({ page }) => {
await page.goto('/dashboard');
// Screenshot just the problematic component
const widget = page.getByTestId('revenue-widget');
await widget.screenshot({ path: 'debug/revenue-widget.png' });
// Screenshot with element highlighted
await page.evaluate(() => {
const el = document.querySelector('[data-testid="revenue-widget"]');
if (el) {
(el as HTMLElement).style.border = '3px solid red';
}
});
await page.screenshot({ path: 'debug/highlighted-widget.png' });
});
test('monitor console for errors', async ({ page }) => {
const consoleMessages: string[] = [];
const consoleErrors: string[] = [];
// Capture all console messages
page.on('console', (msg) => {
const text = `[${msg.type()}] ${msg.text()}`;
consoleMessages.push(text);
if (msg.type() === 'error') {
consoleErrors.push(text);
}
});
// Capture uncaught exceptions
page.on('pageerror', (error) => {
consoleErrors.push(`[uncaught] ${error.message}`);
});
await page.goto('/dashboard');
await page.getByRole('button', { name: 'Load Data' }).click();
// Assert no unexpected console errors
const unexpectedErrors = consoleErrors.filter(
(err) => !err.includes('Expected warning') // Filter known warnings
);
(unexpectedErrors, ).();
});
test('debug API calls', async ({ page }) => {
const apiCalls: Array<{ method: string; url: string; status: number }> = [];
// Log all API responses
page.on('response', (response) => {
if (response.url().includes('/api/')) {
apiCalls.push({
method: response.request().method(),
url: response.url(),
status: response.status(),
});
}
});
// Log failed requests
page.on('requestfailed', (request) => {
console.error(`Request failed: ${request.method()} ${request.url()}`);
console.error(`Reason: ${request.failure()?.errorText}`);
});
await page.goto('/products');
// Verify expected API calls were made
console.log(, .(apiCalls, , ));
(apiCalls.( call..())).();
});
test('wait for API before asserting', async ({ page }) => {
await page.goto('/dashboard');
// ✅ Good - Wait for specific API response before asserting
const [response] = await Promise.all([
page.waitForResponse('**/api/analytics'),
page.getByRole('button', { name: 'Refresh' }).click(),
]);
expect(response.status()).toBe(200);
const data = await response.json();
expect(data.totalRevenue).toBeGreaterThan(0);
});
// SYMPTOM: "Timeout waiting for selector"
// CAUSE: Selector doesn't match any element
// Debugging steps:
test('debug element not found', async ({ page }) => {
await page.goto('/products');
// Step 1: Check if page loaded correctly
console.log('Page URL:', page.url());
console.log('Page title:', await page.title());
// Step 2: Check if element exists at all
const count = await page.getByRole('button', { name: 'Add to Cart' }).count();
console.log('Matching elements:', count);
// Step 3: Check what's actually on the page
const buttons = await page.getByRole('button').allTextContents();
console.log('All buttons:', buttons);
// Step 4: Try a broader selector
const allText = await page.textContent('body');
console.log('Page text includes "Add":', allText?.());
});
// SYMPTOM: Test passes locally but fails in CI
// CAUSE: Race condition between UI update and assertion
// ✅ Fix: Use proper Playwright waiting
test('fix race condition', async ({ page }) => {
await page.goto('/products');
await page.getByRole('button', { name: 'Add to Cart' }).click();
// ✅ Wait for the specific response that triggers UI update
await page.waitForResponse('**/api/cart');
// ✅ Then assert with auto-waiting
await expect(page.getByRole('alert')).toHaveText('Added to cart');
});
// SYMPTOM: "Element is not attached to the DOM"
// CAUSE: Page re-rendered and element reference is stale
// ✅ Fix: Use locators (not element handles)
test('avoid stale element', async ({ page }) => {
await page.goto('/products');
// ✅ Locators always re-query the DOM
const addButton = page.getByRole('button', { name: 'Add to Cart' });
await addButton.click(); // Always finds the latest element
// ❌ Element handles can become stale
// const handle = await page.$('button.add-to-cart');
// await handle.click(); // May fail if DOM re-rendered
});
// SYMPTOM: "Target page, context or browser has been closed"
// CAUSE: Navigation triggered but test didn't wait for it
// ✅ Fix: Wait for navigation explicitly
test('handle navigation', async ({ page }) => {
await page.goto('/login');
// ✅ Wait for navigation triggered by form submit
await Promise.all([
page.waitForURL('**/dashboard'),
page.getByRole('button', { name: 'Login' }).click(),
]);
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
// playwright.config.ts - CI-specific configuration
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Retry failed tests in CI
retries: process.env.CI ? 2 : 0,
use: {
// Capture artifacts on failure in CI
screenshot: 'only-on-failure',
trace: 'on-first-retry',
video: 'on-first-retry',
},
// Output directory for artifacts
outputDir: 'test-results/',
// HTML report
reporter: process.env.CI
? [['html', { open: 'never' }], ['github']]
: [['html', { open: 'on-failure' }]],
});
# Download CI artifacts and view the HTML report
npx playwright show-report path/to/downloaded/report
# View trace from CI artifacts
npx playwright show-trace path/to/trace.zip
# Run specific failing test locally with CI-like settings
CI=true npx playwright test tests/failing-test.spec.ts --retries=0 --headed
// Add environment info to test output for comparison
test.beforeAll(async () => {
console.log('Environment:', {
ci: process.env.CI,
os: process.platform,
nodeVersion: process.version,
pwVersion: require('@playwright/test/package.json').version,
});
});
# Open a browser to test selectors
npx playwright open https://your-app.com
# Use the Locator picker in the toolbar to find selectors
# Type selectors in the console to test them:
# > page.getByRole('button', { name: 'Submit' })
# > page.getByLabel('Email')
test('debug selectors', async ({ page }) => {
await page.goto('/products');
// List all role-based matches
const buttons = page.getByRole('button');
console.log('Total buttons:', await buttons.count());
for (let i = 0; i < await buttons.count(); i++) {
console.log(`Button ${i}:`, await buttons.nth(i).textContent());
}
// Check if element is hidden vs missing
const submitBtn = page.getByRole('button', { name: 'Submit' });
const isVisible = await submitBtn.isVisible();
const count = await submitBtn.count();
console.log(`Submit button - count: ${count}, visible: ${isVisible}`);
// Use evaluate to inspect element properties
const element = page.getByTestId('product-card');
( element.() > ) {
classes = element.().();
.(, classes);
}
});
# Generate test code by interacting with the app
npx playwright codegen https://your-app.com
# Codegen will:
# 1. Open a browser with your app
# 2. Record your interactions
# 3. Generate Playwright test code with recommended selectors
# 4. You can copy selectors directly into your tests
Reproduce the failure
npx playwright test --headedGather evidence
test-results/npx playwright show-trace <trace.zip>Narrow the scope
page.pause() before the failing stepIdentify root cause
Apply the fix
test.only, , or Before considering a test complete, run it multiple times to confirm stability:
# Run a specific test 5 times to check for flakiness
npx playwright test -g "Should display product details" --repeat-each=5 --reporter=line
# Run a specific file 5 times
npx playwright test tests/checkout/cart.spec.ts --repeat-each=5 --reporter=line
# Use the provided hook script for convenience
./hooks/validate-test.sh "Should display product details"
./hooks/validate-test.sh "tests/checkout/cart.spec.ts"
Why 5 times?
// ✅ Good - Test is deterministic and passes every time
test('Should display product details', async ({ page }) => {
// Set up via API (not dependent on UI state)
const product = await createTestProduct(page, { name: 'Laptop' });
await page.goto(`/products/${product.id}`);
// Wait for specific API response, not arbitrary timeout
await page.waitForResponse('**/api/products/*');
await expect(page.getByRole('heading', { name: 'Laptop' })).toBeVisible();
});
// ❌ Bad - Test has timing issues that cause flakiness
test('display products', async ({ page }) => {
await page.goto('/products');
await page.waitForTimeout(2000); // Flaky!
await expect(page.getByText('Laptop')).toBeVisible();
});
# Debug a specific test
npx playwright test tests/my-test.spec.ts --debug
# Run headed with slow motion
npx playwright test --headed --slow-mo=500
# Generate test with codegen
npx playwright codegen http://localhost:3000
# View HTML report
npx playwright show-report
# View trace file
npx playwright show-trace test-results/trace.zip
# Run with full trace
npx playwright test --trace on
# List available tests
npx playwright test --list
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
page.pause()console.log