本文へ移動
cccskills
無料GitHub で公開

playwright-automation

Write production-grade Playwright tests in TypeScript: Page Object Model, fixtures, auto-waiting, user-facing locators, parallel execution, CI integration, sharding, and 2025-2026 feature awareness. Includes an explicit "do not" list for AI agents. Use when: "Playwright," "write E2E test," "page object," "new Playwright suite," "Playwright config." Not for: fixing one flaky test at runtime — use test-reliability. Not for: bulk regenerating selectors after a UI refactor — use selector-drift-recovery. Not for: visual baseline creation/management — use visual-testing. Not for: deep WCAG/axe audits — use accessibility-testing. Related: visual-testing, ci-cd-integration, api-testing, test-reliability, selector-drift-recovery, accessibility-testing.

インストール方法を見る

含まれるファイル(9)

  • SKILL.md21.6 KB
  • references/anti-patterns.md13.9 KB
  • references/auth-patterns.md11.9 KB
  • references/ci-recipes.md12.2 KB
  • references/debugging-and-triage.md9.6 KB
  • references/fixtures-and-projects.md12.8 KB
  • references/multi-site-architecture.md13.4 KB
  • references/network-and-mocking.md13.3 KB
  • references/selector-strategies.md12.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

<objective> How an expert agent writes stable, maintainable, production-grade Playwright tests in TypeScript. The failure this prevents: AI agents reflexively reach for the three patterns that produce suites which pass once and flake forever — never use `waitForTimeout`, never default to CSS selectors, and avoid the legacy `page.click()` family. This skill encodes the auto-waiting, user-facing-locator, fixture-based discipline that makes a suite survive a refactor. </objective>

Discovery Questions

Check .agents/qa-project-context.md first — if it exists, use it and skip any question answered there. Then ask only what's missing:

  1. TypeScript or JavaScript? TypeScript is strongly recommended — it catches locator and assertion mistakes at compile time, and every example here assumes it.
  2. Which browsers? Chromium for local dev; add Firefox and WebKit in CI. Mobile viewports are separate Playwright projects, not separate test files — they change the device descriptor.
  3. Existing suite or fresh start? Migrating from Cypress/Selenium, rewrite the flakiest tests first; never big-bang. Changes the sequencing entirely.
  4. Single site or multi-site? Multi-site needs shared fixtures and per-site config objects — see references/multi-site-architecture.md.

Core Principles

  1. User-facing locators first. getByRole > getByLabel > getByTestId > CSS (last resort). Locators must reflect what the user sees, not how the DOM is structured. See references/selector-strategies.md.
  2. Auto-waiting — NEVER use waitForTimeout. Every Playwright action and web-first assertion auto-waits. If you think you need a timeout, you need a better locator or assertion.
  3. Test isolation. Each test gets a fresh BrowserContext. Tests must never depend on other tests' state or execution order.
  4. Parallel by default, serial only when necessary. Use fullyParallel: true. Reserve test.describe.serial for flows that genuinely cannot be isolated (rare).
  5. Fixtures for setup, not hooks. Fixtures compose, provide type safety, and tear down automatically. Prefer them over beforeEach/afterEach for anything non-trivial. See references/fixtures-and-projects.md.

Calibrate to your team maturity (set team_maturity in .agents/qa-project-context.md):

  • startup — Chromium only, 5–10 critical-path tests, basic CI run on PR. Skip sharding and visual baselines until the suite is stable.
  • growing — Chromium + Firefox, POM structure, parallel execution, sharding in CI, HTML report artifacts.
  • established — Full browser matrix, auth fixtures, API mocking layer, visual regression baseline, trace-on-failure, flakiness tracking.

Project Structure

project-root/
├── playwright.config.ts
├── e2e/
│   ├── fixtures/              # base.fixture.ts, auth.fixture.ts, data.fixture.ts
│   ├── pages/                 # Page objects by feature
│   │   ├── base.page.ts
│   │   ├── dashboard.page.ts
│   │   └── components/        # Reusable component objects (data-table, modal)
│   ├── tests/                 # Test files by feature (auth/, dashboard/, settings/)
│   ├── helpers/               # test-data.ts, api-client.ts
│   └── global-setup.ts
├── .auth/                     # Git-ignored storageState files
└── test-results/              # Git-ignored artifacts

