@kosuke-ai/cli 0.0.12 → 0.0.14

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 (55) hide show
  1. package/dist/index.d.ts +14 -6
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +148 -6
  4. package/dist/index.js.map +1 -1
  5. package/dist/kosuke/commands/build.d.ts +22 -0
  6. package/dist/kosuke/commands/build.d.ts.map +1 -0
  7. package/dist/kosuke/commands/build.js +135 -0
  8. package/dist/kosuke/commands/build.js.map +1 -0
  9. package/dist/kosuke/commands/review.d.ts +21 -0
  10. package/dist/kosuke/commands/review.d.ts.map +1 -0
  11. package/dist/kosuke/commands/review.js +185 -0
  12. package/dist/kosuke/commands/review.js.map +1 -0
  13. package/dist/kosuke/commands/ship.d.ts +23 -0
  14. package/dist/kosuke/commands/ship.d.ts.map +1 -0
  15. package/dist/kosuke/commands/ship.js +419 -0
  16. package/dist/kosuke/commands/ship.js.map +1 -0
  17. package/dist/kosuke/commands/test.d.ts +27 -0
  18. package/dist/kosuke/commands/test.d.ts.map +1 -0
  19. package/dist/kosuke/commands/test.js +338 -0
  20. package/dist/kosuke/commands/test.js.map +1 -0
  21. package/dist/kosuke/types.d.ts +82 -2
  22. package/dist/kosuke/types.d.ts.map +1 -1
  23. package/dist/kosuke/utils/error-analyzer.d.ts +32 -0
  24. package/dist/kosuke/utils/error-analyzer.d.ts.map +1 -0
  25. package/dist/kosuke/utils/error-analyzer.js +129 -0
  26. package/dist/kosuke/utils/error-analyzer.js.map +1 -0
  27. package/dist/kosuke/utils/git.d.ts +12 -0
  28. package/dist/kosuke/utils/git.d.ts.map +1 -1
  29. package/dist/kosuke/utils/git.js +39 -0
  30. package/dist/kosuke/utils/git.js.map +1 -1
  31. package/dist/kosuke/utils/log-collector.d.ts +81 -0
  32. package/dist/kosuke/utils/log-collector.d.ts.map +1 -0
  33. package/dist/kosuke/utils/log-collector.js +226 -0
  34. package/dist/kosuke/utils/log-collector.js.map +1 -0
  35. package/dist/kosuke/utils/playwright-agent.d.ts +39 -0
  36. package/dist/kosuke/utils/playwright-agent.d.ts.map +1 -0
  37. package/dist/kosuke/utils/playwright-agent.js +245 -0
  38. package/dist/kosuke/utils/playwright-agent.js.map +1 -0
  39. package/dist/kosuke/utils/test-generator.d.ts +22 -0
  40. package/dist/kosuke/utils/test-generator.d.ts.map +1 -0
  41. package/dist/kosuke/utils/test-generator.js +174 -0
  42. package/dist/kosuke/utils/test-generator.js.map +1 -0
  43. package/dist/kosuke/utils/validator.d.ts +11 -0
  44. package/dist/kosuke/utils/validator.d.ts.map +1 -1
  45. package/dist/kosuke/utils/validator.js +100 -0
  46. package/dist/kosuke/utils/validator.js.map +1 -1
  47. package/dist/kosuke/utils/visual-tester.d.ts +71 -0
  48. package/dist/kosuke/utils/visual-tester.d.ts.map +1 -0
  49. package/dist/kosuke/utils/visual-tester.js +202 -0
  50. package/dist/kosuke/utils/visual-tester.js.map +1 -0
  51. package/dist/lib.d.ts +6 -2
  52. package/dist/lib.d.ts.map +1 -1
  53. package/dist/lib.js +5 -1
  54. package/dist/lib.js.map +1 -1
  55. package/package.json +6 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-agent.js","sourceRoot":"","sources":["../../../kosuke/utils/playwright-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Test Generator - AI-powered Playwright test generation
