qa-skills 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -0
- package/bin/cli.js +42 -0
- package/dist/agents/registry.d.ts +5 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +101 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/types.d.ts +9 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/dependencies.d.ts +21 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +125 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/installer.d.ts +25 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +437 -0
- package/dist/installer.js.map +1 -0
- package/dist/scaffold.d.ts +27 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +182 -0
- package/dist/scaffold.js.map +1 -0
- package/package.json +40 -0
- package/skills/qa-accessibility-test-writer/SKILL.md +127 -0
- package/skills/qa-accessibility-test-writer/references/axe-core-patterns.md +349 -0
- package/skills/qa-accessibility-test-writer/references/best-practices.md +184 -0
- package/skills/qa-accessibility-test-writer/references/wcag-tests.md +331 -0
- package/skills/qa-api-contract-curator/SKILL.md +104 -0
- package/skills/qa-api-contract-curator/references/breaking-changes.md +363 -0
- package/skills/qa-api-contract-curator/references/openapi-structure.md +404 -0
- package/skills/qa-browser-data-collector/SKILL.md +132 -0
- package/skills/qa-browser-data-collector/references/data-collection-checklist.md +91 -0
- package/skills/qa-browser-data-collector/references/playwright-mcp-patterns.md +113 -0
- package/skills/qa-bug-ticket-creator/SKILL.md +148 -0
- package/skills/qa-bug-ticket-creator/references/bug-report-format.md +149 -0
- package/skills/qa-bug-ticket-creator/references/severity-guide.md +81 -0
- package/skills/qa-bug-ticket-creator/templates/bug-ticket-template.md +39 -0
- package/skills/qa-changelog-analyzer/SKILL.md +134 -0
- package/skills/qa-changelog-analyzer/references/git-analysis-patterns.md +138 -0
- package/skills/qa-changelog-analyzer/references/impact-mapping.md +120 -0
- package/skills/qa-clickup-integration/SKILL.md +166 -0
- package/skills/qa-clickup-integration/references/api-patterns.md +102 -0
- package/skills/qa-clickup-integration/references/field-mapping.md +71 -0
- package/skills/qa-codeceptjs-writer/SKILL.md +136 -0
- package/skills/qa-codeceptjs-writer/references/best-practices.md +207 -0
- package/skills/qa-codeceptjs-writer/references/config.md +255 -0
- package/skills/qa-codeceptjs-writer/references/patterns.md +285 -0
- package/skills/qa-coverage-analyzer/SKILL.md +166 -0
- package/skills/qa-coverage-analyzer/references/best-practices.md +142 -0
- package/skills/qa-coverage-analyzer/references/coverage-dimensions.md +155 -0
- package/skills/qa-coverage-analyzer/references/tools.md +204 -0
- package/skills/qa-cypress-writer/SKILL.md +134 -0
- package/skills/qa-cypress-writer/references/assertions.md +121 -0
- package/skills/qa-cypress-writer/references/best-practices.md +82 -0
- package/skills/qa-cypress-writer/references/config.md +121 -0
- package/skills/qa-cypress-writer/references/patterns.md +170 -0
- package/skills/qa-data-factory/SKILL.md +126 -0
- package/skills/qa-data-factory/references/factory-patterns.md +164 -0
- package/skills/qa-data-factory/references/faker-guide.md +131 -0
- package/skills/qa-diagram-generator/SKILL.md +125 -0
- package/skills/qa-diagram-generator/references/c4-model.md +53 -0
- package/skills/qa-diagram-generator/references/charts.md +58 -0
- package/skills/qa-diagram-generator/references/class-diagram.md +85 -0
- package/skills/qa-diagram-generator/references/er-diagram.md +69 -0
- package/skills/qa-diagram-generator/references/flowchart.md +92 -0
- package/skills/qa-diagram-generator/references/from-screenshot.md +45 -0
- package/skills/qa-diagram-generator/references/gantt.md +49 -0
- package/skills/qa-diagram-generator/references/journey.md +50 -0
- package/skills/qa-diagram-generator/references/mindmap.md +75 -0
- package/skills/qa-diagram-generator/references/sequence.md +69 -0
- package/skills/qa-diagram-generator/references/state-diagram.md +56 -0
- package/skills/qa-discovery-interview/SKILL.md +182 -0
- package/skills/qa-discovery-interview/references/completeness-checklist.md +53 -0
- package/skills/qa-discovery-interview/references/conflict-patterns.md +101 -0
- package/skills/qa-discovery-interview/references/qa-categories.md +147 -0
- package/skills/qa-discovery-interview/templates/qa-brief-template.md +168 -0
- package/skills/qa-environment-checker/SKILL.md +142 -0
- package/skills/qa-environment-checker/references/dependency-matrix.md +101 -0
- package/skills/qa-environment-checker/references/health-checks.md +209 -0
- package/skills/qa-environment-checker/templates/env-readiness-template.md +64 -0
- package/skills/qa-flaky-detector/SKILL.md +153 -0
- package/skills/qa-flaky-detector/references/ci-analysis.md +140 -0
- package/skills/qa-flaky-detector/references/flaky-patterns.md +247 -0
- package/skills/qa-github-issues-enhanced/SKILL.md +175 -0
- package/skills/qa-github-issues-enhanced/references/issue-templates.md +425 -0
- package/skills/qa-github-issues-enhanced/references/label-taxonomy.md +130 -0
- package/skills/qa-github-issues-enhanced/references/workflow-patterns.md +188 -0
- package/skills/qa-httpx-writer/SKILL.md +138 -0
- package/skills/qa-httpx-writer/references/assertions.md +195 -0
- package/skills/qa-httpx-writer/references/best-practices.md +140 -0
- package/skills/qa-httpx-writer/references/config.md +212 -0
- package/skills/qa-httpx-writer/references/patterns.md +262 -0
- package/skills/qa-jest-writer/SKILL.md +131 -0
- package/skills/qa-jest-writer/references/assertions.md +125 -0
- package/skills/qa-jest-writer/references/best-practices.md +136 -0
- package/skills/qa-jest-writer/references/config.md +134 -0
- package/skills/qa-jest-writer/references/patterns.md +172 -0
- package/skills/qa-jira-integration/SKILL.md +135 -0
- package/skills/qa-jira-integration/references/api-patterns.md +143 -0
- package/skills/qa-jira-integration/references/field-mapping.md +79 -0
- package/skills/qa-jira-integration/references/xray-integration.md +85 -0
- package/skills/qa-jmeter-writer/SKILL.md +171 -0
- package/skills/qa-jmeter-writer/references/best-practices.md +157 -0
- package/skills/qa-jmeter-writer/references/config.md +204 -0
- package/skills/qa-jmeter-writer/references/patterns.md +242 -0
- package/skills/qa-junit5-writer/SKILL.md +157 -0
- package/skills/qa-junit5-writer/references/assertions.md +118 -0
- package/skills/qa-junit5-writer/references/config.md +97 -0
- package/skills/qa-junit5-writer/references/patterns.md +162 -0
- package/skills/qa-k6-writer/SKILL.md +155 -0
- package/skills/qa-k6-writer/references/best-practices.md +236 -0
- package/skills/qa-k6-writer/references/config.md +219 -0
- package/skills/qa-k6-writer/references/patterns.md +304 -0
- package/skills/qa-linear-integration/SKILL.md +137 -0
- package/skills/qa-linear-integration/references/api-patterns.md +249 -0
- package/skills/qa-linear-integration/references/field-mapping.md +121 -0
- package/skills/qa-locust-writer/SKILL.md +151 -0
- package/skills/qa-locust-writer/references/best-practices.md +126 -0
- package/skills/qa-locust-writer/references/config.md +170 -0
- package/skills/qa-locust-writer/references/patterns.md +235 -0
- package/skills/qa-manual-test-designer/SKILL.md +145 -0
- package/skills/qa-manual-test-designer/references/exploratory-charters.md +138 -0
- package/skills/qa-manual-test-designer/references/personas.md +146 -0
- package/skills/qa-manual-test-designer/templates/exploratory-charter-template.md +47 -0
- package/skills/qa-manual-test-designer/templates/test-case-template.md +31 -0
- package/skills/qa-mobile-test-writer/SKILL.md +144 -0
- package/skills/qa-mobile-test-writer/references/best-practices.md +214 -0
- package/skills/qa-mobile-test-writer/references/config.md +309 -0
- package/skills/qa-mobile-test-writer/references/patterns.md +304 -0
- package/skills/qa-nfr-analyst/SKILL.md +177 -0
- package/skills/qa-nfr-analyst/references/iso-25010-model.md +159 -0
- package/skills/qa-nfr-analyst/references/owasp-wstg-baseline.md +202 -0
- package/skills/qa-nfr-analyst/references/wcag-checklist.md +184 -0
- package/skills/qa-nfr-analyst/templates/owasp-checklist-template.md +89 -0
- package/skills/qa-nfr-analyst/templates/wcag-checklist-template.md +48 -0
- package/skills/qa-orchestrator/SKILL.md +132 -0
- package/skills/qa-orchestrator/references/handoff-chains.md +105 -0
- package/skills/qa-orchestrator/references/pipeline-modes.md +115 -0
- package/skills/qa-orchestrator/references/scheduler-rules.md +84 -0
- package/skills/qa-pact-writer/SKILL.md +133 -0
- package/skills/qa-pact-writer/references/best-practices.md +100 -0
- package/skills/qa-pact-writer/references/config.md +135 -0
- package/skills/qa-pact-writer/references/patterns.md +161 -0
- package/skills/qa-plan-creator/SKILL.md +139 -0
- package/skills/qa-plan-creator/references/introduction-plan.md +43 -0
- package/skills/qa-plan-creator/references/migration-plan.md +44 -0
- package/skills/qa-plan-creator/references/onboarding-plan.md +46 -0
- package/skills/qa-plan-creator/references/performance-plan.md +44 -0
- package/skills/qa-plan-creator/references/regression-plan.md +45 -0
- package/skills/qa-plan-creator/references/release-plan.md +45 -0
- package/skills/qa-plan-creator/references/sprint-plan.md +44 -0
- package/skills/qa-plan-creator/references/test-plan.md +59 -0
- package/skills/qa-plan-creator/references/uat-plan.md +43 -0
- package/skills/qa-plan-creator/templates/checklist-template.md +36 -0
- package/skills/qa-plan-creator/templates/regression-checklist-template.md +49 -0
- package/skills/qa-plan-creator/templates/release-checklist-template.md +46 -0
- package/skills/qa-plan-creator/templates/test-plan-template.md +74 -0
- package/skills/qa-playwright-py-writer/SKILL.md +156 -0
- package/skills/qa-playwright-py-writer/references/best-practices.md +194 -0
- package/skills/qa-playwright-py-writer/references/config.md +195 -0
- package/skills/qa-playwright-py-writer/references/patterns.md +212 -0
- package/skills/qa-playwright-ts-writer/SKILL.md +151 -0
- package/skills/qa-playwright-ts-writer/references/assertions.md +109 -0
- package/skills/qa-playwright-ts-writer/references/best-practices.md +191 -0
- package/skills/qa-playwright-ts-writer/references/config.md +144 -0
- package/skills/qa-playwright-ts-writer/references/patterns.md +171 -0
- package/skills/qa-pytest-writer/SKILL.md +145 -0
- package/skills/qa-pytest-writer/references/assertions.md +149 -0
- package/skills/qa-pytest-writer/references/best-practices.md +97 -0
- package/skills/qa-pytest-writer/references/config.md +176 -0
- package/skills/qa-pytest-writer/references/patterns.md +251 -0
- package/skills/qa-qase-integration/SKILL.md +149 -0
- package/skills/qa-qase-integration/references/api-reference.md +354 -0
- package/skills/qa-qase-integration/references/ci-integration.md +196 -0
- package/skills/qa-qase-integration/references/field-mapping.md +157 -0
- package/skills/qa-requirements-generator/SKILL.md +152 -0
- package/skills/qa-requirements-generator/references/iso-29148-structure.md +153 -0
- package/skills/qa-requirements-generator/references/requirement-patterns.md +278 -0
- package/skills/qa-rest-assured-writer/SKILL.md +137 -0
- package/skills/qa-rest-assured-writer/references/best-practices.md +50 -0
- package/skills/qa-rest-assured-writer/references/config.md +124 -0
- package/skills/qa-rest-assured-writer/references/patterns.md +192 -0
- package/skills/qa-risk-analyzer/SKILL.md +158 -0
- package/skills/qa-risk-analyzer/references/impact-analysis.md +133 -0
- package/skills/qa-risk-analyzer/references/risk-factors.md +123 -0
- package/skills/qa-robot-framework-writer/SKILL.md +147 -0
- package/skills/qa-robot-framework-writer/references/best-practices.md +249 -0
- package/skills/qa-robot-framework-writer/references/config.md +204 -0
- package/skills/qa-robot-framework-writer/references/libraries.md +273 -0
- package/skills/qa-robot-framework-writer/references/patterns.md +216 -0
- package/skills/qa-security-test-writer/SKILL.md +123 -0
- package/skills/qa-security-test-writer/references/best-practices.md +155 -0
- package/skills/qa-security-test-writer/references/owasp-top10.md +331 -0
- package/skills/qa-security-test-writer/references/zap-config.md +258 -0
- package/skills/qa-selenium-java-writer/SKILL.md +143 -0
- package/skills/qa-selenium-java-writer/references/best-practices.md +59 -0
- package/skills/qa-selenium-java-writer/references/config.md +143 -0
- package/skills/qa-selenium-java-writer/references/patterns.md +170 -0
- package/skills/qa-selenium-py-writer/SKILL.md +150 -0
- package/skills/qa-selenium-py-writer/references/best-practices.md +175 -0
- package/skills/qa-selenium-py-writer/references/config.md +224 -0
- package/skills/qa-selenium-py-writer/references/patterns.md +255 -0
- package/skills/qa-shortcut-integration/SKILL.md +143 -0
- package/skills/qa-shortcut-integration/references/api-patterns.md +126 -0
- package/skills/qa-shortcut-integration/references/field-mapping.md +66 -0
- package/skills/qa-spec-auditor/SKILL.md +162 -0
- package/skills/qa-spec-auditor/references/audit-checklist.md +144 -0
- package/skills/qa-spec-auditor/references/drift-patterns.md +207 -0
- package/skills/qa-spec-writer/SKILL.md +143 -0
- package/skills/qa-spec-writer/references/gherkin-guide.md +253 -0
- package/skills/qa-spec-writer/references/specification-patterns.md +274 -0
- package/skills/qa-spring-test-writer/SKILL.md +170 -0
- package/skills/qa-spring-test-writer/references/best-practices.md +57 -0
- package/skills/qa-spring-test-writer/references/config.md +179 -0
- package/skills/qa-spring-test-writer/references/patterns.md +235 -0
- package/skills/qa-supertest-writer/SKILL.md +150 -0
- package/skills/qa-supertest-writer/references/assertions.md +192 -0
- package/skills/qa-supertest-writer/references/best-practices.md +102 -0
- package/skills/qa-supertest-writer/references/config.md +166 -0
- package/skills/qa-supertest-writer/references/patterns.md +242 -0
- package/skills/qa-task-creator/SKILL.md +142 -0
- package/skills/qa-task-creator/references/linking-patterns.md +127 -0
- package/skills/qa-task-creator/references/task-types.md +169 -0
- package/skills/qa-task-creator/templates/task-template.md +24 -0
- package/skills/qa-test-doc-compiler/SKILL.md +114 -0
- package/skills/qa-test-doc-compiler/references/agile-tailoring.md +220 -0
- package/skills/qa-test-doc-compiler/references/iso-29119-3-documents.md +302 -0
- package/skills/qa-test-healer/SKILL.md +101 -0
- package/skills/qa-test-healer/references/diagnosis-patterns.md +142 -0
- package/skills/qa-test-healer/references/fix-strategies.md +177 -0
- package/skills/qa-test-reporter/SKILL.md +130 -0
- package/skills/qa-test-reporter/references/best-practices.md +162 -0
- package/skills/qa-test-reporter/references/iso-29119-reports.md +236 -0
- package/skills/qa-test-reporter/references/report-formats.md +287 -0
- package/skills/qa-test-reviewer/SKILL.md +142 -0
- package/skills/qa-test-reviewer/references/anti-patterns.md +268 -0
- package/skills/qa-test-reviewer/references/review-checklist.md +93 -0
- package/skills/qa-test-strategy/SKILL.md +133 -0
- package/skills/qa-test-strategy/references/entry-exit-criteria.md +176 -0
- package/skills/qa-test-strategy/references/risk-matrix.md +102 -0
- package/skills/qa-test-strategy/references/testing-types.md +143 -0
- package/skills/qa-testcase-from-docs/SKILL.md +161 -0
- package/skills/qa-testcase-from-docs/references/test-case-format.md +196 -0
- package/skills/qa-testcase-from-docs/references/test-design-techniques.md +126 -0
- package/skills/qa-testcase-from-docs/templates/test-case-template.md +31 -0
- package/skills/qa-testcase-from-ui/SKILL.md +109 -0
- package/skills/qa-testcase-from-ui/references/ui-element-patterns.md +126 -0
- package/skills/qa-testcase-from-ui/references/visual-analysis-guide.md +146 -0
- package/skills/qa-testcase-from-ui/templates/test-case-template.md +31 -0
- package/skills/qa-visual-regression-writer/SKILL.md +175 -0
- package/skills/qa-visual-regression-writer/references/best-practices.md +154 -0
- package/skills/qa-visual-regression-writer/references/config.md +220 -0
- package/skills/qa-visual-regression-writer/references/patterns.md +213 -0
- package/skills/qa-vitest-writer/SKILL.md +141 -0
- package/skills/qa-vitest-writer/references/assertions.md +105 -0
- package/skills/qa-vitest-writer/references/best-practices.md +62 -0
- package/skills/qa-vitest-writer/references/config.md +127 -0
- package/skills/qa-vitest-writer/references/patterns.md +141 -0
- package/skills/qa-webdriverio-writer/SKILL.md +145 -0
- package/skills/qa-webdriverio-writer/references/best-practices.md +176 -0
- package/skills/qa-webdriverio-writer/references/config.md +240 -0
- package/skills/qa-webdriverio-writer/references/patterns.md +269 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Playwright Configuration Guide
|
|
2
|
+
|
|
3
|
+
Configuration for `playwright.config.ts` and related setup.
|
|
4
|
+
|
|
5
|
+
## Basic Structure
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
9
|
+
|
|
10
|
+
export default defineConfig({
|
|
11
|
+
testDir: './e2e',
|
|
12
|
+
fullyParallel: true,
|
|
13
|
+
forbidOnly: !!process.env.CI,
|
|
14
|
+
retries: process.env.CI ? 2 : 0,
|
|
15
|
+
workers: process.env.CI ? 1 : undefined,
|
|
16
|
+
reporter: 'html',
|
|
17
|
+
use: {
|
|
18
|
+
baseURL: 'http://localhost:3000',
|
|
19
|
+
trace: 'on-first-retry',
|
|
20
|
+
screenshot: 'only-on-failure',
|
|
21
|
+
video: 'retain-on-failure',
|
|
22
|
+
},
|
|
23
|
+
projects: [
|
|
24
|
+
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
|
25
|
+
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
|
|
26
|
+
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Projects Matrix
|
|
32
|
+
|
|
33
|
+
| Option | Description | Example |
|
|
34
|
+
|--------|-------------|---------|
|
|
35
|
+
| Multiple browsers | Run same tests on Chromium, Firefox, WebKit | `projects: [{ use: devices['Desktop Chrome'] }, ...]` |
|
|
36
|
+
| Mobile emulation | iPhone, Pixel | `devices['iPhone 13']` |
|
|
37
|
+
| Custom project | Named project with overrides | `{ name: 'auth', use: { storageState: 'auth.json' } }` |
|
|
38
|
+
| Dependencies | Run project B after A | `{ name: 'setup', testMatch: /global-setup/ }, { name: 'e2e', dependencies: ['setup'] }` |
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
projects: [
|
|
42
|
+
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
|
|
43
|
+
{
|
|
44
|
+
name: 'chromium',
|
|
45
|
+
use: { ...devices['Desktop Chrome'] },
|
|
46
|
+
dependencies: ['setup'],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'mobile',
|
|
50
|
+
use: { ...devices['iPhone 13'] },
|
|
51
|
+
dependencies: ['setup'],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Reporter Options
|
|
57
|
+
|
|
58
|
+
| Reporter | Output | Use Case |
|
|
59
|
+
|----------|--------|----------|
|
|
60
|
+
| `list` | Console | Default, readable |
|
|
61
|
+
| `html` | HTML report | `npx playwright show-report` |
|
|
62
|
+
| `json` | JSON file | CI integration |
|
|
63
|
+
| `junit` | JUnit XML | Jenkins, Azure DevOps |
|
|
64
|
+
| `github` | GitHub Actions annotations | CI |
|
|
65
|
+
| Multiple | Array | `reporter: [['html'], ['junit', { outputFile: 'results.xml' }]]` |
|
|
66
|
+
|
|
67
|
+
## Retry Strategies
|
|
68
|
+
|
|
69
|
+
| Option | Description | Example |
|
|
70
|
+
|--------|-------------|---------|
|
|
71
|
+
| `retries` | Number of retries on failure | `retries: 2` |
|
|
72
|
+
| `retries` in CI | Often 2 in CI, 0 locally | `retries: process.env.CI ? 2 : 0` |
|
|
73
|
+
| Per-test | `test.describe.configure({ retries: 1 })` | For flaky tests only |
|
|
74
|
+
|
|
75
|
+
## Test Directory
|
|
76
|
+
|
|
77
|
+
| Option | Description | Example |
|
|
78
|
+
|--------|-------------|---------|
|
|
79
|
+
| `testDir` | Root for tests | `testDir: './e2e'` |
|
|
80
|
+
| `testMatch` | Glob pattern | `testMatch: '**/*.spec.ts'` |
|
|
81
|
+
| `testIgnore` | Exclude | `testIgnore: '**/node_modules/**'` |
|
|
82
|
+
|
|
83
|
+
## Global Setup/Teardown
|
|
84
|
+
|
|
85
|
+
| File | Purpose |
|
|
86
|
+
|------|---------|
|
|
87
|
+
| `global-setup.ts` | Run once before all tests (auth, DB seed) |
|
|
88
|
+
| `global-teardown.ts` | Run once after all tests (cleanup) |
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// playwright.config.ts
|
|
92
|
+
export default defineConfig({
|
|
93
|
+
globalSetup: require.resolve('./global-setup'),
|
|
94
|
+
globalTeardown: require.resolve('./global-teardown'),
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// global-setup.ts
|
|
100
|
+
async function globalSetup() {
|
|
101
|
+
// Login and save auth state
|
|
102
|
+
const request = await request.newContext();
|
|
103
|
+
await request.post('/api/login', { data: { email, password } });
|
|
104
|
+
await request.storageState({ path: 'auth.json' });
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Authentication State
|
|
109
|
+
|
|
110
|
+
| Option | Description | Example |
|
|
111
|
+
|--------|-------------|---------|
|
|
112
|
+
| `storageState` | Reuse cookies/localStorage | `use: { storageState: 'auth.json' }` |
|
|
113
|
+
| Per-project | Auth only for some projects | `projects: [{ name: 'authenticated', use: { storageState: 'auth.json' } }]` |
|
|
114
|
+
| In test | `context.addCookies()` for dynamic auth | For test-specific auth |
|
|
115
|
+
|
|
116
|
+
## Use Options
|
|
117
|
+
|
|
118
|
+
| Option | Description | Values |
|
|
119
|
+
|--------|-------------|--------|
|
|
120
|
+
| `baseURL` | Prepend to relative URLs | `'http://localhost:3000'` |
|
|
121
|
+
| `trace` | When to capture trace | `'on-first-retry'`, `'on'`, `'off'` |
|
|
122
|
+
| `screenshot` | When to capture | `'on'`, `'off'`, `'only-on-failure'` |
|
|
123
|
+
| `video` | When to record | `'on'`, `'off'`, `'retain-on-failure'`, `'on-first-retry'` |
|
|
124
|
+
| `actionTimeout` | Default action timeout | `15000` |
|
|
125
|
+
| `navigationTimeout` | Page load timeout | `30000` |
|
|
126
|
+
| `expect` | Assertion timeout | `{ timeout: 5000 }` |
|
|
127
|
+
|
|
128
|
+
## Component Testing Config
|
|
129
|
+
|
|
130
|
+
For `@playwright/experimental-ct-react` (and ct-vue, ct-svelte):
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// playwright-ct.config.ts
|
|
134
|
+
import { defineConfig } from '@playwright/experimental-ct-react';
|
|
135
|
+
|
|
136
|
+
export default defineConfig({
|
|
137
|
+
testDir: './components',
|
|
138
|
+
use: {
|
|
139
|
+
ctViteConfig: {
|
|
140
|
+
// Vite config for component tests
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
```
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Playwright Test Patterns
|
|
2
|
+
|
|
3
|
+
Common patterns for E2E testing with Playwright TypeScript.
|
|
4
|
+
|
|
5
|
+
## Navigation
|
|
6
|
+
|
|
7
|
+
| Pattern | Example |
|
|
8
|
+
|---------|---------|
|
|
9
|
+
| Go to URL | `await page.goto('/login')` or `await page.goto(baseURL + '/login')` |
|
|
10
|
+
| Go back | `await page.goBack()` |
|
|
11
|
+
| Reload | `await page.reload()` |
|
|
12
|
+
| Wait for navigation | `await page.waitForURL('**/dashboard')` |
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
test('navigates to dashboard after login', async ({ page }) => {
|
|
16
|
+
await page.goto('/login');
|
|
17
|
+
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
|
18
|
+
await page.getByLabel('Password').fill('secret');
|
|
19
|
+
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
20
|
+
await expect(page).toHaveURL(/.*dashboard/);
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Forms
|
|
25
|
+
|
|
26
|
+
| Pattern | Example |
|
|
27
|
+
|---------|---------|
|
|
28
|
+
| Fill text | `await page.getByLabel('Name').fill('John')` |
|
|
29
|
+
| Fill by role | `await page.getByRole('textbox', { name: 'Email' }).fill('a@b.com')` |
|
|
30
|
+
| Select dropdown | `await page.getByLabel('Country').selectOption('US')` |
|
|
31
|
+
| Check checkbox | `await page.getByRole('checkbox', { name: 'Subscribe' }).check()` |
|
|
32
|
+
| Radio | `await page.getByRole('radio', { name: 'Option A' }).check()` |
|
|
33
|
+
| Submit | `await page.getByRole('button', { name: 'Submit' }).click()` |
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
test('submits registration form', async ({ page }) => {
|
|
37
|
+
await page.goto('/register');
|
|
38
|
+
await page.getByLabel('Email').fill('new@example.com');
|
|
39
|
+
await page.getByLabel('Password').fill('SecurePass123');
|
|
40
|
+
await page.getByRole('checkbox', { name: 'Terms' }).check();
|
|
41
|
+
await page.getByRole('button', { name: 'Create account' }).click();
|
|
42
|
+
await expect(page.getByText('Welcome')).toBeVisible();
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Authentication
|
|
47
|
+
|
|
48
|
+
| Pattern | Example |
|
|
49
|
+
|---------|---------|
|
|
50
|
+
| Login before each test | Use global setup or beforeEach with storageState |
|
|
51
|
+
| Reuse auth state | Save storageState in setup; reuse via project config |
|
|
52
|
+
| API login | Call login API, save cookies to storageState file |
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// global-setup.ts
|
|
56
|
+
async function globalSetup() {
|
|
57
|
+
const response = await request.post('/api/login', { data: { email, password } });
|
|
58
|
+
const cookies = await response.headers['set-cookie'];
|
|
59
|
+
await fs.writeFile('auth.json', JSON.stringify({ cookies }));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// playwright.config.ts
|
|
63
|
+
use: { storageState: 'auth.json' }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
See `references/config.md` for auth state configuration.
|
|
67
|
+
|
|
68
|
+
## File Upload
|
|
69
|
+
|
|
70
|
+
| Pattern | Example |
|
|
71
|
+
|---------|---------|
|
|
72
|
+
| Single file | `await page.getByLabel('Upload').setInputFiles('fixtures/doc.pdf')` |
|
|
73
|
+
| Multiple files | `await page.getByLabel('Upload').setInputFiles(['a.pdf', 'b.pdf'])` |
|
|
74
|
+
| Buffer | `await page.getByLabel('Upload').setInputFiles({ name: 'test.txt', mimeType: 'text/plain', buffer: Buffer.from('content') })` |
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
test('uploads file', async ({ page }) => {
|
|
78
|
+
await page.goto('/upload');
|
|
79
|
+
await page.getByLabel('Choose file').setInputFiles(path.join(__dirname, 'fixtures/sample.pdf'));
|
|
80
|
+
await page.getByRole('button', { name: 'Upload' }).click();
|
|
81
|
+
await expect(page.getByText('Upload complete')).toBeVisible();
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Drag and Drop
|
|
86
|
+
|
|
87
|
+
| Pattern | Example |
|
|
88
|
+
|---------|---------|
|
|
89
|
+
| locator.dragTo | `await page.locator('.item').dragTo(page.locator('.dropzone'))` |
|
|
90
|
+
| Manual (low-level) | `await page.dispatchEvent(source, 'dragstart'); await page.dispatchEvent(target, 'drop')` |
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
test('drags item to list', async ({ page }) => {
|
|
94
|
+
await page.goto('/kanban');
|
|
95
|
+
await page.locator('[data-id="task-1"]').dragTo(page.locator('[data-column="done"]'));
|
|
96
|
+
await expect(page.locator('[data-column="done"]')).toContainText('Task 1');
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Iframe Handling
|
|
101
|
+
|
|
102
|
+
| Pattern | Example |
|
|
103
|
+
|---------|---------|
|
|
104
|
+
| Get frame | `const frame = page.frameLocator('iframe[name="embed"]')` |
|
|
105
|
+
| Interact in frame | `await frame.getByRole('button').click()` |
|
|
106
|
+
| Nested frame | `const inner = frame.frameLocator('iframe')` |
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
test('interacts with iframe content', async ({ page }) => {
|
|
110
|
+
await page.goto('/embed');
|
|
111
|
+
const frame = page.frameLocator('iframe#widget');
|
|
112
|
+
await frame.getByRole('button', { name: 'Submit' }).click();
|
|
113
|
+
await expect(frame.getByText('Success')).toBeVisible();
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Multi-Tab
|
|
118
|
+
|
|
119
|
+
| Pattern | Example |
|
|
120
|
+
|---------|---------|
|
|
121
|
+
| Wait for popup | `const [popup] = await Promise.all([page.waitForEvent('popup'), page.getByRole('link').click()])` |
|
|
122
|
+
| New tab | `const context = page.context(); const newPage = await context.newPage()` |
|
|
123
|
+
| Switch | Use `popup` or `newPage` for subsequent actions |
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
test('opens link in new tab', async ({ page }) => {
|
|
127
|
+
const [popup] = await Promise.all([
|
|
128
|
+
page.waitForEvent('popup'),
|
|
129
|
+
page.getByRole('link', { name: 'External' }).click()
|
|
130
|
+
]);
|
|
131
|
+
await popup.waitForLoadState();
|
|
132
|
+
await expect(popup).toHaveURL(/external\.com/);
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## API Mocking with page.route
|
|
137
|
+
|
|
138
|
+
| Pattern | Example |
|
|
139
|
+
|---------|---------|
|
|
140
|
+
| Mock response | `await page.route('**/api/users', route => route.fulfill({ status: 200, body: JSON.stringify([]) }))` |
|
|
141
|
+
| Abort request | `await page.route('**/analytics', route => route.abort())` |
|
|
142
|
+
| Modify request | `await page.route('**/api/**', route => route.continue({ headers: { ...route.request().headers(), 'X-Custom': '1' } }))` |
|
|
143
|
+
| Unroute | `await page.unroute('**/api/users')` |
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
test('shows empty state when API returns no data', async ({ page }) => {
|
|
147
|
+
await page.route('**/api/items', route => route.fulfill({
|
|
148
|
+
status: 200,
|
|
149
|
+
contentType: 'application/json',
|
|
150
|
+
body: JSON.stringify({ items: [] })
|
|
151
|
+
}));
|
|
152
|
+
await page.goto('/items');
|
|
153
|
+
await expect(page.getByText('No items found')).toBeVisible();
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Visual Comparison
|
|
158
|
+
|
|
159
|
+
| Pattern | Example |
|
|
160
|
+
|---------|---------|
|
|
161
|
+
| Screenshot | `await expect(page).toHaveScreenshot('home.png')` |
|
|
162
|
+
| Element screenshot | `await expect(page.locator('.widget')).toHaveScreenshot('widget.png')` |
|
|
163
|
+
| Update snapshots | Run with `--update-snapshots` |
|
|
164
|
+
| Mask | `await expect(page).toHaveScreenshot({ mask: [page.locator('.dynamic')] })` |
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
test('homepage matches snapshot', async ({ page }) => {
|
|
168
|
+
await page.goto('/');
|
|
169
|
+
await expect(page).toHaveScreenshot('homepage.png');
|
|
170
|
+
});
|
|
171
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-pytest-writer
|
|
3
|
+
description: Generate pytest unit and integration tests for Python with fixtures, parametrize, markers, conftest patterns, and plugin ecosystem support.
|
|
4
|
+
output_dir: tests/unit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# QA Pytest Writer
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Write pytest unit and integration tests from test case specifications. Transform structured test cases (from qa-testcase-from-docs, qa-manual-test-designer, or specs) into executable pytest code with fixtures, parametrization, markers, and conftest patterns.
|
|
12
|
+
|
|
13
|
+
## Trigger Phrases
|
|
14
|
+
|
|
15
|
+
- "Write pytest tests for [module/function]"
|
|
16
|
+
- "Generate pytest unit tests from test cases"
|
|
17
|
+
- "Create pytest integration tests"
|
|
18
|
+
- "Add pytest tests with fixtures for [feature]"
|
|
19
|
+
- "Pytest parametrized tests for [function]"
|
|
20
|
+
- "Pytest tests with conftest fixtures"
|
|
21
|
+
- "Pytest async tests for [API handler]"
|
|
22
|
+
- "Pytest tests with mocking (monkeypatch/patch)"
|
|
23
|
+
|
|
24
|
+
## Key Features
|
|
25
|
+
|
|
26
|
+
| Feature | Description |
|
|
27
|
+
| ------- | ----------- |
|
|
28
|
+
| **Fixtures** | Scope: function, class, module, session; autouse, yield for teardown |
|
|
29
|
+
| **@pytest.mark.parametrize** | Data-driven tests with multiple input/output sets |
|
|
30
|
+
| **Markers** | skip, skipif, xfail, custom markers for categorization |
|
|
31
|
+
| **conftest.py** | Shared fixtures across test modules/directories |
|
|
32
|
+
| **Plugin ecosystem** | pytest-cov, pytest-xdist, pytest-asyncio, pytest-html, pytest-factoryboy |
|
|
33
|
+
| **Assertion introspection** | Rich failure output; plain `assert` statements |
|
|
34
|
+
|
|
35
|
+
## Workflow
|
|
36
|
+
|
|
37
|
+
1. **Read test cases** — From specs, requirements, or manual test designs
|
|
38
|
+
2. **Analyze Python code** — Inspect module under test: functions, classes, dependencies
|
|
39
|
+
3. **Generate test files** — Produce `test_{module}.py` with test functions
|
|
40
|
+
4. **Add fixtures/conftest** — Shared setup, teardown, parametrization
|
|
41
|
+
5. **Run** — User runs `pytest` to execute tests
|
|
42
|
+
|
|
43
|
+
## Context7 MCP
|
|
44
|
+
|
|
45
|
+
Use **Context7 MCP** for current pytest documentation when:
|
|
46
|
+
- Fixture scope or parametrize syntax is uncertain
|
|
47
|
+
- Plugin APIs (pytest-asyncio, pytest-cov) need verification
|
|
48
|
+
- Marker or configuration options require up-to-date reference
|
|
49
|
+
|
|
50
|
+
## Key Patterns
|
|
51
|
+
|
|
52
|
+
| Pattern | Usage |
|
|
53
|
+
| ------- | ----- |
|
|
54
|
+
| `test_` prefix | Test functions: `def test_something():` |
|
|
55
|
+
| `assert` | Plain assertions; no special API needed |
|
|
56
|
+
| Fixtures | `def fixture_name():` with scope, autouse, yield |
|
|
57
|
+
| `@pytest.mark.parametrize` | Data-driven tests |
|
|
58
|
+
| Markers | `@pytest.mark.skip`, `@pytest.mark.skipif`, `@pytest.mark.xfail` |
|
|
59
|
+
| conftest.py | Shared fixtures in package/directory |
|
|
60
|
+
| monkeypatch | Built-in for patching attributes/env |
|
|
61
|
+
| tmp_path | Built-in temporary directory fixture |
|
|
62
|
+
| unittest.mock | `patch`, `MagicMock` for mocking |
|
|
63
|
+
|
|
64
|
+
## Mocking
|
|
65
|
+
|
|
66
|
+
| Approach | Use Case |
|
|
67
|
+
| -------- | -------- |
|
|
68
|
+
| **unittest.mock.patch** | Patch modules, classes, functions |
|
|
69
|
+
| **unittest.mock.MagicMock** | Create mock objects with configurable behavior |
|
|
70
|
+
| **pytest-mock (mocker)** | `mocker` fixture wraps patch; cleaner syntax |
|
|
71
|
+
| **monkeypatch** | Built-in; patch attributes, env vars, sys.path |
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
- **pytest.ini** — Legacy config (markers, addopts, testpaths)
|
|
76
|
+
- **pyproject.toml** — Modern config under `[tool.pytest.ini_options]`
|
|
77
|
+
- **conftest.py** — Fixtures, hooks, plugin config
|
|
78
|
+
|
|
79
|
+
See `references/config.md` for configuration patterns.
|
|
80
|
+
|
|
81
|
+
## Plugin Recommendations
|
|
82
|
+
|
|
83
|
+
| Plugin | Purpose |
|
|
84
|
+
| ------ | ------- |
|
|
85
|
+
| pytest-cov | Code coverage reporting |
|
|
86
|
+
| pytest-xdist | Parallel test execution |
|
|
87
|
+
| pytest-asyncio | Async test support |
|
|
88
|
+
| pytest-html | HTML test reports |
|
|
89
|
+
| pytest-factoryboy | Factory fixtures for models |
|
|
90
|
+
|
|
91
|
+
## File Naming
|
|
92
|
+
|
|
93
|
+
- `test_{module}.py` — Preferred (e.g., `test_calculator.py`)
|
|
94
|
+
- Place in `tests/` or colocated with source per project convention
|
|
95
|
+
|
|
96
|
+
## Scope
|
|
97
|
+
|
|
98
|
+
**Can do (autonomous):**
|
|
99
|
+
- Generate pytest unit and integration tests from test case specs
|
|
100
|
+
- Add fixtures (function/class/module/session scope), conftest.py
|
|
101
|
+
- Use @pytest.mark.parametrize for data-driven tests
|
|
102
|
+
- Apply markers (skip, skipif, xfail, custom)
|
|
103
|
+
- Mock with patch, MagicMock, monkeypatch, pytest-mock
|
|
104
|
+
- Configure pytest.ini / pyproject.toml
|
|
105
|
+
- Call qa-diagram-generator for test flow diagrams if needed
|
|
106
|
+
|
|
107
|
+
**Cannot do (requires confirmation):**
|
|
108
|
+
- Change production code to satisfy tests
|
|
109
|
+
- Add tests for requirements not in source documents
|
|
110
|
+
- Override project-level pytest config without approval
|
|
111
|
+
|
|
112
|
+
**Will not do (out of scope):**
|
|
113
|
+
- Execute tests (user runs `pytest`)
|
|
114
|
+
- Write Playwright/Selenium E2E tests (use qa-playwright-ts-writer or Python E2E skills)
|
|
115
|
+
- Modify CI/CD pipelines
|
|
116
|
+
|
|
117
|
+
## References
|
|
118
|
+
|
|
119
|
+
- `references/patterns.md` — Fixtures, parametrize, conftest, async testing, mocking
|
|
120
|
+
- `references/assertions.md` — Assertion patterns: comparison, exceptions, warnings, approximate
|
|
121
|
+
- `references/config.md` — pyproject.toml, pytest.ini, conftest.py, markers, plugins
|
|
122
|
+
- `references/best-practices.md` — Fixture scope, naming, organization, test isolation, coverage
|
|
123
|
+
|
|
124
|
+
## Quality Checklist
|
|
125
|
+
|
|
126
|
+
- [ ] Tests match test case steps and expected results
|
|
127
|
+
- [ ] Fixtures are properly scoped (function vs session)
|
|
128
|
+
- [ ] No hardcoded secrets or sensitive data
|
|
129
|
+
- [ ] Assertions are specific (avoid only truthiness where value matters)
|
|
130
|
+
- [ ] Teardown via yield in fixtures where resources need cleanup
|
|
131
|
+
- [ ] File naming follows `test_{module}.py` convention
|
|
132
|
+
- [ ] Parametrize used for data-driven cases; markers for categorization
|
|
133
|
+
- [ ] Coverage targets considered if specified in requirements
|
|
134
|
+
|
|
135
|
+
## Troubleshooting
|
|
136
|
+
|
|
137
|
+
| Symptom | Likely Cause | Fix |
|
|
138
|
+
| ------- | ------------ | --- |
|
|
139
|
+
| Fixture not found | Scope or conftest location | Ensure conftest.py in same dir or parent; check fixture scope |
|
|
140
|
+
| Parametrize id collision | Duplicate ids | Use `ids` parameter for unique test names |
|
|
141
|
+
| Tests pass individually, fail together | Shared mutable state | Use function-scoped fixtures; avoid module/session for mutable data |
|
|
142
|
+
| monkeypatch not persisting | Wrong target path | Patch where object is used (e.g., `mymodule.func` not `builtins.func`) |
|
|
143
|
+
| Async tests fail | Missing pytest-asyncio | Add `@pytest.mark.asyncio`; install pytest-asyncio |
|
|
144
|
+
| Coverage not collected | Plugin not configured | Add pytest-cov; run `pytest --cov=src` |
|
|
145
|
+
| Import errors in tests | Path/sys.path | Add `conftest.py` with `sys.path` or use `pyproject.toml` pythonpath |
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Pytest Assertion Patterns
|
|
2
|
+
|
|
3
|
+
Pytest uses Python's built-in `assert` statement. Failed assertions are rewritten for rich, readable output.
|
|
4
|
+
|
|
5
|
+
## Basic Assertions
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
assert x == 5
|
|
9
|
+
assert x != 0
|
|
10
|
+
assert x > 3
|
|
11
|
+
assert x >= 3
|
|
12
|
+
assert x < 10
|
|
13
|
+
assert x <= 10
|
|
14
|
+
assert x in [1, 2, 3]
|
|
15
|
+
assert x not in []
|
|
16
|
+
assert "hello" in s
|
|
17
|
+
assert True
|
|
18
|
+
assert not False
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Comparison Assertions
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
# Equality
|
|
25
|
+
assert result == expected
|
|
26
|
+
assert result != unexpected
|
|
27
|
+
|
|
28
|
+
# Identity
|
|
29
|
+
assert x is None
|
|
30
|
+
assert x is not None
|
|
31
|
+
|
|
32
|
+
# Type
|
|
33
|
+
assert isinstance(obj, MyClass)
|
|
34
|
+
assert not isinstance(obj, str)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Collection Assertions
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
# Lists
|
|
41
|
+
assert len(items) == 3
|
|
42
|
+
assert item in items
|
|
43
|
+
assert items == [1, 2, 3]
|
|
44
|
+
assert items != []
|
|
45
|
+
|
|
46
|
+
# Dicts
|
|
47
|
+
assert "key" in d
|
|
48
|
+
assert d["key"] == value
|
|
49
|
+
assert d.get("missing") is None
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Exception Testing
|
|
53
|
+
|
|
54
|
+
### pytest.raises
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import pytest
|
|
58
|
+
|
|
59
|
+
def test_raises_exception():
|
|
60
|
+
with pytest.raises(ValueError):
|
|
61
|
+
raise ValueError("invalid")
|
|
62
|
+
|
|
63
|
+
def test_raises_with_message():
|
|
64
|
+
with pytest.raises(ValueError, match="invalid"):
|
|
65
|
+
raise ValueError("invalid input")
|
|
66
|
+
|
|
67
|
+
def test_raises_exception_info():
|
|
68
|
+
with pytest.raises(ValueError) as exc_info:
|
|
69
|
+
raise ValueError("error message")
|
|
70
|
+
assert "error" in str(exc_info.value)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Exception Type and Message
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
with pytest.raises(ValueError, match=r"expected pattern"):
|
|
77
|
+
failing_function()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Warning Testing
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import pytest
|
|
84
|
+
import warnings
|
|
85
|
+
|
|
86
|
+
def test_warning():
|
|
87
|
+
with pytest.warns(UserWarning, match="deprecated"):
|
|
88
|
+
deprecated_function()
|
|
89
|
+
|
|
90
|
+
def test_warning_count():
|
|
91
|
+
with pytest.warns(UserWarning) as record:
|
|
92
|
+
warn_twice()
|
|
93
|
+
assert len(record) == 2
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Approximate Comparisons
|
|
97
|
+
|
|
98
|
+
For floating-point values, use `pytest.approx`:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
def test_float_approximate():
|
|
102
|
+
assert 0.1 + 0.2 == pytest.approx(0.3)
|
|
103
|
+
|
|
104
|
+
def test_float_with_tolerance():
|
|
105
|
+
assert 3.14159 == pytest.approx(3.14, rel=1e-2)
|
|
106
|
+
|
|
107
|
+
def test_sequence_approximate():
|
|
108
|
+
assert [1.0, 2.0] == pytest.approx([1.001, 2.002], rel=1e-2)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Mock Assertions (unittest.mock)
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from unittest.mock import MagicMock
|
|
115
|
+
|
|
116
|
+
def test_mock_called(mock_obj):
|
|
117
|
+
mock_obj.method()
|
|
118
|
+
mock_obj.method.assert_called_once()
|
|
119
|
+
mock_obj.method.assert_called_with(arg1, arg2)
|
|
120
|
+
mock_obj.method.assert_called_once_with(arg1, arg2)
|
|
121
|
+
assert mock_obj.method.call_count == 1
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Boolean and Truthiness
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
assert result
|
|
128
|
+
assert not empty_list
|
|
129
|
+
assert bool(value) is True
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## String Assertions
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
assert "substring" in full_string
|
|
136
|
+
assert full_string.startswith("prefix")
|
|
137
|
+
assert full_string.endswith("suffix")
|
|
138
|
+
assert "pattern" in full_string
|
|
139
|
+
import re
|
|
140
|
+
assert re.search(r"pattern", full_string)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Best Practices
|
|
144
|
+
|
|
145
|
+
1. **One logical assertion per test** — Easier to diagnose failures
|
|
146
|
+
2. **Use descriptive variable names** — `expected_total` vs `x`
|
|
147
|
+
3. **Prefer `pytest.approx` for floats** — Avoid direct `==` on floats
|
|
148
|
+
4. **Use `pytest.raises` for exceptions** — Don't use try/except with assert
|
|
149
|
+
5. **Assert on behavior, not implementation** — Test outcomes, not internals
|