testeranto 0.158.1 → 0.160.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.
@@ -5,11 +5,11 @@ export default async () => {
5
5
  `testeranto/`,
6
6
  `testeranto/bundles/`,
7
7
  `testeranto/bundles/node`,
8
- `testeranto/bundles/pure`,
9
8
  `testeranto/bundles/web`,
10
- `testeranto/externalTests/`,
11
- `testeranto/features/`,
9
+ `testeranto/bundles/pure`,
12
10
  `testeranto/reports/`,
11
+ `testeranto/features/`,
12
+ `testeranto/externalTests/`,
13
13
  ].forEach((f) => {
14
14
  try {
15
15
  fs.mkdirSync(`${process.cwd()}/${f}`);
@@ -1,10 +1,113 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { Tab, Container, Alert, Table } from 'react-bootstrap';
2
+ import { Tab } from 'react-bootstrap';
3
+ import { Card, ListGroup, Badge } from 'react-bootstrap';
4
+ const BuildLogViewer = ({ logs, runtime }) => {
5
+ var _a, _b, _c, _d, _e, _f;
6
+ if (!logs)
7
+ return React.createElement(Alert, { variant: "info" },
8
+ "Loading ",
9
+ runtime.toLowerCase(),
10
+ " build logs...");
11
+ const hasErrors = ((_a = logs.errors) === null || _a === void 0 ? void 0 : _a.length) > 0;
12
+ const hasWarnings = ((_b = logs.warnings) === null || _b === void 0 ? void 0 : _b.length) > 0;
13
+ const [activeTab, setActiveTab] = useState('summary');
14
+ return (React.createElement("div", null,
15
+ React.createElement(Tab.Container, { activeKey: activeTab, onSelect: (k) => setActiveTab(k || 'summary') },
16
+ React.createElement(Nav, { variant: "tabs", className: "mb-3" },
17
+ React.createElement(Nav.Item, null,
18
+ React.createElement(Nav.Link, { eventKey: "summary" }, "Build Summary")),
19
+ React.createElement(Nav.Item, null,
20
+ React.createElement(Nav.Link, { eventKey: "warnings" }, hasWarnings ? `⚠️ Warnings (${logs.warnings.length})` : 'Warnings')),
21
+ React.createElement(Nav.Item, null,
22
+ React.createElement(Nav.Link, { eventKey: "errors" }, hasErrors ? `❌ Errors (${logs.errors.length})` : 'Errors'))),
23
+ React.createElement(Tab.Content, null,
24
+ React.createElement(Tab.Pane, { eventKey: "summary" },
25
+ React.createElement(Card, null,
26
+ React.createElement(Card.Header, { className: "d-flex justify-content-between align-items-center" },
27
+ React.createElement("h5", null, "Build Summary"),
28
+ React.createElement("div", null,
29
+ hasErrors && (React.createElement(Badge, { bg: "danger", className: "me-2" },
30
+ logs.errors.length,
31
+ " Error",
32
+ logs.errors.length !== 1 ? 's' : '')),
33
+ hasWarnings && (React.createElement(Badge, { bg: "warning", text: "dark" },
34
+ logs.warnings.length,
35
+ " Warning",
36
+ logs.warnings.length !== 1 ? 's' : '')),
37
+ !hasErrors && !hasWarnings && (React.createElement(Badge, { bg: "success" }, "Build Successful")))),
38
+ React.createElement(Card.Body, null,
39
+ React.createElement("div", { className: "mb-3" },
40
+ React.createElement("h6", null,
41
+ "Input Files (",
42
+ Object.keys(((_c = logs.metafile) === null || _c === void 0 ? void 0 : _c.inputs) || {}).length,
43
+ ")"),
44
+ React.createElement(ListGroup, { className: "max-h-200 overflow-auto" }, Object.keys(((_d = logs.metafile) === null || _d === void 0 ? void 0 : _d.inputs) || {}).map((file) => (React.createElement(ListGroup.Item, { key: file, className: "py-2" },
45
+ React.createElement("code", null, file),
46
+ React.createElement("div", { className: "text-muted small" },
47
+ logs.metafile.inputs[file].bytes,
48
+ " bytes")))))),
49
+ React.createElement("div", null,
50
+ React.createElement("h6", null,
51
+ "Output Files (",
52
+ Object.keys(((_e = logs.metafile) === null || _e === void 0 ? void 0 : _e.outputs) || {}).length,
53
+ ")"),
54
+ React.createElement(ListGroup, { className: "max-h-200 overflow-auto" }, Object.keys(((_f = logs.metafile) === null || _f === void 0 ? void 0 : _f.outputs) || {}).map((file) => (React.createElement(ListGroup.Item, { key: file, className: "py-2" },
55
+ React.createElement("code", null, file),
56
+ React.createElement("div", { className: "text-muted small" },
57
+ logs.metafile.outputs[file].bytes,
58
+ " bytes",
59
+ logs.metafile.outputs[file].entryPoint && (React.createElement("span", { className: "ms-2 badge bg-info" }, "Entry Point"))))))))))),
60
+ React.createElement(Tab.Pane, { eventKey: "warnings" }, hasWarnings ? (React.createElement(Card, { className: "border-warning" },
61
+ React.createElement(Card.Header, { className: "bg-warning text-white d-flex justify-content-between align-items-center" },
62
+ React.createElement("span", null,
63
+ "Build Warnings (",
64
+ logs.warnings.length,
65
+ ")"),
66
+ React.createElement(Badge, { bg: "light", text: "dark" }, new Date().toLocaleString())),
67
+ React.createElement(Card.Body, { className: "p-0" },
68
+ React.createElement(ListGroup, { variant: "flush" }, logs.warnings.map((warn, i) => {
69
+ var _a, _b;
70
+ return (React.createElement(ListGroup.Item, { key: i, className: "text-warning" },
71
+ React.createElement("div", { className: "d-flex justify-content-between" },
72
+ React.createElement("strong", null,
73
+ ((_a = warn.location) === null || _a === void 0 ? void 0 : _a.file) || 'Unknown file',
74
+ ((_b = warn.location) === null || _b === void 0 ? void 0 : _b.line) && `:${warn.location.line}`),
75
+ React.createElement("small", { className: "text-muted" }, warn.pluginName ? `[${warn.pluginName}]` : '')),
76
+ React.createElement("div", { className: "mt-1" },
77
+ React.createElement("pre", { className: "mb-0 p-2 bg-light rounded" }, warn.text || warn.message || JSON.stringify(warn))),
78
+ warn.detail && (React.createElement("div", { className: "mt-1 small text-muted" },
79
+ React.createElement("pre", { className: "mb-0 p-2 bg-light rounded" }, warn.detail)))));
80
+ }))))) : (React.createElement(Alert, { variant: "info" }, "No warnings found"))),
81
+ React.createElement(Tab.Pane, { eventKey: "errors" }, hasErrors ? (React.createElement(Card, { className: "border-danger" },
82
+ React.createElement(Card.Header, { className: "bg-danger text-white d-flex justify-content-between align-items-center" },
83
+ React.createElement("span", null,
84
+ "Build Errors (",
85
+ logs.errors.length,
86
+ ")"),
87
+ React.createElement(Badge, { bg: "light", text: "dark" }, new Date().toLocaleString())),
88
+ React.createElement(Card.Body, { className: "p-0" },
89
+ React.createElement(ListGroup, { variant: "flush" }, logs.errors.map((err, i) => {
90
+ var _a, _b;
91
+ return (React.createElement(ListGroup.Item, { key: i, className: "text-danger" },
92
+ React.createElement("div", { className: "d-flex justify-content-between" },
93
+ React.createElement("strong", null,
94
+ ((_a = err.location) === null || _a === void 0 ? void 0 : _a.file) || 'Unknown file',
95
+ ((_b = err.location) === null || _b === void 0 ? void 0 : _b.line) && `:${err.location.line}`),
96
+ React.createElement("small", { className: "text-muted" }, err.pluginName ? `[${err.pluginName}]` : '')),
97
+ React.createElement("div", { className: "mt-1" },
98
+ React.createElement("pre", { className: "mb-0 p-2 bg-light rounded" }, err.text || err.message || JSON.stringify(err))),
99
+ err.detail && (React.createElement("div", { className: "mt-1 small text-muted" },
100
+ React.createElement("pre", { className: "mb-0 p-2 bg-light rounded" }, err.detail)))));
101
+ }))))) : (React.createElement(Alert, { variant: "success" },
102
+ React.createElement("h5", null, "No Errors Found"),
103
+ React.createElement("p", { className: "mb-0" }, "The build completed without any errors."))))))));
104
+ };
105
+ import { Nav, Container, Alert, Table } from 'react-bootstrap';
3
106
  import { useParams, useNavigate, useLocation } from 'react-router-dom';
4
107
  import "./TestReport.scss";
5
108
  import { NavBar } from './NavBar';
6
109
  export const ProjectPage = () => {
7
- var _a, _b, _c, _d, _e, _f;
110
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
8
111
  const [summary, setSummary] = useState(null);
9
112
  const [nodeLogs, setNodeLogs] = useState(null);
10
113
  const [webLogs, setWebLogs] = useState(null);
@@ -83,24 +186,37 @@ export const ProjectPage = () => {
83
186
  return React.createElement(Alert, { variant: "warning" }, "No data found for project");
84
187
  return (React.createElement(Container, { fluid: true },
85
188
  React.createElement(NavBar, { title: projectName, backLink: "/", navItems: [
86
- { to: `#tests`, label: 'Tests', active: route === 'tests' },
189
+ {
190
+ to: `#tests`,
191
+ label: Object.values(summary).some(t => t.runTimeErrors > 0) ? '❌ Tests' :
192
+ Object.values(summary).some(t => t.typeErrors > 0 || t.staticErrors > 0) ? '⚠️ Tests' : '✅ Tests',
193
+ active: route === 'tests',
194
+ className: Object.values(summary).some(t => t.runTimeErrors > 0) ? 'text-danger fw-bold' :
195
+ Object.values(summary).some(t => t.typeErrors > 0 || t.staticErrors > 0) ? 'text-warning fw-bold' : ''
196
+ },
87
197
  {
88
198
  to: `#node`,
89
- label: ((_a = nodeLogs === null || nodeLogs === void 0 ? void 0 : nodeLogs.errors) === null || _a === void 0 ? void 0 : _a.length) ? '❌ Node Build' : '✅ Node Build',
199
+ label: ((_a = nodeLogs === null || nodeLogs === void 0 ? void 0 : nodeLogs.errors) === null || _a === void 0 ? void 0 : _a.length) ? '❌ Node Build' :
200
+ ((_b = nodeLogs === null || nodeLogs === void 0 ? void 0 : nodeLogs.warnings) === null || _b === void 0 ? void 0 : _b.length) ? '⚠️ Node Build' : 'Node Build',
90
201
  active: route === 'node',
91
- className: ((_b = nodeLogs === null || nodeLogs === void 0 ? void 0 : nodeLogs.errors) === null || _b === void 0 ? void 0 : _b.length) ? 'text-danger fw-bold' : 'text-success fw-bold'
202
+ className: ((_c = nodeLogs === null || nodeLogs === void 0 ? void 0 : nodeLogs.errors) === null || _c === void 0 ? void 0 : _c.length) ? 'text-danger fw-bold' :
203
+ ((_d = nodeLogs === null || nodeLogs === void 0 ? void 0 : nodeLogs.warnings) === null || _d === void 0 ? void 0 : _d.length) ? 'text-warning fw-bold' : ''
92
204
  },
93
205
  {
94
206
  to: `#web`,
95
- label: ((_c = webLogs === null || webLogs === void 0 ? void 0 : webLogs.errors) === null || _c === void 0 ? void 0 : _c.length) ? '❌ Web Build' : '✅ Web Build',
207
+ label: ((_e = webLogs === null || webLogs === void 0 ? void 0 : webLogs.errors) === null || _e === void 0 ? void 0 : _e.length) ? '❌ Web Build' :
208
+ ((_f = webLogs === null || webLogs === void 0 ? void 0 : webLogs.warnings) === null || _f === void 0 ? void 0 : _f.length) ? '⚠️ Web Build' : 'Web Build',
96
209
  active: route === 'web',
97
- className: ((_d = webLogs === null || webLogs === void 0 ? void 0 : webLogs.errors) === null || _d === void 0 ? void 0 : _d.length) ? 'text-danger fw-bold' : 'text-success fw-bold'
210
+ className: ((_g = webLogs === null || webLogs === void 0 ? void 0 : webLogs.errors) === null || _g === void 0 ? void 0 : _g.length) ? 'text-danger fw-bold' :
211
+ ((_h = webLogs === null || webLogs === void 0 ? void 0 : webLogs.warnings) === null || _h === void 0 ? void 0 : _h.length) ? 'text-warning fw-bold' : ''
98
212
  },
99
213
  {
100
214
  to: `#pure`,
101
- label: ((_e = pureLogs === null || pureLogs === void 0 ? void 0 : pureLogs.errors) === null || _e === void 0 ? void 0 : _e.length) ? '❌ Pure Build' : '✅ Pure Build',
215
+ label: ((_j = pureLogs === null || pureLogs === void 0 ? void 0 : pureLogs.errors) === null || _j === void 0 ? void 0 : _j.length) ? '❌ Pure Build' :
216
+ ((_k = pureLogs === null || pureLogs === void 0 ? void 0 : pureLogs.warnings) === null || _k === void 0 ? void 0 : _k.length) ? '⚠️ Pure Build' : 'Pure Build',
102
217
  active: route === 'pure',
103
- className: ((_f = pureLogs === null || pureLogs === void 0 ? void 0 : pureLogs.errors) === null || _f === void 0 ? void 0 : _f.length) ? 'text-danger fw-bold' : 'text-success fw-bold'
218
+ className: ((_l = pureLogs === null || pureLogs === void 0 ? void 0 : pureLogs.errors) === null || _l === void 0 ? void 0 : _l.length) ? 'text-danger fw-bold' :
219
+ ((_m = pureLogs === null || pureLogs === void 0 ? void 0 : pureLogs.warnings) === null || _m === void 0 ? void 0 : _m.length) ? 'text-warning fw-bold' : ''
104
220
  },
105
221
  ] }),
106
222
  React.createElement(Tab.Container, { activeKey: route, onSelect: (k) => {
@@ -115,7 +231,6 @@ export const ProjectPage = () => {
115
231
  React.createElement("thead", null,
116
232
  React.createElement("tr", null,
117
233
  React.createElement("th", null, "Test"),
118
- React.createElement("th", null, "Build logs"),
119
234
  React.createElement("th", null, "BDD Errors"),
120
235
  React.createElement("th", null, "Type Errors"),
121
236
  React.createElement("th", null, "Lint Errors"))),
@@ -124,11 +239,6 @@ export const ProjectPage = () => {
124
239
  return (React.createElement("tr", { key: testName },
125
240
  React.createElement("td", null,
126
241
  React.createElement("a", { href: `#/projects/${projectName}/tests/${encodeURIComponent(testName)}/${runTime}` }, testName)),
127
- React.createElement("td", null,
128
- React.createElement("a", { href: `#/projects/${projectName}#${runTime}` },
129
- runTime,
130
- " ",
131
- testData.runTimeErrors === 0 ? '✅' : '❌')),
132
242
  React.createElement("td", null,
133
243
  React.createElement("a", { href: `#/projects/${projectName}/tests/${encodeURIComponent(testName)}/${runTime}#results` }, testData.runTimeErrors === 0 ? '✅ Passed' :
134
244
  testData.runTimeErrors > 0 ? `⚠️ ${testData.runTimeErrors} errors` :
@@ -139,12 +249,9 @@ export const ProjectPage = () => {
139
249
  React.createElement("a", { href: `#/projects/${projectName}/tests/${encodeURIComponent(testName)}/${runTime}#lint` }, testData.staticErrors))));
140
250
  })))),
141
251
  React.createElement(Tab.Pane, { eventKey: "node" },
142
- React.createElement("ul", null, nodeLogs.errors.map((err, i) => (React.createElement("li", { key: i }, err.text || err.message || JSON.stringify(err))))),
143
- React.createElement("pre", { className: "bg-dark text-white p-3" }, nodeLogs ? JSON.stringify(nodeLogs, null, 2) : 'Loading node build logs...')),
252
+ React.createElement(BuildLogViewer, { logs: nodeLogs, runtime: "Node" })),
144
253
  React.createElement(Tab.Pane, { eventKey: "web" },
145
- React.createElement("ul", null, webLogs.errors.map((err, i) => (React.createElement("li", { key: i }, err.text || err.message || JSON.stringify(err))))),
146
- React.createElement("pre", { className: "bg-dark text-white p-3" }, webLogs ? JSON.stringify(webLogs, null, 2) : 'Loading web build logs...')),
254
+ React.createElement(BuildLogViewer, { logs: webLogs, runtime: "Web" })),
147
255
  React.createElement(Tab.Pane, { eventKey: "pure" },
148
- React.createElement("ul", null, pureLogs.errors.map((err, i) => (React.createElement("li", { key: i }, err.text || err.message || JSON.stringify(err))))),
149
- React.createElement("pre", { className: "bg-dark text-white p-3" }, pureLogs ? JSON.stringify(pureLogs, null, 2) : 'Loading pure build logs...'))))));
256
+ React.createElement(BuildLogViewer, { logs: pureLogs, runtime: "Pure" }))))));
150
257
  };
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { Table, Alert, Badge } from 'react-bootstrap';
2
+ import { Table, Alert } from 'react-bootstrap';
3
3
  import { useNavigate } from 'react-router-dom';
