@assertrx/dino 1.0.9 → 1.0.11

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.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/prompts/generate-bdd-from-url.md +5 -1
  3. package/prompts/generate-k6-test-from-endpoint.md +68 -0
  4. package/prompts/generate-k6-test-from-openapi.md +85 -0
  5. package/prompts/setup-k6.md +130 -0
  6. package/scripts/api-server.mjs +32 -2
  7. package/skills/analyzing-test-results/SKILL.md +150 -0
  8. package/skills/analyzing-test-results/reference/bottleneck-patterns.md +130 -0
  9. package/skills/analyzing-test-results/reference/metrics.md +134 -0
  10. package/skills/analyzing-test-results/reference/visualization.md +152 -0
  11. package/skills/designing-test-scenarios/SKILL.md +247 -0
  12. package/skills/designing-test-scenarios/reference/executors.md +215 -0
  13. package/skills/designing-test-scenarios/reference/test-types.md +215 -0
  14. package/skills/designing-test-scenarios/reference/thresholds.md +208 -0
  15. package/skills/generating-api-load-tests/SKILL.md +199 -0
  16. package/skills/generating-api-load-tests/reference/data-parameterization.md +343 -0
  17. package/skills/generating-api-load-tests/reference/grpc.md +315 -0
  18. package/skills/generating-api-load-tests/reference/http.md +380 -0
  19. package/skills/generating-api-load-tests/reference/websocket.md +369 -0
  20. package/skills/generating-browser-tests/SKILL.md +269 -0
  21. package/skills/generating-browser-tests/reference/browser-api.md +251 -0
  22. package/skills/generating-browser-tests/reference/web-vitals.md +148 -0
  23. package/skills/generating-tests-from-code/SKILL.md +142 -0
  24. package/skills/generating-tests-from-code/reference/auth-analysis.md +220 -0
  25. package/skills/generating-tests-from-code/reference/framework-patterns.md +242 -0
  26. package/skills/generating-tests-from-openapi/SKILL.md +234 -0
  27. package/skills/generating-tests-from-openapi/reference/openapi-auth-mapping.md +247 -0
  28. package/skills/generating-tests-from-openapi/reference/openapi-parsing.md +194 -0
  29. package/skills/operating-k6-in-ci-cd/SKILL.md +98 -0
  30. package/skills/operating-k6-in-ci-cd/reference/ci-cd-pipelines.md +265 -0
  31. package/skills/operating-k6-in-ci-cd/reference/extensions.md +144 -0
  32. package/skills/operating-k6-in-ci-cd/reference/k6-operator.md +214 -0
  33. package/skills/testing-resilience/SKILL.md +230 -0
  34. package/skills/testing-resilience/reference/fault-injection.md +153 -0
  35. package/skills/testing-resilience/reference/resilience-patterns.md +500 -0
