@torus-engineering/tas-kit 1.8.0 → 1.9.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.
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# /tas-apitest-plan $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Vai trò: SE - Software Engineer
|
|
4
|
+
Generate API Test Specification (Markdown) từ API Spec (OpenAPI 3.0, Markdown, YAML) hoặc phân tích code API.
|
|
5
|
+
|
|
6
|
+
## Always / Ask / Never
|
|
7
|
+
|
|
8
|
+
| | Hành động |
|
|
9
|
+
|---|---|
|
|
10
|
+
| **Always** | Đọc toàn bộ spec hoặc phân tích code trước khi tạo test spec |
|
|
11
|
+
| **Always** | Tổ chức test cases theo API version — mỗi version một section riêng |
|
|
12
|
+
| **Always** | Append-only: không sửa sections trong version cũ đã tồn tại |
|
|
13
|
+
| **Always** | Coverage matrix: mỗi endpoint cần ≥1 happy path + ≥1 error path |
|
|
14
|
+
| **Always** | Đọc `.claude/rules/csharp/api-testing.md` để nắm convention |
|
|
15
|
+
| **Ask** | Khi spec không rõ expected response schema hoặc business rule |
|
|
16
|
+
| **Never** | Sử dụng version folder/syntax trong test spec file (dùng section headers thay vì) |
|
|
17
|
+
| **Never** | Bỏ qua error path — mỗi endpoint cần cover validation errors |
|
|
18
|
+
|
|
19
|
+
## Hành động
|
|
20
|
+
|
|
21
|
+
### Bước 1 — Locate Inputs
|
|
22
|
+
|
|
23
|
+
`$ARGUMENTS` là path đến:
|
|
24
|
+
- API Spec file (OpenAPI 3.0 JSON/YAML, Markdown)
|
|
25
|
+
- Hoặc Story ID — glob tìm `docs/epics/**/Story-{ID}*.md`
|
|
26
|
+
- Hoặc path tới project code API cần phân tích
|
|
27
|
+
|
|
28
|
+
Nếu không có → hỏi user:
|
|
29
|
+
```
|
|
30
|
+
Nhập input cho /tas-apitest-plan:
|
|
31
|
+
1. Path đến API Spec file (OpenAPI/Markdown/YAML)
|
|
32
|
+
2. Story ID (để tìm link spec trong Story)
|
|
33
|
+
3. Path đến code API cần phân tích tự động
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Bước 2 — Detect Existing Test Spec
|
|
37
|
+
|
|
38
|
+
Glob tìm `docs/tests/API-Test-Spec-*.md`.
|
|
39
|
+
|
|
40
|
+
- **Tìm thấy**: Đọc file, detect versions đã có (tìm section headers `## v{N}`)
|
|
41
|
+
- **Không tìm thấy**: Tạo mới với version v1
|
|
42
|
+
|
|
43
|
+
### Bước 3 — Parse Input
|
|
44
|
+
|
|
45
|
+
**Nếu là API Spec file:**
|
|
46
|
+
- Đọc và parse OpenAPI/Markdown/YAML
|
|
47
|
+
- Thu thập cho mỗi endpoint:
|
|
48
|
+
- HTTP method + path, path/query params, request body schema
|
|
49
|
+
- Response schemas theo từng status code
|
|
50
|
+
- Auth requirement, description/summary
|
|
51
|
+
- Tags để nhóm endpoints
|
|
52
|
+
|
|
53
|
+
**Nếu là Story:**
|
|
54
|
+
- Đọc Story để tìm link spec trong `## Technical Plan` hoặc `## Acceptance Criteria`
|
|
55
|
+
- Parse spec như trên
|
|
56
|
+
- Thêm AC mapping vào test spec
|
|
57
|
+
|
|
58
|
+
**Nếu là code path:**
|
|
59
|
+
- Glob tìm controller/handler files (`.cs`, `.ts`, `.py` tùy stack)
|
|
60
|
+
- Phân tích attributes/routes để phát hiện endpoints
|
|
61
|
+
- Extract DTO classes để biết request/response schema
|
|
62
|
+
- Hỏi user confirm nếu detect không rõ
|
|
63
|
+
|
|
64
|
+
### Bước 4 — Detect API Version
|
|
65
|
+
|
|
66
|
+
Ưu tiên theo thứ tự:
|
|
67
|
+
1. `info.version` trong OpenAPI
|
|
68
|
+
2. Prefix trong URL path (v1/, v2/)
|
|
69
|
+
3. Hỏi user
|
|
70
|
+
|
|
71
|
+
Version format: `v1`, `v2` (không có dot).
|
|
72
|
+
|
|
73
|
+
### Bước 5 — Determine Output Path
|
|
74
|
+
|
|
75
|
+
Output: `docs/tests/API-Test-Spec-{slug}.md`
|
|
76
|
+
|
|
77
|
+
**Slug generation:**
|
|
78
|
+
- Từ `api_name` trong spec → lowercase, replace spaces với dashes
|
|
79
|
+
- Hoặc hỏi user nhập slug ngắn gọn (ví dụ: `users`, `orders`, `products`)
|
|
80
|
+
|
|
81
|
+
### Bước 6 — Determine Update Mode
|
|
82
|
+
|
|
83
|
+
Nếu spec file đã tồn tại và version đã có:
|
|
84
|
+
- **Append mode** (default): thêm test cases mới vào cuối section version hiện tại
|
|
85
|
+
- Hỏi user nếu muốn tạo version mới (v2, v3...):
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
Spec file đã có với version {current}. Bạn muốn:
|
|
89
|
+
1. Append test cases vào version {current} (default)
|
|
90
|
+
2. Tạo version mới (v{next}) cho test cases
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Bước 7 — Generate Test Spec
|
|
94
|
+
|
|
95
|
+
Đọc template `.tas/templates/API-Test-Spec.md` để nắm cấu trúc.
|
|
96
|
+
|
|
97
|
+
**Phân tích endpoints để tạo coverage matrix:**
|
|
98
|
+
|
|
99
|
+
Với mỗi endpoint, generate test cases cho:
|
|
100
|
+
1. **Happy path** (2xx) — luôn có
|
|
101
|
+
2. **Unauthorized** (401) — nếu endpoint yêu cầu auth
|
|
102
|
+
3. **Forbidden** (403) — nếu có RBAC/ownership check
|
|
103
|
+
4. **Not found** (404) — nếu có path param
|
|
104
|
+
5. **Validation error** (400/422) — nếu có required fields hoặc business rules
|
|
105
|
+
6. **Business rules** — từ Story ACs hoặc spec descriptions
|
|
106
|
+
|
|
107
|
+
**Coverage matrix format:**
|
|
108
|
+
```
|
|
109
|
+
| Endpoint | Happy Path | 401 Unauthorized | 403 Forbidden | 404 Not Found | 400/422 Validation | Business Rule |
|
|
110
|
+
|----------|:---------:|:----------------:|:-------------:|:-------------:|:------------------:|:-------------:|
|
|
111
|
+
| GET /api/users | ✓ | ✓ | | | | |
|
|
112
|
+
| POST /api/users | ✓ | ✓ | | | ✓ | |
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Test case detail format:**
|
|
116
|
+
```
|
|
117
|
+
#### TC-XXX: {Title} — {Modifier}
|
|
118
|
+
- **Endpoint**: `{METHOD} {path}`
|
|
119
|
+
- **Auth**: Required/Not Required
|
|
120
|
+
- **Preconditions**:
|
|
121
|
+
- {List preconditions}
|
|
122
|
+
- **Request Query/Path/Body**:
|
|
123
|
+
- {Request details}
|
|
124
|
+
- **Expected Response**:
|
|
125
|
+
- Status: {code}
|
|
126
|
+
- Body: {schema}
|
|
127
|
+
- **Assertions**:
|
|
128
|
+
- {List assertions}
|
|
129
|
+
- **AC Reference**: AC-{N} (nếu có)
|
|
130
|
+
- **Test Method Name**: `{Method}_{Resource}_Returns{Status}_When{Condition}`
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Bước 8 — Write Test Spec File
|
|
134
|
+
|
|
135
|
+
**File chưa tồn tại:** Tạo mới từ template.
|
|
136
|
+
|
|
137
|
+
**File đã tồn tại (append mode):**
|
|
138
|
+
- Đọc file hiện tại
|
|
139
|
+
- Find section `## v{N}` mà đang làm việc
|
|
140
|
+
- Append test cases mới vào cuối section trước `## Version History` hoặc `## Changelog`
|
|
141
|
+
- Preserve toàn bộ content cũ
|
|
142
|
+
|
|
143
|
+
### Bước 9 — Summary
|
|
144
|
+
|
|
145
|
+
Hiển thị:
|
|
146
|
+
1. Output file path
|
|
147
|
+
2. Number of endpoints detected
|
|
148
|
+
3. Number of test cases generated
|
|
149
|
+
4. Coverage matrix
|
|
150
|
+
5. Next steps:
|
|
151
|
+
- Review test spec file
|
|
152
|
+
- Run `/tas-apitest docs/tests/API-Test-Spec-{slug}.md` để generate code
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
## API Test Spec Generated
|
|
156
|
+
|
|
157
|
+
**Output**: `docs/tests/API-Test-Spec-{slug}.md`
|
|
158
|
+
**Version**: v{N}
|
|
159
|
+
**Endpoints**: {N}
|
|
160
|
+
**Test Cases**: {N}
|
|
161
|
+
|
|
162
|
+
### Coverage Matrix
|
|
163
|
+
[Print coverage matrix]
|
|
164
|
+
|
|
165
|
+
### Next Steps
|
|
166
|
+
1. Review test spec: `docs/tests/API-Test-Spec-{slug}.md`
|
|
167
|
+
2. Generate test code: `/tas-apitest docs/tests/API-Test-Spec-{slug}.md`
|
|
168
|
+
3. Run tests: `dotnet test tests/ApiTests/`
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Bước cuối — Token Log
|
|
172
|
+
|
|
173
|
+
Invoke skill `token-logger`: ghi AI Usage Log vào test spec file.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# /tas-apitest $ARGUMENTS
|
|
2
|
+
|
|
3
|
+
Vai trò: SE - Software Engineer
|
|
4
|
+
Generate .NET xUnit automation test project cho REST API từ API Test Spec file (Markdown).
|
|
5
|
+
|
|
6
|
+
## Always / Ask / Never
|
|
7
|
+
|
|
8
|
+
| | Hành động |
|
|
9
|
+
|---|---|
|
|
10
|
+
| **Always** | Đọc toàn bộ API Test Spec file trước khi generate bất kỳ test nào |
|
|
11
|
+
| **Always** | Tổ chức tests theo API version — mỗi version một folder riêng |
|
|
12
|
+
| **Always** | Append-only: không sửa files trong version folder cũ đã tồn tại |
|
|
13
|
+
| **Always** | URL và credentials ra `appsettings.json` — không hardcode trong code |
|
|
14
|
+
| **Always** | XML doc comment trên mỗi test method |
|
|
15
|
+
| **Ask** | Khi test spec không rõ expected response schema |
|
|
16
|
+
| **Never** | Sửa hoặc xóa test files của version cũ hơn |
|
|
17
|
+
| **Never** | Hardcode base URL, API key, credentials trong test code |
|
|
18
|
+
| **Never** | Bỏ qua error path — mỗi endpoint cần ≥1 happy path + ≥1 error path |
|
|
19
|
+
|
|
20
|
+
## Hành động
|
|
21
|
+
|
|
22
|
+
### Bước 1 — Locate Input
|
|
23
|
+
|
|
24
|
+
`$ARGUMENTS` là path đến API Test Spec file: `docs/tests/API-Test-Spec-{slug}.md`.
|
|
25
|
+
|
|
26
|
+
Nếu không có → hỏi user:
|
|
27
|
+
```
|
|
28
|
+
Nhập path đến API Test Spec file (vd: docs/tests/API-Test-Spec-users.md)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Bước 2 — Parse API Test Spec
|
|
32
|
+
|
|
33
|
+
Đọc `.claude/rules/csharp/api-testing.md` để nắm convention trước khi generate.
|
|
34
|
+
|
|
35
|
+
Từ API Test Spec file, thu thập:
|
|
36
|
+
- API version
|
|
37
|
+
- Endpoints với method, path, params
|
|
38
|
+
- Test cases theo từng endpoint (TC-XXX)
|
|
39
|
+
- Request/response schemas
|
|
40
|
+
- Auth requirements
|
|
41
|
+
- Test data requirements
|
|
42
|
+
- Setup/teardown notes
|
|
43
|
+
|
|
44
|
+
### Bước 3 — Detect Existing Test Project
|
|
45
|
+
|
|
46
|
+
Glob tìm `**/ApiTests/*.csproj`, `**/Api.Tests/*.csproj`, `**/IntegrationTests/*.csproj`.
|
|
47
|
+
|
|
48
|
+
- **Tìm thấy**: Đọc framework đang dùng (xUnit/NUnit/MSTest), glob `v*/` folders để biết versions đã có.
|
|
49
|
+
- **Không tìm thấy**: Tạo mới tại `tests/ApiTests/` với xUnit + FluentAssertions (per `csharp/testing.md`).
|
|
50
|
+
|
|
51
|
+
### Bước 4 — Get API Version from Spec
|
|
52
|
+
|
|
53
|
+
Đọc version từ API Test Spec file (tìm frontmatter `api_version` hoặc section headers `## v{N}`).
|
|
54
|
+
|
|
55
|
+
Version folder: lowercase, không có dot — `v1`, `v2` (không phải `v1.0`).
|
|
56
|
+
|
|
57
|
+
### Bước 5 — Generate Infrastructure (chỉ khi tạo project mới)
|
|
58
|
+
|
|
59
|
+
Đọc `.claude/rules/csharp/api-testing.md` section **Project Structure** và **Config Pattern** để generate:
|
|
60
|
+
- `ApiTests.csproj` với packages chuẩn
|
|
61
|
+
- `appsettings.json` (base) + `appsettings.Test.json` + `appsettings.Staging.json` với values từ spec
|
|
62
|
+
- `Shared/TestBase.cs` — load config, HttpClient, helper methods
|
|
63
|
+
- `Shared/ApiTestSettings.cs` — strongly typed settings
|
|
64
|
+
- `.gitignore` cho `appsettings.*.local.json`
|
|
65
|
+
|
|
66
|
+
### Bước 6 — Generate Test Classes từ Spec
|
|
67
|
+
|
|
68
|
+
Nhóm endpoints theo resource. Mỗi nhóm → `tests/ApiTests/{version}/{Resource}ApiTests.cs`.
|
|
69
|
+
|
|
70
|
+
Với mỗi test case (TC-XXX) trong spec:
|
|
71
|
+
1. Đọc test case details
|
|
72
|
+
2. Map sang test method với naming: `{HttpMethod}_{Resource}_Returns{Status}_When{Condition}`
|
|
73
|
+
3. Generate XML doc từ test case title
|
|
74
|
+
4. Generate assertions từ expected response
|
|
75
|
+
5. Add AC reference comment nếu có
|
|
76
|
+
|
|
77
|
+
Test class header comment:
|
|
78
|
+
```csharp
|
|
79
|
+
// ============================================================
|
|
80
|
+
// {Resource} API Tests — v{N}
|
|
81
|
+
// Spec: docs/tests/API-Test-Spec-{slug}.md
|
|
82
|
+
// Generated: {YYYY-MM-DD}
|
|
83
|
+
// Story: {ID} (if applicable)
|
|
84
|
+
// APPEND-ONLY: không sửa methods đã tồn tại.
|
|
85
|
+
// ============================================================
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Bước 7 — Append-Only Guard
|
|
89
|
+
|
|
90
|
+
Trước khi ghi file: kiểm tra file đã tồn tại chưa.
|
|
91
|
+
- **File chưa có** → tạo mới bình thường.
|
|
92
|
+
- **File đã có** trong version folder → check từng test method:
|
|
93
|
+
- Method đã tồn tại (cùng tên) → **SKIP**, không ghi đè
|
|
94
|
+
- Method chưa có → append vào cuối class
|
|
95
|
+
|
|
96
|
+
### Bước 8 — Generate Test Data Files (nếu spec yêu cầu)
|
|
97
|
+
|
|
98
|
+
Nếu spec có `test-data.{env}.json` references:
|
|
99
|
+
- Tạo `tests/ApiTests/data/test-data.Test.json` với sample data từ spec
|
|
100
|
+
- Hướng dẫn user tạo `test-data.Staging.json` và `test-data.local.json`
|
|
101
|
+
|
|
102
|
+
### Bước 9 — Post-Generate Review
|
|
103
|
+
|
|
104
|
+
Launch `csharp-reviewer` agent:
|
|
105
|
+
> Review `tests/ApiTests/{version}/`. Đọc `.claude/rules/csharp/testing.md` + `.claude/rules/csharp/api-testing.md`.
|
|
106
|
+
> Tập trung: async/await, HttpClient disposal, assertion completeness, XML doc coverage.
|
|
107
|
+
> Format: Critical / High / Medium / Low với file:line.
|
|
108
|
+
|
|
109
|
+
Gate: Critical/High → fix ngay. Medium/Low → list gợi ý.
|
|
110
|
+
|
|
111
|
+
### Bước 10 — Summary
|
|
112
|
+
|
|
113
|
+
Hiển thị:
|
|
114
|
+
1. Test project path
|
|
115
|
+
2. Number of test classes generated
|
|
116
|
+
3. Number of test methods generated
|
|
117
|
+
4. Coverage matrix (so với spec)
|
|
118
|
+
5. Next steps để chạy tests
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
## API Tests Generated
|
|
122
|
+
|
|
123
|
+
**Project**: `tests/ApiTests/`
|
|
124
|
+
**Version**: v{N}
|
|
125
|
+
**Test Classes**: {N}
|
|
126
|
+
**Test Methods**: {N}
|
|
127
|
+
|
|
128
|
+
### Generated Files
|
|
129
|
+
- tests/ApiTests/{version}/{Resource}ApiTests.cs
|
|
130
|
+
- tests/ApiTests/Shared/TestBase.cs (if new project)
|
|
131
|
+
|
|
132
|
+
### Coverage (vs Spec)
|
|
133
|
+
[Print coverage table: spec test cases vs generated methods]
|
|
134
|
+
|
|
135
|
+
### Next Steps
|
|
136
|
+
1. Configure test environment: edit tests/ApiTests/appsettings.Test.json
|
|
137
|
+
2. Add test data: tests/ApiTests/data/test-data.Test.json
|
|
138
|
+
3. Run tests: `dotnet test tests/ApiTests/`
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Bước cuối — Token Log
|
|
142
|
+
|
|
143
|
+
Invoke skill `token-logger`: ghi AI Usage Log vào API Test Spec file.
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
---
|
|
2
|
+
api_name:
|
|
3
|
+
api_slug:
|
|
4
|
+
api_version:
|
|
5
|
+
spec_source:
|
|
6
|
+
code_path:
|
|
7
|
+
status:
|
|
8
|
+
created_date:
|
|
9
|
+
updated_date:
|
|
10
|
+
executor:
|
|
11
|
+
story_id:
|
|
12
|
+
framework: xUnit
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# API Test Specification: {API Name}
|
|
16
|
+
|
|
17
|
+
**API Version**: v{api_version}
|
|
18
|
+
**Framework**: {framework}
|
|
19
|
+
**Author**: @[executor]
|
|
20
|
+
**Created**: [created_date]
|
|
21
|
+
**Updated**: [updated_date]
|
|
22
|
+
**Status**: [status] (Draft | Review | Approved | Deprecated)
|
|
23
|
+
**Spec Source**: [spec_source]
|
|
24
|
+
**Code Path**: [code_path]
|
|
25
|
+
**Story**: [story_id] (if applicable)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Version History
|
|
30
|
+
|
|
31
|
+
> Mỗi API version có section riêng biệt. APPEND-ONLY: không sửa version cũ.
|
|
32
|
+
|
|
33
|
+
| Version | Status | Created | Description |
|
|
34
|
+
|---------|--------|---------|-------------|
|
|
35
|
+
| v1 | Draft | [created_date] | Initial version |
|
|
36
|
+
| v2 | Draft | [updated_date] | Added new endpoints |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Test Environment Setup
|
|
41
|
+
|
|
42
|
+
### Configuration (appsettings.json)
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"ApiTest": {
|
|
47
|
+
"BaseUrl": "https://localhost:5001",
|
|
48
|
+
"TimeoutSeconds": 30,
|
|
49
|
+
"Auth": {
|
|
50
|
+
"Type": "Bearer",
|
|
51
|
+
"TokenEndpoint": "/api/auth/token",
|
|
52
|
+
"Username": "",
|
|
53
|
+
"Password": ""
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Environment-Specific Overrides
|
|
60
|
+
|
|
61
|
+
| Environment | BaseUrl | Notes |
|
|
62
|
+
|-------------|---------|-------|
|
|
63
|
+
| Local | https://localhost:5001 | Development environment |
|
|
64
|
+
| Test | https://test-api.example.com | Shared test environment |
|
|
65
|
+
| Staging | https://staging-api.example.com | Pre-production |
|
|
66
|
+
| Production | https://api.example.com | Smoke tests only |
|
|
67
|
+
|
|
68
|
+
### Test Data Requirements
|
|
69
|
+
|
|
70
|
+
| Data Item | Value | Source | Environment-Specific | Notes |
|
|
71
|
+
|-----------|-------|--------|---------------------|-------|
|
|
72
|
+
| Test User Email | test@example.com | test-data.{env}.json | Yes | Different per env |
|
|
73
|
+
| Test User Password | (from .env) | process.env.APITEST__AUTH__PASSWORD | Yes | NEVER hardcode |
|
|
74
|
+
| Auth Token | Generated at runtime | POST /api/auth/token | Yes | Refresh per test class |
|
|
75
|
+
| {Entity} ID | {value} | test-data.{env}.json | Yes | Pre-seeded data |
|
|
76
|
+
|
|
77
|
+
### Setup/Teardown Notes
|
|
78
|
+
|
|
79
|
+
**Before All Tests:**
|
|
80
|
+
- Authenticate and store token for authenticated requests
|
|
81
|
+
- Seed test data if required
|
|
82
|
+
- Configure HttpClient with base address and timeout
|
|
83
|
+
|
|
84
|
+
**After All Tests:**
|
|
85
|
+
- Dispose HttpClient
|
|
86
|
+
- Clean up test data (unless debugging needed)
|
|
87
|
+
|
|
88
|
+
**Before Each Test:**
|
|
89
|
+
- Reset state if needed (clear headers, reset counters)
|
|
90
|
+
|
|
91
|
+
**After Each Test:**
|
|
92
|
+
- Log test result
|
|
93
|
+
- Capture response on failure for debugging
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## v{N} — Test Cases
|
|
98
|
+
|
|
99
|
+
### Endpoints Overview
|
|
100
|
+
|
|
101
|
+
| Method | Path | Description | Auth Required |
|
|
102
|
+
|--------|------|-------------|---------------|
|
|
103
|
+
| GET | /api/users | List users | Yes |
|
|
104
|
+
| POST | /api/users | Create user | Yes |
|
|
105
|
+
| GET | /api/users/{id} | Get user by ID | Yes |
|
|
106
|
+
| PUT | /api/users/{id} | Update user | Yes |
|
|
107
|
+
| DELETE | /api/users/{id} | Delete user | Yes |
|
|
108
|
+
|
|
109
|
+
### Coverage Matrix
|
|
110
|
+
|
|
111
|
+
| Endpoint | Happy Path | 401 Unauthorized | 403 Forbidden | 404 Not Found | 400/422 Validation | Business Rule |
|
|
112
|
+
|----------|:---------:|:----------------:|:-------------:|:-------------:|:------------------:|:-------------:|
|
|
113
|
+
| GET /api/users | ✓ | ✓ | | | | |
|
|
114
|
+
| POST /api/users | ✓ | ✓ | | | ✓ | |
|
|
115
|
+
| GET /api/users/{id} | ✓ | ✓ | | ✓ | | |
|
|
116
|
+
| PUT /api/users/{id} | ✓ | ✓ | | ✓ | ✓ | |
|
|
117
|
+
| DELETE /api/users/{id} | ✓ | ✓ | ✓ | ✓ | | |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### Test Case Details
|
|
122
|
+
|
|
123
|
+
#### GET /api/users — List Users
|
|
124
|
+
|
|
125
|
+
##### TC-001: Happy Path — Returns Paginated User List
|
|
126
|
+
- **Endpoint**: `GET /api/users?page=1&limit=10`
|
|
127
|
+
- **Auth**: Required (Bearer token)
|
|
128
|
+
- **Preconditions**:
|
|
129
|
+
- Valid authentication token
|
|
130
|
+
- At least 10 users exist in database
|
|
131
|
+
- **Request Query Params**:
|
|
132
|
+
- `page`: 1
|
|
133
|
+
- `limit`: 10
|
|
134
|
+
- **Expected Response**:
|
|
135
|
+
- Status: 200 OK
|
|
136
|
+
- Body:
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"data": [
|
|
140
|
+
{
|
|
141
|
+
"id": "guid",
|
|
142
|
+
"email": "user@example.com",
|
|
143
|
+
"name": "John Doe",
|
|
144
|
+
"role": "User",
|
|
145
|
+
"createdAt": "2024-01-01T00:00:00Z"
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
"total": 100,
|
|
149
|
+
"page": 1,
|
|
150
|
+
"limit": 10
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
- **Assertions**:
|
|
154
|
+
- Response status is 200
|
|
155
|
+
- `data` is array with length ≤ 10
|
|
156
|
+
- Each item has required fields: id, email, name, role, createdAt
|
|
157
|
+
- `total` ≥ 0
|
|
158
|
+
- `page` and `limit` match request
|
|
159
|
+
- **AC Reference**: N/A (API spec)
|
|
160
|
+
- **Test Method Name**: `Get_Users_Returns200_WhenAuthenticated`
|
|
161
|
+
|
|
162
|
+
##### TC-002: Security — Returns 401 When No Token
|
|
163
|
+
- **Endpoint**: `GET /api/users`
|
|
164
|
+
- **Auth**: Not provided
|
|
165
|
+
- **Preconditions**: None
|
|
166
|
+
- **Expected Response**:
|
|
167
|
+
- Status: 401 Unauthorized
|
|
168
|
+
- Body contains error message
|
|
169
|
+
- **Assertions**:
|
|
170
|
+
- Response status is 401
|
|
171
|
+
- **AC Reference**: N/A
|
|
172
|
+
- **Test Method Name**: `Get_Users_Returns401_WhenNotAuthenticated`
|
|
173
|
+
|
|
174
|
+
##### TC-003: Edge Case — Empty List When No Users Exist
|
|
175
|
+
- **Endpoint**: `GET /api/users`
|
|
176
|
+
- **Auth**: Required
|
|
177
|
+
- **Preconditions**:
|
|
178
|
+
- Database is empty or no users match filter
|
|
179
|
+
- **Expected Response**:
|
|
180
|
+
- Status: 200 OK
|
|
181
|
+
- Body:
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"data": [],
|
|
185
|
+
"total": 0,
|
|
186
|
+
"page": 1,
|
|
187
|
+
"limit": 10
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
- **Assertions**:
|
|
191
|
+
- Response status is 200
|
|
192
|
+
- `data` is empty array
|
|
193
|
+
- `total` is 0
|
|
194
|
+
- **AC Reference**: N/A
|
|
195
|
+
- **Test Method Name**: `Get_Users_ReturnsEmptyArray_WhenNoUsersExist`
|
|
196
|
+
|
|
197
|
+
#### POST /api/users — Create User
|
|
198
|
+
|
|
199
|
+
##### TC-004: Happy Path — Creates New User
|
|
200
|
+
- **Endpoint**: `POST /api/users`
|
|
201
|
+
- **Auth**: Required
|
|
202
|
+
- **Request Body**:
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"email": "newuser@example.com",
|
|
206
|
+
"name": "New User",
|
|
207
|
+
"password": "SecurePass123!",
|
|
208
|
+
"role": "User"
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
- **Expected Response**:
|
|
212
|
+
- Status: 201 Created
|
|
213
|
+
- Body contains created user with generated `id`
|
|
214
|
+
- `Location` header contains URL of new resource
|
|
215
|
+
- **Assertions**:
|
|
216
|
+
- Response status is 201
|
|
217
|
+
- `id` is valid GUID
|
|
218
|
+
- `email`, `name`, `role` match request
|
|
219
|
+
- `password` is NOT in response
|
|
220
|
+
- `createdAt` is recent
|
|
221
|
+
- **AC Reference**: N/A
|
|
222
|
+
- **Test Method Name**: `Post_Users_Returns201_WhenValidRequest`
|
|
223
|
+
|
|
224
|
+
##### TC-005: Validation — Returns 400 When Email Invalid
|
|
225
|
+
- **Endpoint**: `POST /api/users`
|
|
226
|
+
- **Auth**: Required
|
|
227
|
+
- **Request Body**:
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"email": "invalid-email",
|
|
231
|
+
"name": "Test User",
|
|
232
|
+
"password": "SecurePass123!",
|
|
233
|
+
"role": "User"
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
- **Expected Response**:
|
|
237
|
+
- Status: 400 Bad Request
|
|
238
|
+
- Body contains validation errors
|
|
239
|
+
- **Assertions**:
|
|
240
|
+
- Response status is 400
|
|
241
|
+
- Error message indicates email format issue
|
|
242
|
+
- **AC Reference**: N/A
|
|
243
|
+
- **Test Method Name**: `Post_Users_Returns400_WhenEmailInvalid`
|
|
244
|
+
|
|
245
|
+
##### TC-006: Business Rule — Returns 409 When Email Already Exists
|
|
246
|
+
- **Endpoint**: `POST /api/users`
|
|
247
|
+
- **Auth**: Required
|
|
248
|
+
- **Preconditions**: User with email already exists
|
|
249
|
+
- **Request Body**:
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"email": "existing@example.com",
|
|
253
|
+
"name": "Test User",
|
|
254
|
+
"password": "SecurePass123!",
|
|
255
|
+
"role": "User"
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
- **Expected Response**:
|
|
259
|
+
- Status: 409 Conflict
|
|
260
|
+
- Body indicates email already registered
|
|
261
|
+
- **Assertions**:
|
|
262
|
+
- Response status is 409
|
|
263
|
+
- Error message mentions duplicate email
|
|
264
|
+
- **AC Reference**: N/A
|
|
265
|
+
- **Test Method Name**: `Post_Users_Returns409_WhenEmailAlreadyExists`
|
|
266
|
+
|
|
267
|
+
#### GET /api/users/{id} — Get User by ID
|
|
268
|
+
|
|
269
|
+
##### TC-007: Happy Path — Returns User When ID Exists
|
|
270
|
+
- **Endpoint**: `GET /api/users/{id}`
|
|
271
|
+
- **Auth**: Required
|
|
272
|
+
- **Path Params**: `id` = valid GUID
|
|
273
|
+
- **Expected Response**:
|
|
274
|
+
- Status: 200 OK
|
|
275
|
+
- Body contains user details
|
|
276
|
+
- **Assertions**:
|
|
277
|
+
- Response status is 200
|
|
278
|
+
- All required fields present
|
|
279
|
+
- **AC Reference**: N/A
|
|
280
|
+
- **Test Method Name**: `GetById_Users_Returns200_WhenExists`
|
|
281
|
+
|
|
282
|
+
##### TC-008: Error Path — Returns 404 When ID Not Found
|
|
283
|
+
- **Endpoint**: `GET /api/users/{id}`
|
|
284
|
+
- **Auth**: Required
|
|
285
|
+
- **Path Params**: `id` = valid but non-existent GUID
|
|
286
|
+
- **Expected Response**:
|
|
287
|
+
- Status: 404 Not Found
|
|
288
|
+
- **Assertions**:
|
|
289
|
+
- Response status is 404
|
|
290
|
+
- **AC Reference**: N/A
|
|
291
|
+
- **Test Method Name**: `GetById_Users_Returns404_WhenNotFound`
|
|
292
|
+
|
|
293
|
+
#### PUT /api/users/{id} — Update User
|
|
294
|
+
|
|
295
|
+
##### TC-009: Happy Path — Updates User
|
|
296
|
+
- **Endpoint**: `PUT /api/users/{id}`
|
|
297
|
+
- **Auth**: Required
|
|
298
|
+
- **Request Body**:
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"name": "Updated Name"
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
- **Expected Response**:
|
|
305
|
+
- Status: 200 OK
|
|
306
|
+
- Body contains updated user
|
|
307
|
+
- **Assertions**:
|
|
308
|
+
- Response status is 200
|
|
309
|
+
- `name` matches request
|
|
310
|
+
- **AC Reference**: N/A
|
|
311
|
+
- **Test Method Name**: `Put_Users_Returns200_WhenValidUpdate`
|
|
312
|
+
|
|
313
|
+
##### TC-010: Validation — Returns 400 When Name Empty
|
|
314
|
+
- **Endpoint**: `PUT /api/users/{id}`
|
|
315
|
+
- **Auth**: Required
|
|
316
|
+
- **Request Body**:
|
|
317
|
+
```json
|
|
318
|
+
{
|
|
319
|
+
"name": ""
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
- **Expected Response**:
|
|
323
|
+
- Status: 400 Bad Request
|
|
324
|
+
- **Assertions**:
|
|
325
|
+
- Response status is 400
|
|
326
|
+
- **AC Reference**: N/A
|
|
327
|
+
- **Test Method Name**: `Put_Users_Returns400_WhenNameEmpty`
|
|
328
|
+
|
|
329
|
+
#### DELETE /api/users/{id} — Delete User
|
|
330
|
+
|
|
331
|
+
##### TC-011: Happy Path — Deletes User
|
|
332
|
+
- **Endpoint**: `DELETE /api/users/{id}`
|
|
333
|
+
- **Auth**: Required
|
|
334
|
+
- **Expected Response**:
|
|
335
|
+
- Status: 204 No Content
|
|
336
|
+
- **Assertions**:
|
|
337
|
+
- Response status is 204
|
|
338
|
+
- Subsequent GET returns 404
|
|
339
|
+
- **AC Reference**: N/A
|
|
340
|
+
- **Test Method Name**: `Delete_Users_Returns204_WhenExists`
|
|
341
|
+
|
|
342
|
+
##### TC-012: Authorization — Returns 403 When Deleting Self
|
|
343
|
+
- **Endpoint**: `DELETE /api/users/{id}` where id = current user's id
|
|
344
|
+
- **Auth**: Required
|
|
345
|
+
- **Expected Response**:
|
|
346
|
+
- Status: 403 Forbidden
|
|
347
|
+
- **Assertions**:
|
|
348
|
+
- Response status is 403
|
|
349
|
+
- Error message indicates cannot delete own account
|
|
350
|
+
- **AC Reference**: N/A
|
|
351
|
+
- **Test Method Name**: `Delete_Users_Returns403_WhenDeletingSelf`
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Story-Specific Test Cases (Optional)
|
|
356
|
+
|
|
357
|
+
> Nếu spec được generate từ Story, thêm AC mapping ở đây.
|
|
358
|
+
|
|
359
|
+
| AC ID | AC Description | Test Case IDs |
|
|
360
|
+
|-------|----------------|---------------|
|
|
361
|
+
| AC-1 | {Given...When...Then...} | TC-001, TC-002 |
|
|
362
|
+
| AC-2 | {Given...When...Then...} | TC-004, TC-005 |
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Regression Tests (Optional)
|
|
367
|
+
|
|
368
|
+
> Test cases cho bugs đã được tìm thấy và fix.
|
|
369
|
+
|
|
370
|
+
| Bug ID | Description | Test Case ID | Date Added |
|
|
371
|
+
|--------|-------------|--------------|------------|
|
|
372
|
+
| BUG-001 | User profile missing notification_settings field | TC-R001 | 2024-01-15 |
|
|
373
|
+
|
|
374
|
+
### TC-R001: BUG-001 Regression — notification_settings Present in Response
|
|
375
|
+
- **Endpoint**: `GET /api/users/{id}`
|
|
376
|
+
- **Auth**: Required
|
|
377
|
+
- **Expected Response**:
|
|
378
|
+
- Status: 200 OK
|
|
379
|
+
- Body includes `notification_settings` field
|
|
380
|
+
- **Assertions**:
|
|
381
|
+
- `notification_settings` is present and not undefined
|
|
382
|
+
- **Test Method Name**: `BUG_R001_NotificationSettings_IsPresent`
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## Changelog
|
|
387
|
+
|
|
388
|
+
| Date | Version | Changes | Author |
|
|
389
|
+
|------|---------|---------|--------|
|
|
390
|
+
| [created_date] | v1 | Initial API test specification | @[executor] |
|
|
391
|
+
| [updated_date] | v2 | Added endpoints for user management | @[executor] |
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## AI Usage Log
|
|
396
|
+
|
|
397
|
+
| # | Date | Command | Input (est.) | Output (est.) |
|
|
398
|
+
|---|------|---------|-------------|---------------|
|
|
399
|
+
| 1 | [created_date] | /tas-apitest-plan | ~{N}k | ~{N}k |
|
|
400
|
+
| **Total** | | | **~{N}k** | **~{N}k** |
|
package/lib/deleted-files.json
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"1.6.0": [
|
|
3
|
-
".claude/commands/tas-dev-story.md",
|
|
4
|
-
".claude/commands/tas-review-code.md",
|
|
5
|
-
".claude/commands/tas-security-check.md"
|
|
6
|
-
],
|
|
7
|
-
"1.8.0": [
|
|
8
|
-
".claude/agents/README.md",
|
|
9
|
-
".claude/agents/ado-agent.md",
|
|
10
|
-
".claude/agents/code-architect.md",
|
|
11
|
-
".claude/agents/code-simplifier.md",
|
|
12
|
-
".claude/agents/comment-analyzer.md",
|
|
13
|
-
".claude/agents/conversation-analyzer.md",
|
|
14
|
-
".claude/agents/docs-lookup.md",
|
|
15
|
-
".claude/agents/harness-optimizer.md",
|
|
16
|
-
".claude/agents/loop-operator.md",
|
|
17
|
-
".claude/agents/performance-optimizer.md",
|
|
18
|
-
".claude/agents/pr-test-analyzer.md",
|
|
19
|
-
".claude/agents/pytorch-build-resolver.md",
|
|
20
|
-
".claude/agents/refactor-cleaner.md",
|
|
21
|
-
".claude/agents/seo-specialist.md",
|
|
22
|
-
".claude/agents/silent-failure-hunter.md",
|
|
23
|
-
".claude/agents/type-design-analyzer.md",
|
|
24
|
-
".claude/rules/common/agents.md",
|
|
25
|
-
".claude/rules/common/coding-style.md",
|
|
26
|
-
".claude/rules/common/development-workflow.md",
|
|
27
|
-
".claude/rules/common/git-workflow.md",
|
|
28
|
-
".claude/rules/common/performance.md",
|
|
29
|
-
".claude/skills/agent-harness-construction/SKILL.md",
|
|
30
|
-
".claude/skills/agent-introspection-debugging/SKILL.md",
|
|
31
|
-
".claude/skills/backend-patterns/SKILL.md"
|
|
32
|
-
]
|
|
33
|
-
|
|
1
|
+
{
|
|
2
|
+
"1.6.0": [
|
|
3
|
+
".claude/commands/tas-dev-story.md",
|
|
4
|
+
".claude/commands/tas-review-code.md",
|
|
5
|
+
".claude/commands/tas-security-check.md"
|
|
6
|
+
],
|
|
7
|
+
"1.8.0": [
|
|
8
|
+
".claude/agents/README.md",
|
|
9
|
+
".claude/agents/ado-agent.md",
|
|
10
|
+
".claude/agents/code-architect.md",
|
|
11
|
+
".claude/agents/code-simplifier.md",
|
|
12
|
+
".claude/agents/comment-analyzer.md",
|
|
13
|
+
".claude/agents/conversation-analyzer.md",
|
|
14
|
+
".claude/agents/docs-lookup.md",
|
|
15
|
+
".claude/agents/harness-optimizer.md",
|
|
16
|
+
".claude/agents/loop-operator.md",
|
|
17
|
+
".claude/agents/performance-optimizer.md",
|
|
18
|
+
".claude/agents/pr-test-analyzer.md",
|
|
19
|
+
".claude/agents/pytorch-build-resolver.md",
|
|
20
|
+
".claude/agents/refactor-cleaner.md",
|
|
21
|
+
".claude/agents/seo-specialist.md",
|
|
22
|
+
".claude/agents/silent-failure-hunter.md",
|
|
23
|
+
".claude/agents/type-design-analyzer.md",
|
|
24
|
+
".claude/rules/common/agents.md",
|
|
25
|
+
".claude/rules/common/coding-style.md",
|
|
26
|
+
".claude/rules/common/development-workflow.md",
|
|
27
|
+
".claude/rules/common/git-workflow.md",
|
|
28
|
+
".claude/rules/common/performance.md",
|
|
29
|
+
".claude/skills/agent-harness-construction/SKILL.md",
|
|
30
|
+
".claude/skills/agent-introspection-debugging/SKILL.md",
|
|
31
|
+
".claude/skills/backend-patterns/SKILL.md"
|
|
32
|
+
],
|
|
33
|
+
"1.9.0": [
|
|
34
|
+
".claude/commands/tas-api-test.md"
|
|
35
|
+
]
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# /tas-api-test $ARGUMENTS
|
|
2
|
-
|
|
3
|
-
Vai trò: SE - Software Engineer
|
|
4
|
-
Generate .NET xUnit automation test project cho REST API từ spec (OpenAPI 3.0, Markdown, YAML).
|
|
5
|
-
|
|
6
|
-
## Always / Ask / Never
|
|
7
|
-
|
|
8
|
-
| | Hành động |
|
|
9
|
-
|---|---|
|
|
10
|
-
| **Always** | Đọc toàn bộ spec trước khi generate bất kỳ test nào |
|
|
11
|
-
| **Always** | Tổ chức tests theo API version — mỗi version một folder riêng |
|
|
12
|
-
| **Always** | Append-only: không sửa files trong version folder cũ đã tồn tại |
|
|
13
|
-
| **Always** | URL và credentials ra `appsettings.json` — không hardcode trong code |
|
|
14
|
-
| **Always** | XML doc comment trên mỗi test method |
|
|
15
|
-
| **Ask** | Khi spec không rõ expected response schema |
|
|
16
|
-
| **Never** | Sửa hoặc xóa test files của version cũ hơn |
|
|
17
|
-
| **Never** | Hardcode base URL, API key, credentials trong test code |
|
|
18
|
-
| **Never** | Bỏ qua error path — mỗi endpoint cần ≥1 happy path + ≥1 error path |
|
|
19
|
-
|
|
20
|
-
## Hành động
|
|
21
|
-
|
|
22
|
-
### Bước 1 — Locate Inputs
|
|
23
|
-
|
|
24
|
-
`$ARGUMENTS` là path đến spec file hoặc Story ID. Nếu không có → hỏi user.
|
|
25
|
-
|
|
26
|
-
Nếu là Story ID: glob tìm `docs/epics/**/Story-{ID}*.md`, đọc Story để tìm link spec trong `## Technical Plan` hoặc `## Acceptance Criteria`.
|
|
27
|
-
|
|
28
|
-
### Bước 2 — Parse API Spec
|
|
29
|
-
|
|
30
|
-
Đọc `.claude/rules/csharp/api-testing.md` để nắm convention trước khi generate.
|
|
31
|
-
|
|
32
|
-
Từ spec, thu thập cho mỗi endpoint:
|
|
33
|
-
- HTTP method + path, path/query params, request body schema
|
|
34
|
-
- Response schemas theo từng status code
|
|
35
|
-
- Auth requirement, description/summary
|
|
36
|
-
|
|
37
|
-
Nếu có Story: đọc thêm `## Acceptance Criteria` để bổ sung business rule test cases.
|
|
38
|
-
|
|
39
|
-
### Bước 3 — Detect Existing Test Project
|
|
40
|
-
|
|
41
|
-
Glob tìm `**/ApiTests/*.csproj`, `**/Api.Tests/*.csproj`, `**/IntegrationTests/*.csproj`.
|
|
42
|
-
|
|
43
|
-
- **Tìm thấy**: Đọc framework đang dùng (xUnit/NUnit/MSTest), glob `v*/` folders để biết versions đã có.
|
|
44
|
-
- **Không tìm thấy**: Tạo mới tại `tests/ApiTests/` với xUnit + FluentAssertions (per `csharp/testing.md`).
|
|
45
|
-
|
|
46
|
-
### Bước 4 — Detect API Version
|
|
47
|
-
|
|
48
|
-
Ưu tiên theo thứ tự: `info.version` trong OpenAPI → prefix trong URL path → hỏi user.
|
|
49
|
-
Version folder: lowercase, không có dot — `v1`, `v2` (không phải `v1.0`).
|
|
50
|
-
|
|
51
|
-
### Bước 5 — Generate Infrastructure (chỉ khi tạo project mới)
|
|
52
|
-
|
|
53
|
-
Đọc `.claude/rules/csharp/api-testing.md` section **Project Structure** và **Config Pattern** để generate:
|
|
54
|
-
- `ApiTests.csproj` với packages chuẩn
|
|
55
|
-
- `appsettings.json` (base) + `appsettings.Test.json` + `appsettings.Staging.json`
|
|
56
|
-
- `Shared/TestBase.cs` — load config, HttpClient, helper methods
|
|
57
|
-
- `Shared/ApiTestSettings.cs` — strongly typed settings
|
|
58
|
-
- `.gitignore` cho `appsettings.*.local.json`
|
|
59
|
-
|
|
60
|
-
### Bước 6 — Generate Test Classes
|
|
61
|
-
|
|
62
|
-
Nhóm endpoints theo resource/tag. Mỗi nhóm → `tests/ApiTests/{version}/{Resource}ApiTests.cs`.
|
|
63
|
-
|
|
64
|
-
Với mỗi endpoint, generate tối thiểu:
|
|
65
|
-
1. Happy path (2xx)
|
|
66
|
-
2. Unauthorized (401) — nếu endpoint yêu cầu auth
|
|
67
|
-
3. Not found (404) — nếu có path param
|
|
68
|
-
4. Validation error (400/422) — nếu có required fields
|
|
69
|
-
|
|
70
|
-
Từ Story ACs: thêm test methods tương ứng, comment rõ `// AC: {AC text}`.
|
|
71
|
-
|
|
72
|
-
Đầu mỗi file: block comment ghi `Spec`, `Generated date`, `Story ID`, và nhắc **APPEND-ONLY rule**.
|
|
73
|
-
|
|
74
|
-
### Bước 7 — Append-Only Guard
|
|
75
|
-
|
|
76
|
-
Trước khi ghi file: kiểm tra file đã tồn tại chưa.
|
|
77
|
-
- File chưa có → tạo mới bình thường.
|
|
78
|
-
- File đã tồn tại trong version folder → **DỪNG**, thông báo tên file cho user tự edit thủ công.
|
|
79
|
-
|
|
80
|
-
### Bước 8 — Post-Generate Review
|
|
81
|
-
|
|
82
|
-
Launch `csharp-reviewer` agent:
|
|
83
|
-
> Review `tests/ApiTests/{version}/`. Đọc `.claude/rules/csharp/testing.md` + `.claude/rules/csharp/api-testing.md`.
|
|
84
|
-
> Tập trung: async/await, HttpClient disposal, assertion completeness, XML doc coverage.
|
|
85
|
-
> Format: Critical / High / Medium / Low với file:line.
|
|
86
|
-
|
|
87
|
-
Gate: Critical/High → fix ngay. Medium/Low → list gợi ý.
|
|
88
|
-
|
|
89
|
-
### Bước 9 — Summary
|
|
90
|
-
|
|
91
|
-
Hiển thị bảng coverage (endpoint × test type: ✓/—) và next steps để chạy tests.
|
|
92
|
-
|
|
93
|
-
## Bước cuối — Token Log
|
|
94
|
-
|
|
95
|
-
Invoke skill `token-logger`: ghi AI Usage Log vào spec file hoặc Story đang làm việc.
|