testeranto 0.159.0 → 0.161.0

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 (60) hide show
  1. package/dist/common/src/PM/PM_WithEslintAndTsc.js +8 -1
  2. package/dist/common/src/lib/baseBuilder.test/baseBuilder.test.implementation.js +13 -1
  3. package/dist/common/src/lib/baseBuilder.test/baseBuilder.test.mock.js +4 -1
  4. package/dist/common/src/lib/baseBuilder.test/baseBuilder.test.specification.js +6 -1
  5. package/dist/common/src/lib/classBuilder.test/classBuilder.test.implementation.js +9 -8
  6. package/dist/common/tsconfig.common.tsbuildinfo +1 -1
  7. package/dist/module/src/PM/PM_WithEslintAndTsc.js +8 -1
  8. package/dist/module/src/ProjectPage.js +128 -21
  9. package/dist/module/src/ProjectsPage.js +15 -9
  10. package/dist/module/src/TestPage.js +13 -1
  11. package/dist/module/src/lib/baseBuilder.test/baseBuilder.test.implementation.js +13 -1
  12. package/dist/module/src/lib/baseBuilder.test/baseBuilder.test.mock.js +4 -1
  13. package/dist/module/src/lib/baseBuilder.test/baseBuilder.test.specification.js +6 -1
  14. package/dist/module/src/lib/classBuilder.test/classBuilder.test.implementation.js +9 -8
  15. package/dist/module/tsconfig.module.tsbuildinfo +1 -1
  16. package/dist/prebuild/App.js +814 -376
  17. package/dist/prebuild/run.mjs +8 -1
  18. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  19. package/notify.sh +47 -0
  20. package/package.json +1 -1
  21. package/src/PM/PM_WithEslintAndTsc.ts +8 -1
  22. package/src/ProjectPage.tsx +204 -38
  23. package/src/ProjectsPage.tsx +23 -19
  24. package/src/TestPage.tsx +12 -1
  25. package/src/lib/baseBuilder.test/baseBuilder.test.implementation.ts +15 -9
  26. package/src/lib/baseBuilder.test/baseBuilder.test.mock.ts +4 -1
  27. package/src/lib/baseBuilder.test/baseBuilder.test.specification.ts +6 -1
  28. package/src/lib/classBuilder.test/classBuilder.test.implementation.ts +8 -5
  29. package/testeranto/App.js +814 -376
  30. package/testeranto/bundles/node/allTests/metafile.json +15 -10
  31. package/testeranto/bundles/node/allTests/src/lib/baseBuilder.test/baseBuilder.test.node.mjs +22 -5
  32. package/testeranto/bundles/node/allTests/src/lib/classBuilder.test/classBuilder.test.mjs +7 -7
  33. package/testeranto/bundles/pure/allTests/metafile.json +7 -7
  34. package/testeranto/bundles/pure/allTests/src/lib/baseBuilder.test/baseBuilder.test.pure.mjs +22 -5
  35. package/testeranto/bundles/web/allTests/metafile.json +7 -7
  36. package/testeranto/bundles/web/allTests/src/lib/baseBuilder.test/baseBuilder.test.web.mjs +22 -5
  37. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.node/node/lint_errors.txt +4 -4
  38. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.node/node/message.txt +2 -1
  39. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.node/node/prompt.txt +5 -0
  40. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.node/node/type_errors.txt +22 -19
  41. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.pure/pure/lint_errors.txt +4 -4
  42. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.pure/pure/message.txt +2 -1
  43. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.pure/pure/prompt.txt +5 -0
  44. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.pure/pure/type_errors.txt +22 -19
  45. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.web/web/lint_errors.txt +4 -4
  46. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.web/web/logs.txt +1 -9
  47. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.web/web/message.txt +2 -1
  48. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.web/web/prompt.txt +5 -0
  49. package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.web/web/type_errors.txt +22 -19
  50. package/testeranto/reports/allTests/src/lib/classBuilder.test/classBuilder.test/node/bdd_errors.txt +1 -0
  51. package/testeranto/reports/allTests/src/lib/classBuilder.test/classBuilder.test/node/logs.txt +85 -23
  52. package/testeranto/reports/allTests/src/lib/classBuilder.test/classBuilder.test/node/message.txt +2 -1
  53. package/testeranto/reports/allTests/src/lib/classBuilder.test/classBuilder.test/node/prompt.txt +5 -0
  54. package/testeranto/reports/allTests/src/lib/classBuilder.test/classBuilder.test/node/tests.json +24 -0
  55. package/testeranto/reports/allTests/src/lib/classBuilder.test/classBuilder.test/node/type_errors.txt +13 -9
  56. package/testeranto/reports/allTests/summary.json +5 -5
  57. package/dist/module/src/BuildLogsPage.js +0 -99
  58. package/dist/module/src/Project.js +0 -332
  59. package/src/BuildLogsPage.tsx +0 -108
  60. package/src/Project.tsx +0 -375
