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,224 @@
|
|
|
1
|
+
# Selenium Python Configuration
|
|
2
|
+
|
|
3
|
+
Setup and configuration for Selenium WebDriver with Python.
|
|
4
|
+
|
|
5
|
+
## Dependencies
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install selenium
|
|
9
|
+
pip install webdriver-manager # Optional: auto-manage driver binaries
|
|
10
|
+
pip install pytest # For test runner
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## WebDriver Manager (Recommended)
|
|
14
|
+
|
|
15
|
+
Automatically downloads and manages ChromeDriver, GeckoDriver, etc.:
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from selenium import webdriver
|
|
19
|
+
from webdriver_manager.chrome import ChromeDriverManager
|
|
20
|
+
from selenium.webdriver.chrome.service import Service
|
|
21
|
+
|
|
22
|
+
service = Service(ChromeDriverManager().install())
|
|
23
|
+
driver = webdriver.Chrome(service=service)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
# Firefox
|
|
28
|
+
from webdriver_manager.firefox import GeckoDriverManager
|
|
29
|
+
service = Service(GeckoDriverManager().install())
|
|
30
|
+
driver = webdriver.Firefox(service=service)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
# Edge
|
|
35
|
+
from webdriver_manager.microsoft import EdgeChromiumDriverManager
|
|
36
|
+
service = Service(EdgeChromiumDriverManager().install())
|
|
37
|
+
driver = webdriver.Edge(service=service)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Browser Options
|
|
41
|
+
|
|
42
|
+
### Chrome
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from selenium import webdriver
|
|
46
|
+
from selenium.webdriver.chrome.options import Options
|
|
47
|
+
|
|
48
|
+
options = Options()
|
|
49
|
+
options.add_argument("--headless")
|
|
50
|
+
options.add_argument("--no-sandbox")
|
|
51
|
+
options.add_argument("--disable-dev-shm-usage")
|
|
52
|
+
options.add_argument("--disable-gpu")
|
|
53
|
+
options.add_argument("--window-size=1920,1080")
|
|
54
|
+
|
|
55
|
+
driver = webdriver.Chrome(options=options)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Firefox
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from selenium import webdriver
|
|
62
|
+
from selenium.webdriver.firefox.options import Options
|
|
63
|
+
|
|
64
|
+
options = Options()
|
|
65
|
+
options.add_argument("--headless")
|
|
66
|
+
|
|
67
|
+
driver = webdriver.Firefox(options=options)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Edge
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from selenium import webdriver
|
|
74
|
+
from selenium.webdriver.edge.options import Options
|
|
75
|
+
|
|
76
|
+
options = Options()
|
|
77
|
+
options.add_argument("--headless")
|
|
78
|
+
|
|
79
|
+
driver = webdriver.Edge(options=options)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Pytest Integration
|
|
83
|
+
|
|
84
|
+
### conftest.py (Driver Fixture)
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# tests/conftest.py
|
|
88
|
+
import pytest
|
|
89
|
+
from selenium import webdriver
|
|
90
|
+
from selenium.webdriver.chrome.options import Options
|
|
91
|
+
from webdriver_manager.chrome import ChromeDriverManager
|
|
92
|
+
from selenium.webdriver.chrome.service import Service
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@pytest.fixture(scope="function")
|
|
96
|
+
def driver():
|
|
97
|
+
options = Options()
|
|
98
|
+
options.add_argument("--headless")
|
|
99
|
+
options.add_argument("--no-sandbox")
|
|
100
|
+
options.add_argument("--disable-dev-shm-usage")
|
|
101
|
+
service = Service(ChromeDriverManager().install())
|
|
102
|
+
driver = webdriver.Chrome(service=service, options=options)
|
|
103
|
+
yield driver
|
|
104
|
+
driver.quit()
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@pytest.fixture(scope="function")
|
|
108
|
+
def driver_visible():
|
|
109
|
+
"""Non-headless for local debugging."""
|
|
110
|
+
service = Service(ChromeDriverManager().install())
|
|
111
|
+
driver = webdriver.Chrome(service=service)
|
|
112
|
+
yield driver
|
|
113
|
+
driver.quit()
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Test Module
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# tests/test_login.py
|
|
120
|
+
import pytest
|
|
121
|
+
from selenium.webdriver.common.by import By
|
|
122
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
123
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_login_success(driver):
|
|
127
|
+
driver.get("https://example.com/login")
|
|
128
|
+
driver.find_element(By.ID, "username").send_keys("user")
|
|
129
|
+
driver.find_element(By.ID, "password").send_keys("pass")
|
|
130
|
+
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
|
|
131
|
+
|
|
132
|
+
WebDriverWait(driver, 10).until(EC.url_contains("dashboard"))
|
|
133
|
+
assert "dashboard" in driver.current_url
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Headless Configuration
|
|
137
|
+
|
|
138
|
+
| Browser | Headless Flag |
|
|
139
|
+
| ------- | ------------- |
|
|
140
|
+
| Chrome | `--headless=new` or `--headless` |
|
|
141
|
+
| Firefox | `--headless` |
|
|
142
|
+
| Edge | `--headless` |
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
def get_headless_chrome():
|
|
146
|
+
options = Options()
|
|
147
|
+
options.add_argument("--headless=new")
|
|
148
|
+
options.add_argument("--no-sandbox")
|
|
149
|
+
options.add_argument("--disable-dev-shm-usage")
|
|
150
|
+
options.add_argument("--disable-gpu")
|
|
151
|
+
options.add_argument("--window-size=1920,1080")
|
|
152
|
+
return webdriver.Chrome(options=options)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Environment-Based Config
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
import os
|
|
159
|
+
|
|
160
|
+
def create_driver():
|
|
161
|
+
browser = os.getenv("SELENIUM_BROWSER", "chrome")
|
|
162
|
+
headless = os.getenv("SELENIUM_HEADLESS", "true").lower() == "true"
|
|
163
|
+
|
|
164
|
+
if browser == "chrome":
|
|
165
|
+
options = Options()
|
|
166
|
+
if headless:
|
|
167
|
+
options.add_argument("--headless=new")
|
|
168
|
+
return webdriver.Chrome(options=options)
|
|
169
|
+
elif browser == "firefox":
|
|
170
|
+
options = webdriver.FirefoxOptions()
|
|
171
|
+
if headless:
|
|
172
|
+
options.add_argument("--headless")
|
|
173
|
+
return webdriver.Firefox(options=options)
|
|
174
|
+
else:
|
|
175
|
+
raise ValueError(f"Unsupported browser: {browser}")
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Base URL Fixture
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
# conftest.py
|
|
182
|
+
@pytest.fixture(scope="session")
|
|
183
|
+
def base_url():
|
|
184
|
+
return os.getenv("BASE_URL", "https://example.com")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@pytest.fixture
|
|
188
|
+
def login_page(driver, base_url):
|
|
189
|
+
from pages.login import LoginPage
|
|
190
|
+
return LoginPage(driver, base_url)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Timeouts
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
# Page load timeout
|
|
197
|
+
driver.set_page_load_timeout(30)
|
|
198
|
+
|
|
199
|
+
# Script timeout (async scripts)
|
|
200
|
+
driver.set_script_timeout(10)
|
|
201
|
+
|
|
202
|
+
# Implicit wait (use sparingly)
|
|
203
|
+
driver.implicitly_wait(5)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## pyproject.toml / pytest.ini
|
|
207
|
+
|
|
208
|
+
```toml
|
|
209
|
+
[tool.pytest.ini_options]
|
|
210
|
+
testpaths = ["tests"]
|
|
211
|
+
addopts = "-v --tb=short"
|
|
212
|
+
markers = [
|
|
213
|
+
"e2e: end-to-end Selenium tests",
|
|
214
|
+
"slow: slow-running tests",
|
|
215
|
+
]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Run only E2E tests
|
|
220
|
+
pytest -m e2e
|
|
221
|
+
|
|
222
|
+
# Run with visible browser
|
|
223
|
+
SELENIUM_HEADLESS=false pytest tests/
|
|
224
|
+
```
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Selenium Python Patterns
|
|
2
|
+
|
|
3
|
+
Common patterns for E2E testing with Selenium WebDriver in Python.
|
|
4
|
+
|
|
5
|
+
## Locators
|
|
6
|
+
|
|
7
|
+
| Strategy | Example | When to Use |
|
|
8
|
+
| -------- | ------- | ----------- |
|
|
9
|
+
| By.ID | `driver.find_element(By.ID, "username")` | Unique ID attribute |
|
|
10
|
+
| By.CSS_SELECTOR | `driver.find_element(By.CSS_SELECTOR, "button.submit")` | Complex selectors |
|
|
11
|
+
| By.XPATH | `driver.find_element(By.XPATH, "//button[text()='Submit']")` | Text, hierarchy, axes |
|
|
12
|
+
| By.NAME | `driver.find_element(By.NAME, "email")` | Form inputs by name |
|
|
13
|
+
| By.CLASS_NAME | `driver.find_element(By.CLASS_NAME, "btn-primary")` | Single class |
|
|
14
|
+
| By.LINK_TEXT | `driver.find_element(By.LINK_TEXT, "Sign in")` | Exact link text |
|
|
15
|
+
| By.PARTIAL_LINK_TEXT | `driver.find_element(By.PARTIAL_LINK_TEXT, "Sign")` | Partial link text |
|
|
16
|
+
| By.TAG_NAME | `driver.find_element(By.TAG_NAME, "input")` | Tag type |
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from selenium.webdriver.common.by import By
|
|
20
|
+
|
|
21
|
+
element = driver.find_element(By.ID, "submit-btn")
|
|
22
|
+
elements = driver.find_elements(By.CSS_SELECTOR, ".list-item")
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Waits
|
|
26
|
+
|
|
27
|
+
### Explicit Wait (Preferred)
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
31
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
32
|
+
|
|
33
|
+
# Wait for element to be visible
|
|
34
|
+
element = WebDriverWait(driver, 10).until(
|
|
35
|
+
EC.visibility_of_element_located((By.ID, "username"))
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Wait for element to be clickable
|
|
39
|
+
button = WebDriverWait(driver, 10).until(
|
|
40
|
+
EC.element_to_be_clickable((By.CSS_SELECTOR, "button.submit"))
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Wait for URL change
|
|
44
|
+
WebDriverWait(driver, 10).until(EC.url_contains("dashboard"))
|
|
45
|
+
|
|
46
|
+
# Wait for element to be present in DOM
|
|
47
|
+
element = WebDriverWait(driver, 10).until(
|
|
48
|
+
EC.presence_of_element_located((By.ID, "results"))
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Common Expected Conditions
|
|
53
|
+
|
|
54
|
+
| Condition | Use Case |
|
|
55
|
+
| --------- | -------- |
|
|
56
|
+
| `visibility_of_element_located` | Element visible and has dimensions |
|
|
57
|
+
| `element_to_be_clickable` | Element visible and enabled |
|
|
58
|
+
| `presence_of_element_located` | Element in DOM (may be hidden) |
|
|
59
|
+
| `text_to_be_present_in_element` | Specific text in element |
|
|
60
|
+
| `url_contains` | URL contains substring |
|
|
61
|
+
| `title_is` | Page title exact match |
|
|
62
|
+
| `alert_is_present` | Alert dialog present |
|
|
63
|
+
|
|
64
|
+
### Implicit Wait (Use Sparingly)
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# Sets default wait for find_element; applies to all subsequent calls
|
|
68
|
+
driver.implicitly_wait(10) # Seconds
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Note:** Prefer explicit waits. Implicit waits can cause unexpected delays and mask timing issues.
|
|
72
|
+
|
|
73
|
+
## Page Object Model (POM)
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from selenium.webdriver.common.by import By
|
|
77
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
78
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
79
|
+
|
|
80
|
+
class LoginPage:
|
|
81
|
+
def __init__(self, driver, base_url):
|
|
82
|
+
self.driver = driver
|
|
83
|
+
self.base_url = base_url
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def username_input(self):
|
|
87
|
+
return WebDriverWait(self.driver, 10).until(
|
|
88
|
+
EC.visibility_of_element_located((By.ID, "username"))
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def password_input(self):
|
|
93
|
+
return self.driver.find_element(By.ID, "password")
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def submit_button(self):
|
|
97
|
+
return self.driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
|
|
98
|
+
|
|
99
|
+
def open(self):
|
|
100
|
+
self.driver.get(f"{self.base_url}/login")
|
|
101
|
+
|
|
102
|
+
def login(self, username: str, password: str):
|
|
103
|
+
self.open()
|
|
104
|
+
self.username_input.send_keys(username)
|
|
105
|
+
self.password_input.send_keys(password)
|
|
106
|
+
self.submit_button.click()
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## ActionChains (Complex Interactions)
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from selenium.webdriver.common.action_chains import ActionChains
|
|
113
|
+
|
|
114
|
+
# Hover
|
|
115
|
+
actions = ActionChains(driver)
|
|
116
|
+
actions.move_to_element(menu_element).perform()
|
|
117
|
+
|
|
118
|
+
# Click and hold, drag and drop
|
|
119
|
+
actions = ActionChains(driver)
|
|
120
|
+
actions.click_and_hold(source).move_to_element(target).release().perform()
|
|
121
|
+
|
|
122
|
+
# Double click
|
|
123
|
+
actions = ActionChains(driver)
|
|
124
|
+
actions.double_click(element).perform()
|
|
125
|
+
|
|
126
|
+
# Right click (context menu)
|
|
127
|
+
actions = ActionChains(driver)
|
|
128
|
+
actions.context_click(element).perform()
|
|
129
|
+
|
|
130
|
+
# Send keys with modifier
|
|
131
|
+
actions = ActionChains(driver)
|
|
132
|
+
actions.key_down(Keys.CONTROL).send_keys("a").key_up(Keys.CONTROL).perform()
|
|
133
|
+
|
|
134
|
+
# Chain multiple actions
|
|
135
|
+
actions = ActionChains(driver)
|
|
136
|
+
actions.move_to_element(menu).click(hidden_submenu).perform()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Select (Dropdowns)
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from selenium.webdriver.support.ui import Select
|
|
143
|
+
|
|
144
|
+
select = Select(driver.find_element(By.ID, "country"))
|
|
145
|
+
|
|
146
|
+
# By value
|
|
147
|
+
select.select_by_value("us")
|
|
148
|
+
|
|
149
|
+
# By visible text
|
|
150
|
+
select.select_by_visible_text("United States")
|
|
151
|
+
|
|
152
|
+
# By index (0-based)
|
|
153
|
+
select.select_by_index(0)
|
|
154
|
+
|
|
155
|
+
# Get options
|
|
156
|
+
options = select.options
|
|
157
|
+
first_selected = select.first_selected_option.text
|
|
158
|
+
|
|
159
|
+
# Deselect (multi-select only)
|
|
160
|
+
select.deselect_all()
|
|
161
|
+
select.deselect_by_visible_text("Option A")
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## File Upload
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
# Input type="file" - send path directly
|
|
168
|
+
file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']")
|
|
169
|
+
file_input.send_keys("/absolute/path/to/file.pdf")
|
|
170
|
+
|
|
171
|
+
# Multiple files (if supported)
|
|
172
|
+
file_input.send_keys("/path/file1.pdf\n/path/file2.pdf")
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Alerts
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from selenium.webdriver.support.ui import WebDriverWait
|
|
179
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
180
|
+
|
|
181
|
+
# Wait for alert and accept
|
|
182
|
+
WebDriverWait(driver, 10).until(EC.alert_is_present())
|
|
183
|
+
alert = driver.switch_to.alert
|
|
184
|
+
alert.accept() # OK
|
|
185
|
+
# alert.dismiss() # Cancel
|
|
186
|
+
# text = alert.text # Get message
|
|
187
|
+
# alert.send_keys("input") # For prompt()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Frames
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
# Switch to frame by index, name, or element
|
|
194
|
+
driver.switch_to.frame(0) # First frame
|
|
195
|
+
driver.switch_to.frame("frame-name")
|
|
196
|
+
driver.switch_to.frame(frame_element)
|
|
197
|
+
|
|
198
|
+
# Switch back to main content
|
|
199
|
+
driver.switch_to.default_content()
|
|
200
|
+
|
|
201
|
+
# Switch to parent frame (nested frames)
|
|
202
|
+
driver.switch_to.parent_frame()
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Windows / Tabs
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
# Get current window handle
|
|
209
|
+
current = driver.current_window_handle
|
|
210
|
+
|
|
211
|
+
# Get all window handles
|
|
212
|
+
handles = driver.window_handles
|
|
213
|
+
|
|
214
|
+
# Switch to new tab/window
|
|
215
|
+
driver.switch_to.window(handles[-1])
|
|
216
|
+
|
|
217
|
+
# Close current and switch back
|
|
218
|
+
driver.close()
|
|
219
|
+
driver.switch_to.window(handles[0])
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Basic Interactions
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
# Navigation
|
|
226
|
+
driver.get("https://example.com")
|
|
227
|
+
driver.back()
|
|
228
|
+
driver.forward()
|
|
229
|
+
driver.refresh()
|
|
230
|
+
|
|
231
|
+
# Element interactions
|
|
232
|
+
element.click()
|
|
233
|
+
element.send_keys("text")
|
|
234
|
+
element.clear()
|
|
235
|
+
element.submit() # Form submit
|
|
236
|
+
|
|
237
|
+
# Get attributes and text
|
|
238
|
+
text = element.text
|
|
239
|
+
value = element.get_attribute("value")
|
|
240
|
+
href = element.get_attribute("href")
|
|
241
|
+
is_displayed = element.is_displayed()
|
|
242
|
+
is_enabled = element.is_enabled()
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Keys
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
from selenium.webdriver.common.keys import Keys
|
|
249
|
+
|
|
250
|
+
element.send_keys(Keys.ENTER)
|
|
251
|
+
element.send_keys(Keys.TAB)
|
|
252
|
+
element.send_keys(Keys.ESCAPE)
|
|
253
|
+
element.send_keys(Keys.ARROW_DOWN)
|
|
254
|
+
element.send_keys(Keys.CONTROL + "a") # Select all
|
|
255
|
+
```
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-shortcut-integration
|
|
3
|
+
description: Shortcut (formerly Clubhouse) integration for creating stories, managing epics/iterations, and tracking QA workflows via REST API.
|
|
4
|
+
dependencies:
|
|
5
|
+
recommended:
|
|
6
|
+
- qa-bug-ticket-creator
|
|
7
|
+
- qa-task-creator
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# QA Shortcut Integration
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
Integrate QA workflow with Shortcut for project management. Create and update stories from bug reports, test coverage gaps, and QA tasks. Sync QA metadata (severity, test type, labels) with Shortcut epics, iterations, and workflow states.
|
|
15
|
+
|
|
16
|
+
## Primary Target
|
|
17
|
+
|
|
18
|
+
**Shortcut** (formerly Clubhouse) via REST API v3. Base URL: `https://api.app.shortcut.com/api/v3`.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
### Create/Update Stories
|
|
23
|
+
|
|
24
|
+
- **Create** stories in projects with full metadata
|
|
25
|
+
- **Update** existing stories (status, labels, description, external links)
|
|
26
|
+
- **Search** stories by query, epic, iteration, or label
|
|
27
|
+
|
|
28
|
+
### Epics and Iterations
|
|
29
|
+
|
|
30
|
+
- **Epics** — Group stories by feature/release; link stories to epics
|
|
31
|
+
- **Iterations** — Assign stories to sprints; query by iteration
|
|
32
|
+
- **Workflow states** — Map QA status to Shortcut workflow states
|
|
33
|
+
|
|
34
|
+
### Labels and Story Types
|
|
35
|
+
|
|
36
|
+
- **Story types** — Bug, feature, chore (map from QA task type)
|
|
37
|
+
- **Labels** — Component, severity, test type, coverage area
|
|
38
|
+
- **Custom fields** — Use Shortcut custom fields for QA metadata when configured
|
|
39
|
+
|
|
40
|
+
### Story Relationships
|
|
41
|
+
|
|
42
|
+
- **Blocking / blocked by** — Link stories for dependencies
|
|
43
|
+
- **External links** — Link to test cases, requirements, coverage reports
|
|
44
|
+
- **Comments** — Add reproduction steps, evidence, verification notes
|
|
45
|
+
|
|
46
|
+
## Authentication
|
|
47
|
+
|
|
48
|
+
| Variable | Description |
|
|
49
|
+
| -------- | ----------- |
|
|
50
|
+
| `SHORTCUT_API_TOKEN` | API token from Shortcut Settings → Account → API Tokens |
|
|
51
|
+
|
|
52
|
+
Store in `.env`; never hardcode. Header: `Shortcut-Token: <token>`.
|
|
53
|
+
|
|
54
|
+
## Key API Endpoints
|
|
55
|
+
|
|
56
|
+
| Method | Endpoint | Use |
|
|
57
|
+
| ------ | -------- | --- |
|
|
58
|
+
| POST | `/api/v3/stories` | Create story |
|
|
59
|
+
| GET | `/api/v3/stories/{story_id}` | Get story |
|
|
60
|
+
| PUT | `/api/v3/stories/{story_id}` | Update story |
|
|
61
|
+
| GET | `/api/v3/search/stories` | Search stories (query, epic, iteration) |
|
|
62
|
+
| GET | `/api/v3/epics` | List epics |
|
|
63
|
+
| GET | `/api/v3/iterations` | List iterations |
|
|
64
|
+
| GET | `/api/v3/workflows` | List workflow states |
|
|
65
|
+
|
|
66
|
+
See `references/api-patterns.md` for request/response patterns.
|
|
67
|
+
|
|
68
|
+
## Integration with QA Skills
|
|
69
|
+
|
|
70
|
+
| Skill | Integration |
|
|
71
|
+
| ----- | ----------- |
|
|
72
|
+
| **qa-bug-ticket-creator** | Create Shortcut story from bug report; map severity/priority to labels |
|
|
73
|
+
| **qa-task-creator** | Create Shortcut story from QA task; link to epic/iteration |
|
|
74
|
+
| **qa-coverage-analyzer** | Create stories for coverage gaps; label by component |
|
|
75
|
+
| **qa-flaky-detector** | Create stories for flaky tests; story type = bug |
|
|
76
|
+
|
|
77
|
+
When qa-bug-ticket-creator or qa-task-creator outputs a structured ticket, this skill translates it to Shortcut story format and creates/updates via API.
|
|
78
|
+
|
|
79
|
+
## Trigger Phrases
|
|
80
|
+
|
|
81
|
+
- "Create Shortcut story from [bug report / test failure]"
|
|
82
|
+
- "Add QA task to Shortcut"
|
|
83
|
+
- "Create story in Shortcut for coverage gap"
|
|
84
|
+
- "Update Shortcut story #123 with verification result"
|
|
85
|
+
- "Search Shortcut for stories in epic [name]"
|
|
86
|
+
- "Link story to test case / requirement"
|
|
87
|
+
- "Bulk-create Shortcut stories from [coverage / spec / flaky] output"
|
|
88
|
+
|
|
89
|
+
## Workflow
|
|
90
|
+
|
|
91
|
+
1. **Input** — Bug report, QA task, coverage gap, or user request
|
|
92
|
+
2. **Map** — Translate to Shortcut story format per `references/field-mapping.md`
|
|
93
|
+
3. **Resolve** — Get project_id, epic_id, iteration_id from workspace (or user input)
|
|
94
|
+
4. **Create/Update** — POST or PUT via REST API
|
|
95
|
+
5. **Link** — Add external links to test cases, requirements, evidence
|
|
96
|
+
6. **Output** — Return story URL and ID
|
|
97
|
+
|
|
98
|
+
## Scope
|
|
99
|
+
|
|
100
|
+
**Can do (autonomous):**
|
|
101
|
+
- Create stories from bug reports and QA tasks
|
|
102
|
+
- Update story status, labels, description
|
|
103
|
+
- Search stories by query, epic, iteration
|
|
104
|
+
- Map QA metadata to Shortcut labels and story types
|
|
105
|
+
- Add external links to test cases and requirements
|
|
106
|
+
- Work with qa-bug-ticket-creator and qa-task-creator outputs
|
|
107
|
+
|
|
108
|
+
**Cannot do (requires confirmation):**
|
|
109
|
+
- Create stories without project_id (user must provide or configure)
|
|
110
|
+
- Assign to members without mapping
|
|
111
|
+
- Create epics/iterations without workspace admin
|
|
112
|
+
|
|
113
|
+
**Will not do (out of scope):**
|
|
114
|
+
- Modify production or test code
|
|
115
|
+
- Close or archive stories (stakeholder responsibility)
|
|
116
|
+
- Integrate with Jira/Linear/GitHub (use respective skills)
|
|
117
|
+
|
|
118
|
+
## Quality Checklist
|
|
119
|
+
|
|
120
|
+
- [ ] Story includes title, description, and appropriate story type
|
|
121
|
+
- [ ] Labels map to QA metadata (severity, component, test type)
|
|
122
|
+
- [ ] External links added for test cases/requirements when applicable
|
|
123
|
+
- [ ] No hardcoded secrets; token from `SHORTCUT_API_TOKEN`
|
|
124
|
+
- [ ] Field mapping follows `references/field-mapping.md`
|
|
125
|
+
- [ ] API patterns from `references/api-patterns.md` used correctly
|
|
126
|
+
|
|
127
|
+
## Troubleshooting
|
|
128
|
+
|
|
129
|
+
| Symptom | Likely Cause | Fix |
|
|
130
|
+
| ------- | ------------ | --- |
|
|
131
|
+
| 401 Unauthorized | Missing or invalid token | Check `SHORTCUT_API_TOKEN`; regenerate at Shortcut Settings |
|
|
132
|
+
| 404 Not Found | Invalid story_id or project_id | Verify IDs; use search to resolve by name |
|
|
133
|
+
| 422 Validation Error | Invalid field value | Check field-mapping; ensure enum values match Shortcut |
|
|
134
|
+
| Rate limit (429) | >200 req/min | Throttle requests; batch where possible |
|
|
135
|
+
| Epic/iteration not found | ID from wrong workspace | List epics/iterations; use correct IDs |
|
|
136
|
+
| Labels not applied | Label doesn't exist | Create labels in Shortcut; use exact names |
|
|
137
|
+
|
|
138
|
+
## Reference Files
|
|
139
|
+
|
|
140
|
+
| Topic | File |
|
|
141
|
+
| ----- | ---- |
|
|
142
|
+
| API patterns (stories, epics, iterations) | `references/api-patterns.md` |
|
|
143
|
+
| QA field → Shortcut field mapping | `references/field-mapping.md` |
|