3
+ *
4
+ * Uses Claude to generate Playwright tests from ticket descriptions
5
+ */
6
+ import type { Ticket } from '../types.js';
7
+ export interface GeneratedTest {
8
+ filePath: string;
9
+ content: string;
10
+ tokensUsed: {
11
+ input: number;
12
+ output: number;
13
+ cacheCreation: number;
14
+ cacheRead: number;
15
+ };
16
+ cost: number;
17
+ }
18
+ /**
19
+ * Generate Playwright test from ticket description
20
+ */
21
+ export declare function generateTest(ticket: Ticket, baseUrl: string, cwd?: string): Promise<GeneratedTest>;
22
+ //# sourceMappingURL=test-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-generator.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/test-generator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAkDxB"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Test Generator - AI-powered Playwright test generation
3
+ *
4
+ * Uses Claude to generate Playwright tests from ticket descriptions
5
+ */
6
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { runAgent } from './claude-agent.js';
9
+ /**
10
+ * Generate Playwright test from ticket description
11
+ */
12
+ export async function generateTest(ticket, baseUrl, cwd = process.cwd()) {
13
+ const testDir = join(cwd, '.kosuke', 'tests');
14
+ const testFilePath = join(testDir, `${ticket.id}.spec.ts`);
15
+ // Ensure test directory exists
16
+ if (!existsSync(testDir)) {
17
+ mkdirSync(testDir, { recursive: true });
18
+ }
19
+ // Check if test already exists
20
+ if (existsSync(testFilePath)) {
21
+ console.log(` āœ… Test already exists: ${testFilePath}`);
22
+ return {
23
+ filePath: testFilePath,
24
+ content: '',
25
+ tokensUsed: {
26
+ input: 0,
27
+ output: 0,
28
+ cacheCreation: 0,
29
+ cacheRead: 0,
30
+ },
31
+ cost: 0,
32
+ };
33
+ }
34
+ console.log(` šŸ¤– Generating test using Claude...`);
35
+ const systemPrompt = buildTestGenerationPrompt(ticket, baseUrl);
36
+ const result = await runAgent(`Generate Playwright test for ticket ${ticket.id}`, {
37
+ systemPrompt,
38
+ cwd,
39
+ maxTurns: 15,
40
+ verbosity: 'minimal',
41
+ });
42
+ // Extract test code from response
43
+ const testContent = extractTestCode(result.response, ticket, baseUrl);
44
+ // Save test file
45
+ writeFileSync(testFilePath, testContent, 'utf-8');
46
+ console.log(` āœ… Test generated: ${testFilePath}`);
47
+ return {
48
+ filePath: testFilePath,
49
+ content: testContent,
50
+ tokensUsed: result.tokensUsed,
51
+ cost: result.cost,
52
+ };
53
+ }
54
+ /**
55
+ * Build system prompt for test generation
56
+ */
57
+ function buildTestGenerationPrompt(ticket, baseUrl) {
58
+ return `You are an expert QA engineer creating Playwright end-to-end tests.
59
+
60
+ **Your Task:**
61
+ Generate a comprehensive Playwright test file for the following ticket.
62
+
63
+ **Ticket Information:**
64
+ - ID: ${ticket.id}
65
+ - Title: ${ticket.title}
66
+ - Description:
67
+ ${ticket.description}
68
+
69
+ **Application URL:** ${baseUrl}
70
+
71
+ **Test Requirements:**
72
+ 1. Create a complete Playwright test file in TypeScript
73
+ 2. Include multiple test cases covering:
74
+ - Happy path (main functionality)
75
+ - Edge cases (validation, errors)
76
+ - Visual regression test (one screenshot)
77
+ 3. Use proper Playwright selectors (prefer getByRole, getByLabel, getByText)
78
+ 4. Include proper assertions with expect()
79
+ 5. Add comments explaining what each test does
80
+ 6. Follow Playwright best practices
81
+
82
+ **Test Structure:**
83
+ \`\`\`typescript
84
+ import { test, expect } from '@playwright/test';
85
+
86
+ test.describe('${ticket.id}: ${ticket.title}', () => {
87
+ test.beforeEach(async ({ page }) => {
88
+ // Navigate to the relevant page
89
+ await page.goto('${baseUrl}/...');
90
+ });
91
+
92
+ test('should [describe main functionality]', async ({ page }) => {
93
+ // Test implementation
94
+ });
95
+
96
+ test('should handle [edge case]', async ({ page }) => {
97
+ // Test implementation
98
+ });
99
+
100
+ test('visual regression: [page/component] renders correctly', async ({ page }) => {
101
+ // Wait for page to be stable
102
+ await page.waitForLoadState('networkidle');
103
+
104
+ // Take screenshot
105
+ const screenshot = await page.screenshot({ fullPage: true });
106
+
107
+ // Compare with baseline (handled by visual tester)
108
+ expect(screenshot).toBeDefined();
109
+ });
110
+ });
111
+ \`\`\`
112
+
113
+ **Critical Instructions:**
114
+ 1. Analyze the ticket description to understand what features to test
115
+ 2. Determine the correct URL paths based on the feature
116
+ 3. Generate realistic test data (emails, names, etc.)
117
+ 4. Include proper waits (waitForLoadState, waitForSelector)
118
+ 5. Test both success and failure scenarios
119
+ 6. Add one visual regression test at the end
120
+ 7. Output ONLY the test code - no explanations outside the code
121
+
122
+ Generate the complete test file now:`;
123
+ }
124
+ /**
125
+ * Extract test code from Claude's response
126
+ */
127
+ function extractTestCode(response, ticket, baseUrl) {
128
+ // Look for code blocks in the response
129
+ const codeBlockMatch = response.match(/```(?:typescript|ts)?\n([\s\S]+?)\n```/);
130
+ if (codeBlockMatch) {
131
+ return codeBlockMatch[1].trim();
132
+ }
133
+ // If no code block found, try to use the whole response
134
+ // or generate a basic template
135
+ if (response.includes('import') && response.includes('test(')) {
136
+ return response.trim();
137
+ }
138
+ // Fallback: generate basic template
139
+ console.log(' āš ļø Could not extract test code, generating basic template');
140
+ return generateBasicTemplate(ticket, baseUrl);
141
+ }
142
+ /**
143
+ * Generate a basic test template as fallback
144
+ */
145
+ function generateBasicTemplate(ticket, baseUrl) {
146
+ return `import { test, expect } from '@playwright/test';
147
+
148
+ test.describe('${ticket.id}: ${ticket.title}', () => {
149
+ test.beforeEach(async ({ page }) => {
150
+ // TODO: Update this URL to the correct path for the feature
151
+ await page.goto('${baseUrl}');
152
+ });
153
+
154
+ test('should load the page', async ({ page }) => {
155
+ // TODO: Add assertions to verify the page loaded correctly
156
+ await expect(page.locator('body')).toBeVisible();
157
+ });
158
+
159
+ test('should interact with main feature', async ({ page }) => {
160
+ // TODO: Add test steps for the main functionality
161
+ // Example:
162
+ // await page.getByRole('button', { name: 'Submit' }).click();
163
+ // await expect(page.getByText('Success')).toBeVisible();
164
+ });
165
+
166
+ test('visual regression: page renders correctly', async ({ page }) => {
167
+ await page.waitForLoadState('networkidle');
168
+ const screenshot = await page.screenshot({ fullPage: true });
169
+ expect(screenshot).toBeDefined();
170
+ });
171
+ });
172
+ `;
173
+ }
174
+ //# sourceMappingURL=test-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-generator.js","sourceRoot":"","sources":["../../../kosuke/utils/test-generator.ts"],"names":[],"mappings":"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"}
@@ -30,5 +30,16 @@ export declare function runLint(): Promise<ValidationResult>;
30
30
  * Run TypeScript type checking using detected package manager
