testeranto 0.9.20
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/.eslintrc.js +29 -0
- package/.prettierrc +4 -0
- package/.vscode/launch.json +20 -0
- package/.vscode/settings.json +7 -0
- package/README.md +86 -0
- package/bin/build.sh +5 -0
- package/bin/report.sh +6 -0
- package/bin/watch.sh +5 -0
- package/dist/reporter.css +10326 -0
- package/dist/reporter.html +16 -0
- package/dist/reporter.js +26777 -0
- package/example-testeranto.config.json +65 -0
- package/nodemon.json +7 -0
- package/package.json +54 -0
- package/src/BaseClasses.ts +353 -0
- package/src/Features.ts +102 -0
- package/src/Project.ts +23 -0
- package/src/Report.tsx +347 -0
- package/src/build.js +88 -0
- package/src/index.ts +153 -0
- package/src/lib/Scheduler.ts +350 -0
- package/src/lib/level0.ts +157 -0
- package/src/lib/level1.ts +191 -0
- package/src/types.ts +122 -0
- package/src/watch.ts +69 -0
- package/testeranto.ts-0.0.1.tgz +0 -0
- package/truffle-config.js +124 -0
- package/tsconfig.json +33 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/yarn-error.log +3144 -0
package/src/Report.tsx
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import ReactDom from "react-dom/client";
|
|
2
|
+
import React, { useEffect, useState } from "react";
|
|
3
|
+
|
|
4
|
+
import Tab from 'react-bootstrap/Tab';
|
|
5
|
+
import Tabs from 'react-bootstrap/Tabs';
|
|
6
|
+
import Col from 'react-bootstrap/Col';
|
|
7
|
+
import Nav from 'react-bootstrap/Nav';
|
|
8
|
+
import Row from 'react-bootstrap/Row';
|
|
9
|
+
|
|
10
|
+
import 'bootstrap/dist/css/bootstrap.min.css';
|
|
11
|
+
|
|
12
|
+
export function Report() {
|
|
13
|
+
|
|
14
|
+
const [data, setData] = useState<{
|
|
15
|
+
configs: object,
|
|
16
|
+
features: {
|
|
17
|
+
features: any[]
|
|
18
|
+
},
|
|
19
|
+
tests: any[],
|
|
20
|
+
featureTests: object,
|
|
21
|
+
summaries: { dags: [], directed: [], undirected: [] }
|
|
22
|
+
}>({
|
|
23
|
+
configs: {},
|
|
24
|
+
features: {
|
|
25
|
+
features: []
|
|
26
|
+
},
|
|
27
|
+
tests: [],
|
|
28
|
+
featureTests: {},
|
|
29
|
+
summaries: { dags: [], directed: [], undirected: [] }
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const getData = async () => {
|
|
33
|
+
|
|
34
|
+
const configs = await (await fetch('testeranto.config.json')).json();
|
|
35
|
+
const features = await (await fetch('TesterantoFeatures.json')).json();
|
|
36
|
+
const featureTests = await (await fetch('results/featureTestJoin.json')).json();
|
|
37
|
+
const summaries = await (await fetch('report.json')).json();
|
|
38
|
+
const testPromises = await configs.tests.map(async (test) => {
|
|
39
|
+
return await (await (await fetch(`results/${test[0]}.json`)).json())
|
|
40
|
+
})
|
|
41
|
+
const tests = await Promise.all(testPromises);
|
|
42
|
+
|
|
43
|
+
setData({ configs, features, tests, featureTests, summaries });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
useEffect(() => { getData() }, []);
|
|
47
|
+
|
|
48
|
+
return (<div>
|
|
49
|
+
{
|
|
50
|
+
data && data.configs && <>
|
|
51
|
+
<Tabs defaultActiveKey="home">
|
|
52
|
+
<Tab eventKey="home" title="config">
|
|
53
|
+
<pre><code>{JSON.stringify(data.configs, null, 2)}</code></pre>
|
|
54
|
+
</Tab>
|
|
55
|
+
<Tab eventKey="features" title="features">
|
|
56
|
+
<Tab.Container id="left-tabs-example5" defaultActiveKey="feature-0">
|
|
57
|
+
<Row>
|
|
58
|
+
<Col sm={3}>
|
|
59
|
+
<Nav variant="pills" className="flex-column">
|
|
60
|
+
{data.features.features.map((feature, ndx) => <Nav.Item key={ndx}>
|
|
61
|
+
<Nav.Link eventKey={`feature-${ndx}`}>
|
|
62
|
+
{feature.name}
|
|
63
|
+
</Nav.Link>
|
|
64
|
+
</Nav.Item>)}
|
|
65
|
+
</Nav>
|
|
66
|
+
</Col>
|
|
67
|
+
<Col sm={9}>
|
|
68
|
+
<Tab.Content>
|
|
69
|
+
{data.features.features.map((feature, ndx) => <Tab.Pane eventKey={`feature-${ndx}`} key={ndx}>
|
|
70
|
+
<p>{feature.name}</p>
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
<Tab.Container id="left-tabs-example5" defaultActiveKey="relations-0">
|
|
74
|
+
<Row>
|
|
75
|
+
<Col sm={3}>
|
|
76
|
+
<Nav variant="pills" className="flex-column">
|
|
77
|
+
{feature.inNetworks.map((summary, ndx2) => <Nav.Item key={ndx2}>
|
|
78
|
+
<Nav.Link eventKey={`relations-${ndx2}`}>
|
|
79
|
+
{summary.network}
|
|
80
|
+
</Nav.Link>
|
|
81
|
+
</Nav.Item>)}
|
|
82
|
+
</Nav>
|
|
83
|
+
</Col>
|
|
84
|
+
<Col sm={9}>
|
|
85
|
+
<Tab.Content>
|
|
86
|
+
{feature.inNetworks.map((summary, ndx2) => <Tab.Pane eventKey={`relations-${ndx2}`} key={ndx2}>
|
|
87
|
+
<pre>{
|
|
88
|
+
JSON.stringify(summary.neighbors, null, 2)
|
|
89
|
+
}</pre>
|
|
90
|
+
</Tab.Pane>)}
|
|
91
|
+
</Tab.Content>
|
|
92
|
+
</Col>
|
|
93
|
+
</Row>
|
|
94
|
+
</Tab.Container>
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
</Tab.Pane>)}
|
|
99
|
+
</Tab.Content>
|
|
100
|
+
</Col>
|
|
101
|
+
</Row>
|
|
102
|
+
</Tab.Container>
|
|
103
|
+
</Tab>
|
|
104
|
+
<Tab eventKey="results" title="tests">
|
|
105
|
+
<Tab.Container id="left-tabs-example" defaultActiveKey="first">
|
|
106
|
+
<Row>
|
|
107
|
+
<Col sm={3}>
|
|
108
|
+
<Nav variant="pills" className="flex-column">
|
|
109
|
+
{data.tests.map((suite, ndx) => <Nav.Item key={ndx}>
|
|
110
|
+
<Nav.Link eventKey={`suite-${ndx}`}>
|
|
111
|
+
{(suite.fails.length > 0 ? `❌ * ${suite.fails.length.toString()}` : `✅ * ${suite.givens.length.toString()}`)} - {suite.name}
|
|
112
|
+
</Nav.Link>
|
|
113
|
+
</Nav.Item>)}
|
|
114
|
+
</Nav>
|
|
115
|
+
</Col>
|
|
116
|
+
<Col sm={9}>
|
|
117
|
+
<Tab.Content>
|
|
118
|
+
{data.tests.map((suite, ndx) => <Tab.Pane eventKey={`suite-${ndx}`} key={ndx}>
|
|
119
|
+
<Tab.Container id="left-tabs-example2" defaultActiveKey={`given-0`}>
|
|
120
|
+
<Row>
|
|
121
|
+
<Col sm={3}>
|
|
122
|
+
<Nav variant="pills" className="flex-column">
|
|
123
|
+
{suite.givens.map((g, ndx2) => <Nav.Item key={ndx2}>
|
|
124
|
+
<Nav.Link eventKey={`given-${ndx2}`}>
|
|
125
|
+
{(g.errors ? `❌` : `✅`)} - {g.name}
|
|
126
|
+
</Nav.Link>
|
|
127
|
+
</Nav.Item>)}
|
|
128
|
+
</Nav>
|
|
129
|
+
</Col>
|
|
130
|
+
<Col sm={9}>
|
|
131
|
+
<Tab.Content>
|
|
132
|
+
{suite.givens.map((g, ndx2) => <Tab.Pane key={ndx2} eventKey={`given-${ndx2}`} >
|
|
133
|
+
<p>when</p>
|
|
134
|
+
<ul>
|
|
135
|
+
{g.whens.map((w, ndx3) => <li key={ndx3}>
|
|
136
|
+
{/* <p>{w.name}</p> */}
|
|
137
|
+
{(w.error === true ? `❌` : `✅`)} - {w.name}
|
|
138
|
+
</li>)}
|
|
139
|
+
</ul>
|
|
140
|
+
<p>then</p>
|
|
141
|
+
<ul>
|
|
142
|
+
{g.thens.map((t, ndx3) => <li key={ndx3}>
|
|
143
|
+
<p>
|
|
144
|
+
{(t.error === true ? `❌` : `✅`)} - {t.name}
|
|
145
|
+
</p>
|
|
146
|
+
</li>)}
|
|
147
|
+
</ul>
|
|
148
|
+
<pre><code>{JSON.stringify(g.errors, null, 2)}</code></pre>
|
|
149
|
+
</Tab.Pane>)}
|
|
150
|
+
</Tab.Content>
|
|
151
|
+
</Col>
|
|
152
|
+
</Row>
|
|
153
|
+
</Tab.Container>
|
|
154
|
+
</Tab.Pane>)}
|
|
155
|
+
</Tab.Content>
|
|
156
|
+
</Col>
|
|
157
|
+
</Row>
|
|
158
|
+
</Tab.Container>
|
|
159
|
+
</Tab>
|
|
160
|
+
<Tab eventKey="featureTests" title="feature-tests">
|
|
161
|
+
<Tab.Container id="left-tabs-example7" defaultActiveKey="first">
|
|
162
|
+
<Row>
|
|
163
|
+
<Col sm={3}>
|
|
164
|
+
<Nav variant="pills" className="flex-column">
|
|
165
|
+
{Object.keys(data.featureTests).map((ftKey, ndx) => <Nav.Item key={ndx}>
|
|
166
|
+
<Nav.Link eventKey={`featureTests-${ndx}`}>
|
|
167
|
+
{Object.values(data.featureTests[ftKey]).reduce((testMemo, test: any) => test.errors) ? `❌` : `✅`} {ftKey}
|
|
168
|
+
</Nav.Link>
|
|
169
|
+
</Nav.Item>)}
|
|
170
|
+
</Nav>
|
|
171
|
+
</Col>
|
|
172
|
+
<Col sm={9}>
|
|
173
|
+
<Tab.Content>
|
|
174
|
+
{Object.keys(data.featureTests).map((ftKey, ndx) => <Tab.Pane eventKey={`featureTests-${ndx}`} key={ndx}>
|
|
175
|
+
<Tab.Container id="left-tabs-example8" defaultActiveKey={`ft-suite-0`}>
|
|
176
|
+
<Row>
|
|
177
|
+
<Col sm={6}>
|
|
178
|
+
<Nav variant="pills" className="flex-column">
|
|
179
|
+
{data.featureTests[ftKey].map((s, ndx2) => <Nav.Item key={ndx2}>
|
|
180
|
+
<Nav.Link eventKey={`ft-suite-${ndx2}`}>
|
|
181
|
+
{s.errors ? `❌` : `✅`} <strong>{s.testKey}</strong> <em>{s.name}</em>
|
|
182
|
+
</Nav.Link>
|
|
183
|
+
</Nav.Item>)}
|
|
184
|
+
</Nav>
|
|
185
|
+
</Col>
|
|
186
|
+
<Col sm={6}>
|
|
187
|
+
<Tab.Content>
|
|
188
|
+
{data.featureTests[ftKey].map((g, ndx2) => <Tab.Pane key={ndx2} eventKey={`ft-suite-${ndx2}`} >
|
|
189
|
+
|
|
190
|
+
{/* <pre> <code>{JSON.stringify(x)} </code></pre> */}
|
|
191
|
+
|
|
192
|
+
<p>when</p>
|
|
193
|
+
<ul>
|
|
194
|
+
{g.whens.map((w, ndx3) => <li key={ndx3}>
|
|
195
|
+
<p>{w}</p>
|
|
196
|
+
</li>)}
|
|
197
|
+
</ul>
|
|
198
|
+
<p>then</p>
|
|
199
|
+
<ul>
|
|
200
|
+
{g.thens.map((t, ndx3) => <li key={ndx3}>
|
|
201
|
+
<p>{t}</p>
|
|
202
|
+
</li>)}
|
|
203
|
+
</ul>
|
|
204
|
+
|
|
205
|
+
<pre><code>{JSON.stringify(g.errors, null, 2)}</code></pre>
|
|
206
|
+
|
|
207
|
+
</Tab.Pane>)}
|
|
208
|
+
|
|
209
|
+
</Tab.Content>
|
|
210
|
+
</Col>
|
|
211
|
+
</Row>
|
|
212
|
+
</Tab.Container>
|
|
213
|
+
|
|
214
|
+
</Tab.Pane>)}
|
|
215
|
+
|
|
216
|
+
{/* ////////////////////////// */}
|
|
217
|
+
|
|
218
|
+
</Tab.Content>
|
|
219
|
+
</Col>
|
|
220
|
+
</Row>
|
|
221
|
+
</Tab.Container>
|
|
222
|
+
</Tab>
|
|
223
|
+
|
|
224
|
+
<Tab eventKey="networks" title="networks">
|
|
225
|
+
<Tab.Container id="left-tabs-example88" defaultActiveKey={`networks-dags`}>
|
|
226
|
+
<Row>
|
|
227
|
+
<Col sm={3}>
|
|
228
|
+
<Nav variant="pills" className="flex-column">
|
|
229
|
+
<Nav.Link eventKey={`networks-dags`}>
|
|
230
|
+
DAG
|
|
231
|
+
</Nav.Link>
|
|
232
|
+
<Nav.Link eventKey={`networks-directed`}>
|
|
233
|
+
Directed (not acyclic)
|
|
234
|
+
</Nav.Link>
|
|
235
|
+
<Nav.Link eventKey={`networks-undirected`}>
|
|
236
|
+
Undirected
|
|
237
|
+
</Nav.Link>
|
|
238
|
+
</Nav>
|
|
239
|
+
</Col>
|
|
240
|
+
<Col sm={9}>
|
|
241
|
+
<Tab.Content>
|
|
242
|
+
<Tab.Pane eventKey={`networks-dags`} >
|
|
243
|
+
<Tab.Container defaultActiveKey={`networks-dags-0`}>
|
|
244
|
+
<Row>
|
|
245
|
+
<Col sm={3}>
|
|
246
|
+
<Nav variant="pills" className="flex-column">
|
|
247
|
+
{data.summaries.dags.map((g: any, ndx2) => <Nav.Item key={ndx2}>
|
|
248
|
+
<Nav.Link eventKey={`networks-dags-${ndx2}`}>
|
|
249
|
+
{g.name}
|
|
250
|
+
</Nav.Link>
|
|
251
|
+
</Nav.Item>)}
|
|
252
|
+
</Nav>
|
|
253
|
+
</Col>
|
|
254
|
+
<Col sm={9}>
|
|
255
|
+
<Tab.Content>
|
|
256
|
+
<p>idk dags</p>
|
|
257
|
+
</Tab.Content>
|
|
258
|
+
</Col>
|
|
259
|
+
</Row>
|
|
260
|
+
</Tab.Container>
|
|
261
|
+
</Tab.Pane>
|
|
262
|
+
<Tab.Pane eventKey={`networks-directed`} >
|
|
263
|
+
<Tab.Container defaultActiveKey={`networks-directed-0`}>
|
|
264
|
+
<Row>
|
|
265
|
+
<Col sm={3}>
|
|
266
|
+
<Nav variant="pills" className="flex-column">
|
|
267
|
+
{data.summaries.directed.map((g: any, ndx2) => <Nav.Item key={ndx2}>
|
|
268
|
+
<Nav.Link eventKey={`networks-directed-${ndx2}`}>
|
|
269
|
+
{g.name}
|
|
270
|
+
</Nav.Link>
|
|
271
|
+
</Nav.Item>)}
|
|
272
|
+
</Nav>
|
|
273
|
+
</Col>
|
|
274
|
+
<Col sm={9}>
|
|
275
|
+
<Tab.Content>
|
|
276
|
+
<p>idk directed</p>
|
|
277
|
+
</Tab.Content>
|
|
278
|
+
</Col>
|
|
279
|
+
</Row>
|
|
280
|
+
</Tab.Container>
|
|
281
|
+
</Tab.Pane>
|
|
282
|
+
<Tab.Pane eventKey={`networks-undirected`} >
|
|
283
|
+
<Tab.Container defaultActiveKey={`networks-undirected-0`}>
|
|
284
|
+
<Row>
|
|
285
|
+
<Col sm={3}>
|
|
286
|
+
<Nav variant="pills" className="flex-column">
|
|
287
|
+
{data.summaries.undirected.map((g: any, ndx2) => <Nav.Item key={ndx2}>
|
|
288
|
+
<Nav.Link eventKey={`networks-undirected-${ndx2}`}>
|
|
289
|
+
{g.name}
|
|
290
|
+
</Nav.Link>
|
|
291
|
+
</Nav.Item>)}
|
|
292
|
+
</Nav>
|
|
293
|
+
</Col>
|
|
294
|
+
<Col sm={9}>
|
|
295
|
+
<Tab.Content>
|
|
296
|
+
<p>idk undirected</p>
|
|
297
|
+
</Tab.Content>
|
|
298
|
+
</Col>
|
|
299
|
+
</Row>
|
|
300
|
+
</Tab.Container>
|
|
301
|
+
</Tab.Pane>
|
|
302
|
+
</Tab.Content>
|
|
303
|
+
</Col>
|
|
304
|
+
</Row>
|
|
305
|
+
</Tab.Container>
|
|
306
|
+
</Tab>
|
|
307
|
+
|
|
308
|
+
<Tab eventKey="summary" title="summaries">
|
|
309
|
+
<Tab.Container id="left-tabs-example3" defaultActiveKey={`summary-0`}>
|
|
310
|
+
<Row>
|
|
311
|
+
<Col sm={3}>
|
|
312
|
+
<Nav variant="pills" className="flex-column">
|
|
313
|
+
{data.summaries.dags?.map((summary: any, ndx) => <Nav.Item key={ndx}>
|
|
314
|
+
<Nav.Link eventKey={`summary-${ndx}`}>
|
|
315
|
+
{summary.name}
|
|
316
|
+
</Nav.Link>
|
|
317
|
+
</Nav.Item>)}
|
|
318
|
+
</Nav>
|
|
319
|
+
</Col>
|
|
320
|
+
<Col sm={9}>
|
|
321
|
+
<Tab.Content>
|
|
322
|
+
{Object.keys(data.summaries.dags).map((summaryKey, ndx2) => <Tab.Pane key={ndx2} eventKey={`summary-${ndx2}`} >
|
|
323
|
+
<pre><code>{JSON.stringify(data.summaries.dags[summaryKey].dagReduction, null, 2)}</code></pre>
|
|
324
|
+
</Tab.Pane>)}
|
|
325
|
+
</Tab.Content>
|
|
326
|
+
</Col>
|
|
327
|
+
</Row>
|
|
328
|
+
</Tab.Container>
|
|
329
|
+
</Tab>
|
|
330
|
+
</Tabs>
|
|
331
|
+
</>
|
|
332
|
+
}
|
|
333
|
+
{
|
|
334
|
+
!data && <p>LOADING</p>
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
<footer style={{ position: 'fixed', bottom: 0, right: 0 }}>made with ❤️ and <a href="https://adamwong246.github.io/testeranto/" >testeranto</a></footer>
|
|
338
|
+
|
|
339
|
+
</div>)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
343
|
+
const elem = document.getElementById("root");
|
|
344
|
+
if (elem) {
|
|
345
|
+
ReactDom.createRoot(elem).render(React.createElement(Report));
|
|
346
|
+
}
|
|
347
|
+
});
|
package/src/build.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// /* eslint-disable no-undef */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
3
|
+
|
|
4
|
+
const esbuild = require("esbuild");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const createHash = require("node:crypto").createHash;
|
|
8
|
+
|
|
9
|
+
console.log("hello build.sh", process.cwd(), process.argv);
|
|
10
|
+
|
|
11
|
+
const testerantoConfig = require(process.argv[2]);
|
|
12
|
+
|
|
13
|
+
fs.promises.writeFile("./dist/testeranto.config.json", JSON.stringify(testerantoConfig));
|
|
14
|
+
|
|
15
|
+
esbuild.build({
|
|
16
|
+
entryPoints: [testerantoConfig.features],
|
|
17
|
+
bundle: true,
|
|
18
|
+
minify: false,
|
|
19
|
+
format: "esm",
|
|
20
|
+
target: ["esnext"],
|
|
21
|
+
write: false,
|
|
22
|
+
packages: 'external',
|
|
23
|
+
}).then((res) => {
|
|
24
|
+
const text = res.outputFiles[0].text;
|
|
25
|
+
const hash = createHash('md5').update(text).digest('hex');
|
|
26
|
+
const jsFile = process.cwd() + "/dist/tests/testerantoFeatures.test.js";
|
|
27
|
+
const md5File = process.cwd() + "/dist/tests/testerantoFeatures.test.md5";
|
|
28
|
+
|
|
29
|
+
fs.promises.mkdir(path.dirname(process.cwd() + "./dist/tests/"), { recursive: true }).then(x => {
|
|
30
|
+
console.log("build.js feature", hash, jsFile);
|
|
31
|
+
|
|
32
|
+
fs.promises.writeFile(jsFile, text);
|
|
33
|
+
fs.promises.writeFile(md5File, hash)
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/////////////////////////////////////////////////////////////////////////////////
|
|
38
|
+
|
|
39
|
+
testerantoConfig.tests.forEach(([key, sourcefile, className]) => {
|
|
40
|
+
esbuild.build({
|
|
41
|
+
entryPoints: [sourcefile],
|
|
42
|
+
bundle: true,
|
|
43
|
+
minify: false,
|
|
44
|
+
format: "esm",
|
|
45
|
+
target: ["esnext"],
|
|
46
|
+
write: false,
|
|
47
|
+
packages: 'external',
|
|
48
|
+
plugins: [{
|
|
49
|
+
name: 'import-path',
|
|
50
|
+
setup(build) {
|
|
51
|
+
build.onResolve({ filter: /^\.{1,2}\// }, args => {
|
|
52
|
+
|
|
53
|
+
const importedPath = args.resolveDir + "/" + args.path;
|
|
54
|
+
const absolutePath = path.resolve(importedPath);
|
|
55
|
+
|
|
56
|
+
const absolutePath2 = path.resolve(testerantoConfig.features).split(".ts").slice(0, -1).join('.ts');
|
|
57
|
+
|
|
58
|
+
if (absolutePath === absolutePath2) {
|
|
59
|
+
return {
|
|
60
|
+
path: process.cwd() + "/dist/tests/testerantoFeatures.test.js",
|
|
61
|
+
external: true
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
// return {
|
|
65
|
+
// path: path.resolve(importedPath), external: false
|
|
66
|
+
// }
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
},
|
|
70
|
+
}],
|
|
71
|
+
external: [
|
|
72
|
+
testerantoConfig.features
|
|
73
|
+
],
|
|
74
|
+
}).then((res) => {
|
|
75
|
+
|
|
76
|
+
const text = res.outputFiles[0].text;
|
|
77
|
+
|
|
78
|
+
const pp = "./dist/" + (sourcefile.split(process.cwd()).pop()).split(".ts")[0] + '.js';
|
|
79
|
+
const xx = "./dist/" + (sourcefile.split(process.cwd()).pop()).split(".ts")[0] + `.md5`;
|
|
80
|
+
|
|
81
|
+
fs.promises.mkdir(path.dirname(pp), { recursive: true }).then(x => {
|
|
82
|
+
const hash = createHash('md5').update(text).digest('hex');
|
|
83
|
+
console.log("build.js test", key, hash);
|
|
84
|
+
fs.promises.writeFile(pp, text);
|
|
85
|
+
fs.promises.writeFile(xx, hash);
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { BaseGiven, BaseCheck, BaseSuite, BaseFeature, BaseWhen, BaseThen } from "./BaseClasses";
|
|
2
|
+
import { TesterantoLevelOne } from "./lib/level1";
|
|
3
|
+
import { ITestImplementation, ITestSpecification, ITTestResource, ITTestResourceRequirement, ITTestShape, Modify } from "./types"
|
|
4
|
+
|
|
5
|
+
export type { ITestImplementation, ITestSpecification, ITTestShape, Modify };
|
|
6
|
+
|
|
7
|
+
export const Testeranto = <
|
|
8
|
+
TestShape extends ITTestShape,
|
|
9
|
+
Input,
|
|
10
|
+
Subject,
|
|
11
|
+
Store,
|
|
12
|
+
Selection,
|
|
13
|
+
WhenShape,
|
|
14
|
+
ThenShape,
|
|
15
|
+
InitialStateShape
|
|
16
|
+
>(
|
|
17
|
+
input: Input,
|
|
18
|
+
testSpecification: ITestSpecification<TestShape>,
|
|
19
|
+
testImplementation,
|
|
20
|
+
// testImplementation: ITestImplementation<
|
|
21
|
+
// InitialStateShape,
|
|
22
|
+
// Selection,
|
|
23
|
+
// WhenShape,
|
|
24
|
+
// ThenShape,
|
|
25
|
+
// TestShape
|
|
26
|
+
// >,
|
|
27
|
+
testResource: ITTestResourceRequirement,
|
|
28
|
+
|
|
29
|
+
testInterface: {
|
|
30
|
+
actionHandler?: (b: (...any) => any) => any,
|
|
31
|
+
afterEach?: (store: Store, ndx: number, cb) => unknown,
|
|
32
|
+
andWhen: (store: Store, actioner, testResource: ITTestResource) => Promise<Selection>,
|
|
33
|
+
assertioner?: (t: ThenShape) => any,
|
|
34
|
+
beforeAll?: (input: Input) => Promise<Subject>,
|
|
35
|
+
beforeEach?: (subject: Subject, initialValues, testResource: ITTestResource) => Promise<Store>,
|
|
36
|
+
butThen?: (store: Store, callback, testResource: ITTestResource) => Promise<Selection>,
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
) => {
|
|
40
|
+
|
|
41
|
+
const butThen = testInterface.butThen || (async (a) => a as any);
|
|
42
|
+
const { andWhen } = testInterface;
|
|
43
|
+
const actionHandler = testInterface.actionHandler || function (b: (...any: any[]) => any) {
|
|
44
|
+
return b;
|
|
45
|
+
};
|
|
46
|
+
const assertioner = testInterface.assertioner || (async (t) => t as any);
|
|
47
|
+
const beforeAll = testInterface.beforeAll || (async (input) => input as any);
|
|
48
|
+
const beforeEach = testInterface.beforeEach || async function (subject: Input, initialValues: any, testResource: any) {
|
|
49
|
+
return subject as any;
|
|
50
|
+
}
|
|
51
|
+
const afterEach = testInterface.afterEach || (async (s) => s);
|
|
52
|
+
|
|
53
|
+
return class extends TesterantoLevelOne<
|
|
54
|
+
TestShape,
|
|
55
|
+
InitialStateShape,
|
|
56
|
+
Selection,
|
|
57
|
+
Store,
|
|
58
|
+
Subject,
|
|
59
|
+
WhenShape,
|
|
60
|
+
ThenShape,
|
|
61
|
+
Input
|
|
62
|
+
> {
|
|
63
|
+
constructor() {
|
|
64
|
+
super(
|
|
65
|
+
testImplementation,
|
|
66
|
+
/* @ts-ignore:next-line */
|
|
67
|
+
testSpecification,
|
|
68
|
+
input,
|
|
69
|
+
(class extends BaseSuite<Input, Subject, Store, Selection, ThenShape, TestShape> {
|
|
70
|
+
async setup(s: Input): Promise<Subject> {
|
|
71
|
+
return beforeAll(s);
|
|
72
|
+
}
|
|
73
|
+
test(t: ThenShape): unknown {
|
|
74
|
+
return assertioner(t);
|
|
75
|
+
}
|
|
76
|
+
}),
|
|
77
|
+
|
|
78
|
+
class Given extends BaseGiven<Subject, Store, Selection, ThenShape> {
|
|
79
|
+
initialValues: any;
|
|
80
|
+
constructor(
|
|
81
|
+
name: string,
|
|
82
|
+
features: BaseFeature[],
|
|
83
|
+
whens: BaseWhen<Store, Selection, ThenShape>[],
|
|
84
|
+
thens: BaseThen<Selection, Store, ThenShape>[],
|
|
85
|
+
initialValues: any
|
|
86
|
+
) {
|
|
87
|
+
super(name, features, whens, thens);
|
|
88
|
+
this.initialValues = initialValues;
|
|
89
|
+
}
|
|
90
|
+
async givenThat(subject, testResource) {
|
|
91
|
+
return beforeEach(subject, this.initialValues, testResource);
|
|
92
|
+
}
|
|
93
|
+
afterEach(store: Store, ndx: number, cb): Promise<unknown> {
|
|
94
|
+
return new Promise((res) => res(afterEach(store, ndx, cb)))
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
class When extends BaseWhen<Store, Selection, WhenShape> {
|
|
99
|
+
payload?: any;
|
|
100
|
+
|
|
101
|
+
constructor(name: string, actioner: (...any) => any, payload?: any) {
|
|
102
|
+
super(name, (store) => {
|
|
103
|
+
return actionHandler(actioner)
|
|
104
|
+
});
|
|
105
|
+
this.payload = payload;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async andWhen(store, actioner, testResource) {
|
|
109
|
+
return await andWhen(store, actioner, testResource);
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
class Then extends BaseThen<Selection, Store, ThenShape> {
|
|
114
|
+
constructor(
|
|
115
|
+
name: string,
|
|
116
|
+
callback: (val: Selection) => ThenShape
|
|
117
|
+
) {
|
|
118
|
+
super(name, callback);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async butThen(store: any, testResourceConfiguration?: any): Promise<Selection> {
|
|
122
|
+
return await butThen(store, this.thenCB, testResourceConfiguration)
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
class Check extends BaseCheck<Subject, Store, Selection, ThenShape, TestShape> {
|
|
127
|
+
initialValues: any;
|
|
128
|
+
|
|
129
|
+
constructor(
|
|
130
|
+
name: string,
|
|
131
|
+
features: BaseFeature[],
|
|
132
|
+
checkCallback: (a, b) => any,
|
|
133
|
+
whens,
|
|
134
|
+
thens,
|
|
135
|
+
initialValues: any,
|
|
136
|
+
) {
|
|
137
|
+
super(name, features, checkCallback, whens, thens);
|
|
138
|
+
this.initialValues = initialValues;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async checkThat(subject, testResource) {
|
|
142
|
+
return beforeEach(subject, this.initialValues, testResource);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
afterEach(store: Store, ndx: number, cb): Promise<unknown> {
|
|
146
|
+
return new Promise((res) => res(afterEach(store, ndx, cb)))
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
testResource
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|