projax 3.3.26 → 3.3.27

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/dist/api/database.d.ts +6 -1
  2. package/dist/api/database.d.ts.map +1 -1
  3. package/dist/api/database.js +49 -0
  4. package/dist/api/database.js.map +1 -1
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api/index.js +0 -9
  7. package/dist/api/index.js.map +1 -1
  8. package/dist/api/migrate.d.ts.map +1 -1
  9. package/dist/api/migrate.js +4 -152
  10. package/dist/api/migrate.js.map +1 -1
  11. package/dist/api/routes/projects.d.ts.map +1 -1
  12. package/dist/api/routes/projects.js +65 -0
  13. package/dist/api/routes/projects.js.map +1 -1
  14. package/dist/api/services/test-parser.d.ts +18 -0
  15. package/dist/api/services/test-parser.d.ts.map +1 -0
  16. package/dist/api/services/test-parser.js +200 -0
  17. package/dist/api/services/test-parser.js.map +1 -0
  18. package/dist/api/types.d.ts +15 -0
  19. package/dist/api/types.d.ts.map +1 -1
  20. package/dist/core/database.d.ts +17 -0
  21. package/dist/core/database.js +29 -1
  22. package/dist/electron/core/database.d.ts +17 -0
  23. package/dist/electron/core/database.js +29 -1
  24. package/dist/electron/renderer/assets/index-ByHY-x-j.js +62 -0
  25. package/dist/electron/renderer/assets/index-CS-85xbL.css +1 -0
  26. package/dist/electron/renderer/assets/index-CgB-tTpV.js +62 -0
  27. package/dist/electron/renderer/assets/index-DwRy5FqP.js +62 -0
  28. package/dist/electron/renderer/assets/index-Z_8dJn3i.js +62 -0
  29. package/dist/electron/renderer/assets/index-nts9ST-M.js +62 -0
  30. package/dist/electron/renderer/index.html +2 -2
  31. package/dist/electron/script-runner.js +51 -1
  32. package/dist/script-runner.js +51 -1
  33. package/dist/test-parser.d.ts +17 -0
  34. package/dist/test-parser.js +199 -0
  35. package/package.json +1 -1
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ // Test output parser for extracting test statistics from common test runners
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.parseTestOutput = parseTestOutput;
5
+ exports.isTestOutput = isTestOutput;
6
+ /**
7
+ * Parse test output from various frameworks and extract statistics
8
+ */
9
+ function parseTestOutput(output) {
10
+ const result = {
11
+ framework: null,
12
+ passed: 0,
13
+ failed: 0,
14
+ skipped: 0,
15
+ total: 0,
16
+ duration: null,
17
+ coverage: null,
18
+ };
19
+ // Detect framework and parse accordingly
20
+ if (output.includes('PASS') && output.includes('FAIL') || output.includes('Test Suites:')) {
21
+ // Jest/Vitest
22
+ result.framework = parseJestVitestOutput(output, result);
23
+ }
24
+ else if (output.includes('passing') && output.includes('failing')) {
25
+ // Mocha
26
+ result.framework = parseMochaOutput(output, result);
27
+ }
28
+ else if (output.includes('passed') && output.includes('failed') && output.includes('pytest')) {
29
+ // pytest
30
+ result.framework = parsePytestOutput(output, result);
31
+ }
32
+ else if (output.includes('OK') && output.includes('test')) {
33
+ // Python unittest
34
+ result.framework = parseUnittestOutput(output, result);
35
+ }
36
+ else {
37
+ // Try generic parsing
38
+ return parseGenericOutput(output);
39
+ }
40
+ // Calculate total if not set
41
+ if (result.total === 0) {
42
+ result.total = result.passed + result.failed + result.skipped;
43
+ }
44
+ return result.total > 0 ? result : null;
45
+ }
46
+ /**
47
+ * Parse Jest/Vitest output
48
+ */
49
+ function parseJestVitestOutput(output, result) {
50
+ // Jest format:
51
+ // Test Suites: 2 failed, 1 passed, 3 total
52
+ // Tests: 5 failed, 10 passed, 15 total
53
+ // Time: 2.345 s
54
+ const testSuitesMatch = output.match(/Test Suites:.*?(\d+)\s+passed/i);
55
+ const testsMatch = output.match(/Tests:\s+(?:(\d+)\s+failed,?\s*)?(?:(\d+)\s+skipped,?\s*)?(?:(\d+)\s+passed)/i);
56
+ const totalMatch = output.match(/Tests:.*?(\d+)\s+total/i);
57
+ const timeMatch = output.match(/Time:\s+([\d.]+)\s*s/i);
58
+ const coverageMatch = output.match(/All files\s*\|\s*([\d.]+)/);
59
+ if (testsMatch) {
60
+ result.failed = testsMatch[1] ? parseInt(testsMatch[1], 10) : 0;
61
+ result.skipped = testsMatch[2] ? parseInt(testsMatch[2], 10) : 0;
62
+ result.passed = testsMatch[3] ? parseInt(testsMatch[3], 10) : 0;
63
+ }
64
+ if (totalMatch) {
65
+ result.total = parseInt(totalMatch[1], 10);
66
+ }
67
+ if (timeMatch) {
68
+ result.duration = Math.floor(parseFloat(timeMatch[1]) * 1000);
69
+ }
70
+ if (coverageMatch) {
71
+ result.coverage = parseFloat(coverageMatch[1]);
72
+ }
73
+ // Determine if Jest or Vitest
74
+ return output.includes('vitest') ? 'vitest' : 'jest';
75
+ }
76
+ /**
77
+ * Parse Mocha output
78
+ */
79
+ function parseMochaOutput(output, result) {
80
+ // Mocha format:
81
+ // 10 passing (234ms)
82
+ // 2 failing
83
+ // 1 pending
84
+ const passingMatch = output.match(/(\d+)\s+passing/i);
85
+ const failingMatch = output.match(/(\d+)\s+failing/i);
86
+ const pendingMatch = output.match(/(\d+)\s+pending/i);
87
+ const timeMatch = output.match(/passing\s+\((\d+)ms\)/i);
88
+ if (passingMatch) {
89
+ result.passed = parseInt(passingMatch[1], 10);
90
+ }
91
+ if (failingMatch) {
92
+ result.failed = parseInt(failingMatch[1], 10);
93
+ }
94
+ if (pendingMatch) {
95
+ result.skipped = parseInt(pendingMatch[1], 10);
96
+ }
97
+ if (timeMatch) {
98
+ result.duration = parseInt(timeMatch[1], 10);
99
+ }
100
+ return 'mocha';
101
+ }
102
+ /**
103
+ * Parse pytest output
104
+ */
105
+ function parsePytestOutput(output, result) {
106
+ // pytest format:
107
+ // ===== 10 passed, 2 failed, 1 skipped in 2.34s =====
108
+ const statsMatch = output.match(/=+\s*(?:(\d+)\s+passed)?(?:,\s*(\d+)\s+failed)?(?:,\s*(\d+)\s+skipped)?(?:\s+in\s+([\d.]+)s)?/i);
109
+ if (statsMatch) {
110
+ result.passed = statsMatch[1] ? parseInt(statsMatch[1], 10) : 0;
111
+ result.failed = statsMatch[2] ? parseInt(statsMatch[2], 10) : 0;
112
+ result.skipped = statsMatch[3] ? parseInt(statsMatch[3], 10) : 0;
113
+ if (statsMatch[4]) {
114
+ result.duration = Math.floor(parseFloat(statsMatch[4]) * 1000);
115
+ }
116
+ }
117
+ // Coverage
118
+ const coverageMatch = output.match(/TOTAL\s+\d+\s+\d+\s+(\d+)%/);
119
+ if (coverageMatch) {
120
+ result.coverage = parseInt(coverageMatch[1], 10);
121
+ }
122
+ return 'pytest';
123
+ }
124
+ /**
125
+ * Parse Python unittest output
126
+ */
127
+ function parseUnittestOutput(output, result) {
128
+ // unittest format:
129
+ // Ran 15 tests in 2.345s
130
+ // OK
131
+ // or FAILED (failures=2, errors=1)
132
+ const ranMatch = output.match(/Ran\s+(\d+)\s+tests?\s+in\s+([\d.]+)s/i);
133
+ const failedMatch = output.match(/FAILED\s*\((?:failures=(\d+))?(?:,\s*errors=(\d+))?\)/i);
134
+ if (ranMatch) {
135
+ result.total = parseInt(ranMatch[1], 10);
136
+ result.duration = Math.floor(parseFloat(ranMatch[2]) * 1000);
137
+ }
138
+ if (failedMatch) {
139
+ const failures = failedMatch[1] ? parseInt(failedMatch[1], 10) : 0;
140
+ const errors = failedMatch[2] ? parseInt(failedMatch[2], 10) : 0;
141
+ result.failed = failures + errors;
142
+ result.passed = result.total - result.failed;
143
+ }
144
+ else if (output.includes('OK')) {
145
+ result.passed = result.total;
146
+ }
147
+ return 'unittest';
148
+ }
149
+ /**
150
+ * Generic parser for unrecognized frameworks
151
+ */
152
+ function parseGenericOutput(output) {
153
+ const result = {
154
+ framework: 'unknown',
155
+ passed: 0,
156
+ failed: 0,
157
+ skipped: 0,
158
+ total: 0,
159
+ duration: null,
160
+ coverage: null,
161
+ };
162
+ // Try to find common patterns
163
+ const patterns = [
164
+ { regex: /(\d+)\s+(?:test(?:s)?|spec(?:s)?)\s+passed/i, key: 'passed' },
165
+ { regex: /(\d+)\s+(?:test(?:s)?|spec(?:s)?)\s+failed/i, key: 'failed' },
166
+ { regex: /(\d+)\s+(?:test(?:s)?|spec(?:s)?)\s+skipped/i, key: 'skipped' },
167
+ { regex: /✓\s*(\d+)/i, key: 'passed' },
168
+ { regex: /✗\s*(\d+)/i, key: 'failed' },
169
+ ];
170
+ for (const pattern of patterns) {
171
+ const match = output.match(pattern.regex);
172
+ if (match && pattern.key in result) {
173
+ result[pattern.key] = parseInt(match[1], 10);
174
+ }
175
+ }
176
+ result.total = result.passed + result.failed + result.skipped;
177
+ return result.total > 0 ? result : null;
178
+ }
179
+ /**
180
+ * Check if output appears to be from a test command
181
+ */
182
+ function isTestOutput(output) {
183
+ const testIndicators = [
184
+ 'Test Suites:',
185
+ 'Tests:',
186
+ 'passing',
187
+ 'failing',
188
+ 'passed',
189
+ 'failed',
190
+ 'skipped',
191
+ 'pytest',
192
+ 'Ran',
193
+ 'test',
194
+ 'spec',
195
+ 'PASS',
196
+ 'FAIL',
197
+ ];
198
+ return testIndicators.some(indicator => output.includes(indicator));
199
+ }
200
+ //# sourceMappingURL=test-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-parser.js","sourceRoot":"","sources":["../../src/services/test-parser.ts"],"names":[],"mappings":"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"}
@@ -36,11 +36,26 @@ export interface ProjectPort {
36
36
  last_detected: number;
37
37
  created_at: number;
38
38
  }