playwright.config.ts

import { defineConfig, devices } from '@playwright/test';

const isCI = !!process.env.CI;
const baseURL = process.env.BASE_URL ?? 'http://localhost:3000';

export default defineConfig({
  testDir: './e2e/tests',
  fullyParallel: true,
  forbidOnly: isCI,
  retries: isCI ? 2 : 0,
  workers: isCI ? '50%' : undefined,
  reporter: isCI
    ? [['blob'], ['github'], ['json', { outputFile: 'test-results/results.json' }]]
    : [['html', { open: 'on-failure' }]],
  use: {
    baseURL,
    trace: isCI ? 'on-first-retry' : 'retain-on-failure',
    screenshot: 'only-on-failure',
    video: isCI ? 'on-first-retry' : 'off',
    navigationTimeout: 30_000,
    // Avoid a global actionTimeout — it can mask a genuinely slow auto-waited
    // action. Set per-action only where a known-slow widget needs it.
  },
  projects: [
    { name: 'setup', testMatch: /global-setup\.ts/, teardown: 'teardown' },
    { name: 'teardown', testMatch: /global-teardown\.ts/ },
    { name: 'chromium', use: { ...devices['Desktop Chrome'], storageState: '.auth/user.json' }, dependencies: ['setup'] },
    { name: 'firefox', use: { ...devices['Desktop Firefox'], storageState: '.auth/user.json' }, dependencies: ['setup'] },
    { name: 'webkit', use: { ...devices['Desktop Safari'], storageState: '.auth/user.json' }, dependencies: ['setup'] },
  ],
  webServer: isCI ? undefined : {
    command: 'npm run dev', url: baseURL, reuseExistingServer: !isCI, timeout: 120_000,
  },
});

The blob reporter in CI is what makes sharded runs mergeable — see the sharding section. The setup project writes storageState once before the browser projects depend on it.

Global setup (storageState)

import { test as setup, expect } from '@playwright/test';

setup('authenticate as default user', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill(process.env.TEST_USER_EMAIL!);
  await page.getByLabel('Password').fill(process.env.TEST_USER_PASSWORD!);
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page).toHaveURL(/.*dashboard/);
  await page.context().storageState({ path: '.auth/user.json' });
});

This is the setup project pattern: the setup project (or a globalSetup file) runs UI login once, and every browser project replays the saved cookies/localStorage via storageState in config. For multi-role auth (admin/user/guest) and token seeding, see references/auth-patterns.md.


Page Object Model

import { type Page, type Locator, expect } from '@playwright/test';

export abstract class BasePage {
  constructor(protected readonly page: Page) {}
  abstract readonly path: string;
  async goto(): Promise<void> {
    await this.page.goto(this.path);
    await this.page.waitForLoadState('domcontentloaded');
  }
}

Component objects represent reusable UI fragments (modals, tables, nav). They take a root Locator, not a Page:

export class DataTable {
  readonly rows: Locator;
  constructor(private readonly root: Locator) {
    this.rows = root.getByRole('row');
  }
  getRowByText(text: string | RegExp): Locator {
    return this.rows.filter({ hasText: text });
  }
}

Compose, don't inherit deep. A page holds its components; it does not extend a five-level hierarchy:

export class UsersPage extends BasePage {
  readonly path = '/admin/users';
  readonly table: DataTable;
  constructor(page: Page) {
    super(page);
    this.table = new DataTable(page.getByRole('table', { name: 'Users' }));
  }
}

Inject page objects via fixtures, not constructors in test files:

export const test = base.extend<{ usersPage: UsersPage }>({
  usersPage: async ({ page }, use) => { await use(new UsersPage(page)); },
});
export { expect } from '@playwright/test';

POM methods return state (locators, values); they do not assert. Assertions live in the test so failures point at the test, not the page object.


Test Patterns

Form interactions with test.step

Wrap logical action groups in test.step() for readable trace-viewer output:

test('submits a multi-step form', async ({ page }) => {
  await page.goto('/onboarding');
  await test.step('fill personal info', async () => {
    await page.getByLabel('First name').fill('Jane');
    await page.getByRole('button', { name: 'Next' }).click();
  });
  await test.step('submit', async () => {
    await page.getByRole('button', { name: 'Complete setup' }).click();
  });
  await expect(page).toHaveURL('/dashboard');
});