31
31
  */
32
32
  export declare function runTypecheck(): Promise<ValidationResult>;
33
+ /**
34
+ * Run tests using package.json test script
35
+ */
36
+ export declare function runTests(): Promise<ValidationResult>;
37
+ /**
38
+ * Run comprehensive linting and fixing
39
+ */
40
+ export declare function runComprehensiveLinting(): Promise<{
41
+ success: boolean;
42
+ fixCount: number;
43
+ }>;
33
44
  export {};
34
45
  //# sourceMappingURL=validator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAQxE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAsB,GAAG,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAcjG;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAqC3D;AAED;;GAEG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAwCzD;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAqC9D"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAQxE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAsB,GAAG,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAcjG;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAqC3D;AAED;;GAEG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAwCzD;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAqC9D;AAED;;GAEG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC,CA4B1D;AAOD;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmF/F"}
@@ -149,4 +149,104 @@ export async function runTypecheck() {
149
149
  };
150
150
  }
151
151
  }
152
+ /**
153
+ * Run tests using package.json test script
154
+ */
155
+ export async function runTests() {
156
+ const cwd = process.cwd();
157
+ const scripts = readPackageJsonScripts(cwd);
158
+ if (!scripts || !scripts.test) {
159
+ return {
160
+ success: true,
161
+ warning: 'āš ļø No test script found in package.json. Skipping tests.',
162
+ };
163
+ }
164
+ const packageManager = detectPackageManager(cwd);
165
+ const command = `${packageManager} run test`;
166
+ try {
167
+ const output = execSync(command, {
168
+ cwd,
169
+ encoding: 'utf-8',
170
+ stdio: 'pipe',
171
+ });
172
+ return { success: true, output };
173
+ }
174
+ catch (error) {
175
+ const err = error;
176
+ return {
177
+ success: false,
178
+ error: `$ ${command}\n\n${err.stdout || err.stderr || err.message}`,
179
+ };
180
+ }
181
+ }
182
+ /**
183
+ * Run comprehensive linting and fixing
184
+ */
185
+ export async function runComprehensiveLinting() {
186
+ console.log('\nšŸ” Running comprehensive code quality checks...\n');
187
+ const validationSteps = [
188
+ { name: 'šŸŽØ Format', run: runFormat },
189
+ { name: 'šŸ” Lint', run: runLint },
190
+ { name: 'šŸ”Ž TypeCheck', run: runTypecheck },
191
+ { name: '🧪 Tests', run: runTests },
192
+ ];
193
+ let totalFixCount = 0;
194
+ // Run each validation step
195
+ for (const step of validationSteps) {
196
+ console.log(`\n${'='.repeat(60)}`);
197
+ console.log(`Running: ${step.name}`);
198
+ console.log(`${'='.repeat(60)}\n`);
199
+ let result = await step.run();
200
+ // Handle warnings (non-blocking)
201
+ if (result.warning) {
202
+ console.log(result.warning);
203
+ console.log(`āœ… ${step.name} - SKIPPED\n`);
204
+ continue;
205
+ }
206
+ // Handle success
207
+ if (result.success) {
208
+ console.log(`āœ… ${step.name} - PASSED\n`);
209
+ continue;
210
+ }
211
+ // Handle errors - attempt to fix
212
+ console.log(`āŒ ${step.name} - FAILED:\n`);
213
+ console.log(result.error);
214
+ // Attempt to fix errors with Claude (max 3 attempts per step)
215
+ let attemptCount = 0;
216
+ const maxAttempts = 3;
217
+ while (!result.success && attemptCount < maxAttempts) {
218
+ attemptCount++;
219
+ console.log(`\n${'='.repeat(60)}`);
220
+ console.log(`šŸ”„ ${step.name} Fix Attempt ${attemptCount}/${maxAttempts}`);
221
+ console.log(`${'='.repeat(60)}`);
222
+ const { fixCodeQualityErrors } = await import('../commands/lint.js');
223
+ const fixApplied = await fixCodeQualityErrors(step.name, result.error || '');
224
+ if (!fixApplied) {
225
+ console.log(`\nāš ļø No fixes were applied by Claude for ${step.name}`);
226
+ break;
227
+ }
228
+ totalFixCount++;
229
+ // Verify fixes by running validation again
230
+ console.log(`\nšŸ” Verifying ${step.name} fixes...\n`);
231
+ result = await step.run();
232
+ if (result.success) {
233
+ console.log(`āœ… ${step.name} - All errors fixed!\n`);
234
+ break;
235
+ }
236
+ else {
237
+ const errorLines = result.error?.split('\n').length || 0;
238
+ console.log(`\nāš ļø Some ${step.name} errors remain (${errorLines} lines):`);
239
+ console.log(result.error);
240
+ }
241
+ }
242
+ // Check if step still has errors after attempts
243
+ if (!result.success) {
244
+ throw new Error(`${step.name} errors remain after ${maxAttempts} attempts. Cannot proceed.`);
245
+ }
246
+ }
247
+ console.log('\n' + '='.repeat(60));
248
+ console.log('āœ… All validation steps passed!');
249
+ console.log('='.repeat(60));
250
+ return { success: true, fixCount: totalFixCount };
251
+ }
152
252
  //# sourceMappingURL=validator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../kosuke/utils/validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAa5B;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC9D,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IAC3D,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IACtD,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAE7D,uCAAuC;IACvC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAChE,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAElD,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,WAAW,GAAgB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QACpF,OAAO,WAAW,CAAC,OAAO,IAAI,IAAI,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,qCAAqC,KAAK,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,kDAAkD;SAC1D,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,mIAAmI;SAC7I,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,GAAG,cAAc,aAAa,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE;YAC/B,GAAG;YACH,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAA+D,CAAC;QAC5E,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;QAEnE,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,OAAO,OAAO,YAAY,EAAE;SACzC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,kDAAkD;SAC1D,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,2JAA2J;SACrK,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAEjD,2CAA2C;IAC3C,2DAA2D;IAC3D,MAAM,OAAO,GAAG,GAAG,cAAc,oBAAoB,CAAC;IAEtD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE;YAC/B,GAAG;YACH,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAA+D,CAAC;QAC5E,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;QAEnE,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,OAAO,OAAO,YAAY,EAAE;SACzC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAE5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,kDAAkD;SAC1D,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,sIAAsI;SAChJ,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,GAAG,cAAc,gBAAgB,CAAC;IAElD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE;YAC/B,GAAG;YACH,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAA+D,CAAC;QAC5E,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;QAEnE,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,OAAO,OAAO,YAAY,EAAE;SACzC,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../kosuke/utils/validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Visual Tester - Visual regression testing with screenshot comparison