package/notify.sh ADDED
@@ -0,0 +1,47 @@
1
+ #!/bin/zsh
2
+
3
+ # NOTIFICATION SYSTEM DOCUMENTATION
4
+ # ================================
5
+ # This script plays system sounds for CI/CD notifications. The AI assistant uses it to:
6
+ # 1. Alert when human input is needed
7
+ # 2. Signal completion of tasks
8
+ # 3. Indicate errors/warnings
9
+
10
+ # USAGE:
11
+ # ./notify.sh [sound] [volume]
12
+ # sound: Any from the list below (default: Ping)
13
+ # volume: 0-1 (default: 1)
14
+
15
+ # AVAILABLE SOUNDS:
16
+ # Basso - Low pitch error sound (use for critical failures)
17
+ # Blow - Quick negative sound
18
+ # Bottle - Light glass ping
19
+ # Frog - Unique attention-grabber
20
+ # Funk - Positive completion sound
21
+ # Glass - Clean success notification
22
+ # Hero - Triumphant completion
23
+ # Morse - For process-related events
24
+ # Ping - Default neutral notification
25
+ # Pop - Light positive sound
26
+ # Purr - Subtle background notification
27
+ # Sosumi - Urgent alert sound
28
+ # Submarine- Deep warning sound
29
+ # Tink - High-pitched attention sound
30
+
31
+ # STANDARD USAGE PATTERNS:
32
+ # [ACTION NEEDED] -> ./notify.sh Sosumi 0.8
33
+ # [COMPLETED] -> ./notify.sh Glass 0.5
34
+ # [ERROR] -> ./notify.sh Basso 1
35
+ # [WARNING] -> ./notify.sh Tink 0.6
36
+ # [WORKING] -> ./notify.sh Morse 0.3
37
+
38
+ SOUND=${1:-Ping}
39
+ VOLUME=${2:-1} # Range: 0 (silent) to 1 (full volume)
40
+
41
+ # Play the specified system sound
42
+ afplay -v $VOLUME /System/Library/Sounds/$SOUND.aiff
43
+
44
+ # Exit codes:
45
+ # 0 - Success
46
+ # 1 - Invalid sound specified
47
+ # 2 - Volume out of range
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "testeranto",
3
3
  "description": "the AI powered BDD test framework for typescript projects",
4
- "version": "0.159.0",
4
+ "version": "0.161.0",
5
5
  "engines": {
6
6
  "node": "18.18.0"
7
7
  },
@@ -210,6 +210,11 @@ ${addableFiles
210
210
  })
211
211
  .join("\n")}
212
212
 
213
+ /read node_modules/testeranto/docs/index.md
214
+ /read node_modules/testeranto/docs/style.md
215
+ /read node_modules/testeranto/docs/testing.ai.txt
216
+ /read node_modules/testeranto/src/CoreTypes.ts
217
+
213
218
  /read ${testPaths}
214
219
  /read ${logPath}