39
+ export interface TestResult {
40
+ id: number;
41
+ project_id: number;
42
+ script_name: string;
43
+ framework: string | null;
44
+ passed: number;
45
+ failed: number;
46
+ skipped: number;
47
+ total: number;
48
+ duration: number | null;
49
+ coverage: number | null;
50
+ timestamp: number;
51
+ raw_output: string | null;
52
+ }
39
53
  export interface DatabaseSchema {
40
54
  projects: Project[];
41
55
  tests: Test[];
42
56
  jenkins_jobs: JenkinsJob[];
43
57
  project_ports: ProjectPort[];
58
+ test_results: TestResult[];
44
59
  settings: Array<{
45
60
  key: string;
46
61
  value: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,QAAQ,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrE"}
@@ -36,6 +36,20 @@ export interface ProjectPort {
36
36
  last_detected: number;
37
37
  created_at: number;
38
38
  }
39
+ export interface TestResult {
40
+ id: number;
41
+ project_id: number;
42
+ script_name: string;
43
+ framework: string | null;
44
+ passed: number;
45
+ failed: number;
46
+ skipped: number;
47
+ total: number;
48
+ duration: number | null;
49
+ coverage: number | null;
50
+ timestamp: number;
51
+ raw_output: string | null;
52
+ }
39
53
  type ScanResponse = {
40
54
  project: Project;
41
55
  testsFound: number;
@@ -73,6 +87,9 @@ declare class DatabaseManager {
73
87
  getSetting(key: string): string | null;
74
88
  setSetting(key: string, value: string): void;
75
89
  getAllSettings(): Record<string, string>;
90
+ addTestResult(projectId: number, scriptName: string, passed: number, failed: number, skipped?: number, total?: number, duration?: number | null, coverage?: number | null, framework?: string | null, rawOutput?: string | null): TestResult;
91
+ getLatestTestResult(projectId: number): TestResult | null;
92
+ getTestResultsByProject(projectId: number, limit?: number): TestResult[];
76
93
  close(): void;
77
94
  }
78
95
  export declare function getDatabaseManager(): DatabaseManager;
@@ -40,7 +40,7 @@ const fs = __importStar(require("fs"));
40
40
  const child_process_1 = require("child_process");
41
41
  class DatabaseManager {
42
42
  apiBaseUrl;
43
- defaultPort = 3001;
43
+ defaultPort = 38124;
44
44
  constructor() {
45
45
  // Read API port from file, or use default
46
46
  const dataDir = path.join(os.homedir(), '.projax');
@@ -232,6 +232,34 @@ class DatabaseManager {
232
232
  getAllSettings() {
233
233
  return this.request('/settings');
234
234
  }
235
+ // Test Result operations
236
+ addTestResult(projectId, scriptName, passed, failed, skipped = 0, total = passed + failed + skipped, duration = null, coverage = null, framework = null, rawOutput = null) {
237
+ return this.request(`/projects/${projectId}/test-results`, {
238
+ method: 'POST',
239
+ body: JSON.stringify({
240
+ scriptName,
241
+ passed,
242
+ failed,
243
+ skipped,
244
+ total,
245
+ duration,
246
+ coverage,
247
+ framework,
248
+ rawOutput,
249
+ }),
250
+ });
251
+ }
252
+ getLatestTestResult(projectId) {
253
+ try {
254
+ return this.request(`/projects/${projectId}/test-results/latest`);
255
+ }
256
+ catch (error) {
257
+ return null;
258
+ }
259
+ }
260
+ getTestResultsByProject(projectId, limit = 10) {
261
+ return this.request(`/projects/${projectId}/test-results?limit=${limit}`);
262
+ }
235
263
  close() {
236
264
  // No-op for API client
237
265
  }
@@ -36,6 +36,20 @@ export interface ProjectPort {
36
36
  last_detected: number;
37
37
  created_at: number;
38
38
  }
39
+ export interface TestResult {
40
+ id: number;
41
+ project_id: number;
42
+ script_name: string;
43
+ framework: string | null;
44
+ passed: number;
45
+ failed: number;
46
+ skipped: number;
47
+ total: number;
48
+ duration: number | null;
49
+ coverage: number | null;
50
+ timestamp: number;
51
+ raw_output: string | null;
52
+ }
39
53
  type ScanResponse = {
40
54
  project: Project;
41
55
  testsFound: number;
@@ -73,6 +87,9 @@ declare class DatabaseManager {
73
87
  getSetting(key: string): string | null;
74
88
  setSetting(key: string, value: string): void;
75
89
  getAllSettings(): Record<string, string>;
90
+ addTestResult(projectId: number, scriptName: string, passed: number, failed: number, skipped?: number, total?: number, duration?: number | null, coverage?: number | null, framework?: string | null, rawOutput?: string | null): TestResult;
91
+ getLatestTestResult(projectId: number): TestResult | null;
92
+ getTestResultsByProject(projectId: number, limit?: number): TestResult[];
76
93
  close(): void;
77
94
  }
78
95
  export declare function getDatabaseManager(): DatabaseManager;
@@ -40,7 +40,7 @@ const fs = __importStar(require("fs"));
40
40
  const child_process_1 = require("child_process");
41
41
  class DatabaseManager {
42
42
  apiBaseUrl;
43
- defaultPort = 3001;
43
+ defaultPort = 38124;
44
44
  constructor() {
45
45
  // Read API port from file, or use default
46
46
  const dataDir = path.join(os.homedir(), '.projax');
@@ -232,6 +232,34 @@ class DatabaseManager {
232
232
  getAllSettings() {
233
233
  return this.request('/settings');
234
234
  }
235
+ // Test Result operations
236
+ addTestResult(projectId, scriptName, passed, failed, skipped = 0, total = passed + failed + skipped, duration = null, coverage = null, framework = null, rawOutput = null) {
237
+ return this.request(`/projects/${projectId}/test-results`, {
238
+ method: 'POST',
239
+ body: JSON.stringify({
240
+ scriptName,
241
+ passed,
242
+ failed,
243
+ skipped,
244
+ total,
245
+ duration,
246
+ coverage,
247
+ framework,
248
+ rawOutput,
249
+ }),
250
+ });
251
+ }
252
+ getLatestTestResult(projectId) {
253
+ try {
254
+ return this.request(`/projects/${projectId}/test-results/latest`);
255
+ }
256
+ catch (error) {
257
+ return null;
258
+ }
259
+ }
260
+ getTestResultsByProject(projectId, limit = 10) {
261
+ return this.request(`/projects/${projectId}/test-results?limit=${limit}`);
262
+ }
235
263
  close() {
236
264
  // No-op for API client
237
265
  }