@assertrx/dino 1.0.10 → 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 (34) hide show
  1. package/package.json +1 -1
  2. package/prompts/generate-k6-test-from-endpoint.md +68 -0
  3. package/prompts/generate-k6-test-from-openapi.md +85 -0
  4. package/prompts/setup-k6.md +130 -0
  5. package/scripts/api-server.mjs +23 -0
  6. package/skills/analyzing-test-results/SKILL.md +150 -0
  7. package/skills/analyzing-test-results/reference/bottleneck-patterns.md +130 -0
  8. package/skills/analyzing-test-results/reference/metrics.md +134 -0
  9. package/skills/analyzing-test-results/reference/visualization.md +152 -0
  10. package/skills/designing-test-scenarios/SKILL.md +247 -0
  11. package/skills/designing-test-scenarios/reference/executors.md +215 -0
  12. package/skills/designing-test-scenarios/reference/test-types.md +215 -0
  13. package/skills/designing-test-scenarios/reference/thresholds.md +208 -0
  14. package/skills/generating-api-load-tests/SKILL.md +199 -0
  15. package/skills/generating-api-load-tests/reference/data-parameterization.md +343 -0
  16. package/skills/generating-api-load-tests/reference/grpc.md +315 -0
  17. package/skills/generating-api-load-tests/reference/http.md +380 -0
  18. package/skills/generating-api-load-tests/reference/websocket.md +369 -0
  19. package/skills/generating-browser-tests/SKILL.md +269 -0
  20. package/skills/generating-browser-tests/reference/browser-api.md +251 -0
  21. package/skills/generating-browser-tests/reference/web-vitals.md +148 -0
  22. package/skills/generating-tests-from-code/SKILL.md +142 -0
  23. package/skills/generating-tests-from-code/reference/auth-analysis.md +220 -0
  24. package/skills/generating-tests-from-code/reference/framework-patterns.md +242 -0
  25. package/skills/generating-tests-from-openapi/SKILL.md +234 -0
  26. package/skills/generating-tests-from-openapi/reference/openapi-auth-mapping.md +247 -0
  27. package/skills/generating-tests-from-openapi/reference/openapi-parsing.md +194 -0
  28. package/skills/operating-k6-in-ci-cd/SKILL.md +98 -0
  29. package/skills/operating-k6-in-ci-cd/reference/ci-cd-pipelines.md +265 -0
  30. package/skills/operating-k6-in-ci-cd/reference/extensions.md +144 -0
  31. package/skills/operating-k6-in-ci-cd/reference/k6-operator.md +214 -0
  32. package/skills/testing-resilience/SKILL.md +230 -0
  33. package/skills/testing-resilience/reference/fault-injection.md +153 -0
  34. package/skills/testing-resilience/reference/resilience-patterns.md +500 -0