215
220
  /read ${typePath}
@@ -219,7 +224,9 @@ ${addableFiles
219
224
 
220
225
  fs.writeFileSync(
221
226
  messagePath,
222
- `Fix the failing tests described in ${testPaths} and ${logPath}. DO NOT refactor beyond what is necessary. Always prefer minimal changes, focusing mostly on keeping the BDD tests passing`
227
+ `
228
+ Fix the failing tests described in ${testPaths} and ${logPath}. Focus on the bdd tests before all other concerns. You may add any debugging you think is necessary.
229
+ `
223
230
  );
224
231
 
225
232
  this.summary[
@@ -1,5 +1,185 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { Navbar, Nav, Tab, Container, Alert, Badge, Table, Button } from 'react-bootstrap';
2
+ import { Tab } from 'react-bootstrap';
3
+ import { Card, ListGroup, Badge } from 'react-bootstrap';
4
+
5
+ const BuildLogViewer = ({ logs, runtime }: { logs: any, runtime: string }) => {
6
+ if (!logs) return <Alert variant="info">Loading {runtime.toLowerCase()} build logs...</Alert>;
7
+
8
+ const hasErrors = logs.errors?.length > 0;
9
+ const hasWarnings = logs.warnings?.length > 0;
10
+ const [activeTab, setActiveTab] = useState('summary');
11
+
12
+ return (
13
+ <div>
14
+ <Tab.Container activeKey={activeTab} onSelect={(k) => setActiveTab(k || 'summary')}>
15
+ <Nav variant="tabs" className="mb-3">
16
+ <Nav.Item>
17
+ <Nav.Link eventKey="summary">
18
+ Build Summary
19
+ </Nav.Link>
20
+ </Nav.Item>
21
+ <Nav.Item>
22
+ <Nav.Link eventKey="warnings">
23
+ {hasWarnings ? `⚠️ Warnings (${logs.warnings.length})` : 'Warnings'}
24
+ </Nav.Link>
25
+ </Nav.Item>
26
+ <Nav.Item>
27
+ <Nav.Link eventKey="errors">
28
+ {hasErrors ? `❌ Errors (${logs.errors.length})` : 'Errors'}
29
+ </Nav.Link>
30
+ </Nav.Item>
31
+ </Nav>
32
+
33
+ <Tab.Content>
34
+ <Tab.Pane eventKey="summary">
35
+ <Card>
36
+ <Card.Header className="d-flex justify-content-between align-items-center">
37
+ <h5>Build Summary</h5>
38
+ <div>
39
+ {hasErrors && (
40
+ <Badge bg="danger" className="me-2">
41
+ {logs.errors.length} Error{logs.errors.length !== 1 ? 's' : ''}
42
+ </Badge>
43
+ )}
44
+ {hasWarnings && (
45
+ <Badge bg="warning" text="dark">
46
+ {logs.warnings.length} Warning{logs.warnings.length !== 1 ? 's' : ''}
47
+ </Badge>
48
+ )}
49
+ {!hasErrors && !hasWarnings && (
50
+ <Badge bg="success">Build Successful</Badge>
51
+ )}
52
+ </div>
53
+ </Card.Header>
54
+ <Card.Body>
55
+ <div className="mb-3">
56
+ <h6>Input Files ({Object.keys(logs.metafile?.inputs || {}).length})</h6>
57
+ <ListGroup className="max-h-200 overflow-auto">
58
+ {Object.keys(logs.metafile?.inputs || {}).map((file) => (
59
+ <ListGroup.Item key={file} className="py-2">
60
+ <code>{file}</code>
61
+ <div className="text-muted small">
62
+ {logs.metafile.inputs[file].bytes} bytes
63
+ </div>
64
+ </ListGroup.Item>
65
+ ))}
66
+ </ListGroup>
67
+ </div>
68
+ <div>
69
+ <h6>Output Files ({Object.keys(logs.metafile?.outputs || {}).length})</h6>
70
+ <ListGroup className="max-h-200 overflow-auto">
71
+ {Object.keys(logs.metafile?.outputs || {}).map((file) => (
72
+ <ListGroup.Item key={file} className="py-2">
73
+ <code>{file}</code>
74
+ <div className="text-muted small">
75
+ {logs.metafile.outputs[file].bytes} bytes
76
+ {logs.metafile.outputs[file].entryPoint && (
77
+ <span className="ms-2 badge bg-info">Entry Point</span>
78
+ )}
79
+ </div>
80
+ </ListGroup.Item>
81
+ ))}
82
+ </ListGroup>
83
+ </div>
84
+ </Card.Body>
85
+ </Card>
86
+
87
+ </Tab.Pane>
88
+ <Tab.Pane eventKey="warnings">
89
+ {hasWarnings ? (
90
+ <Card className="border-warning">
91
+ <Card.Header className="bg-warning text-white d-flex justify-content-between align-items-center">
92
+ <span>Build Warnings ({logs.warnings.length})</span>
93
+ <Badge bg="light" text="dark">
94
+ {new Date().toLocaleString()}
95
+ </Badge>
96
+ </Card.Header>
97
+ <Card.Body className="p-0">
98
+ <ListGroup variant="flush">
99
+ {logs.warnings.map((warn: any, i: number) => (
100
+ <ListGroup.Item key={i} className="text-warning">
101
+ <div className="d-flex justify-content-between">
102
+ <strong>
103
+ {warn.location?.file || 'Unknown file'}
104
+ {warn.location?.line && `:${warn.location.line}`}
105
+ </strong>
106
+ <small className="text-muted">
107
+ {warn.pluginName ? `[${warn.pluginName}]` : ''}
108
+ </small>
109
+ </div>
110
+ <div className="mt-1">
111
+ <pre className="mb-0 p-2 bg-light rounded">
112
+ {warn.text || warn.message || JSON.stringify(warn)}
113
+ </pre>
114
+ </div>
115
+ {warn.detail && (
116
+ <div className="mt-1 small text-muted">
117
+ <pre className="mb-0 p-2 bg-light rounded">
118
+ {warn.detail}
119
+ </pre>
120
+ </div>
121
+ )}
122
+ </ListGroup.Item>
123
+ ))}
124
+ </ListGroup>
125
+ </Card.Body>
126
+ </Card>
127
+ ) : (
128
+ <Alert variant="info">No warnings found</Alert>
129
+ )}
130
+ </Tab.Pane>
131
+ <Tab.Pane eventKey="errors">
132
+ {hasErrors ? (
133
+ <Card className="border-danger">
134
+ <Card.Header className="bg-danger text-white d-flex justify-content-between align-items-center">
135
+ <span>Build Errors ({logs.errors.length})</span>
136
+ <Badge bg="light" text="dark">
137
+ {new Date().toLocaleString()}
138
+ </Badge>
139
+ </Card.Header>
140
+ <Card.Body className="p-0">
141
+ <ListGroup variant="flush">
142
+ {logs.errors.map((err: any, i: number) => (
143
+ <ListGroup.Item key={i} className="text-danger">
144
+ <div className="d-flex justify-content-between">
145
+ <strong>
146
+ {err.location?.file || 'Unknown file'}
147
+ {err.location?.line && `:${err.location.line}`}
148
+ </strong>
149
+ <small className="text-muted">
150
+ {err.pluginName ? `[${err.pluginName}]` : ''}
151
+ </small>
152
+ </div>
153
+ <div className="mt-1">
154
+ <pre className="mb-0 p-2 bg-light rounded">
155
+ {err.text || err.message || JSON.stringify(err)}
156
+ </pre>
157
+ </div>
158
+ {err.detail && (
159
+ <div className="mt-1 small text-muted">
160
+ <pre className="mb-0 p-2 bg-light rounded">
161
+ {err.detail}
162
+ </pre>
163
+ </div>
164
+ )}
165
+ </ListGroup.Item>
166
+ ))}
167
+ </ListGroup>
168
+ </Card.Body>
169
+ </Card>
170
+ ) : (
171
+ <Alert variant="success">
172
+ <h5>No Errors Found</h5>
173
+ <p className="mb-0">The build completed without any errors.</p>
174
+ </Alert>
175
+ )}
176
+ </Tab.Pane>
177
+ </Tab.Content>
178
+ </Tab.Container>
179
+ </div>
180
+ );
181
+ };
182
+ import { Navbar, Nav, Tab, Container, Alert, Badge, Table, Button, Card } from 'react-bootstrap';
3
183
  import { useParams, useNavigate, useLocation, Link } from 'react-router-dom';
4
184
 
5
185
  import { ISummary } from './Types';
@@ -95,24 +275,37 @@ export const ProjectPage = () => {
95
275
  title={projectName}
96
276
  backLink="/"
97
277
  navItems={[
98
- { to: `#tests`, label: 'Tests', active: route === 'tests' },
278
+ {
279
+ to: `#tests`,
280
+ label: Object.values(summary).some(t => t.runTimeErrors > 0) ? '❌ Tests' :
281
+ Object.values(summary).some(t => t.typeErrors > 0 || t.staticErrors > 0) ? '⚠️ Tests' : '✅ Tests',
282
+ active: route === 'tests',
283
+ className: Object.values(summary).some(t => t.runTimeErrors > 0) ? 'text-danger fw-bold' :
284
+ Object.values(summary).some(t => t.typeErrors > 0 || t.staticErrors > 0) ? 'text-warning fw-bold' : ''
285
+ },
99
286
  {
100
287
  to: `#node`,
101
- label: nodeLogs?.errors?.length ? '❌ Node Build' : '✅ Node Build',
288
+ label: nodeLogs?.errors?.length ? '❌ Node Build' :
289
+ nodeLogs?.warnings?.length ? '⚠️ Node Build' : 'Node Build',
102
290
  active: route === 'node',
103
- className: nodeLogs?.errors?.length ? 'text-danger fw-bold' : 'text-success fw-bold'
291
+ className: nodeLogs?.errors?.length ? 'text-danger fw-bold' :
292
+ nodeLogs?.warnings?.length ? 'text-warning fw-bold' : ''
104
293
  },
105
294
  {
106
295
  to: `#web`,
107
- label: webLogs?.errors?.length ? '❌ Web Build' : '✅ Web Build',
296
+ label: webLogs?.errors?.length ? '❌ Web Build' :
297
+ webLogs?.warnings?.length ? '⚠️ Web Build' : 'Web Build',
108
298
  active: route === 'web',
109
- className: webLogs?.errors?.length ? 'text-danger fw-bold' : 'text-success fw-bold'
299
+ className: webLogs?.errors?.length ? 'text-danger fw-bold' :
300
+ webLogs?.warnings?.length ? 'text-warning fw-bold' : ''
110
301
  },
111
302
  {
112
303
  to: `#pure`,
113
- label: pureLogs?.errors?.length ? '❌ Pure Build' : '✅ Pure Build',
304
+ label: pureLogs?.errors?.length ? '❌ Pure Build' :
305
+ pureLogs?.warnings?.length ? '⚠️ Pure Build' : 'Pure Build',
114
306
  active: route === 'pure',
115
- className: pureLogs?.errors?.length ? 'text-danger fw-bold' : 'text-success fw-bold'
307
+ className: pureLogs?.errors?.length ? 'text-danger fw-bold' :
308
+ pureLogs?.warnings?.length ? 'text-warning fw-bold' : ''
116
309
  },
117
310
  ]}
118
311
  />
@@ -129,7 +322,6 @@ export const ProjectPage = () => {
129
322
  <thead>
130
323
  <tr>
131
324
  <th>Test</th>
132
- <th>Build logs</th>
133
325
  <th>BDD Errors</th>
134
326
  <th>Type Errors</th>
135
327
  <th>Lint Errors</th>
@@ -147,11 +339,6 @@ export const ProjectPage = () => {
147
339
  {testName}
148
340
  </a>
149
341
  </td>
150
- <td>
151
- <a href={`#/projects/${projectName}#${runTime}`}>
152
- {runTime} {testData.runTimeErrors === 0 ? '✅' : '❌'}
153
- </a>
154
- </td>
155
342
  <td>
156
343
  <a href={`#/projects/${projectName}/tests/${encodeURIComponent(testName)}/${runTime}#results`}>
157
344
  {testData.runTimeErrors === 0 ? '✅ Passed' :
@@ -176,34 +363,13 @@ export const ProjectPage = () => {
176
363
  </Table>
177
364
  </Tab.Pane>
178
365
  <Tab.Pane eventKey="node">
179
- <ul>
180
- {nodeLogs.errors.map((err, i) => (
181
- <li key={i}>{err.text || err.message || JSON.stringify(err)}</li>
182
- ))}
183
- </ul>
184
- <pre className="bg-dark text-white p-3">
185
- {nodeLogs ? JSON.stringify(nodeLogs, null, 2) : 'Loading node build logs...'}
186
- </pre>
366
+ <BuildLogViewer logs={nodeLogs} runtime="Node" />
187
367
  </Tab.Pane>
188
368
  <Tab.Pane eventKey="web">
189
- <ul>
190
- {webLogs.errors.map((err, i) => (
191
- <li key={i}>{err.text || err.message || JSON.stringify(err)}</li>
192
- ))}
193
- </ul>
194
- <pre className="bg-dark text-white p-3">
195
- {webLogs ? JSON.stringify(webLogs, null, 2) : 'Loading web build logs...'}
196
- </pre>
369
+ <BuildLogViewer logs={webLogs} runtime="Web" />
197
370
  </Tab.Pane>
198
371
  <Tab.Pane eventKey="pure">
199
- <ul>
200
- {pureLogs.errors.map((err, i) => (
201
- <li key={i}>{err.text || err.message || JSON.stringify(err)}</li>
202
- ))}
203
- </ul>
204
- <pre className="bg-dark text-white p-3">
205
- {pureLogs ? JSON.stringify(pureLogs, null, 2) : 'Loading pure build logs...'}
206
- </pre>
372
+ <BuildLogViewer logs={pureLogs} runtime="Pure" />
207
373
  </Tab.Pane>
208
374
  </Tab.Content>
209
375
  </Tab.Container>
@@ -54,9 +54,9 @@ export const ProjectsPage = () => {
54
54
  return {
55
55
  name,
56
56
  testCount: Object.keys(summary).length,
57
- nodeStatus: nodeData.errors?.length ? 'failed' : 'success',
58
- webStatus: webData.errors?.length ? 'failed' : 'success',
59
- pureStatus: pureData.errors?.length ? 'failed' : 'success',
57
+ nodeStatus: nodeData.errors?.length ? 'failed' : nodeData.warnings?.length ? 'warning' : 'success',
58
+ webStatus: webData.errors?.length ? 'failed' : webData.warnings?.length ? 'warning' : 'success',
59
+ pureStatus: pureData.errors?.length ? 'failed' : pureData.warnings?.length ? 'warning' : 'success',
60
60
  config: Object.keys(configData).length,
61
61
  };
62
62
  })
@@ -77,6 +77,7 @@ export const ProjectsPage = () => {
77
77
  switch (status) {
78
78
  case 'success': return '✅';
79
79
  case 'failed': return '❌';
80
+ case 'warning': return '⚠️';
80
81
  default: return '❓';
81
82
  }
82
83
  };
@@ -112,11 +113,17 @@ export const ProjectsPage = () => {
112
113
  <div style={{ maxHeight: '200px', overflowY: 'auto' }}>
113
114
  {summaries[project.name] ? (
114
115
  Object.keys(summaries[project.name]).map(testName => {
116
+ const testData = summaries[project.name][testName];
115
117
  const runTime = configs[project.name].tests.find((t) => t[0] === testName)[1];
118
+ const hasRuntimeErrors = testData.runTimeErrors > 0;
119
+ const hasStaticErrors = testData.typeErrors > 0 || testData.staticErrors > 0;
116
120
 
117
121
  return (
118
122
  <div key={testName}>
119
- <a href={`#/projects/${project.name}/tests/${encodeURIComponent(testName)}/${runTime}`}>
123
+ <a
124
+ href={`#/projects/${project.name}/tests/${encodeURIComponent(testName)}/${runTime}`}
125
+ >
126
+ {hasRuntimeErrors ? '❌ ' : hasStaticErrors ? '⚠️ ' : ''}
120
127
  {testName.split('/').pop()}
121
128
  </a>
122
129
  </div>
@@ -128,27 +135,24 @@ export const ProjectsPage = () => {
128
135
  </div>
129
136
  </td>
130
137
  <td>
131
- <a href={`#/projects/${project.name}#node`}>
132
- {getStatusIcon(project.nodeStatus)}
133
- {project.nodeStatus === 'failed' && (
134
- <Badge bg="danger" className="ms-2">Failed</Badge>
135
- )}
138
+ <a
139
+ href={`#/projects/${project.name}#node`}
140
+ >
141
+ {getStatusIcon(project.nodeStatus)} Node build logs
136
142
  </a>
137
143
  </td>
138
144
  <td>
139
- <a href={`#/projects/${project.name}#web`}>
140
- {getStatusIcon(project.webStatus)}
141
- {project.webStatus === 'failed' && (
142
- <Badge bg="danger" className="ms-2">Failed</Badge>
143
- )}
145
+ <a
146
+ href={`#/projects/${project.name}#web`}
147
+ >
148
+ {getStatusIcon(project.webStatus)} Web build logs
144
149
  </a>
145
150
  </td>
146
151
  <td>
147
- <a href={`#/projects/${project.name}#pure`}>
148
- {getStatusIcon(project.pureStatus)}
149
- {project.pureStatus === 'failed' && (
150
- <Badge bg="danger" className="ms-2">Failed</Badge>
151
- )}
152
+ <a
153
+ href={`#/projects/${project.name}#pure`}
154
+ >
155
+ {getStatusIcon(project.pureStatus)} Pure build logs
152
156
  </a>
153
157
  </td>
154
158
  </tr>
package/src/TestPage.tsx CHANGED
@@ -144,7 +144,18 @@ export const TestPage = () => {
144
144
  rightContent={
145
145
  <Button
146
146
  variant="info"
147
- onClick={() => alert("Magic robot activated!")}
147
+ onClick={async () => {
148
+ try {
149
+ const promptPath = `testeranto/reports/${projectName}/${testPath.split('.').slice(0, -1).join('.')}/${runtime}/prompt.txt`;
150
+ const messagePath = `testeranto/reports/${projectName}/${testPath.split('.').slice(0, -1).join('.')}/${runtime}/message.txt`;
151
+ const command = `aider --load ${promptPath} --message-file ${messagePath}`;
152
+ await navigator.clipboard.writeText(command);
153
+ alert("Copied aider command to clipboard!");
154
+ } catch (err) {
155
+ alert("Failed to copy command to clipboard");
156
+ console.error("Copy failed:", err);
157
+ }
158
+ }}
148
159
  className="ms-2"
149
160
  >
150
161
  🤖
@@ -15,16 +15,22 @@ export const implementation: ITestImplementation<I, O, {}> = {
15
15
 
16
16
  givens: {
17
17
  Default: () => {
18
- return new MockBaseBuilder(
19
- {},
20
- {},
21
- {},
22
- {},
23
- {},
24
- {},
25
- { ports: [] },
26
- () => []
18
+ const builder = new MockBaseBuilder(
19
+ {}, // input
20
+ {}, // suitesOverrides
21
+ {}, // givenOverrides
22
+ {}, // whenOverrides
23
+ {}, // thenOverrides
24
+ { ports: [0] }, // testResourceRequirement
25
+ () => [] // testSpecification
27
26
  );
27
+
28
+ // Initialize required arrays
29
+ builder.artifacts = [];
30
+ builder.testJobs = [];
31
+ builder.specs = [];
32
+
33
+ return builder;
28
34
  },
29
35
  WithCustomInput: (input: any) => {
30
36
  return new MockBaseBuilder(
@@ -40,9 +40,12 @@ export class MockBaseBuilder<
40
40
  givenOverrides: Record<keyof GivenExtensions, IGivenKlasser<I>> = {} as any,
41
41
  whenOverrides: Record<keyof WhenExtensions, IWhenKlasser<I>> = {} as any,
42
42
  thenOverrides: Record<keyof ThenExtensions, IThenKlasser<I>> = {} as any,
43
- testResourceRequirement: ITTestResourceRequest = { ports: [] },
43
+ testResourceRequirement: ITTestResourceRequest = { ports: [0] },
44
44
  testSpecification: ITestSpecification<I, O> = () => []
45
45
  ) {
46
+ // Initialize required arrays
47
+ this.artifacts = [];
48
+ this.testJobs = [];
46
49
  super(
47
50
  input,
48
51
  suitesOverrides,
@@ -15,7 +15,12 @@ export const specification: ITestSpecification<I, O> = (
15
15
  testInitialization: Given.Default(
16
16
  ["BaseBuilder should initialize correctly"],
17
17
  [],
18
- [Then.initializedProperly()]
18
+ [
19
+ Then.initializedProperly(),
20
+ Then.artifactsTracked(),
21
+ Then.jobsCreated(),
22
+ Then.specsGenerated()
23
+ ]
19
24
  ),
20
25
  testSpecsGeneration: Given.Default(
21
26
  ["BaseBuilder should generate specs from test specification"],
@@ -4,6 +4,7 @@ import { PassThrough } from "stream";
4
4
 
5
5
  import { ITestImplementation, ITestSpecification } from "../../CoreTypes";
6
6
  import mock from "./mock";
7
+ import { TestClassBuilder } from "../classBuilder";
7
8
 
8
9
  import { I, O, M } from "./classBuilder.test.types";
9
10
 
@@ -19,18 +20,19 @@ export const implementation: ITestImplementation<I, O, M> = {
19
20
 
20
21
  givens: {
21
22
  Default: () => {
22
- return new mock(
23
+ console.log('Creating default test builder instance');
24
+ const builder = new mock(
23
25
  implementation, // Use the current implementation
24
26
  specification, // Use the current specification
25
27
  {}, // Default input
26
28
  MockSuite,
27
- // class {}, // suiteKlasser
28
29
  class {}, // givenKlasser
29
30
  class {}, // whenKlasser
30
31
  class {}, // thenKlasser
31
- class {}, // checkKlasser
32
32
  { ports: [] } // Default resource requirements
33
33
  );
34
+ console.log('Builder created:', builder);
35
+ return builder;
34
36
  },
35
37
  WithCustomInput: (input: any) => {
36
38
  return new mock(
@@ -110,8 +112,9 @@ export const implementation: ITestImplementation<I, O, M> = {
110
112
 
111
113
  thens: {
112
114
  initializedProperly: () => (builder: any) => {
113
- if (!(builder instanceof TestClassBuilder)) {
114
- throw new Error("Builder was not properly initialized");
115
+ console.log('Checking builder initialization:', builder);
116
+ if (!(builder instanceof mock)) {
117
+ throw new Error(`Builder was not properly initialized. Expected mock instance but got ${builder?.constructor?.name}`);
115
118
  }
116
119
  return builder;
117
120
  },