API mocking

// Mock a response
await page.route('**/api/products*', async (route) => {
  await route.fulfill({ json: { items: [{ id: '1', name: 'Widget', price: 29.99 }] } });
});

// Modify a real response
await page.route('**/api/feature-flags', async (route) => {
  const response = await route.fetch();
  const body = await response.json();
  body.flags['new-checkout'] = true;
  await route.fulfill({ response, json: body });
});

// Simulate an error
await page.route('**/api/products*', (route) => route.fulfill({ status: 500 }));

// WebSocket (v1.48+)
await page.routeWebSocket('**/ws/notifications', (ws) => {
  ws.onMessage(() => ws.send(JSON.stringify({ type: 'alert', title: 'Deployed' })));
});

See references/network-and-mocking.md for HAR replay and conditional routing.

Authenticated APIRequestContext fixture

For seeding data or asserting backend state without driving the UI, inject a pre-authenticated APIRequestContext. Acquire the token in the fixture; never hardcode it:

import { test, request, type APIRequestContext } from '@playwright/test';

// test.extend adds an `api` fixture to the base test object.
export const apiTest = test.extend<{ api: APIRequestContext }>({
  api: async ({ baseURL }, use) => {
    const ctx = await request.newContext({
      baseURL,
      extraHTTPHeaders: { Authorization: `Bearer ${process.env.API_TOKEN!}` },
    });
    await use(ctx);
    await ctx.dispose();
  },
});

Tags and annotations

test('checkout @smoke', async ({ page }) => { /* npx playwright test --grep @smoke */ });
test.slow();                                    // Triples timeout
test.skip(({ browserName }) => browserName === 'webkit', 'WebKit bug');
test.fixme('known issue tracked in JIRA-1234', async ({ page }) => { /* ... */ });

Assertions

Always prefer web-first assertions — they auto-retry until the condition holds or the timeout expires:

await expect(page.getByRole('alert')).toBeVisible();
await expect(page.getByRole('heading')).toHaveText('Dashboard');
await expect(page).toHaveURL('/dashboard');
await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled();
await expect(page.getByRole('listitem')).toHaveCount(5);
await expect(page.getByRole('listitem')).toHaveText(['Apple', 'Banana', 'Cherry']);

Soft assertions collect all failures instead of stopping at the first:

await expect.soft(page.getByLabel('Name')).toHaveValue('Jane Doe');
await expect.soft(page.getByLabel('Email')).toHaveValue('jane@example.com');

ARIA snapshots verify accessibility-tree structure and catch semantic regressions:

await expect(page.getByRole('navigation', { name: 'Main' })).toMatchAriaSnapshot(`
  - navigation "Main":
    - link "Home"
    - link "Products"
`);

Visual regression (one-liner; defer the workflow)

Playwright's built-in toHaveScreenshot auto-retries and writes a baseline on first run. Mask dynamic regions; do not precede it with waitForTimeout:

await expect(page.getByTestId('product-card')).toHaveScreenshot('product-card.png', {
  mask: [page.getByTestId('price')],
});

For baseline management, thresholds (maxDiffPixelRatio, maskColor, stylePath), and review workflows, use visual-testing — that is where visual baselines belong.

Accessibility scan (axe; deep audits live elsewhere)

ARIA snapshots above check structure, not WCAG rules. For rule-based scanning, add @axe-core/playwright:

import AxeBuilder from '@axe-core/playwright';

test('dashboard has no a11y violations', async ({ page }) => {
  await page.goto('/dashboard');
  const results = await new AxeBuilder({ page }).analyze();
  expect(results.violations).toEqual([]);
});

For WCAG levels, rule tuning, and remediation guidance, use accessibility-testing.


Parallel Execution & CI

Sharding across CI nodes

Split the suite across matrix jobs, then merge the shard reports into one HTML report. Sharding earns its place at growing+ maturity; a startup suite of 5–10 tests should not shard.

strategy:
  fail-fast: false
  matrix:
    shard: [1, 2, 3, 4]
steps:
  - run: npx playwright test --shard=${{ matrix.shard }}/4

