@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.
- package/dist/index.d.ts +14 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -6
- package/dist/index.js.map +1 -1
- package/dist/kosuke/commands/build.d.ts +22 -0
- package/dist/kosuke/commands/build.d.ts.map +1 -0
- package/dist/kosuke/commands/build.js +135 -0
- package/dist/kosuke/commands/build.js.map +1 -0
- package/dist/kosuke/commands/review.d.ts +21 -0
- package/dist/kosuke/commands/review.d.ts.map +1 -0
- package/dist/kosuke/commands/review.js +185 -0
- package/dist/kosuke/commands/review.js.map +1 -0
- package/dist/kosuke/commands/ship.d.ts +23 -0
- package/dist/kosuke/commands/ship.d.ts.map +1 -0
- package/dist/kosuke/commands/ship.js +419 -0
- package/dist/kosuke/commands/ship.js.map +1 -0
- package/dist/kosuke/commands/test.d.ts +27 -0
- package/dist/kosuke/commands/test.d.ts.map +1 -0
- package/dist/kosuke/commands/test.js +338 -0
- package/dist/kosuke/commands/test.js.map +1 -0
- package/dist/kosuke/types.d.ts +82 -2
- package/dist/kosuke/types.d.ts.map +1 -1
- package/dist/kosuke/utils/error-analyzer.d.ts +32 -0
- package/dist/kosuke/utils/error-analyzer.d.ts.map +1 -0
- package/dist/kosuke/utils/error-analyzer.js +129 -0
- package/dist/kosuke/utils/error-analyzer.js.map +1 -0
- package/dist/kosuke/utils/git.d.ts +12 -0
- package/dist/kosuke/utils/git.d.ts.map +1 -1
- package/dist/kosuke/utils/git.js +39 -0
- package/dist/kosuke/utils/git.js.map +1 -1
- package/dist/kosuke/utils/log-collector.d.ts +81 -0
- package/dist/kosuke/utils/log-collector.d.ts.map +1 -0
- package/dist/kosuke/utils/log-collector.js +226 -0
- package/dist/kosuke/utils/log-collector.js.map +1 -0
- package/dist/kosuke/utils/playwright-agent.d.ts +39 -0
- package/dist/kosuke/utils/playwright-agent.d.ts.map +1 -0
- package/dist/kosuke/utils/playwright-agent.js +245 -0
- package/dist/kosuke/utils/playwright-agent.js.map +1 -0
- package/dist/kosuke/utils/test-generator.d.ts +22 -0
- package/dist/kosuke/utils/test-generator.d.ts.map +1 -0
- package/dist/kosuke/utils/test-generator.js +174 -0
- package/dist/kosuke/utils/test-generator.js.map +1 -0
- package/dist/kosuke/utils/validator.d.ts +11 -0
- package/dist/kosuke/utils/validator.d.ts.map +1 -1
- package/dist/kosuke/utils/validator.js +100 -0
- package/dist/kosuke/utils/validator.js.map +1 -1
- package/dist/kosuke/utils/visual-tester.d.ts +71 -0
- package/dist/kosuke/utils/visual-tester.d.ts.map +1 -0
- package/dist/kosuke/utils/visual-tester.js +202 -0
- package/dist/kosuke/utils/visual-tester.js.map +1 -0
- package/dist/lib.d.ts +6 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +5 -1
- package/dist/lib.js.map +1 -1
- package/package.json +6 -1
package/dist/kosuke/utils/git.js
CHANGED
|
@@ -101,4 +101,43 @@ export async function getCurrentBranch() {
|
|
|
101
101
|
const branch = await git.revparse(['--abbrev-ref', 'HEAD']);
|
|
102
102
|
return branch.trim();
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Commit and push to current branch (no branch creation, no PR)
|
|
106
|
+
*/
|
|
107
|
+
export async function commitAndPushCurrentBranch(message) {
|
|
108
|
+
await ensureGitIdentity();
|
|
109
|
+
// Check if there are changes to commit
|
|
110
|
+
const status = await git.status();
|
|
111
|
+
if (status.files.length === 0) {
|
|
112
|
+
console.log('ℹ️ No changes to commit');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// Commit changes
|
|
116
|
+
await git.add(['-A']);
|
|
117
|
+
await git.commit(message, ['--no-verify']);
|
|
118
|
+
// Push to current branch
|
|
119
|
+
const currentBranch = await getCurrentBranch();
|
|
120
|
+
await git.push('origin', currentBranch);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get git diff of current changes (staged and unstaged)
|
|
124
|
+
*/
|
|
125
|
+
export async function getGitDiff() {
|
|
126
|
+
try {
|
|
127
|
+
// Get diff of both staged and unstaged changes
|
|
128
|
+
const diff = await git.diff(['HEAD']);
|
|
129
|
+
return diff;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.warn('⚠️ Could not get git diff:', error);
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if there are any uncommitted changes
|
|
138
|
+
*/
|
|
139
|
+
export async function hasUncommittedChanges() {
|
|
140
|
+
const status = await git.status();
|
|
141
|
+
return status.files.length > 0;
|
|
142
|
+
}
|
|
104
143
|
//# sourceMappingURL=git.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../kosuke/utils/git.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../kosuke/utils/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log Collector - Collect logs from multiple sources
|
|
3
|
+
*
|
|
4
|
+
* Collects and aggregates logs from:
|
|
5
|
+
* - Browser console (errors, warnings)
|
|
6
|
+
* - Network requests (failed requests, status codes)
|
|
7
|
+
* - Docker Compose logs (backend logs)
|
|
8
|
+
* - Playwright traces
|
|
9
|
+
*/
|
|
10
|
+
import type { Page } from '@playwright/test';
|
|
11
|
+
export interface ConsoleLog {
|
|
12
|
+
type: 'error' | 'warning' | 'info';
|
|
13
|
+
message: string;
|
|
14
|
+
timestamp: Date;
|
|
15
|
+
location?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface NetworkLog {
|
|
18
|
+
url: string;
|
|
19
|
+
method: string;
|
|
20
|
+
status: number;
|
|
21
|
+
statusText: string;
|
|
22
|
+
timestamp: Date;
|
|
23
|
+
responseBody?: string;
|
|
24
|
+
requestBody?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface DockerLog {
|
|
27
|
+
service: string;
|
|
28
|
+
message: string;
|
|
29
|
+
timestamp: Date;
|
|
30
|
+
}
|
|
31
|
+
export interface CollectedLogs {
|
|
32
|
+
console: ConsoleLog[];
|
|
33
|
+
network: NetworkLog[];
|
|
34
|
+
docker: DockerLog[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Log collector class that attaches to a Playwright page
|
|
38
|
+
*/
|
|
39
|
+
export declare class LogCollector {
|
|
40
|
+
private consoleLogs;
|
|
41
|
+
private networkLogs;
|
|
42
|
+
private dockerLogs;
|
|
43
|
+
private page;
|
|
44
|
+
/**
|
|
45
|
+
* Attach log collectors to a Playwright page
|
|
46
|
+
*/
|
|
47
|
+
attach(page: Page): void;
|
|
48
|
+
/**
|
|
49
|
+
* Attach console listener
|
|
50
|
+
*/
|
|
51
|
+
private attachConsoleListener;
|
|
52
|
+
/**
|
|
53
|
+
* Attach network listener
|
|
54
|
+
*/
|
|
55
|
+
private attachNetworkListener;
|
|
56
|
+
/**
|
|
57
|
+
* Collect Docker Compose logs
|
|
58
|
+
*/
|
|
59
|
+
collectDockerLogs(since?: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Get all collected logs
|
|
62
|
+
*/
|
|
63
|
+
getLogs(): CollectedLogs;
|
|
64
|
+
/**
|
|
65
|
+
* Get only error logs
|
|
66
|
+
*/
|
|
67
|
+
getErrors(): CollectedLogs;
|
|
68
|
+
/**
|
|
69
|
+
* Check if there are any errors
|
|
70
|
+
*/
|
|
71
|
+
hasErrors(): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Format logs as human-readable text
|
|
74
|
+
*/
|
|
75
|
+
formatLogs(logs: CollectedLogs): string;
|
|
76
|
+
/**
|
|
77
|
+
* Clear all collected logs
|
|
78
|
+
*/
|
|
79
|
+
clear(): void;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=log-collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-collector.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/log-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,kBAAkB,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,IAAI,CAAqB;IAEjC;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAMxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwB7B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoD7B;;OAEG;IACG,iBAAiB,CAAC,KAAK,GAAE,MAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA6C7D;;OAEG;IACH,OAAO,IAAI,aAAa;IAQxB;;OAEG;IACH,SAAS,IAAI,aAAa;IAa1B;;OAEG;IACH,SAAS,IAAI,OAAO;IAKpB;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM;IAqCvC;;OAEG;IACH,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log Collector - Collect logs from multiple sources
|
|
3
|
+
*
|
|
4
|
+
* Collects and aggregates logs from:
|
|
5
|
+
* - Browser console (errors, warnings)
|
|
6
|
+
* - Network requests (failed requests, status codes)
|
|
7
|
+
* - Docker Compose logs (backend logs)
|
|
8
|
+
* - Playwright traces
|
|
9
|
+
*/
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
/**
|
|
12
|
+
* Log collector class that attaches to a Playwright page
|
|
13
|
+
*/
|
|
14
|
+
export class LogCollector {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.consoleLogs = [];
|
|
17
|
+
this.networkLogs = [];
|
|
18
|
+
this.dockerLogs = [];
|
|
19
|
+
this.page = null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Attach log collectors to a Playwright page
|
|
23
|
+
*/
|
|
24
|
+
attach(page) {
|
|
25
|
+
this.page = page;
|
|
26
|
+
this.attachConsoleListener(page);
|
|
27
|
+
this.attachNetworkListener(page);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Attach console listener
|
|
31
|
+
*/
|
|
32
|
+
attachConsoleListener(page) {
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
page.on('console', (msg) => {
|
|
35
|
+
const type = msg.type();
|
|
36
|
+
if (type === 'error' || type === 'warning' || type === 'info') {
|
|
37
|
+
this.consoleLogs.push({
|
|
38
|
+
type: type,
|
|
39
|
+
message: msg.text(),
|
|
40
|
+
timestamp: new Date(),
|
|
41
|
+
location: msg.location()?.url,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// Also capture page errors
|
|
46
|
+
page.on('pageerror', (error) => {
|
|
47
|
+
this.consoleLogs.push({
|
|
48
|
+
type: 'error',
|
|
49
|
+
message: error.message,
|
|
50
|
+
timestamp: new Date(),
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Attach network listener
|
|
56
|
+
*/
|
|
57
|
+
attachNetworkListener(page) {
|
|
58
|
+
page.on('response', async (response) => {
|
|
59
|
+
const status = response.status();
|
|
60
|
+
// Only log failed requests or important status codes
|
|
61
|
+
if (status >= 400 || status === 0) {
|
|
62
|
+
let responseBody;
|
|
63
|
+
let requestBody;
|
|
64
|
+
try {
|
|
65
|
+
// Try to get response body (might fail for non-text responses)
|
|
66
|
+
responseBody = await response.text();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Ignore if we can't get the body
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
// Try to get request body
|
|
73
|
+
const request = response.request();
|
|
74
|
+
const postData = request.postData();
|
|
75
|
+
if (postData) {
|
|
76
|
+
requestBody = postData;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Ignore if we can't get request data
|
|
81
|
+
}
|
|
82
|
+
this.networkLogs.push({
|
|
83
|
+
url: response.url(),
|
|
84
|
+
method: response.request().method(),
|
|
85
|
+
status,
|
|
86
|
+
statusText: response.statusText(),
|
|
87
|
+
timestamp: new Date(),
|
|
88
|
+
responseBody,
|
|
89
|
+
requestBody,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
// Capture request failures
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
95
|
+
page.on('requestfailed', (request) => {
|
|
96
|
+
this.networkLogs.push({
|
|
97
|
+
url: request.url(),
|
|
98
|
+
method: request.method(),
|
|
99
|
+
status: 0,
|
|
100
|
+
statusText: request.failure()?.errorText || 'Request failed',
|
|
101
|
+
timestamp: new Date(),
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Collect Docker Compose logs
|
|
107
|
+
*/
|
|
108
|
+
async collectDockerLogs(since = '30s') {
|
|
109
|
+
try {
|
|
110
|
+
// Check if docker compose is available
|
|
111
|
+
try {
|
|
112
|
+
execSync('docker compose version', { stdio: 'ignore' });
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
console.log(' ℹ️ Docker Compose not available, skipping backend logs');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Get logs from all services
|
|
119
|
+
const logs = execSync(`docker compose logs --tail=100 --since=${since} --no-color`, {
|
|
120
|
+
encoding: 'utf-8',
|
|
121
|
+
stdio: ['pipe', 'pipe', 'ignore'], // Ignore stderr
|
|
122
|
+
});
|
|
123
|
+
// Parse logs
|
|
124
|
+
const lines = logs.split('\n');
|
|
125
|
+
for (const line of lines) {
|
|
126
|
+
if (!line.trim())
|
|
127
|
+
continue;
|
|
128
|
+
// Docker compose log format: service-name | message
|
|
129
|
+
const match = line.match(/^([a-zA-Z0-9_-]+)\s+\|\s+(.+)$/);
|
|
130
|
+
if (match) {
|
|
131
|
+
const [, service, message] = match;
|
|
132
|
+
this.dockerLogs.push({
|
|
133
|
+
service: service.trim(),
|
|
134
|
+
message: message.trim(),
|
|
135
|
+
timestamp: new Date(),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// Fallback: just store the line as-is
|
|
140
|
+
this.dockerLogs.push({
|
|
141
|
+
service: 'unknown',
|
|
142
|
+
message: line,
|
|
143
|
+
timestamp: new Date(),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.log(' ⚠️ Failed to collect Docker logs:', error);
|
|
150
|
+
// Don't throw - backend logs are optional
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get all collected logs
|
|
155
|
+
*/
|
|
156
|
+
getLogs() {
|
|
157
|
+
return {
|
|
158
|
+
console: this.consoleLogs,
|
|
159
|
+
network: this.networkLogs,
|
|
160
|
+
docker: this.dockerLogs,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get only error logs
|
|
165
|
+
*/
|
|
166
|
+
getErrors() {
|
|
167
|
+
return {
|
|
168
|
+
console: this.consoleLogs.filter((log) => log.type === 'error'),
|
|
169
|
+
network: this.networkLogs.filter((log) => log.status >= 400 || log.status === 0),
|
|
170
|
+
docker: this.dockerLogs.filter((log) => log.message.toLowerCase().includes('error') ||
|
|
171
|
+
log.message.toLowerCase().includes('exception') ||
|
|
172
|
+
log.message.toLowerCase().includes('failed')),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Check if there are any errors
|
|
177
|
+
*/
|
|
178
|
+
hasErrors() {
|
|
179
|
+
const errors = this.getErrors();
|
|
180
|
+
return errors.console.length > 0 || errors.network.length > 0 || errors.docker.length > 0;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Format logs as human-readable text
|
|
184
|
+
*/
|
|
185
|
+
formatLogs(logs) {
|
|
186
|
+
const sections = [];
|
|
187
|
+
// Console logs
|
|
188
|
+
if (logs.console.length > 0) {
|
|
189
|
+
sections.push('=== Console Logs ===');
|
|
190
|
+
for (const log of logs.console) {
|
|
191
|
+
const location = log.location ? ` (${log.location})` : '';
|
|
192
|
+
sections.push(`[${log.type.toUpperCase()}]${location} ${log.message}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Network logs
|
|
196
|
+
if (logs.network.length > 0) {
|
|
197
|
+
sections.push('\n=== Network Logs ===');
|
|
198
|
+
for (const log of logs.network) {
|
|
199
|
+
sections.push(`[${log.method}] ${log.url} - ${log.status} ${log.statusText}`);
|
|
200
|
+
if (log.requestBody) {
|
|
201
|
+
sections.push(` Request: ${log.requestBody.substring(0, 200)}`);
|
|
202
|
+
}
|
|
203
|
+
if (log.responseBody) {
|
|
204
|
+
sections.push(` Response: ${log.responseBody.substring(0, 200)}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Docker logs
|
|
209
|
+
if (logs.docker.length > 0) {
|
|
210
|
+
sections.push('\n=== Docker Compose Logs ===');
|
|
211
|
+
for (const log of logs.docker) {
|
|
212
|
+
sections.push(`[${log.service}] ${log.message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return sections.join('\n');
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Clear all collected logs
|
|
219
|
+
*/
|
|
220
|
+
clear() {
|
|
221
|
+
this.consoleLogs = [];
|
|
222
|
+
this.networkLogs = [];
|
|
223
|
+
this.dockerLogs = [];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=log-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-collector.js","sourceRoot":"","sources":["../../../kosuke/utils/log-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Agent - Test execution orchestration
|
|
3
|
+
*
|
|
4
|
+
* Executes Playwright tests with logging and visual regression
|
|
5
|
+
*/
|
|
6
|
+
import type { TestFailure } from './error-analyzer.js';
|
|
7
|
+
export interface PlaywrightResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
testsRun: number;
|
|
10
|
+
testsPassed: number;
|
|
11
|
+
testsFailed: number;
|
|
12
|
+
failures: TestFailure[];
|
|
13
|
+
tracePath: string;
|
|
14
|
+
duration: number;
|
|
15
|
+
}
|
|
16
|
+
export interface PlaywrightOptions {
|
|
17
|
+
testFile: string;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
headed?: boolean;
|
|
20
|
+
debug?: boolean;
|
|
21
|
+
cwd?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Run Playwright tests
|
|
25
|
+
*/
|
|
26
|
+
export declare function runPlaywrightTests(options: PlaywrightOptions): Promise<PlaywrightResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Check if Playwright is installed
|
|
29
|
+
*/
|
|
30
|
+
export declare function isPlaywrightInstalled(cwd?: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Install Playwright
|
|
33
|
+
*/
|
|
34
|
+
export declare function installPlaywright(cwd?: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Ensure Playwright config exists
|
|
37
|
+
*/
|
|
38
|
+
export declare function ensurePlaywrightConfig(cwd?: string): void;
|
|
39
|
+
//# sourceMappingURL=playwright-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-agent.d.ts","sourceRoot":"","sources":["../../../kosuke/utils/playwright-agent.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6D9F;AA4HD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAW1E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBlF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAsB,GAAG,IAAI,CAmCxE"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Agent - Test execution orchestration
|
|
3
|
+
*
|
|
4
|
+
* Executes Playwright tests with logging and visual regression
|
|
5
|
+
*/
|
|
6
|
+
import { execSync } from 'child_process';
|
|
7
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
/**
|
|
10
|
+
* Run Playwright tests
|
|
11
|
+
*/
|
|
12
|
+
export async function runPlaywrightTests(options) {
|
|
13
|
+
const { testFile, baseUrl, headed = false, debug = false, cwd = process.cwd() } = options;
|
|
14
|
+
// Ensure test results directory exists
|
|
15
|
+
const resultsDir = join(cwd, 'test-results');
|
|
16
|
+
if (!existsSync(resultsDir)) {
|
|
17
|
+
mkdirSync(resultsDir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
const ticketId = testFile.split('/').pop()?.replace('.spec.ts', '') || 'unknown';
|
|
20
|
+
const tracePath = join(resultsDir, `trace-${ticketId}.zip`);
|
|
21
|
+
// Build Playwright command
|
|
22
|
+
const args = [
|
|
23
|
+
'playwright',
|
|
24
|
+
'test',
|
|
25
|
+
testFile,
|
|
26
|
+
`--config=${join(cwd, 'playwright.config.ts')}`,
|
|
27
|
+
'--reporter=json',
|
|
28
|
+
];
|
|
29
|
+
if (headed) {
|
|
30
|
+
args.push('--headed');
|
|
31
|
+
}
|
|
32
|
+
if (debug) {
|
|
33
|
+
args.push('--debug');
|
|
34
|
+
}
|
|
35
|
+
// Set environment variables
|
|
36
|
+
const env = {
|
|
37
|
+
...process.env,
|
|
38
|
+
BASE_URL: baseUrl,
|
|
39
|
+
PLAYWRIGHT_TRACE: 'on',
|
|
40
|
+
};
|
|
41
|
+
console.log(` 🎯 Running Playwright tests...`);
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
try {
|
|
44
|
+
// Run Playwright using npx (works with any package manager)
|
|
45
|
+
const output = execSync(`npx ${args.join(' ')}`, {
|
|
46
|
+
cwd,
|
|
47
|
+
env,
|
|
48
|
+
encoding: 'utf-8',
|
|
49
|
+
stdio: ['pipe', 'pipe', 'pipe'], // Capture all output
|
|
50
|
+
});
|
|
51
|
+
const duration = Date.now() - startTime;
|
|
52
|
+
const result = parsePlaywrightOutput(output, tracePath, duration);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Playwright exits with non-zero code when tests fail
|
|
57
|
+
const duration = Date.now() - startTime;
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
const output = error instanceof Error && 'stdout' in error ? error.stdout : '';
|
|
60
|
+
const result = parsePlaywrightOutput(output, tracePath, duration);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parse Playwright JSON output
|
|
66
|
+
*/
|
|
67
|
+
function parsePlaywrightOutput(output, tracePath, duration) {
|
|
68
|
+
try {
|
|
69
|
+
// Try to parse JSON output
|
|
70
|
+
const jsonMatch = output.match(/\{[\s\S]*"suites"[\s\S]*\}/);
|
|
71
|
+
if (jsonMatch) {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
const json = JSON.parse(jsonMatch[0]);
|
|
74
|
+
return parsePlaywrightJson(json, tracePath, duration);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// If JSON parsing fails, fall back to text parsing
|
|
79
|
+
}
|
|
80
|
+
// Fallback: parse text output
|
|
81
|
+
return parsePlaywrightText(output, tracePath, duration);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Parse Playwright JSON report
|
|
85
|
+
*/
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
+
function parsePlaywrightJson(json, tracePath, duration) {
|
|
88
|
+
const failures = [];
|
|
89
|
+
let testsRun = 0;
|
|
90
|
+
let testsPassed = 0;
|
|
91
|
+
let testsFailed = 0;
|
|
92
|
+
// Parse test results
|
|
93
|
+
for (const suite of json.suites || []) {
|
|
94
|
+
for (const spec of suite.specs || []) {
|
|
95
|
+
for (const test of spec.tests || []) {
|
|
96
|
+
testsRun++;
|
|
97
|
+
const result = test.results?.[0];
|
|
98
|
+
if (result?.status === 'passed') {
|
|
99
|
+
testsPassed++;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
testsFailed++;
|
|
103
|
+
failures.push({
|
|
104
|
+
testName: spec.title || 'Unknown test',
|
|
105
|
+
errorMessage: result?.error?.message || 'Test failed',
|
|
106
|
+
expected: extractExpected(result?.error?.message),
|
|
107
|
+
received: extractReceived(result?.error?.message),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
success: testsFailed === 0,
|
|
115
|
+
testsRun,
|
|
116
|
+
testsPassed,
|
|
117
|
+
testsFailed,
|
|
118
|
+
failures,
|
|
119
|
+
tracePath,
|
|
120
|
+
duration,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Parse Playwright text output (fallback)
|
|
125
|
+
*/
|
|
126
|
+
function parsePlaywrightText(output, tracePath, duration) {
|
|
127
|
+
const failures = [];
|
|
128
|
+
// Look for test failures in output
|
|
129
|
+
const failureMatches = output.matchAll(/✘ (.+?)\n[\s\S]*?Error: (.+?)(?:\n|$)/g);
|
|
130
|
+
for (const match of failureMatches) {
|
|
131
|
+
failures.push({
|
|
132
|
+
testName: match[1].trim(),
|
|
133
|
+
errorMessage: match[2].trim(),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Count tests
|
|
137
|
+
const passedMatch = output.match(/(\d+) passed/);
|
|
138
|
+
const failedMatch = output.match(/(\d+) failed/);
|
|
139
|
+
const testsPassed = passedMatch ? parseInt(passedMatch[1]) : 0;
|
|
140
|
+
const testsFailed = failedMatch ? parseInt(failedMatch[1]) : failures.length;
|
|
141
|
+
const testsRun = testsPassed + testsFailed;
|
|
142
|
+
return {
|
|
143
|
+
success: testsFailed === 0,
|
|
144
|
+
testsRun,
|
|
145
|
+
testsPassed,
|
|
146
|
+
testsFailed,
|
|
147
|
+
failures,
|
|
148
|
+
tracePath,
|
|
149
|
+
duration,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Extract expected value from error message
|
|
154
|
+
*/
|
|
155
|
+
function extractExpected(errorMessage) {
|
|
156
|
+
if (!errorMessage)
|
|
157
|
+
return undefined;
|
|
158
|
+
const match = errorMessage.match(/Expected:?\s*(.+?)(?:\n|Received)/i);
|
|
159
|
+
return match ? match[1].trim() : undefined;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Extract received value from error message
|
|
163
|
+
*/
|
|
164
|
+
function extractReceived(errorMessage) {
|
|
165
|
+
if (!errorMessage)
|
|
166
|
+
return undefined;
|
|
167
|
+
const match = errorMessage.match(/Received:?\s*(.+?)(?:\n|$)/i);
|
|
168
|
+
return match ? match[1].trim() : undefined;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Check if Playwright is installed
|
|
172
|
+
*/
|
|
173
|
+
export function isPlaywrightInstalled(cwd = process.cwd()) {
|
|
174
|
+
try {
|
|
175
|
+
execSync('npx playwright --version', {
|
|
176
|
+
cwd,
|
|
177
|
+
encoding: 'utf-8',
|
|
178
|
+
stdio: 'ignore',
|
|
179
|
+
});
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Install Playwright
|
|
188
|
+
*/
|
|
189
|
+
export async function installPlaywright(cwd = process.cwd()) {
|
|
190
|
+
console.log('📦 Installing Playwright...');
|
|
191
|
+
try {
|
|
192
|
+
// Install @playwright/test
|
|
193
|
+
execSync('npm install --save-dev @playwright/test', {
|
|
194
|
+
cwd,
|
|
195
|
+
encoding: 'utf-8',
|
|
196
|
+
stdio: 'inherit',
|
|
197
|
+
});
|
|
198
|
+
// Install browsers
|
|
199
|
+
execSync('npx playwright install chromium', {
|
|
200
|
+
cwd,
|
|
201
|
+
encoding: 'utf-8',
|
|
202
|
+
stdio: 'inherit',
|
|
203
|
+
});
|
|
204
|
+
console.log(' ✅ Playwright installed\n');
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
throw new Error(`Failed to install Playwright: ${error}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Ensure Playwright config exists
|
|
212
|
+
*/
|
|
213
|
+
export function ensurePlaywrightConfig(cwd = process.cwd()) {
|
|
214
|
+
const configPath = join(cwd, 'playwright.config.ts');
|
|
215
|
+
if (existsSync(configPath)) {
|
|
216
|
+
return; // Config already exists
|
|
217
|
+
}
|
|
218
|
+
console.log('📝 Creating playwright.config.ts...');
|
|
219
|
+
const configContent = `import { defineConfig, devices } from '@playwright/test';
|
|
220
|
+
|
|
221
|
+
export default defineConfig({
|
|
222
|
+
testDir: './.kosuke/tests',
|
|
223
|
+
fullyParallel: false,
|
|
224
|
+
forbidOnly: !!process.env.CI,
|
|
225
|
+
retries: 0,
|
|
226
|
+
workers: 1,
|
|
227
|
+
reporter: 'html',
|
|
228
|
+
use: {
|
|
229
|
+
baseURL: process.env.BASE_URL || 'http://localhost:3000',
|
|
230
|
+
trace: 'retain-on-failure',
|
|
231
|
+
screenshot: 'only-on-failure',
|
|
232
|
+
video: 'retain-on-failure',
|
|
233
|
+
},
|
|
234
|
+
projects: [
|
|
235
|
+
{
|
|
236
|
+
name: 'chromium',
|
|
237
|
+
use: { ...devices['Desktop Chrome'] },
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
`;
|
|
242
|
+
writeFileSync(configPath, configContent, 'utf-8');
|
|
243
|
+
console.log(' ✅ Config created\n');
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=playwright-agent.js.map
|