3
+ *
4
+ * Inspired by Subito.it's approach:
5
+ * - Capture screenshots of pages
6
+ * - Compare against baseline images
7
+ * - Detect pixel differences above threshold
8
+ * - Hide dynamic content (ads, analytics)
9
+ */
10
+ import type { Page } from '@playwright/test';
11
+ export interface VisualDiff {
12
+ testName: string;
13
+ diffPixels: number;
14
+ diffPercentage: number;
15
+ threshold: number;
16
+ passed: boolean;
17
+ baselinePath: string;
18
+ currentPath: string;
19
+ diffPath: string;
20
+ }
21
+ export interface VisualTestOptions {
22
+ ticketId: string;
23
+ testName: string;
24
+ threshold?: number;
25
+ updateBaseline?: boolean;
26
+ }
27
+ /**
28
+ * Visual Tester class for screenshot comparison
29
+ */
30
+ export declare class VisualTester {
31
+ private cwd;
32
+ private diffs;
33
+ constructor(cwd?: string);
34
+ /**
35
+ * Hide dynamic content that shouldn't be tested
36
+ */
37
+ hideDynamicContent(page: Page): Promise<void>;
38
+ /**
39
+ * Take a screenshot and compare with baseline
40
+ */
41
+ captureAndCompare(page: Page, options: VisualTestOptions): Promise<VisualDiff>;
42
+ /**
43
+ * Compare two images and generate diff
44
+ */
45
+ private compareImages;
46
+ /**
47
+ * Get all visual diffs
48
+ */
49
+ getDiffs(): VisualDiff[];
50
+ /**
51
+ * Get failed visual diffs
52
+ */
53
+ getFailedDiffs(): VisualDiff[];
54
+ /**
55
+ * Check if there are any visual regressions
56
+ */
57
+ hasRegressions(): boolean;
58
+ /**
59
+ * Format visual diff report
60
+ */
61
+ formatReport(): string;
62
+ /**
63
+ * Clear all diffs
64
+ */
65
+ clear(): void;
66
+ /**
67
+ * Ensure directory exists
68
+ */
69
+ private ensureDir;
70
+ }
71
+ //# sourceMappingURL=visual-tester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-tester.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/visual-tester.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI7C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,KAAK,CAAoB;gBAErB,GAAG,GAAE,MAAsB;IAIvC;;OAEG;IACG,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnD;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAuDpF;;OAEG;IACH,OAAO,CAAC,aAAa;IAwErB;;OAEG;IACH,QAAQ,IAAI,UAAU,EAAE;IAIxB;;OAEG;IACH,cAAc,IAAI,UAAU,EAAE;IAI9B;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB;;OAEG;IACH,YAAY,IAAI,MAAM;IA2BtB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,CAAC,SAAS;CAKlB"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Visual Tester - Visual regression testing with screenshot comparison
3
+ *
4
+ * Inspired by Subito.it's approach:
5
+ * - Capture screenshots of pages
6
+ * - Compare against baseline images
7
+ * - Detect pixel differences above threshold
8
+ * - Hide dynamic content (ads, analytics)
9
+ */
10
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
11
+ import { join } from 'path';
12
+ import { PNG } from 'pngjs';
13
+ import pixelmatch from 'pixelmatch';
14
+ /**
15
+ * Visual Tester class for screenshot comparison
16
+ */
17
+ export class VisualTester {
18
+ constructor(cwd = process.cwd()) {
19
+ this.diffs = [];
20
+ this.cwd = cwd;
21
+ }
22
+ /**
23
+ * Hide dynamic content that shouldn't be tested
24
+ */
25
+ async hideDynamicContent(page) {
26
+ await page.addStyleTag({
27
+ content: `
28
+ /* Hide common dynamic content */
29
+ .advertisement,
30
+ .ad-banner,
31
+ .analytics-widget,
32
+ .third-party-banner,
33
+ [class*="ad-"],
34
+ [id*="ad-"],
35
+ [class*="analytics"],
36
+ [id*="analytics"] {
37
+ display: none !important;
38
+ visibility: hidden !important;
39
+ }
40
+ `,
41
+ });
42
+ }
43
+ /**
44
+ * Take a screenshot and compare with baseline
45
+ */
46
+ async captureAndCompare(page, options) {
47
+ const { ticketId, testName, threshold = 0.01, updateBaseline = false } = options;
48
+ // Ensure visual test directories exist
49
+ const baselineDir = join(this.cwd, '.kosuke', 'visual-tests', 'baselines', ticketId);
50
+ const currentDir = join(this.cwd, '.kosuke', 'visual-tests', 'current', ticketId);
51
+ const diffDir = join(this.cwd, '.kosuke', 'visual-tests', 'diffs', ticketId);
52
+ this.ensureDir(baselineDir);
53
+ this.ensureDir(currentDir);
54
+ this.ensureDir(diffDir);
55
+ const baselinePath = join(baselineDir, `${testName}.png`);
56
+ const currentPath = join(currentDir, `${testName}.png`);
57
+ const diffPath = join(diffDir, `${testName}.png`);
58
+ // Hide dynamic content before taking screenshot
59
+ await this.hideDynamicContent(page);
60
+ // Wait for page to be stable
61
+ await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {
62
+ // Ignore timeout - some pages never reach networkidle
63
+ });
64
+ // Take screenshot
65
+ const screenshot = await page.screenshot({ fullPage: true });
66
+ writeFileSync(currentPath, screenshot);
67
+ // If no baseline exists or updateBaseline flag is set, create/update baseline
68
+ if (!existsSync(baselinePath) || updateBaseline) {
69
+ writeFileSync(baselinePath, screenshot);
70
+ console.log(` šŸ“ø ${updateBaseline ? 'Updated' : 'Created'} baseline: ${testName}`);
71
+ const diff = {
72
+ testName,
73
+ diffPixels: 0,
74
+ diffPercentage: 0,
75
+ threshold,
76
+ passed: true,
77
+ baselinePath,
78
+ currentPath,
79
+ diffPath,
80
+ };
81
+ this.diffs.push(diff);
82
+ return diff;
83
+ }
84
+ // Compare with baseline
85
+ const result = this.compareImages(baselinePath, currentPath, diffPath, threshold);
86
+ this.diffs.push(result);
87
+ return result;
88
+ }
89
+ /**
90
+ * Compare two images and generate diff
91
+ */
92
+ compareImages(baselinePath, currentPath, diffPath, threshold) {
93
+ const testName = baselinePath.split('/').pop()?.replace('.png', '') || 'unknown';
94
+ try {
95
+ const baseline = PNG.sync.read(readFileSync(baselinePath));
96
+ const current = PNG.sync.read(readFileSync(currentPath));
97
+ // Check if dimensions match
98
+ if (baseline.width !== current.width || baseline.height !== current.height) {
99
+ return {
100
+ testName,
101
+ diffPixels: baseline.width * baseline.height, // All pixels are different
102
+ diffPercentage: 1,
103
+ threshold,
104
+ passed: false,
105
+ baselinePath,
106
+ currentPath,
107
+ diffPath,
108
+ };
109
+ }
110
+ // Create diff image
111
+ const diff = new PNG({ width: baseline.width, height: baseline.height });
112
+ // Compare pixels
113
+ const diffPixels = pixelmatch(baseline.data, current.data, diff.data, baseline.width, baseline.height, { threshold: 0.1 } // Pixel sensitivity
114
+ );
115
+ const totalPixels = baseline.width * baseline.height;
116
+ const diffPercentage = diffPixels / totalPixels;
117
+ // Save diff image if there are differences
118
+ if (diffPixels > 0) {
119
+ writeFileSync(diffPath, PNG.sync.write(diff));
120
+ }
121
+ return {
122
+ testName,
123
+ diffPixels,
124
+ diffPercentage,
125
+ threshold,
126
+ passed: diffPercentage <= threshold,
127
+ baselinePath,
128
+ currentPath,
129
+ diffPath,
130
+ };
131
+ }
132
+ catch (error) {
133
+ console.error(` āš ļø Failed to compare images: ${error}`);
134
+ return {
135
+ testName,
136
+ diffPixels: 0,
137
+ diffPercentage: 0,
138
+ threshold,
139
+ passed: false,
140
+ baselinePath,
141
+ currentPath,
142
+ diffPath,
143
+ };
144
+ }
145
+ }
146
+ /**
147
+ * Get all visual diffs
148
+ */
149
+ getDiffs() {
150
+ return this.diffs;
151
+ }
152
+ /**
153
+ * Get failed visual diffs
154
+ */
155
+ getFailedDiffs() {
156
+ return this.diffs.filter((diff) => !diff.passed);
157
+ }
158
+ /**
159
+ * Check if there are any visual regressions
160
+ */
161
+ hasRegressions() {
162
+ return this.getFailedDiffs().length > 0;
163
+ }
164
+ /**
165
+ * Format visual diff report
166
+ */
167
+ formatReport() {
168
+ if (this.diffs.length === 0) {
169
+ return 'No visual tests run';
170
+ }
171
+ const failed = this.getFailedDiffs();
172
+ const passed = this.diffs.filter((diff) => diff.passed);
173
+ const lines = [];
174
+ lines.push(`\nšŸ“ø Visual Regression Report:`);
175
+ lines.push(` āœ… Passed: ${passed.length}`);
176
+ lines.push(` āŒ Failed: ${failed.length}`);
177
+ if (failed.length > 0) {
178
+ lines.push('\n Failed tests:');
179
+ for (const diff of failed) {
180
+ const percentage = (diff.diffPercentage * 100).toFixed(2);
181
+ lines.push(` - ${diff.testName}: ${percentage}% difference (threshold: ${diff.threshold * 100}%)`);
182
+ lines.push(` Diff image: ${diff.diffPath}`);
183
+ }
184
+ }
185
+ return lines.join('\n');
186
+ }
187
+ /**
188
+ * Clear all diffs
189
+ */
190
+ clear() {
191
+ this.diffs = [];
192
+ }
193
+ /**
194
+ * Ensure directory exists
195
+ */
196
+ ensureDir(dir) {
197
+ if (!existsSync(dir)) {
198
+ mkdirSync(dir, { recursive: true });
199
+ }
200
+ }
201
+ }
202
+ //# sourceMappingURL=visual-tester.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-tester.js","sourceRoot":"","sources":["../../../kosuke/utils/visual-tester.ts"],"names":[],"mappings":"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"}