Each shard uploads its blob-report/; a final job runs npx playwright merge-reports --reporter=html ./all-blob-reports. The blob reporter (set in the config above) is what makes merge work — --shard alone produces fragmented HTML reports. See references/ci-recipes.md for the full GitHub Actions workflow, blob upload/download, and artifact patterns.

Debugging

  • Trace viewer: npx playwright show-trace test-results/.../trace.zip — timeline of actions, network, DOM snapshots, console.
  • UI mode: npx playwright test --ui — live, step-by-step, time-travel.
  • Debug flag: npx playwright test my-test.spec.ts --debug — headed, pauses each action.
  • VS Code extension ms-playwright.playwright — run/debug from gutter, pick locators, watch mode.
  • page.pause() opens the Inspector mid-test. Local only — never commit it.

See references/debugging-and-triage.md for flaky-test triage and artifact analysis.


New Features (2025-2026)

Current latest is Playwright 1.60.0 (May 2026). Pin the same version in package.json and your CI Docker image. Recent additions worth knowing:

VersionFeatureWhat it does
v1.45Clock APIpage.clock.install() / fastForward() — control time without monkey-patching Date
v1.45--fail-on-flaky-testsFail the CI run if any test needed a retry to pass
v1.46--only-changedRun only tests affected by changed files (git-diff aware)
v1.46ARIA snapshotstoMatchAriaSnapshot() for accessibility-tree assertions
v1.48routeWebSocketFirst-class WebSocket interception (replaces CDP hacks)
v1.55Test MigratorAutomated Cypress→/Selenium→Playwright via npx playwright migrate
v1.56Test Agentsnpx playwright init-agents --loop=claude|vscode|opencode — planner/generator/healer agents inside the coding agent's loop
v1.57Chrome for Testing defaultHeaded uses chrome, headless uses chrome-headless-shell instead of bundled Chromium. Caveat: a high-memory regression was reported (microsoft/playwright #38489) — pin a known-good image tag for CI.
v1.57toHaveScreenshot optionsmaskColor, stylePath, pathTemplate for masking color, custom stylesheet, and output path control
v1.59Screencast APIpage.screencast.start() / .stop() for mid-test video with start/stop control — an alternative to recordVideo, not a replacement. Adds action annotations, chapter markers, custom HTML overlays, and screencast.showOverlays() / hideOverlays(). Useful for agent self-verification: a coding agent can hand off a reviewable video receipt.
v1.59--debug=cliPause-and-attach so an agent can step through a test
v1.60locator.drop()Simulate an external file/clipboard drag-and-drop onto an element
v1.60tracing.startHar()HAR recording as a first-class tracing API

AI-augmented authoring (Test Agents vs MCP)

Two integration paths — pick based on whether the agent runs inside your editor loop or drives a real browser remotely.

Path A — Test Agents (npx playwright init-agents --loop=claude): scaffolds planner/generator/healer agents the coding agent loads during its loop. Token-efficient — no MCP server, no inter-process traffic. Best for "Claude/VS Code/opencode writes Playwright tests for me."

Path B — @playwright/mcp: an MCP server exposing browser actions to any MCP-aware agent. Higher overhead (process boundary, JSON marshalling) but the right choice when the agent must drive a live browser interactively rather than author tests offline. Config: { "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest"] } } } in .mcp.json.

For test-failure repair, see test-reliability. For first-time generation from PRDs/specs, see ai-test-generation.


Anti-Patterns

Design-time mistakes that quietly rot a suite. The code-level "never do X" list lives in references/anti-patterns.md with BAD/GOOD pairs — load it when writing test bodies.

1. The God Page Object

One class for the whole app turns into a 2000-line file every test imports and nothing can refactor safely. Split by page/feature and compose component objects.

2. POM methods that assert

A page object whose methods call expect hides the assertion from the test. When it fails, the stack points at the page object, not the failing scenario. Return locators/state; assert in the test.

3. Asserting on implementation detail

Tests keyed to CSS classes, DOM nesting, or internal IDs break on every refactor without a real behavior change. Assert what the user perceives — visible text, roles, URLs.

4. Fixtures that depend on test order

A fixture that mutates shared module state, or assumes another test ran first, fails the moment tests parallelize or run in isolation. Each fixture must stand alone.

