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,304 @@
|
|
|
1
|
+
# k6 Patterns Reference
|
|
2
|
+
|
|
3
|
+
## Load Profiles
|
|
4
|
+
|
|
5
|
+
### Load Testing (Steady Load)
|
|
6
|
+
Gradual ramp-up, sustained load, gradual ramp-down.
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
export const options = {
|
|
10
|
+
stages: [
|
|
11
|
+
{ duration: '2m', target: 50 },
|
|
12
|
+
{ duration: '5m', target: 50 },
|
|
13
|
+
{ duration: '2m', target: 0 },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Stress Testing (Beyond Capacity)
|
|
19
|
+
Increase load until system breaks; identify breaking point.
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
export const options = {
|
|
23
|
+
stages: [
|
|
24
|
+
{ duration: '2m', target: 100 },
|
|
25
|
+
{ duration: '5m', target: 100 },
|
|
26
|
+
{ duration: '2m', target: 200 },
|
|
27
|
+
{ duration: '5m', target: 200 },
|
|
28
|
+
{ duration: '2m', target: 300 },
|
|
29
|
+
{ duration: '5m', target: 300 },
|
|
30
|
+
{ duration: '2m', target: 0 },
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Soak Testing (Endurance)
|
|
36
|
+
Sustained load over extended period to find memory leaks, degradation.
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
export const options = {
|
|
40
|
+
stages: [
|
|
41
|
+
{ duration: '5m', target: 50 },
|
|
42
|
+
{ duration: '2h', target: 50 },
|
|
43
|
+
{ duration: '5m', target: 0 },
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Spike Testing (Sudden Burst)
|
|
49
|
+
Rapid spike to simulate traffic surge.
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
export const options = {
|
|
53
|
+
stages: [
|
|
54
|
+
{ duration: '10s', target: 0 },
|
|
55
|
+
{ duration: '1m', target: 500 },
|
|
56
|
+
{ duration: '3m', target: 500 },
|
|
57
|
+
{ duration: '1m', target: 0 },
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Smoke Testing (Minimal Validation)
|
|
63
|
+
Light load to verify script and basic functionality.
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
export const options = {
|
|
67
|
+
vus: 5,
|
|
68
|
+
duration: '1m',
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Breakpoint Testing
|
|
73
|
+
Find maximum capacity by incrementally increasing load.
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
export const options = {
|
|
77
|
+
stages: [
|
|
78
|
+
{ duration: '2m', target: 50 },
|
|
79
|
+
{ duration: '2m', target: 100 },
|
|
80
|
+
{ duration: '2m', target: 150 },
|
|
81
|
+
{ duration: '2m', target: 200 },
|
|
82
|
+
{ duration: '2m', target: 250 },
|
|
83
|
+
{ duration: '2m', target: 0 },
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Scenario Executors
|
|
91
|
+
|
|
92
|
+
| Executor | Use Case | Key Params |
|
|
93
|
+
| -------- | -------- | ---------- |
|
|
94
|
+
| **shared-iterations** | Fixed total iterations across all VUs | `iterations`, `vus` |
|
|
95
|
+
| **per-vu-iterations** | Each VU runs N iterations | `vus`, `iterations` |
|
|
96
|
+
| **constant-vus** | Fixed VU count for duration | `vus`, `duration` |
|
|
97
|
+
| **ramping-vus** | Ramp VUs up/down | `startVUs`, `stages`, `gracefulRampDown` |
|
|
98
|
+
| **constant-arrival-rate** | Fixed request rate (arrivals/sec) | `rate`, `timeUnit`, `duration`, `preAllocatedVUs`, `maxVUs` |
|
|
99
|
+
| **ramping-arrival-rate** | Variable request rate | `startRate`, `stages`, `preAllocatedVUs`, `maxVUs` |
|
|
100
|
+
| **externally-controlled** | Control VUs from external source | `maxVUs`, `duration` |
|
|
101
|
+
|
|
102
|
+
### Example: Multiple Scenarios
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
export const options = {
|
|
106
|
+
scenarios: {
|
|
107
|
+
browse: {
|
|
108
|
+
executor: 'constant-vus',
|
|
109
|
+
vus: 10,
|
|
110
|
+
duration: '5m',
|
|
111
|
+
exec: 'browseFlow',
|
|
112
|
+
startTime: '0s',
|
|
113
|
+
},
|
|
114
|
+
api: {
|
|
115
|
+
executor: 'constant-arrival-rate',
|
|
116
|
+
rate: 20,
|
|
117
|
+
timeUnit: '1s',
|
|
118
|
+
duration: '5m',
|
|
119
|
+
preAllocatedVUs: 10,
|
|
120
|
+
maxVUs: 50,
|
|
121
|
+
exec: 'apiFlow',
|
|
122
|
+
startTime: '0s',
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Thresholds
|
|
131
|
+
|
|
132
|
+
### Common Threshold Patterns
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
export const options = {
|
|
136
|
+
thresholds: {
|
|
137
|
+
// p95 response time under 200ms
|
|
138
|
+
http_req_duration: ['p(95)<200'],
|
|
139
|
+
// Error rate under 1%
|
|
140
|
+
http_req_failed: ['rate<0.01'],
|
|
141
|
+
// Combined: both must pass
|
|
142
|
+
'http_req_duration{name:api}': ['p(99)<500'],
|
|
143
|
+
'http_req_failed{name:api}': ['rate<0.005'],
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Threshold Operators
|
|
149
|
+
|
|
150
|
+
| Operator | Meaning |
|
|
151
|
+
| -------- | ------- |
|
|
152
|
+
| `<` | Less than |
|
|
153
|
+
| `<=` | Less than or equal |
|
|
154
|
+
| `>` | Greater than |
|
|
155
|
+
| `>=` | Greater than or equal |
|
|
156
|
+
| `==` | Equal |
|
|
157
|
+
|
|
158
|
+
### Built-in Metrics
|
|
159
|
+
|
|
160
|
+
| Metric | Description |
|
|
161
|
+
| ------ | ----------- |
|
|
162
|
+
| `http_req_duration` | Request duration (ms) |
|
|
163
|
+
| `http_req_failed` | Failed request rate (0–1) |
|
|
164
|
+
| `http_reqs` | Total HTTP requests |
|
|
165
|
+
| `iterations` | Completed iterations |
|
|
166
|
+
| `vus` | Current virtual users |
|
|
167
|
+
| `vus_max` | Max configured VUs |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Custom Metrics
|
|
172
|
+
|
|
173
|
+
### Trend (Duration)
|
|
174
|
+
```javascript
|
|
175
|
+
import { Trend } from 'k6/metrics';
|
|
176
|
+
const myTrend = new Trend('my_custom_duration');
|
|
177
|
+
|
|
178
|
+
export default function () {
|
|
179
|
+
const start = Date.now();
|
|
180
|
+
// ... do work ...
|
|
181
|
+
myTrend.add(Date.now() - start);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Rate (Success/Failure)
|
|
186
|
+
```javascript
|
|
187
|
+
import { Rate } from 'k6/metrics';
|
|
188
|
+
const myRate = new Rate('my_success_rate');
|
|
189
|
+
|
|
190
|
+
export default function () {
|
|
191
|
+
const success = doSomething();
|
|
192
|
+
myRate.add(success);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Counter
|
|
197
|
+
```javascript
|
|
198
|
+
import { Counter } from 'k6/metrics';
|
|
199
|
+
const myCounter = new Counter('my_counter');
|
|
200
|
+
|
|
201
|
+
export default function () {
|
|
202
|
+
myCounter.add(1);
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Gauge (Latest Value)
|
|
207
|
+
```javascript
|
|
208
|
+
import { Gauge } from 'k6/metrics';
|
|
209
|
+
const myGauge = new Gauge('my_gauge');
|
|
210
|
+
|
|
211
|
+
export default function () {
|
|
212
|
+
myGauge.add(someValue);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Groups
|
|
219
|
+
|
|
220
|
+
Organize related operations for clearer output and metrics.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
import http from 'k6/http';
|
|
224
|
+
import { group } from 'k6';
|
|
225
|
+
|
|
226
|
+
export default function () {
|
|
227
|
+
group('Homepage', function () {
|
|
228
|
+
const res = http.get('https://example.com/');
|
|
229
|
+
// assertions
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
group('API - List', function () {
|
|
233
|
+
const res = http.get('https://api.example.com/items');
|
|
234
|
+
// assertions
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
group('API - Create', function () {
|
|
238
|
+
const res = http.post('https://api.example.com/items', JSON.stringify({ name: 'item' }), {
|
|
239
|
+
headers: { 'Content-Type': 'application/json' },
|
|
240
|
+
});
|
|
241
|
+
// assertions
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Checks vs Thresholds
|
|
249
|
+
|
|
250
|
+
**Checks** — Assertions per iteration; don't fail the test.
|
|
251
|
+
```javascript
|
|
252
|
+
import { check } from 'k6';
|
|
253
|
+
import http from 'k6/http';
|
|
254
|
+
|
|
255
|
+
export default function () {
|
|
256
|
+
const res = http.get('https://example.com/');
|
|
257
|
+
check(res, { 'status is 200': (r) => r.status === 200 });
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Thresholds** — Pass/fail criteria for the entire test run.
|
|
262
|
+
```javascript
|
|
263
|
+
export const options = {
|
|
264
|
+
thresholds: {
|
|
265
|
+
checks: ['rate>0.95'],
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## HTTP Patterns
|
|
273
|
+
|
|
274
|
+
### Basic GET/POST
|
|
275
|
+
```javascript
|
|
276
|
+
import http from 'k6/http';
|
|
277
|
+
|
|
278
|
+
const res = http.get('https://api.example.com/items');
|
|
279
|
+
const res2 = http.post('https://api.example.com/items', JSON.stringify({ name: 'test' }), {
|
|
280
|
+
headers: { 'Content-Type': 'application/json' },
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Correlation (Extract from Response)
|
|
285
|
+
```javascript
|
|
286
|
+
const res = http.get('https://api.example.com/login');
|
|
287
|
+
const token = res.json('token');
|
|
288
|
+
http.get('https://api.example.com/protected', {
|
|
289
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Parameterization (CSV)
|
|
294
|
+
```javascript
|
|
295
|
+
import { SharedArray } from 'k6/data';
|
|
296
|
+
const data = new SharedArray('users', function () {
|
|
297
|
+
return JSON.parse(open('./users.json'));
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
export default function () {
|
|
301
|
+
const user = data[__ITER % data.length];
|
|
302
|
+
http.post('https://api.example.com/login', JSON.stringify(user));
|
|
303
|
+
}
|
|
304
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-linear-integration
|
|
3
|
+
description: Linear integration for creating issues, managing projects/cycles, and tracking QA workflows via GraphQL API or Linear MCP.
|
|
4
|
+
dependencies:
|
|
5
|
+
recommended:
|
|
6
|
+
- qa-bug-ticket-creator
|
|
7
|
+
- qa-task-creator
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# QA Linear Integration
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
Integrate QA workflow with Linear for issue tracking and project management. Create and update issues, manage projects and cycles, and sync with qa-bug-ticket-creator and qa-task-creator for end-to-end QA traceability.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
| Feature | Description |
|
|
19
|
+
| ------- | ----------- |
|
|
20
|
+
| **Create/update issues** | Bug, Story, Task via GraphQL mutations |
|
|
21
|
+
| **Projects and cycles** | Assign issues to projects; add to cycles (sprints) |
|
|
22
|
+
| **Labels and priority** | Map severity/priority to Linear labels and priority |
|
|
23
|
+
| **Issue relations** | Blocks, relates to, duplicates |
|
|
24
|
+
| **Team assignment** | Assign issues to teams |
|
|
25
|
+
| **GraphQL API** | Full GraphQL for queries and mutations |
|
|
26
|
+
|
|
27
|
+
## Authentication
|
|
28
|
+
|
|
29
|
+
Store in `.env` (never hardcode):
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
LINEAR_API_KEY=lin_api_xxxxxxxxxxxx
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **Header:** `Authorization: Bearer {LINEAR_API_KEY}`
|
|
36
|
+
- Linear uses API keys; no Basic Auth. Create keys at Linear → Settings → API.
|
|
37
|
+
|
|
38
|
+
## Key API Patterns
|
|
39
|
+
|
|
40
|
+
| Operation | GraphQL |
|
|
41
|
+
| --------- | ------- |
|
|
42
|
+
| Create issue | `mutation { issueCreate(input: {...}) { issue { id identifier url } } }` |
|
|
43
|
+
| Update issue | `mutation { issueUpdate(id: "...", input: {...}) { issue { ... } } }` |
|
|
44
|
+
| Query issues | `query { issues(filter: {...}) { nodes { id identifier title state { name } } } }` |
|
|
45
|
+
| Projects | `query { projects { nodes { id name } } }` |
|
|
46
|
+
| Teams | `query { teams { nodes { id name key } } }` |
|
|
47
|
+
| Cycles | `query { cycles(filter: { teamId: { eq: "..." } }) { nodes { id name } } }` |
|
|
48
|
+
|
|
49
|
+
See `references/api-patterns.md` for full GraphQL examples.
|
|
50
|
+
|
|
51
|
+
## Integration with QA Skills
|
|
52
|
+
|
|
53
|
+
### qa-bug-ticket-creator
|
|
54
|
+
|
|
55
|
+
When creating a bug report for Linear:
|
|
56
|
+
|
|
57
|
+
1. **Input** — Bug report from test failure (title, expected/actual, steps, severity, component)
|
|
58
|
+
2. **Map** — Use `references/field-mapping.md` to map to Linear fields
|
|
59
|
+
3. **Create** — `issueCreate` with `teamId`, `title`, `description`, `priority`, `labels`
|
|
60
|
+
4. **Link** — Add "blocks" or "relates to" for related issues when applicable
|
|
61
|
+
|
|
62
|
+
### qa-task-creator
|
|
63
|
+
|
|
64
|
+
When creating tasks for Linear:
|
|
65
|
+
|
|
66
|
+
1. **Input** — Task from coverage gap, spec finding, or bug fix request
|
|
67
|
+
2. **Map** — Map task type to Linear issue type (Story, Task)
|
|
68
|
+
3. **Create** — `issueCreate` with project, cycle, labels
|
|
69
|
+
4. **Link** — Use `parentId` for sub-tasks; "blocks" for fix tasks referencing bugs
|
|
70
|
+
|
|
71
|
+
## Trigger Phrases
|
|
72
|
+
|
|
73
|
+
- "Create Linear issue for [bug/task description]"
|
|
74
|
+
- "Add bug to Linear from test failure"
|
|
75
|
+
- "Create Linear story for [feature]"
|
|
76
|
+
- "Sync QA tasks to Linear"
|
|
77
|
+
- "Linear issue from qa-bug-ticket-creator output"
|
|
78
|
+
- "Add to Linear cycle [name]"
|
|
79
|
+
- "Query Linear issues by [filter]"
|
|
80
|
+
|
|
81
|
+
## Workflow
|
|
82
|
+
|
|
83
|
+
1. **Auth** — Load `LINEAR_API_KEY` from `.env`
|
|
84
|
+
2. **Resolve IDs** — Query teams, projects, cycles to get IDs (or use user-provided)
|
|
85
|
+
3. **Map fields** — Apply `references/field-mapping.md` for QA → Linear
|
|
86
|
+
4. **Execute** — Run GraphQL mutation (issueCreate, issueUpdate)
|
|
87
|
+
5. **Output** — Return issue identifier (e.g., `BUG-123`), URL, and summary
|
|
88
|
+
|
|
89
|
+
## Scope
|
|
90
|
+
|
|
91
|
+
**Can do (autonomous):**
|
|
92
|
+
- Create and update Linear issues via GraphQL
|
|
93
|
+
- Map QA bug/task fields to Linear fields
|
|
94
|
+
- Query issues, projects, teams, cycles
|
|
95
|
+
- Add labels, priority, project, cycle
|
|
96
|
+
- Create issue relations (blocks, relates to)
|
|
97
|
+
- Work with qa-bug-ticket-creator and qa-task-creator outputs
|
|
98
|
+
|
|
99
|
+
**Cannot do (requires confirmation):**
|
|
100
|
+
- Create issues in workspaces without API access
|
|
101
|
+
- Assign to specific users without mapping
|
|
102
|
+
- Delete or archive issues
|
|
103
|
+
- Modify workspace settings
|
|
104
|
+
|
|
105
|
+
**Will not do (out of scope):**
|
|
106
|
+
- Modify production or test code
|
|
107
|
+
- Execute tests or deployments
|
|
108
|
+
- Manage Linear workspace billing or admin
|
|
109
|
+
|
|
110
|
+
## Quality Checklist
|
|
111
|
+
|
|
112
|
+
- [ ] `LINEAR_API_KEY` loaded from `.env`; never hardcoded
|
|
113
|
+
- [ ] Field mapping applied per `references/field-mapping.md`
|
|
114
|
+
- [ ] Issue includes title, description, and appropriate labels/priority
|
|
115
|
+
- [ ] Team ID (or project) specified for issue creation
|
|
116
|
+
- [ ] GraphQL errors handled; user-friendly message on failure
|
|
117
|
+
- [ ] Issue identifier and URL returned to user
|
|
118
|
+
- [ ] Relations (blocks, relates to) set when linking to bugs/tasks
|
|
119
|
+
|
|
120
|
+
## Troubleshooting
|
|
121
|
+
|
|
122
|
+
| Symptom | Likely Cause | Fix |
|
|
123
|
+
| ------- | ------------ | --- |
|
|
124
|
+
| 401 Unauthorized | Invalid or missing API key | Verify `LINEAR_API_KEY` in `.env`; regenerate if needed |
|
|
125
|
+
| Team not found | Wrong team ID or key | Query `teams { nodes { id key } }`; use correct ID |
|
|
126
|
+
| Invalid input | Required field missing | Check `references/field-mapping.md`; ensure `teamId` and `title` present |
|
|
127
|
+
| Cycle not found | Cycle doesn't exist or wrong team | Query cycles for team; use active cycle ID |
|
|
128
|
+
| GraphQL errors | Malformed mutation/query | Validate query syntax; check Linear API docs |
|
|
129
|
+
| Label not applied | Label doesn't exist in workspace | Create label in Linear or use existing label name |
|
|
130
|
+
| Relation fails | Invalid issue ID | Verify target issue exists; use correct `id` (UUID) |
|
|
131
|
+
|
|
132
|
+
## Reference Files
|
|
133
|
+
|
|
134
|
+
| Topic | File |
|
|
135
|
+
| ----- | ---- |
|
|
136
|
+
| GraphQL API patterns | `references/api-patterns.md` |
|
|
137
|
+
| QA → Linear field mapping | `references/field-mapping.md` |
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Linear GraphQL API Patterns
|
|
2
|
+
|
|
3
|
+
*GraphQL operations for creating, querying, and updating Linear issues.*
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Base URL
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
https://api.linear.app/graphql
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Headers:**
|
|
14
|
+
```
|
|
15
|
+
Authorization: Bearer {LINEAR_API_KEY}
|
|
16
|
+
Content-Type: application/json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Create Issue
|
|
22
|
+
|
|
23
|
+
```graphql
|
|
24
|
+
mutation IssueCreate($input: IssueCreateInput!) {
|
|
25
|
+
issueCreate(input: $input) {
|
|
26
|
+
issue {
|
|
27
|
+
id
|
|
28
|
+
identifier
|
|
29
|
+
title
|
|
30
|
+
url
|
|
31
|
+
state { name }
|
|
32
|
+
}
|
|
33
|
+
success
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Variables:**
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"input": {
|
|
42
|
+
"teamId": "uuid-of-team",
|
|
43
|
+
"title": "Login fails when password contains special chars",
|
|
44
|
+
"description": "**Expected:** User should log in successfully.\n\n**Actual:** 500 error.\n\n**Steps:** 1. Go to /login 2. Enter password with !@# 3. Submit",
|
|
45
|
+
"priority": 1,
|
|
46
|
+
"labelIds": ["uuid-of-label"],
|
|
47
|
+
"projectId": "uuid-of-project",
|
|
48
|
+
"cycleId": "uuid-of-cycle"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Priority values:** 0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Update Issue
|
|
58
|
+
|
|
59
|
+
```graphql
|
|
60
|
+
mutation IssueUpdate($id: String!, $input: IssueUpdateInput!) {
|
|
61
|
+
issueUpdate(id: $id, input: $input) {
|
|
62
|
+
issue {
|
|
63
|
+
id
|
|
64
|
+
identifier
|
|
65
|
+
title
|
|
66
|
+
state { name }
|
|
67
|
+
}
|
|
68
|
+
success
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Variables:**
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"id": "uuid-of-issue",
|
|
77
|
+
"input": {
|
|
78
|
+
"title": "Updated title",
|
|
79
|
+
"description": "Updated description",
|
|
80
|
+
"priority": 2,
|
|
81
|
+
"stateId": "uuid-of-state"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Query Issues
|
|
89
|
+
|
|
90
|
+
```graphql
|
|
91
|
+
query Issues($filter: IssueFilter) {
|
|
92
|
+
issues(filter: $filter, first: 50) {
|
|
93
|
+
nodes {
|
|
94
|
+
id
|
|
95
|
+
identifier
|
|
96
|
+
title
|
|
97
|
+
description
|
|
98
|
+
state { name }
|
|
99
|
+
priority
|
|
100
|
+
url
|
|
101
|
+
createdAt
|
|
102
|
+
}
|
|
103
|
+
pageInfo { hasNextPage endCursor }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Filter examples:**
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"filter": {
|
|
112
|
+
"state": { "name": { "neq": "Done" } },
|
|
113
|
+
"team": { "key": { "eq": "ENG" } }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"filter": {
|
|
121
|
+
"identifier": { "containsIgnoreCase": "BUG" }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Query Teams
|
|
129
|
+
|
|
130
|
+
```graphql
|
|
131
|
+
query Teams {
|
|
132
|
+
teams {
|
|
133
|
+
nodes {
|
|
134
|
+
id
|
|
135
|
+
name
|
|
136
|
+
key
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Use `id` for `teamId` in issueCreate.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Query Projects
|
|
147
|
+
|
|
148
|
+
```graphql
|
|
149
|
+
query Projects {
|
|
150
|
+
projects {
|
|
151
|
+
nodes {
|
|
152
|
+
id
|
|
153
|
+
name
|
|
154
|
+
state
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Query Cycles
|
|
163
|
+
|
|
164
|
+
```graphql
|
|
165
|
+
query Cycles($filter: CycleFilter) {
|
|
166
|
+
cycles(filter: $filter, first: 20) {
|
|
167
|
+
nodes {
|
|
168
|
+
id
|
|
169
|
+
name
|
|
170
|
+
state
|
|
171
|
+
startsAt
|
|
172
|
+
endsAt
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Filter by team:**
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"filter": {
|
|
182
|
+
"teamId": { "eq": "uuid-of-team" }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Create Issue Relation (Blocks / Relates To)
|
|
190
|
+
|
|
191
|
+
```graphql
|
|
192
|
+
mutation IssueRelationCreate($input: IssueRelationCreateInput!) {
|
|
193
|
+
issueRelationCreate(input: $input) {
|
|
194
|
+
issueRelation {
|
|
195
|
+
id
|
|
196
|
+
}
|
|
197
|
+
success
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Variables (blocks):**
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"input": {
|
|
206
|
+
"issueId": "uuid-of-blocking-issue",
|
|
207
|
+
"relatedIssueId": "uuid-of-blocked-issue",
|
|
208
|
+
"type": "blocks"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Relation types:** `blocks`, `duplicate`, `related`.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Create Sub-Issue (Parent)
|
|
218
|
+
|
|
219
|
+
Use `parentId` in issueCreate:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"input": {
|
|
224
|
+
"teamId": "uuid",
|
|
225
|
+
"title": "Sub-task title",
|
|
226
|
+
"parentId": "uuid-of-parent-issue"
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Error Handling
|
|
234
|
+
|
|
235
|
+
GraphQL returns `errors` array on failure:
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"data": null,
|
|
240
|
+
"errors": [
|
|
241
|
+
{
|
|
242
|
+
"message": "Issue validation failed",
|
|
243
|
+
"extensions": { "code": "VALIDATION_ERROR" }
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Check `errors` before using `data`; surface `message` to user.
|