4
4
  import { NavBar } from "./NavBar";
5
5
  export const ProjectsPage = () => {
@@ -16,7 +16,7 @@ export const ProjectsPage = () => {
16
16
  const projectNames = await projectsRes.json();
17
17
  // const projectNames = Object.keys(config.projects);
18
18
  const projectsData = await Promise.all(projectNames.map(async (name) => {
19
- var _a, _b, _c;
19
+ var _a, _b, _c, _d, _e, _f;
20
20
  const [summaryRes, nodeRes, webRes, pureRes, configRes] = await Promise.all([
21
21
  fetch(`reports/${name}/summary.json`),
22
22
  fetch(`bundles/node/${name}/metafile.json`),
@@ -36,9 +36,9 @@ export const ProjectsPage = () => {
36
36
  return {
37
37
  name,
38
38
  testCount: Object.keys(summary).length,
39
- nodeStatus: ((_a = nodeData.errors) === null || _a === void 0 ? void 0 : _a.length) ? 'failed' : 'success',
40
- webStatus: ((_b = webData.errors) === null || _b === void 0 ? void 0 : _b.length) ? 'failed' : 'success',
41
- pureStatus: ((_c = pureData.errors) === null || _c === void 0 ? void 0 : _c.length) ? 'failed' : 'success',
39
+ nodeStatus: ((_a = nodeData.errors) === null || _a === void 0 ? void 0 : _a.length) ? 'failed' : ((_b = nodeData.warnings) === null || _b === void 0 ? void 0 : _b.length) ? 'warning' : 'success',
40
+ webStatus: ((_c = webData.errors) === null || _c === void 0 ? void 0 : _c.length) ? 'failed' : ((_d = webData.warnings) === null || _d === void 0 ? void 0 : _d.length) ? 'warning' : 'success',
41
+ pureStatus: ((_e = pureData.errors) === null || _e === void 0 ? void 0 : _e.length) ? 'failed' : ((_f = pureData.warnings) === null || _f === void 0 ? void 0 : _f.length) ? 'warning' : 'success',
42
42
  config: Object.keys(configData).length,
43
43
  };
44
44
  }));
@@ -57,6 +57,7 @@ export const ProjectsPage = () => {
57
57
  switch (status) {
58
58
  case 'success': return '✅';
59
59
  case 'failed': return '❌';
60
+ case 'warning': return '⚠️';
60
61
  default: return '❓';
61
62
  }
62
63
  };
@@ -85,20 +86,25 @@ export const ProjectsPage = () => {
85
86
  } }, project.name)),
86
87
  React.createElement("td", null,
87
88
  React.createElement("div", { style: { maxHeight: '200px', overflowY: 'auto' } }, summaries[project.name] ? (Object.keys(summaries[project.name]).map(testName => {
89
+ const testData = summaries[project.name][testName];
88
90
  const runTime = configs[project.name].tests.find((t) => t[0] === testName)[1];
91
+ const hasRuntimeErrors = testData.runTimeErrors > 0;
92
+ const hasStaticErrors = testData.typeErrors > 0 || testData.staticErrors > 0;
89
93
  return (React.createElement("div", { key: testName },
90
- React.createElement("a", { href: `#/projects/${project.name}/tests/${encodeURIComponent(testName)}/${runTime}` }, testName.split('/').pop())));
94
+ React.createElement("a", { href: `#/projects/${project.name}/tests/${encodeURIComponent(testName)}/${runTime}` },
95
+ hasRuntimeErrors ? '❌ ' : hasStaticErrors ? '⚠️ ' : '',
96
+ testName.split('/').pop())));
91
97
  })) : (React.createElement("div", null, "Loading tests...")))),