5. data-testid where getByRole would work

Sprinkling test ids onto buttons and headings that already have an accessible name skips the cheapest accessibility signal you get for free. Reserve getByTestId for elements with no stable role/label.

The most damaging runtime mistake — synchronizing with waitForTimeout instead of an auto-waiting locator:

// BAD — slow on fast machines, flaky on slow ones, hides the real condition
await page.waitForTimeout(2000);
await page.click('#submit');

// GOOD — the action auto-waits for actionability
await page.getByRole('button', { name: 'Submit' }).click();

The other nine code-level offenders (CSS over roles, page.* over locators, force: true, shared state, per-test login, locator.all() without a stability check, allTextContents() over toHaveText(), hitting real third-party services, committed test.only) are in references/anti-patterns.md.


Verification

Run these against the generated artifact, smallest first:

npx playwright test --list                 # tests are discovered and parse
grep -rn 'waitForTimeout\|page.pause' e2e/  # must print nothing
npx tsc --noEmit                            # locator/assertion types compile

Enforce the "never do X" rules in CI with eslint-plugin-playwright — rules no-wait-for-timeout, no-force-option, no-element-handle, no-page-pause turn this skill's prose bans into a failing lint.


Done When

  • playwright.config.ts exists with projects for at least Chromium (Firefox + WebKit added when targeting CI), and forbidOnly: !!process.env.CI.
  • Page Object Model files live in e2e/pages/ (or equivalent), with component objects composed via a root Locator and no expect inside POM methods.
  • grep -rn 'waitForTimeout' e2e/ returns nothing, and eslint-plugin-playwright's no-wait-for-timeout is enabled.
  • Every locator uses getByRole / getByLabel / getByTestId — grep -rn 'page.locator(\|xpath=\|css=' e2e/ returns nothing (or only justified, commented exceptions).
  • CI runs the suite on PR; at growing+ maturity it shards across matrix jobs with the blob reporter and a merge-reports step, uploading the HTML report as an artifact on failure.

Related Skills

  • visual-testing — screenshot baseline creation, threshold tuning, and review/approval workflows. Go here for anything beyond a single inline toHaveScreenshot check.
  • accessibility-testing — WCAG levels, axe rule tuning, and remediation. This skill only shows a minimal axe scan.
  • api-testing — backend API validation, schema/contract testing, and the full APIRequestContext patterns.
  • ci-cd-integration — pipeline config, parallelization, and reporting beyond Playwright's own.
  • test-reliability — runtime healing of a single flaky test (quarantine, retry strategy).
  • selector-drift-recovery — offline bulk regeneration of selectors after a UI refactor breaks many tests.

Reference files (in references/)

FilePurpose
anti-patterns.mdBAD vs GOOD code pairs for every code-level mistake
fixtures-and-projects.mdAuth fixtures, data fixtures, multi-env projects, composition
selector-strategies.mdLocator decision tree, getByRole examples, stability scoring
auth-patterns.mdstorageState, multi-role, token seeding, session expiry
multi-site-architecture.mdShared fixtures, per-site config, monorepo patterns
network-and-mocking.mdpage.route, route.fetch, HAR, WebSocket, conditional routing
debugging-and-triage.mdTrace viewer, flaky-test triage, retries, artifacts
ci-recipes.mdReporters, sharding + merge, --only-changed, browser caching, Docker

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Test for WCAG 2.2 AA compliance with axe-core + Playwright, keyboard navigation audits, screen reader testing, ARIA pattern validation, and legal compliance mapping (ADA, EAA, Section 508). Automated tools catch 30-40% of issues — this skill covers automated and manual testing together. Use when: "accessibility," "a11y," "WCAG," "screen reader," "axe," "keyboard navigation," "ARIA," "ADA compliance." Not for: cookie-consent/GDPR compliance — use compliance-testing; pixel-diff visual regression — use visual-testing. Related: playwright-automation, compliance-testing, visual-testing, ci-cd-integration.

日本語の概要は準備中です。原文の説明を表示しています。

petrkindlmann/qa-skills1802026年6月11日 更新