@@ -0,0 +1,220 @@
1
+ # Authentication Analysis Reference
2
+
3
+ ## Auth Detection Patterns by Framework
4
+
5
+ ### Express (Node.js)
6
+
7
+ **JWT Authentication:**
8
+ ```javascript
9
+ // Look for: passport, jsonwebtoken, express-jwt, middleware patterns
10
+ const jwt = require('jsonwebtoken');
11
+ app.use('/api', authenticateToken); // Global auth middleware
12
+
13
+ function authenticateToken(req, res, next) {
14
+ const token = req.headers['authorization']?.split(' ')[1];
15
+ jwt.verify(token, process.env.SECRET, (err, user) => { /* ... */ });
16
+ }
17
+ ```
18
+ **Detection:** Search for `jsonwebtoken`, `passport-jwt`, `express-jwt`, `Authorization` header parsing.
19
+
20
+ **Session Authentication:**
21
+ ```javascript
22
+ // Look for: express-session, passport with session strategy
23
+ app.use(session({ secret: '...', resave: false }));
24
+ app.use(passport.initialize());
25
+ app.use(passport.session());
26
+ ```
27
+ **Detection:** Search for `express-session`, `passport.session()`, `req.session`.
28
+
29
+ **API Key:**
30
+ ```javascript
31
+ // Look for: custom middleware checking headers or query params
32
+ app.use((req, res, next) => {
33
+ const apiKey = req.headers['x-api-key'];
34
+ if (!apiKey || !validKeys.includes(apiKey)) return res.status(401).json({});
35
+ });
36
+ ```
37
+ **Detection:** Search for `x-api-key`, `apikey`, `api_key` in middleware.
38
+
39
+ ### NestJS
40
+
41
+ **Guards (JWT):**
42
+ ```typescript
43
+ // Look for: @UseGuards, AuthGuard, JwtAuthGuard
44
+ @UseGuards(JwtAuthGuard)
45
+ @Controller('users')
46
+ export class UsersController { /* ... */ }
47
+
48
+ // Or per-route
49
+ @UseGuards(AuthGuard('jwt'))
50
+ @Get('profile')
51
+ getProfile() { /* ... */ }
52
+ ```
53
+ **Detection:** Search for `@UseGuards`, `AuthGuard`, `JwtStrategy`, `@nestjs/passport`.
54
+
55
+ **Public Routes:**
56
+ ```typescript
57
+ // Look for: @Public(), @SkipAuth(), or custom decorators
58
+ @Public()
59
+ @Get('health')
60
+ healthCheck() { /* ... */ }
61
+ ```
62
+ **Detection:** Search for `@Public`, `@SkipAuth`, `SetMetadata('isPublic', true)`.
63
+
64
+ ### Spring Boot (Java)
65
+
66
+ **Spring Security:**
67
+ ```java
68
+ // Look for: SecurityFilterChain, WebSecurityConfigurerAdapter
69
+ @Bean
70
+ public SecurityFilterChain filterChain(HttpSecurity http) {
71
+ http.authorizeHttpRequests(auth -> auth
72
+ .requestMatchers("/api/public/**").permitAll()
73
+ .requestMatchers("/api/admin/**").hasRole("ADMIN")
74
+ .anyRequest().authenticated()
75
+ );
76
+ }
77
+ ```
78
+ **Detection:** Search for `SecurityFilterChain`, `@EnableWebSecurity`, `authorizeHttpRequests`, `antMatchers`.
79
+
80
+ **JWT in Spring:**
81
+ ```java
82
+ // Look for: OncePerRequestFilter, JWT token parsing
83
+ @Component
84
+ public class JwtAuthFilter extends OncePerRequestFilter {
85
+ protected void doFilterInternal(request, response, chain) {
86
+ String token = request.getHeader("Authorization");
87
+ // verify token
88
+ }
89
+ }
90
+ ```
91
+ **Detection:** Search for `JwtAuthFilter`, `OncePerRequestFilter`, `@PreAuthorize`.
92
+
93
+ ### FastAPI (Python)
94
+
95
+ **OAuth2/JWT:**
96
+ ```python
97
+ # Look for: Depends(), OAuth2PasswordBearer, HTTPBearer
98
+ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
99
+
100
+ @app.get("/users/me")
101
+ async def read_users_me(token: str = Depends(oauth2_scheme)):
102
+ user = decode_token(token)
103
+ return user
104
+ ```
105
+ **Detection:** Search for `Depends(`, `OAuth2PasswordBearer`, `HTTPBearer`, `Security(`.
106
+
107
+ **API Key:**
108
+ ```python
109
+ api_key_header = APIKeyHeader(name="X-API-Key")
110
+
111
+ @app.get("/data")
112
+ async def get_data(api_key: str = Depends(api_key_header)):
113
+ pass
114
+ ```
115
+ **Detection:** Search for `APIKeyHeader`, `APIKeyQuery`, `APIKeyCookie`.
116
+
117
+ ### Django REST Framework (Python)
118
+
119
+ **Permission Classes:**
120
+ ```python
121
+ # Look for: permission_classes, authentication_classes
122
+ class UserViewSet(viewsets.ModelViewSet):
123
+ authentication_classes = [TokenAuthentication, SessionAuthentication]
124
+ permission_classes = [IsAuthenticated]
125
+ ```
126
+ **Detection:** Search for `permission_classes`, `authentication_classes`, `IsAuthenticated`, `AllowAny`, `TokenAuthentication`, `JWTAuthentication`.
127
+
128
+ ---
129
+
130
+ ## k6 Auth Setup Generation
131
+
132
+ ### JWT Token Flow
133
+
134
+ ```javascript
135
+ export function setup() {
136
+ const loginRes = http.post(`${BASE_URL}/auth/login`,
137
+ JSON.stringify({
138
+ username: __ENV.TEST_USERNAME || 'testuser',
139
+ password: __ENV.TEST_PASSWORD || 'testpass',
140
+ }),
141
+ { headers: { 'Content-Type': 'application/json' } }
142
+ );
143
+
144
+ check(loginRes, { 'login successful': (r) => r.status === 200 });
145
+ const token = loginRes.json('access_token');
146
+ return { token };
147
+ }
148
+
149
+ export default function (data) {
150
+ const headers = {
151
+ 'Content-Type': 'application/json',
152
+ 'Authorization': `Bearer ${data.token}`,
153
+ };
154
+ // Use headers in all requests
155
+ }
156
+ ```
157
+
158
+ ### Session/Cookie Flow
159
+
160
+ ```javascript
161
+ export default function () {
162
+ // Login (cookies auto-stored in VU cookie jar)
163
+ const loginRes = http.post(`${BASE_URL}/login`, {
164
+ username: 'testuser',
165
+ password: 'testpass',
166
+ });
167
+ check(loginRes, { 'logged in': (r) => r.status === 200 || r.status === 302 });
168
+
169
+ // Subsequent requests include session cookie automatically
170
+ http.get(`${BASE_URL}/dashboard`);
171
+ }
172
+ ```
173
+
174
+ ### API Key Flow
175
+
176
+ ```javascript
177
+ const API_KEY = __ENV.API_KEY || 'test-api-key';
178
+
179
+ export default function () {
180
+ http.get(`${BASE_URL}/data`, {
181
+ headers: { 'X-API-Key': API_KEY },
182
+ });
183
+ }
184
+ ```
185
+
186
+ ### OAuth2 Client Credentials Flow
187
+
188
+ ```javascript
189
+ import encoding from 'k6/encoding';
190
+
191
+ export function setup() {
192
+ const res = http.post(`${AUTH_URL}/oauth/token`,
193
+ 'grant_type=client_credentials&scope=read write',
194
+ {
195
+ headers: {
196
+ 'Content-Type': 'application/x-www-form-urlencoded',
197
+ 'Authorization': `Basic ${encoding.b64encode(`${CLIENT_ID}:${CLIENT_SECRET}`)}`,
198
+ },
199
+ }
200
+ );
201
+ return { token: res.json('access_token') };
202
+ }
203
+ ```
204
+
205
+ ## Identifying Protected vs Public Endpoints
206
+
207
+ Build a table of endpoints with their auth requirements:
208
+
209
+ | Endpoint | Method | Auth Required | Auth Type | Notes |
210
+ |----------|--------|---------------|-----------|-------|
211
+ | `/health` | GET | No | - | Health check |
212
+ | `/auth/login` | POST | No | - | Login endpoint |
213
+ | `/api/users` | GET | Yes | JWT Bearer | List users |
214
+ | `/api/admin/settings` | GET | Yes | JWT + Admin Role | Admin only |
215
+
216
+ Use this table to:
217
+ 1. Generate `setup()` with appropriate login flow
218
+ 2. Test public endpoints without auth
219
+ 3. Group protected endpoints under authenticated scenarios
220
+ 4. Test authorization (access control) with different user roles
@@ -0,0 +1,242 @@
1
+ # Framework Route Analysis Patterns
2
+
3
+ ## Express (Node.js)
4
+
5
+ ### Where to Find Routes
6
+
7
+ ```
8
+ src/routes/ — Route files
9
+ src/app.js — Main app with app.use() mounts
10
+ src/index.js — Entry point
11
+ src/controllers/ — Controller functions
12
+ ```
13
+
14
+ ### Route Patterns
15
+
16
+ ```javascript
17
+ // Direct route definition
18
+ app.get('/users', getUsers);
19
+ app.post('/users', createUser);
20
+ app.put('/users/:id', updateUser);
21
+ app.delete('/users/:id', deleteUser);
22
+
23
+ // Router module
24
+ const router = express.Router();
25
+ router.get('/', listItems);
26
+ router.post('/', createItem);
27
+ router.get('/:id', getItem);
28
+
29
+ // Mount point
30
+ app.use('/api/items', router);
31
+ // → Full paths: GET /api/items, POST /api/items, GET /api/items/:id
32
+ ```
33
+
34
+ ### Extracting Info
35
+
36
+ - **URL params:** `:id`, `:userId` → dynamic path segments
37
+ - **Query params:** Look for `req.query.page`, `req.query.limit`
38
+ - **Body:** Look for `req.body.name`, `req.body.email` or validation schemas
39
+ - **Middleware:** `app.use(auth)`, `router.use(validateBody)` → auth/validation requirements
40
+
41
+ ---
42
+
43
+ ## NestJS
44
+
45
+ ### Where to Find Routes
46
+
47
+ ```
48
+ src/modules/*/ — Feature modules
49
+ *.controller.ts — Controllers with decorators
50
+ *.service.ts — Business logic
51
+ *.dto.ts — Request/Response DTOs
52
+ *.module.ts — Module definitions
53
+ src/app.module.ts — Root module
54
+ ```
55
+
56
+ ### Route Patterns
57
+
58
+ ```typescript
59
+ @Controller('users') // Base path: /users
60
+ export class UsersController {
61
+ @Get() // GET /users
62
+ findAll() {}
63
+
64
+ @Get(':id') // GET /users/:id
65
+ findOne(@Param('id') id: string) {}
66
+
67
+ @Post() // POST /users
68
+ create(@Body() dto: CreateUserDto) {}
69
+
70
+ @Put(':id') // PUT /users/:id
71
+ update(@Param('id') id: string, @Body() dto: UpdateUserDto) {}
72
+
73
+ @Delete(':id') // DELETE /users/:id
74
+ remove(@Param('id') id: string) {}
75
+ }
76
+ ```
77
+
78
+ ### Extracting Info
79
+
80
+ - **Path prefix:** `@Controller('prefix')` decorator
81
+ - **Global prefix:** Check `app.setGlobalPrefix('api')` in main.ts
82
+ - **DTOs:** `CreateUserDto`, `UpdateUserDto` → request body shape
83
+ - **Params:** `@Param()`, `@Query()`, `@Body()` decorators
84
+ - **Guards:** `@UseGuards()` → authentication requirements
85
+ - **Pipes:** `@UsePipes(ValidationPipe)` → validation rules
86
+
87
+ ---
88
+
89
+ ## Spring Boot (Java)
90
+
91
+ ### Where to Find Routes
92
+
93
+ ```
94
+ src/main/java/**/controller/ — Controller classes
95
+ src/main/java/**/config/ — Security config
96
+ src/main/resources/ — application.yml (context path)
97
+ ```
98
+
99
+ ### Route Patterns
100
+
101
+ ```java
102
+ @RestController
103
+ @RequestMapping("/api/users") // Base path
104
+ public class UserController {
105
+
106
+ @GetMapping // GET /api/users
107
+ public List<User> findAll() {}
108
+
109
+ @GetMapping("/{id}") // GET /api/users/{id}
110
+ public User findById(@PathVariable Long id) {}
111
+
112
+ @PostMapping // POST /api/users
113
+ public User create(@RequestBody @Valid CreateUserRequest req) {}
114
+
115
+ @PutMapping("/{id}") // PUT /api/users/{id}
116
+ public User update(@PathVariable Long id, @RequestBody UpdateUserRequest req) {}
117
+
118
+ @DeleteMapping("/{id}") // DELETE /api/users/{id}
119
+ public void delete(@PathVariable Long id) {}
120
+ }
121
+ ```
122
+
123
+ ### Extracting Info
124
+
125
+ - **Context path:** Check `server.servlet.context-path` in application.yml
126
+ - **Path prefix:** `@RequestMapping` on class
127
+ - **Request body:** `@RequestBody` with DTO class → field types
128
+ - **Path vars:** `@PathVariable` → dynamic segments
129
+ - **Query params:** `@RequestParam` → query parameters
130
+ - **Validation:** `@Valid`, `@NotNull`, `@Size` annotations
131
+ - **Security:** `@PreAuthorize`, `SecurityFilterChain` → auth requirements
132
+
133
+ ---
134
+
135
+ ## FastAPI (Python)
136
+
137
+ ### Where to Find Routes
138
+
139
+ ```
140
+ app/main.py — Main app with app.include_router()
141
+ app/routers/ — Router modules
142
+ app/models/ — Pydantic models
143
+ app/dependencies.py — Shared dependencies
144
+ ```
145
+
146
+ ### Route Patterns
147
+
148
+ ```python
149
+ router = APIRouter(prefix="/users", tags=["users"])
150
+
151
+ @router.get("/") # GET /users
152
+ async def list_users(
153
+ skip: int = 0, # Query param
154
+ limit: int = 100, # Query param
155
+ ):
156
+ pass
157
+
158
+ @router.get("/{user_id}") # GET /users/{user_id}
159
+ async def get_user(user_id: int): # Path param (typed)
160
+ pass
161
+
162
+ @router.post("/", status_code=201) # POST /users
163
+ async def create_user(user: UserCreate): # Body from Pydantic model
164
+ pass
165
+
166
+ @router.put("/{user_id}") # PUT /users/{user_id}
167
+ async def update_user(user_id: int, user: UserUpdate):
168
+ pass
169
+ ```
170
+
171
+ ### Extracting Info
172
+
173
+ - **Router prefix:** `APIRouter(prefix="/prefix")`
174
+ - **App mount:** `app.include_router(router, prefix="/api")`
175
+ - **Pydantic models:** Define request/response shapes with types
176
+ - **Dependencies:** `Depends()` → auth, DB session, etc.
177
+ - **Status codes:** `status_code=201` → expected response codes
178
+ - **Response model:** `response_model=UserResponse` → response shape
179
+
180
+ ---
181
+
182
+ ## Django REST Framework (Python)
183
+
184
+ ### Where to Find Routes
185
+
186
+ ```
187
+ project/urls.py — Root URL configuration
188
+ app/urls.py — App URL patterns
189
+ app/views.py — View classes/functions
190
+ app/serializers.py — Request/Response serializers
191
+ app/permissions.py — Permission classes
192
+ ```
193
+
194
+ ### Route Patterns
195
+
196
+ ```python
197
+ # urls.py with ViewSet + Router
198
+ router = DefaultRouter()
199
+ router.register(r'users', UserViewSet)
200
+ urlpatterns = [path('api/', include(router.urls))]
201
+ # → GET/POST /api/users/
202
+ # → GET/PUT/PATCH/DELETE /api/users/{pk}/
203
+
204
+ # ViewSet
205
+ class UserViewSet(viewsets.ModelViewSet):
206
+ queryset = User.objects.all()
207
+ serializer_class = UserSerializer
208
+ permission_classes = [IsAuthenticated]
209
+
210
+ @action(detail=False, methods=['get'])
211
+ def me(self, request): # GET /api/users/me/
212
+ pass
213
+
214
+ # Function-based views
215
+ @api_view(['GET', 'POST'])
216
+ @permission_classes([AllowAny])
217
+ def user_list(request):
218
+ pass
219
+ ```
220
+
221
+ ### Extracting Info
222
+
223
+ - **URL patterns:** `path()`, `re_path()`, `router.register()`
224
+ - **Serializers:** Define request/response shapes
225
+ - **Permissions:** `permission_classes` → auth requirements
226
+ - **ViewSet actions:** Standard CRUD + custom `@action` methods
227
+ - **Pagination:** Check `DEFAULT_PAGINATION_CLASS` in settings
228
+
229
+ ---
230
+
231
+ ## Common Analysis Steps
232
+
233
+ For any framework:
234
+
235
+ 1. **Find the entry point** (main app file)
236
+ 2. **Trace route registration** (how routes are mounted)
237
+ 3. **List all endpoints** with methods and paths
238
+ 4. **Check for global prefix** (e.g., `/api/v1`)
239
+ 5. **Identify auth middleware** (global vs per-route)
240
+ 6. **Extract request shapes** from DTOs/models/schemas
241
+ 7. **Note response codes** for checks
242
+ 8. **Find validation rules** for generating valid test data
@@ -0,0 +1,234 @@
1
+ ---
2
+ name: generating-tests-from-openapi
3
+ description: Use when generating k6 load test scripts from OpenAPI specification files (YAML or JSON). Use when the user has an OpenAPI spec, API specification, or wants to create k6 tests from API documentation defined in OpenAPI 3.0 or 3.1 format.
4
+ ---
5
+
6
+ # Generating k6 Tests from OpenAPI
7
+
8
+ Generate k6 load test scripts by parsing OpenAPI specification files (YAML format). Extracts endpoints, parameters, request bodies, and security schemes to create comprehensive test suites.
9
+
10
+ ## Workflow
11
+
12
+ ### Step 1: Parse OpenAPI Spec
13
+
14
+ Read the OpenAPI YAML file and extract:
15
+ - API info (title, version, base URL)
16
+ - All paths and operations
17
+ - Request parameters, bodies, and response schemas
18
+ - Security definitions and requirements
19
+
20
+ ### Step 2: Security Scheme Analysis (Prerequisite)
21
+
22
+ **Before generating test scripts, analyze security requirements.**
23
+
24
+ 1. **Extract security definitions** from `components.securitySchemes`:
25
+ - OAuth2 flows (authorization_code, client_credentials, password)
26
+ - API Key (header, query, cookie)
27
+ - HTTP Bearer / Basic Auth
28
+ - OpenID Connect
29
+
30
+ 2. **Map per-endpoint security:**
31
+ - Check global `security` array
32
+ - Check per-operation `security` overrides
33
+ - Identify public endpoints (empty security array `security: []`)
34
+
35
+ 3. **Generate k6 auth setup:**
36
+ - Create `setup()` function matching the required auth flow
37
+ - Configure token/key handling for requests
38
+
39
+ See [reference/openapi-auth-mapping.md](reference/openapi-auth-mapping.md) for mapping security schemes to k6 code.
40
+
41
+ ### Step 3: Endpoint Extraction
42
+
43
+ For each path and operation, extract:
44
+
45
+ ```yaml
46
+ paths:
47
+ /users:
48
+ get: # HTTP method
49
+ operationId: listUsers # Operation identifier
50
+ tags: [Users] # Grouping
51
+ parameters: # Query/header/path params
52
+ - name: page
53
+ in: query
54
+ schema:
55
+ type: integer
56
+ security: # Per-operation security
57
+ - bearerAuth: []
58
+ responses:
59
+ '200':
60
+ description: Success
61
+ ```
62
+
63
+ Map to k6:
64
+ - **Path + method** → HTTP request
65
+ - **Parameters** → URL params, query string, headers
66
+ - **Request body** → `http.post()` body
67
+ - **Tags** → k6 groups
68
+ - **Security** → Auth headers
69
+
70
+ ### Step 4: Generate Request Bodies
71
+
72
+ Convert schema definitions to example values:
73
+
74
+ | Schema Type | Example Value |
75
+ |------------|---------------|
76
+ | `string` | `"test-string"` |
77
+ | `string (email)` | `"test@example.com"` |
78
+ | `string (date-time)` | `"2024-01-01T00:00:00Z"` |
79
+ | `string (uuid)` | `"550e8400-e29b-41d4-a716-446655440000"` |
80
+ | `integer` | `1` |
81
+ | `number` | `1.0` |
82
+ | `boolean` | `true` |
83
+ | `array` | `[<item_example>]` |
84
+ | `object` | `{<property_examples>}` |
85
+ | `enum` | First enum value |
86
+
87
+ Use `example` or `default` values from the spec when available.
88
+
89
+ See [reference/openapi-parsing.md](reference/openapi-parsing.md) for detailed parsing logic.
90
+
91
+ ### Step 5: Script Generation
92
+
93
+ Organize the generated script by API tags:
94
+
95
+ ```javascript
96
+ import http from 'k6/http';
97
+ import { check, group, sleep } from 'k6';
98
+
99
+ const BASE_URL = __ENV.BASE_URL || 'https://api.example.com';
100
+
101
+ export const options = {
102
+ scenarios: {
103
+ api_test: {
104
+ executor: 'ramping-vus',
105
+ startVUs: 0,
106
+ stages: [
107
+ { duration: '2m', target: 10 },
108
+ { duration: '5m', target: 10 },
109
+ { duration: '1m', target: 0 },
110
+ ],
111
+ },
112
+ },
113
+ thresholds: {
114
+ http_req_duration: ['p(95)<500'],
115
+ http_req_failed: ['rate<0.01'],
116
+ },
117
+ };
118
+
119
+ export function setup() {
120
+ // Auth flow based on security scheme
121
+ }
122
+
123
+ export default function (data) {
124
+ const headers = {
125
+ 'Content-Type': 'application/json',
126
+ 'Authorization': `Bearer ${data.token}`,
127
+ };
128
+
129
+ group('Users', () => {
130
+ // GET /users
131
+ const listRes = http.get(`${BASE_URL}/users?page=1&limit=10`, {
132
+ headers, tags: { name: 'ListUsers' },
133
+ });
134
+ check(listRes, { 'list users 200': (r) => r.status === 200 });
135
+
136
+ // POST /users
137
+ const createRes = http.post(`${BASE_URL}/users`,
138
+ JSON.stringify({ name: 'Test User', email: 'test@example.com' }),
139
+ { headers, tags: { name: 'CreateUser' } }
140
+ );
141
+ check(createRes, { 'create user 201': (r) => r.status === 201 });
142
+
143
+ // GET /users/{id}
144
+ const userId = createRes.json('id') || 1;
145
+ const getRes = http.get(`${BASE_URL}/users/${userId}`, {
146
+ headers, tags: { name: 'GetUser' },
147
+ });
148
+ check(getRes, { 'get user 200': (r) => r.status === 200 });
149
+ });
150
+
151
+ sleep(1);
152
+ }
153
+ ```
154
+
155
+ ### Step 6: Configure Scenarios
156
+
157
+ Based on endpoint characteristics:
158
+ - **Read-heavy endpoints** (GET list) → Higher rate
159
+ - **Write endpoints** (POST, PUT) → Lower rate
160
+ - **Admin endpoints** → Separate scenario or excluded
161
+ - **Public endpoints** → No auth scenario
162
+
163
+ ## OpenAPI Spec Quick Reference
164
+
165
+ ```yaml
166
+ openapi: '3.1.0'
167
+ info:
168
+ title: My API
169
+ version: '1.0.0'
170
+ servers:
171
+ - url: https://api.example.com/v1
172
+ security:
173
+ - bearerAuth: [] # Global security
174
+ components:
175
+ securitySchemes:
176
+ bearerAuth:
177
+ type: http
178
+ scheme: bearer
179
+ apiKey:
180
+ type: apiKey
181
+ in: header
182
+ name: X-API-Key
183
+ schemas:
184
+ User:
185
+ type: object
186
+ required: [name, email]
187
+ properties:
188
+ id:
189
+ type: integer
190
+ name:
191
+ type: string
192
+ email:
193
+ type: string
194
+ format: email
195
+ paths:
196
+ /users:
197
+ get:
198
+ tags: [Users]
199
+ parameters:
200
+ - name: page
201
+ in: query
202
+ schema: { type: integer, default: 1 }
203
+ responses:
204
+ '200':
205
+ description: User list
206
+ post:
207
+ tags: [Users]
208
+ requestBody:
209
+ required: true
210
+ content:
211
+ application/json:
212
+ schema:
213
+ $ref: '#/components/schemas/User'
214
+ responses:
215
+ '201':
216
+ description: Created
217
+ /users/{id}:
218
+ get:
219
+ tags: [Users]
220
+ parameters:
221
+ - name: id
222
+ in: path
223
+ required: true
224
+ schema: { type: integer }
225
+ responses:
226
+ '200':
227
+ description: User details
228
+ ```
229
+
230
+ ## Related Skills
231
+
232
+ - For HTTP/gRPC/WebSocket API patterns: `/k6:generating-api-load-tests`
233
+ - For scenario and threshold design: `/k6:designing-test-scenarios`
234
+ - For code-based test generation: `/k6:generating-tests-from-code`