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.
- package/dist/common/src/Init.js +3 -3
- package/dist/common/src/utils/api.js +33 -192
- package/dist/common/tsconfig.common.tsbuildinfo +1 -1
- package/dist/module/src/Init.js +3 -3
- package/dist/module/src/ProjectPage.js +128 -21
- package/dist/module/src/ProjectsPage.js +15 -9
- package/dist/module/src/TestPage.js +65 -18
- package/dist/module/src/utils/api.js +33 -192
- package/dist/module/tsconfig.module.tsbuildinfo +1 -1
- package/dist/prebuild/App.js +901 -581
- package/dist/prebuild/init-docs.mjs +3 -3
- package/dist/types/src/utils/api.d.ts +2 -20
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/notify.sh +47 -0
- package/package.json +2 -2
- package/src/Init.ts +3 -3
- package/src/ProjectPage.tsx +204 -38
- package/src/ProjectsPage.tsx +23 -19
- package/src/TestPage.tsx +79 -18
- package/src/utils/api.ts +40 -193
- package/testeranto/App.js +901 -581
- package/testeranto/reports/allTests/src/lib/baseBuilder.test/baseBuilder.test.web/web/logs.txt +4 -4
- package/testeranto/reports/allTests/src/lib/classBuilder.test/classBuilder.test/node/logs.txt +1 -1
- package/dist/module/src/BuildLogsPage.js +0 -99
- package/dist/module/src/Project.js +0 -332
- package/src/BuildLogsPage.tsx +0 -108
- package/src/Project.tsx +0 -375
package/dist/module/src/Init.js
CHANGED
|
@@ -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/
|
|
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
|
|
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
|
-
{
|
|
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' :
|
|
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: ((
|
|
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: ((
|
|
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: ((
|
|
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: ((
|
|
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: ((
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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: ((
|
|
41
|
-
pureStatus: ((
|
|
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}` },
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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:
|
|
95
|
+
label: !testsExist
|
|
66
96
|
? '❌ BDD'
|
|
67
|
-
:
|
|
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:
|
|
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
|
-
?
|
|
81
|
-
: '✅
|
|
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:
|
|
87
|
-
?
|
|
88
|
-
: '✅
|
|
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: () =>
|
|
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" },
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
};
|