Goal-driven E2E testing where a browser agent (Playwright MCP / computer-use) reads a natural-language goal and explores the app via the accessibility tree to assert outcomes — no pre-written script. Covers when intent-driven beats scripted, making agent runs deterministic (pinned model, temperature 0, seeded data, bounded steps, explicit success assertion, snapshot-not-pixel), cost/latency control, the accessibility-tree-first interaction model, CI gating, and graduating a stable run into a scripted Playwright test. Use when: "agentic browser test," "goal-driven browser test," "let an agent explore the app," "natural-language E2E," "browser agent smoke test," "Playwright MCP test." Not for: Writing/maintaining deterministic scripted Playwright tests — that is playwright-automation. Testing your product's OWN LLM features — that is ai-system-testing. Related: playwright-automation, ai-system-testing, exploratory-testing, test-reliability, qa-project-context.

日本語の概要は準備中です。原文の説明を表示しています。

petrkindlmann/qa-skills1802026年6月11日 更新

Hybrid fingerprint + LLM pipeline for bug classification, deduplication, and ticket generation. Normalizes CI logs, creates stable fingerprints, clusters near-duplicates, then uses LLM for severity classification and ticket writing. Includes bug reporting templates and severity/priority matrix. Use when: "bug triage," "classify bugs," "failure analysis," "auto-classify," "CI failures," "bug report," "defect template." Not for: runtime self-healing of one flaky locator — use test-reliability. Not for: designing new tests from production telemetry — use observability-driven-testing. Related: qa-metrics, qa-dashboard, ci-cd-integration, qa-project-context.

日本語の概要は準備中です。原文の説明を表示しています。

petrkindlmann/qa-skills1802026年6月11日 更新

Review EXISTING test code for quality, smells, and testability issues. Detects test smells across six dimensions — readability, reliability, diagnostic value, design, AI-generated, and coverage — analyzes testability of application code, and backs the qualitative smells with mutation testing. Use when: "review my tests," "test quality audit," "test smells," "testability analysis," "are these tests any good." Not for: generating new tests — use `ai-test-generation`. Not for: testing AI features in your product — use `ai-system-testing`. Related: unit-testing, shift-left-testing, coverage-analysis, ai-test-generation.

日本語の概要は準備中です。原文の説明を表示しています。

petrkindlmann/qa-skills1802026年6月11日 更新

Test AI/LLM features that ship in your product. Covers prompt regression testing, response quality evaluation, tool-call validation, hallucination and RAG grounding checks, nondeterministic-output strategies, red-team/safety scans, eval frameworks, and agent-as-target injection (indirect injection via tool output / RAG / scan reports, self-propagating payloads, data exfiltration via an agent) plus a bundled detector for untrusted content. Use when: "test our LLM feature," "prompt regression test," "eval framework," "hallucination test," "RAG grounding," "nondeterministic output," "AI feature testing," "red-team our chatbot," "indirect prompt injection," "agent reading untrusted tool output," "production AI quality." Not for: using AI to generate your own test code — use ai-test-generation. Not for: classifying CI failures with AI — use ai-bug-triage. Not for: EU AI Act / GDPR conformity of an AI feature — use compliance-testing. Not for: canary/flag rollout of an AI feature — use testing-in-production. Related: ai-test-generation, ai-qa-review, api-testing, compliance-testing, security-testing, risk-based-testing, test-data-management.

日本語の概要は準備中です。原文の説明を表示しています。

petrkindlmann/qa-skills1802026年6月11日 更新

Use AI to write NEW test code from specs, PRDs, user stories, code diffs, bug reports, or OpenAPI specs. Staged pipeline: requirements extraction → risk analysis → coverage matrix → scenario generation → oracle design → test code → human review, with guardrails against hallucinated APIs and weak assertions. Use when: "generate tests from spec," "tests from PRD," "tests from user story," "auto-generate test cases," "AI write tests for me." Not for: testing AI/LLM features in your product — use ai-system-testing. Not for: auditing a pre-existing test suite you did not just generate — use ai-qa-review (Step 7 here only reviews tests THIS pipeline produced). Related: playwright-automation, unit-testing, api-testing, qa-project-context.

日本語の概要は準備中です。原文の説明を表示しています。

petrkindlmann/qa-skills1802026年6月11日 更新

petrkindlmann のスキルをすべて見る

このスキルの問題を報告する