92
98
  React.createElement("td", null,
93
99
  React.createElement("a", { href: `#/projects/${project.name}#node` },
94
100
  getStatusIcon(project.nodeStatus),
95
- project.nodeStatus === 'failed' && (React.createElement(Badge, { bg: "danger", className: "ms-2" }, "Failed")))),
101
+ " Node build logs")),
96
102
  React.createElement("td", null,
97
103
  React.createElement("a", { href: `#/projects/${project.name}#web` },
98
104
  getStatusIcon(project.webStatus),
99
- project.webStatus === 'failed' && (React.createElement(Badge, { bg: "danger", className: "ms-2" }, "Failed")))),
105
+ " Web build logs")),
100
106
  React.createElement("td", null,
101
107
  React.createElement("a", { href: `#/projects/${project.name}#pure` },
102
108
  getStatusIcon(project.pureStatus),
103
- project.pureStatus === 'failed' && (React.createElement(Badge, { bg: "danger", className: "ms-2" }, "Failed")))))))))));
109
+ " Pure build logs")))))))));
104
110
  };
@@ -25,6 +25,13 @@ export const TestPage = () => {
25
25
  const [lintErrors, setLintErrors] = useState('');
26
26
  const [loading, setLoading] = useState(true);
27
27
  const [error, setError] = useState(null);
28
+ const [testsExist, setTestsExist] = useState(true);
29
+ const [errorCounts, setErrorCounts] = useState({
30
+ typeErrors: 0,
31
+ staticErrors: 0,
32
+ runTimeErrors: 0
33
+ });
34
+ const [summary, setSummary] = useState(null);
28
35
  const { projectName, '*': splat } = useParams();
29
36
  const pathParts = splat ? splat.split('/') : [];
30
37
  const runtime = pathParts.pop() || '';
@@ -37,14 +44,37 @@ export const TestPage = () => {
37
44
  // setProjectName(projectName);
38
45
  const fetchData = async () => {
39
46
  try {
40
- const { testData, logs, typeErrors, lintErrors } = await fetchTestData(projectName, testPath, runtime);
41
- setTestData(testData);
42
- setLogs(logs);
43
- setTypeErrors(typeErrors);
44
- setLintErrors(lintErrors);
47
+ // First fetch test data
48
+ const testResponse = await fetchTestData(projectName, testPath, runtime);
49
+ setTestData(testResponse.testData);
50
+ setTestsExist(!!testResponse.testData);
51
+ setLogs(testResponse.logs);
52
+ setTypeErrors(testResponse.typeErrors);
53
+ setLintErrors(testResponse.lintErrors);
54
+ // Then fetch summary.json
55
+ try {
56
+ const summaryResponse = await fetch(`reports/${projectName}/summary.json`);
57
+ if (!summaryResponse.ok)
58
+ throw new Error('Failed to fetch summary');
59
+ const allSummaries = await summaryResponse.json();
60
+ const testSummary = allSummaries[testPath];
61
+ console.log("testSummary", testSummary);
62
+ if (testSummary) {
63
+ setSummary(testSummary);
64
+ setErrorCounts({
65
+ typeErrors: testSummary.typeErrors || 0,
66
+ staticErrors: testSummary.staticErrors || 0,
67
+ runTimeErrors: testSummary.runTimeErrors || 0
68
+ });
69
+ }
70
+ }
71
+ catch (err) {
72
+ console.error('Failed to load summary:', err);
73
+ }
45
74
  }
46
75
  catch (err) {
47
76
  setError(err instanceof Error ? err.message : 'Unknown error');
77
+ setTestsExist(false);
48
78
  }
49
79
  finally {
50
80
  setLoading(false);
@@ -62,33 +92,45 @@ export const TestPage = () => {
62
92
  React.createElement(NavBar, { title: decodedTestPath, backLink: `/projects/${projectName}`, navItems: [
63
93
  {
64
94
  to: `#results`,
65
- label: (testData === null || testData === void 0 ? void 0 : testData.givens.some(g => g.whens.some(w => w.error) || g.thens.some(t => t.error)))
95
+ label: !testsExist
66
96
  ? '❌ BDD'
67
- : '✅ BDD',
97
+ : (testData === null || testData === void 0 ? void 0 : testData.givens.some(g => g.whens.some(w => w.error) || g.thens.some(t => t.error)))
98
+ ? '❌ BDD'
99
+ : '✅ BDD',
68
100
  active: route === 'results'
69
101
  },
70
102
  {
71
103
  to: `#logs`,
72
- label: (logs === null || logs === void 0 ? void 0 : logs.includes('error')) || (logs === null || logs === void 0 ? void 0 : logs.includes('fail'))
73
- ? '❌ Logs'
74
- : '✅ Logs',
104
+ label: `Runtime logs`,
75
105
  active: route === 'logs'
76
106
  },
77
107
  {
78
108
  to: `#types`,
79
- label: typeErrors
80
- ? `❌ ${typeErrors.split('\n').filter(l => l.includes('error')).length} Type Errors`
81
- : '✅ Type check',
109
+ label: errorCounts.typeErrors > 0
110
+ ? `tsc ( * ${errorCounts.typeErrors})`
111
+ : 'tsc ✅ ',
82
112
  active: route === 'types'
83
113
  },
84
114
  {
85
115
  to: `#lint`,
86
- label: lintErrors
87
- ? `❌ ${lintErrors.split('\n').filter(l => l.includes('error')).length} Lint Errors`
88
- : '✅ Lint',
116
+ label: errorCounts.staticErrors > 0
117
+ ? `eslint ( *${errorCounts.staticErrors}) `
118
+ : 'eslint ✅',
89
119
  active: route === 'lint'
90
120
  },
91
- ], rightContent: React.createElement(Button, { variant: "info", onClick: () => alert("Magic robot activated!"), className: "ms-2" }, "\uD83E\uDD16") }),
121
+ ], rightContent: React.createElement(Button, { variant: "info", onClick: async () => {
122
+ try {
123
+ const promptPath = `testeranto/reports/${projectName}/${testPath.split('.').slice(0, -1).join('.')}/${runtime}/prompt.txt`;
124
+ const messagePath = `testeranto/reports/${projectName}/${testPath.split('.').slice(0, -1).join('.')}/${runtime}/message.txt`;
125
+ const command = `aider --load ${promptPath} --message-file ${messagePath}`;
126
+ await navigator.clipboard.writeText(command);
127
+ alert("Copied aider command to clipboard!");
128
+ }
129
+ catch (err) {
130
+ alert("Failed to copy command to clipboard");
131
+ console.error("Copy failed:", err);
132
+ }
133
+ }, className: "ms-2" }, "\uD83E\uDD16") }),
92
134
  React.createElement(Tab.Container, { activeKey: route, onSelect: (k) => {
93
135
  if (k) {
94
136
  setRoute(k);
@@ -96,7 +138,12 @@ export const TestPage = () => {
96
138
  }
97
139
  } },
98
140
  React.createElement(Tab.Content, { className: "mt-3" },
99
- React.createElement(Tab.Pane, { eventKey: "results" }, testData ? (React.createElement("div", { className: "test-results" },
141
+ React.createElement(Tab.Pane, { eventKey: "results" }, !testsExist ? (React.createElement(Alert, { variant: "danger", className: "mt-3" },
142
+ React.createElement("h4", null, "Tests did not run to completion"),
143
+ React.createElement("p", null, "The test results file (tests.json) was not found or could not be loaded."),
144
+ React.createElement("div", { className: "mt-3" },
145
+ React.createElement(Button, { variant: "outline-light", onClick: () => setRoute('logs'), className: "me-2" }, "View Runtime Logs"),
146
+ React.createElement(Button, { variant: "outline-light", onClick: () => navigate(`/projects/${projectName}#${runtime}`) }, "View Build Logs")))) : testData ? (React.createElement("div", { className: "test-results" },
100
147
  React.createElement("div", { className: "mb-3" }),
101
148
  testData.givens.map((given, i) => (React.createElement("div", { key: i, className: "mb-4 card" },
102
149
  React.createElement("div", { className: "card-header bg-primary text-white" },
@@ -13,200 +13,41 @@ export const fetchTestData = async (projectName, filepath, runTime) => {
13
13
  .split(".")
14
14
  .slice(0, -1)
15
15
  .join(".")}/${runTime}`;
16
- const [testRes, logsRes, typeRes, lintRes] = await Promise.all([
17
- fetch(`${basePath}/tests.json`),
18
- fetch(`${basePath}/logs.txt`),
19
- fetch(`${basePath}/type_errors.txt`),
20
- fetch(`${basePath}/lint_errors.txt`),
21
- ]);
22
- return {
23
- // testData: await testRes.json(),
24
- testData: fakeTestJson,
25
- logs: await logsRes.text(),
26
- typeErrors: await typeRes.text(),
27
- lintErrors: await lintRes.text(),
28
- };
16
+ try {
17
+ const [testRes, logsRes, typeRes, lintRes] = await Promise.all([
18
+ fetch(`${basePath}/tests.json`),
19
+ fetch(`${basePath}/logs.txt`),
20
+ fetch(`${basePath}/type_errors.txt`),
21
+ fetch(`${basePath}/lint_errors.txt`),
22
+ ]);
23
+ if (!testRes.ok) {
24
+ return {
25
+ testData: null,
26
+ logs: await logsRes.text(),
27
+ typeErrors: await typeRes.text(),
28
+ lintErrors: await lintRes.text(),
29
+ error: "Tests did not complete successfully. Please check the build and runtime logs for errors."
30
+ };
31
+ }
32
+ return {
33
+ testData: await testRes.json(),
34
+ logs: await logsRes.text(),
35
+ typeErrors: await typeRes.text(),
36
+ lintErrors: await lintRes.text(),
37
+ error: null
38
+ };
39
+ }
40
+ catch (err) {
41
+ return {
42
+ testData: null,
43
+ logs: "",
44
+ typeErrors: "",
45
+ lintErrors: "",
46
+ error: `Failed to load test data: ${err instanceof Error ? err.message : String(err)}`
47
+ };
48
+ }
29
49
  };
30
50
  export const fetchBuildLogs = async (projectName, runtime) => {
31
51
  const res = await fetch(`reports/${projectName}/src/lib/${projectName}.${testName}/${runtime}/metafile.json`);
32
52
  return await res.json();
33
53
  };
34
- const fakeTestJson = {
35
- name: "Testing the Rectangle class",
36
- givens: [
37
- {
38
- key: "test0",
39
- name: "Default",
40
- whens: [
41
- {
42
- name: "setWidth: 4",
43
- error: true,
44
- },
45
- {
46
- name: "setHeight: 19",
47
- error: true,
48
- },
49
- ],
50
- thens: [
51
- {
52
- name: "getWidth: 4",
53
- error: false,
54
- },
55
- {
56
- name: "getHeight: 19",
57
- error: false,
58
- },
59
- ],
60
- error: null,
61
- features: [
62
- "https://api.github.com/repos/adamwong246/testeranto/issues/8",
63
- ],
64
- },
65
- {
66
- key: "test1",
67
- name: "Default",
68
- whens: [
69
- {
70
- name: "setWidth: 4",
71
- error: true,
72
- },
73
- {
74
- name: "setHeight: 5",
75
- error: true,
76
- },
77
- ],
78
- thens: [
79
- {
80
- name: "getWidth: 4",
81
- error: false,
82
- },
83
- {
84
- name: "getHeight: 5",
85
- error: false,
86
- },
87
- {
88
- name: "area: 20",
89
- error: false,
90
- },
91
- {
92
- name: "AreaPlusCircumference: 38",
93
- error: false,
94
- },
95
- ],
96
- error: null,
97
- features: ["Rectangles have width and height."],
98
- },
99
- {
100
- key: "test2",
101
- name: "Default",
102
- whens: [
103
- {
104
- name: "setHeight: 4",
105
- error: true,
106
- },
107
- {
108
- name: "setWidth: 33",
109
- error: true,
110
- },
111
- ],
112
- thens: [
113
- {
114
- name: "area: 132",
115
- error: false,
116
- },
117
- ],
118
- error: null,
119
- features: ["Rectangles have area"],
120
- },
121
- {
122
- key: "test2_1",
123
- name: "Default",
124
- whens: [],
125
- thens: [
126
- {
127
- name: "getWidth: 2",
128
- error: false,
129
- },
130
- {
131
- name: "getHeight: 2",
132
- error: false,
133
- },
134
- ],
135
- error: null,
136
- features: ["Rectangles have default size"],
137
- },
138
- {
139
- key: "test3",
140
- name: "Default",
141
- whens: [
142
- {
143
- name: "setHeight: 5",
144
- error: true,
145
- },
146
- {
147
- name: "setWidth: 5",
148
- error: true,
149
- },
150
- ],
151
- thens: [
152
- {
153
- name: "area: 25",
154
- error: false,
155
- },
156
- ],
157
- error: null,
158
- features: [
159
- "file:///Users/adam/Code/testeranto-starter/src/Rectangle/README.md",
160
- ],
161
- },
162
- {
163
- key: "test4",
164
- name: "Default",
165
- whens: [
166
- {
167
- name: "setHeight: 6",
168
- error: true,
169
- },
170
- {
171
- name: "setWidth: 6",
172
- error: true,
173
- },
174
- ],
175
- thens: [
176
- {
177
- name: "area: 36",
178
- error: false,
179
- },
180
- ],
181
- error: null,
182
- features: ["Rectangles have area"],
183
- },
184
- {
185
- key: "test5",
186
- name: "Default",
187
- whens: [],
188
- thens: [
189
- {
190
- name: "getWidth: 2",
191
- error: false,
192
- },
193
- {
194
- name: "getHeight: 2",
195
- error: false,
196
- },
197
- ],
198
- error: null,
199
- features: ["Rectangles have default size, again"],
200
- },
201
- ],
202
- checks: [],
203
- fails: 0,
204
- features: [
205
- "https://api.github.com/repos/adamwong246/testeranto/issues/8",
206
- "Rectangles have width and height.",
207
- "Rectangles have area",
208
- "Rectangles have default size",
209
- "file:///Users/adam/Code/testeranto-starter/src/Rectangle/README.md",
210
- "Rectangles have default size, again",
211
- ],
212
- };