@@ -0,0 +1,251 @@
1
+ # k6 Browser API Reference
2
+
3
+ ## Page API
4
+
5
+ ### Navigation
6
+
7
+ ```javascript
8
+ await page.goto(url, {
9
+ waitUntil: 'networkidle', // 'domcontentloaded' | 'load' | 'networkidle'
10
+ timeout: 30000,
11
+ referer: 'https://referrer.example.com',
12
+ });
13
+
14
+ await page.waitForNavigation({
15
+ waitUntil: 'networkidle',
16
+ timeout: 30000,
17
+ });
18
+
19
+ await page.waitForLoadState('networkidle'); // 'domcontentloaded' | 'load' | 'networkidle'
20
+
21
+ await page.goBack();
22
+ await page.goForward();
23
+ await page.reload();
24
+ ```
25
+
26
+ ### Page Information
27
+
28
+ ```javascript
29
+ page.url(); // Current URL (sync)
30
+ await page.title(); // Page title
31
+ await page.content(); // Full HTML content
32
+ ```
33
+
34
+ ### Screenshots
35
+
36
+ ```javascript
37
+ await page.screenshot({
38
+ path: 'screenshot.png',
39
+ fullPage: true, // false = viewport only
40
+ type: 'png', // 'png' | 'jpeg'
41
+ quality: 80, // JPEG quality (0-100)
42
+ omitBackground: false, // Transparent background
43
+ clip: { x: 0, y: 0, width: 800, height: 600 }, // Clipping region
44
+ });
45
+ ```
46
+
47
+ ### Element Selection
48
+
49
+ ```javascript
50
+ // CSS selector
51
+ page.locator('div.container > button.primary')
52
+
53
+ // Semantic selectors (recommended)
54
+ page.getByRole('button', { name: 'Submit' })
55
+ page.getByLabel('Email address')
56
+ page.getByPlaceholder('Search...')
57
+ page.getByText('Welcome back')
58
+ page.getByTestId('login-form')
59
+ page.getByAltText('Company logo')
60
+ page.getByTitle('Settings')
61
+ ```
62
+
63
+ ### Executing JavaScript
64
+
65
+ ```javascript
66
+ const result = await page.evaluate(() => {
67
+ return {
68
+ width: document.documentElement.clientWidth,
69
+ height: document.documentElement.clientHeight,
70
+ userAgent: navigator.userAgent,
71
+ };
72
+ });
73
+
74
+ // Pass arguments
75
+ const text = await page.evaluate((selector) => {
76
+ return document.querySelector(selector).textContent;
77
+ }, '.header');
78
+ ```
79
+
80
+ ### Event Handlers
81
+
82
+ ```javascript
83
+ page.on('console', (msg) => console.log('PAGE LOG:', msg.text()));
84
+ page.on('request', (req) => console.log('REQUEST:', req.url()));
85
+ page.on('response', (res) => console.log('RESPONSE:', res.url(), res.status()));
86
+ page.on('requestfailed', (req) => console.log('FAILED:', req.url()));
87
+ ```
88
+
89
+ ### Timeouts
90
+
91
+ ```javascript
92
+ page.setDefaultTimeout(10000); // All operations (ms)
93
+ page.setDefaultNavigationTimeout(30000); // Navigation only (ms)
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Locator API
99
+
100
+ ### Interaction Methods
101
+
102
+ | Method | Description | Returns |
103
+ |--------|-------------|---------|
104
+ | `click([options])` | Click element | `Promise<void>` |
105
+ | `dblclick([options])` | Double-click | `Promise<void>` |
106
+ | `fill(value, [options])` | Fill input/textarea | `Promise<void>` |
107
+ | `type(text, [options])` | Type with key events | `Promise<void>` |
108
+ | `press(key, [options])` | Press key combo | `Promise<void>` |
109
+ | `selectOption(values, [options])` | Select dropdown | `Promise<string[]>` |
110
+ | `check([options])` | Check checkbox | `Promise<void>` |
111
+ | `uncheck([options])` | Uncheck checkbox | `Promise<void>` |
112
+ | `hover([options])` | Hover over element | `Promise<void>` |
113
+ | `tap([options])` | Touch tap | `Promise<void>` |
114
+
115
+ Click options: `button` ('left'|'middle'|'right'), `clickCount`, `delay`, `force`, `modifiers` (['Alt','Control','Meta','Shift']), `timeout`
116
+
117
+ ### State Queries
118
+
119
+ | Method | Returns | Description |
120
+ |--------|---------|-------------|
121
+ | `isVisible()` | `Promise<bool>` | Element is visible |
122
+ | `isHidden()` | `Promise<bool>` | Element is hidden |
123
+ | `isEnabled([options])` | `Promise<bool>` | Element is enabled |
124
+ | `isDisabled([options])` | `Promise<bool>` | Element is disabled |
125
+ | `isEditable([options])` | `Promise<bool>` | Element is editable |
126
+ | `isChecked([options])` | `Promise<bool>` | Checkbox/radio is checked |
127
+
128
+ ### Content Queries
129
+
130
+ | Method | Returns | Description |
131
+ |--------|---------|-------------|
132
+ | `textContent([options])` | `Promise<string\|null>` | element.textContent |
133
+ | `innerText([options])` | `Promise<string>` | element.innerText |
134
+ | `innerHTML([options])` | `Promise<string>` | element.innerHTML |
135
+ | `inputValue([options])` | `Promise<string>` | Input value |
136
+ | `getAttribute(name, [options])` | `Promise<string\|null>` | Attribute value |
137
+
138
+ ### Collection Methods
139
+
140
+ ```javascript
141
+ await locator.count(); // Number of matching elements
142
+ locator.first(); // First element (Locator)
143
+ locator.last(); // Last element (Locator)
144
+ locator.nth(2); // 3rd element, zero-indexed (Locator)
145
+ await locator.all(); // All elements (Locator[])
146
+ ```
147
+
148
+ ### Filtering
149
+
150
+ ```javascript
151
+ locator.filter({ hasText: 'Active' }); // Filter by text
152
+ locator.filter({ hasNotText: 'Disabled' }); // Exclude by text
153
+ ```
154
+
155
+ ### Waiting
156
+
157
+ ```javascript
158
+ await locator.waitFor({
159
+ state: 'visible', // 'attached' | 'visible' | 'hidden' | 'stable'
160
+ timeout: 5000,
161
+ });
162
+ ```
163
+
164
+ ---
165
+
166
+ ## BrowserContext API
167
+
168
+ ### Creating Contexts
169
+
170
+ ```javascript
171
+ const context = await browser.newContext();
172
+ const page = await context.newPage();
173
+
174
+ // Or directly
175
+ const page = await browser.newPage(); // Uses default context
176
+ ```
177
+
178
+ ### Cookie Management
179
+
180
+ ```javascript
181
+ // Add cookies
182
+ await context.addCookies([{
183
+ name: 'session',
184
+ value: 'abc123',
185
+ domain: '.example.com',
186
+ path: '/',
187
+ secure: true,
188
+ httpOnly: true,
189
+ sameSite: 'Lax',
190
+ expires: Date.now() / 1000 + 3600,
191
+ }]);
192
+
193
+ // Get cookies
194
+ const cookies = await context.cookies();
195
+ const siteCookies = await context.cookies(['https://example.com']);
196
+
197
+ // Clear cookies
198
+ await context.clearCookies();
199
+ ```
200
+
201
+ ### Permissions and Geolocation
202
+
203
+ ```javascript
204
+ await context.grantPermissions(['geolocation']);
205
+ await context.setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
206
+ await context.clearPermissions();
207
+ ```
208
+
209
+ ### Offline Mode
210
+
211
+ ```javascript
212
+ await context.setOffline(true); // Simulate offline
213
+ await context.setOffline(false); // Back online
214
+ ```
215
+
216
+ ### Init Scripts
217
+
218
+ ```javascript
219
+ await context.addInitScript('window.__TEST_MODE__ = true;');
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Keyboard API
225
+
226
+ ```javascript
227
+ await page.keyboard.type('Hello World', { delay: 100 });
228
+ await page.keyboard.press('Enter');
229
+ await page.keyboard.press('Control+a');
230
+ await page.keyboard.down('Shift');
231
+ await page.keyboard.press('ArrowDown');
232
+ await page.keyboard.up('Shift');
233
+ await page.keyboard.insertText('Pasted text');
234
+ ```
235
+
236
+ ## Mouse API
237
+
238
+ ```javascript
239
+ await page.mouse.click(100, 200);
240
+ await page.mouse.dblclick(100, 200);
241
+ await page.mouse.move(100, 200, { steps: 10 }); // Smooth move
242
+ await page.mouse.down();
243
+ await page.mouse.move(300, 400);
244
+ await page.mouse.up(); // Drag effect
245
+ ```
246
+
247
+ ## Touchscreen API
248
+
249
+ ```javascript
250
+ await page.touchscreen.tap(100, 200);
251
+ ```
@@ -0,0 +1,148 @@
1
+ # k6 Browser Web Vitals Reference
2
+
3
+ ## Core Web Vitals
4
+
5
+ | Metric | Full Name | What It Measures | Good | Needs Improvement | Poor |
6
+ |--------|-----------|------------------|------|-------------------|------|
7
+ | LCP | Largest Contentful Paint | Largest visible content render time | < 2.5s | 2.5s - 4s | > 4s |
8
+ | FCP | First Contentful Paint | First content render time | < 1.8s | 1.8s - 3s | > 3s |
9
+ | CLS | Cumulative Layout Shift | Visual stability score | < 0.1 | 0.1 - 0.25 | > 0.25 |
10
+ | INP | Interaction to Next Paint | Input responsiveness | < 200ms | 200ms - 500ms | > 500ms |
11
+ | TTFB | Time to First Byte | Server response time | < 600ms | 600ms - 1.5s | > 1.5s |
12
+
13
+ ## k6 Metric Names
14
+
15
+ | k6 Metric | Type | Description |
16
+ |-----------|------|-------------|
17
+ | `browser_web_vital_lcp` | Trend | Largest Contentful Paint timing |
18
+ | `browser_web_vital_fcp` | Trend | First Contentful Paint timing |
19
+ | `browser_web_vital_cls` | Trend | Cumulative Layout Shift score |
20
+ | `browser_web_vital_inp` | Trend | Interaction to Next Paint timing |
21
+ | `browser_web_vital_ttfb` | Trend | Time to First Byte timing |
22
+ | `browser_web_vital_fid` | Trend | First Input Delay (deprecated, use INP) |
23
+
24
+ ## Additional Browser Metrics
25
+
26
+ | k6 Metric | Type | Description |
27
+ |-----------|------|-------------|
28
+ | `browser_data_received` | Counter | Data downloaded (bytes) |
29
+ | `browser_data_sent` | Counter | Data uploaded (bytes) |
30
+ | `browser_http_req_duration` | Trend | Browser HTTP request duration |
31
+ | `browser_http_req_failed` | Rate | Browser failed request rate |
32
+
33
+ ## Threshold Configuration
34
+
35
+ ### Recommended Thresholds
36
+
37
+ ```javascript
38
+ export const options = {
39
+ thresholds: {
40
+ // Core Web Vitals (Good targets)
41
+ 'browser_web_vital_lcp': ['p(90)<2500'], // 90% of pages LCP < 2.5s
42
+ 'browser_web_vital_fcp': ['p(90)<1800'], // 90% of pages FCP < 1.8s
43
+ 'browser_web_vital_cls': ['p(95)<0.1'], // 95% of pages CLS < 0.1
44
+ 'browser_web_vital_inp': ['p(90)<200'], // 90% of interactions INP < 200ms
45
+ 'browser_web_vital_ttfb': ['p(90)<600'], // 90% of pages TTFB < 600ms
46
+
47
+ // Browser network metrics
48
+ 'browser_http_req_failed': ['rate<0.01'], // Browser request error rate < 1%
49
+ },
50
+ };
51
+ ```
52
+
53
+ ### Strict Thresholds (High-Performance)
54
+
55
+ ```javascript
56
+ thresholds: {
57
+ 'browser_web_vital_lcp': ['p(90)<1500', 'p(99)<2500'],
58
+ 'browser_web_vital_fcp': ['p(90)<1000', 'p(99)<1800'],
59
+ 'browser_web_vital_cls': ['p(99)<0.05'],
60
+ 'browser_web_vital_inp': ['p(90)<100', 'p(99)<200'],
61
+ 'browser_web_vital_ttfb': ['p(90)<300', 'p(99)<600'],
62
+ }
63
+ ```
64
+
65
+ ## Custom Performance Measurement
66
+
67
+ ### Using Performance API
68
+
69
+ ```javascript
70
+ export default async function () {
71
+ const page = await browser.newPage();
72
+ try {
73
+ await page.goto('https://app.example.com');
74
+
75
+ // Mark start of user action
76
+ await page.evaluate(() => window.performance.mark('action-start'));
77
+
78
+ // Perform action
79
+ await page.getByRole('button', { name: 'Load Data' }).click();
80
+ await page.waitForLoadState('networkidle');
81
+
82
+ // Mark end and measure
83
+ await page.evaluate(() => {
84
+ window.performance.mark('action-end');
85
+ window.performance.measure('action-time', 'action-start', 'action-end');
86
+ });
87
+
88
+ const duration = await page.evaluate(() =>
89
+ window.performance.getEntriesByName('action-time')[0].duration
90
+ );
91
+
92
+ console.log(`Action took ${duration}ms`);
93
+ } finally {
94
+ await page.close();
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### Using k6 Custom Metrics
100
+
101
+ ```javascript
102
+ import { browser } from 'k6/browser';
103
+ import { Trend } from 'k6/metrics';
104
+
105
+ const pageLoadTime = new Trend('page_load_time');
106
+ const loginDuration = new Trend('login_duration');
107
+
108
+ export default async function () {
109
+ const page = await browser.newPage();
110
+ try {
111
+ const start = Date.now();
112
+ await page.goto('https://app.example.com');
113
+ await page.waitForLoadState('networkidle');
114
+ pageLoadTime.add(Date.now() - start);
115
+
116
+ const loginStart = Date.now();
117
+ await page.getByLabel('Email').fill('user@test.com');
118
+ await page.getByLabel('Password').fill('pass123');
119
+ await page.getByRole('button', { name: 'Login' }).click();
120
+ await page.waitForNavigation();
121
+ loginDuration.add(Date.now() - loginStart);
122
+ } finally {
123
+ await page.close();
124
+ }
125
+ }
126
+ ```
127
+
128
+ ## Interpreting Results
129
+
130
+ ### LCP (Largest Contentful Paint)
131
+ - **What affects it:** Large images, web fonts, CSS background images, block-level text
132
+ - **Optimization:** Optimize images, preload critical resources, use CDN, server-side render
133
+
134
+ ### FCP (First Contentful Paint)
135
+ - **What affects it:** Server response time, render-blocking resources, CSS complexity
136
+ - **Optimization:** Reduce server response time, eliminate render-blocking resources, inline critical CSS
137
+
138
+ ### CLS (Cumulative Layout Shift)
139
+ - **What affects it:** Images without dimensions, dynamic content injection, web font loading
140
+ - **Optimization:** Set image dimensions, reserve space for dynamic content, use font-display
141
+
142
+ ### INP (Interaction to Next Paint)
143
+ - **What affects it:** Long JavaScript tasks, heavy DOM manipulation, main thread blocking
144
+ - **Optimization:** Break long tasks, use web workers, optimize event handlers
145
+
146
+ ### TTFB (Time to First Byte)
147
+ - **What affects it:** Server processing time, network latency, TLS negotiation
148
+ - **Optimization:** Server caching, CDN, optimize database queries, HTTP/2
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: generating-tests-from-code
3
+ description: Use when analyzing an existing API codebase to auto-generate k6 load test scripts. Use when the user wants to create k6 tests from source code, route definitions, controllers, or middleware in frameworks like Express, NestJS, Spring Boot, FastAPI, or Django.
4
+ context: fork
5
+ agent: Explore
6
+ ---
7
+
8
+ # Generating k6 Tests from Code
9
+
10
+ Analyze an existing API codebase to automatically generate k6 load test scripts. Detects endpoints, authentication patterns, request/response shapes, and generates comprehensive test suites.
11
+
12
+ ## Workflow
13
+
14
+ Follow this workflow strictly in order:
15
+
16
+ ### Step 1: Security & Authentication Analysis (Prerequisite)
17
+
18
+ **Before analyzing routes, always detect the authentication mechanism first.**
19
+
20
+ 1. **Scan for auth middleware/decorators:**
21
+ - Look for authentication middleware, guards, decorators, or filters
22
+ - Identify the auth type: JWT, session, OAuth2, API Key, Basic Auth
23
+ - Determine which endpoints are protected vs public
24
+
25
+ 2. **Extract the authentication flow:**
26
+ - Find login/token endpoints
27
+ - Identify how tokens are obtained, refreshed, and passed
28
+ - Check for CSRF protection patterns
29
+
30
+ 3. **Generate k6 auth setup:**
31
+ - Create `setup()` function for authentication
32
+ - Configure token/session handling for `default()` function
33
+ - Handle token refresh if needed
34
+
35
+ See [reference/auth-analysis.md](reference/auth-analysis.md) for auth detection patterns per framework.
36
+
37
+ ### Step 2: Route & Controller Analysis
38
+
39
+ 1. **Scan route definitions:**
40
+ - Map all endpoints with HTTP methods
41
+ - Extract URL parameters, query parameters, request body schemas
42
+ - Identify middleware chain per route
43
+
44
+ 2. **Extract request/response shapes:**
45
+ - Analyze request body types/validation
46
+ - Identify required vs optional fields
47
+ - Note content types (JSON, form-data, multipart)
48
+
49
+ 3. **Categorize endpoints:**
50
+ - Group by resource/domain (users, products, orders, etc.)
51
+ - Identify CRUD patterns
52
+ - Note rate-limited or special endpoints
53
+
54
+ See [reference/framework-patterns.md](reference/framework-patterns.md) for framework-specific analysis patterns.
55
+
56
+ ### Step 3: Scenario Design
57
+
58
+ 1. **Map endpoints to test scenarios:**
59
+ - High-traffic endpoints → higher iteration rate
60
+ - CRUD sequences → grouped in order (create → read → update → delete)
61
+ - Background/admin endpoints → lower priority
62
+
63
+ 2. **Design realistic user flows:**
64
+ - Login → browse → select → purchase
65
+ - Weighted distribution matching production traffic
66
+
67
+ ### Step 4: Script Generation
68
+
69
+ Generate the k6 test script with:
70
+ - `setup()` for authentication
71
+ - `default()` with grouped endpoint calls
72
+ - Checks for each response
73
+ - Appropriate thresholds
74
+ - Data parameterization where needed
75
+ - Tags for per-endpoint metrics
76
+
77
+ ## Supported Frameworks
78
+
79
+ ### Node.js
80
+ - **Express** — `app.get()`, `router.get()`, route files
81
+ - **Fastify** — `fastify.get()`, route plugins, schemas
82
+ - **NestJS** — `@Controller()`, `@Get()`, `@Post()` decorators, Guards
83
+
84
+ ### Java
85
+ - **Spring Boot** — `@RestController`, `@GetMapping`, `@PostMapping`, `@RequestMapping`, Security config
86
+
87
+ ### Python
88
+ - **FastAPI** — `@app.get()`, `@router.get()`, Pydantic models, Depends()
89
+ - **Django REST Framework** — `ViewSet`, `@api_view`, `urlpatterns`, permissions
90
+
91
+ ## Output Structure
92
+
93
+ The generated script should follow this structure:
94
+
95
+ ```javascript
96
+ import http from 'k6/http';
97
+ import { check, group, sleep } from 'k6';
98
+ import { SharedArray } from 'k6/data';
99
+
100
+ // Test data (if applicable)
101
+ const testData = new SharedArray('data', function () {
102
+ return JSON.parse(open('./test-data.json'));
103
+ });
104
+
105
+ export const options = {
106
+ scenarios: { /* ... */ },
107
+ thresholds: { /* ... */ },
108
+ };
109
+
110
+ // Authentication setup
111
+ export function setup() {
112
+ // Login and return auth token/session
113
+ }
114
+
115
+ // Main test function
116
+ export default function (data) {
117
+ const headers = {
118
+ 'Content-Type': 'application/json',
119
+ 'Authorization': `Bearer ${data.token}`,
120
+ };
121
+
122
+ group('Resource A', () => {
123
+ // CRUD operations for Resource A
124
+ });
125
+
126
+ group('Resource B', () => {
127
+ // CRUD operations for Resource B
128
+ });
129
+
130
+ sleep(1);
131
+ }
132
+
133
+ export function teardown(data) {
134
+ // Cleanup if needed
135
+ }
136
+ ```
137
+
138
+ ## Related Skills
139
+
140
+ - For HTTP/gRPC/WebSocket API patterns: `/k6:generating-api-load-tests`
141
+ - For scenario and threshold design: `/k6:designing-test-scenarios`
142
+ - For OpenAPI spec-based generation: `/k6:generating-tests-from-openapi`