risei 1.2.0 → 1.3.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/README.md +113 -46
- package/index.js +18 -5
- package/package.json +3 -4
- package/system/ASpoofingFixture.js +3 -3
- package/system/ATestFinder.js +13 -0
- package/system/Risei.js +82 -52
- package/system/SpoofClassMethodsFixture.js +5 -5
- package/system/{SpoofTuple.js → SpoofDefinition.js} +20 -20
- package/system/SpoofObjectMethodsFixture.js +3 -3
- package/system/{TestTuple.js → TestDefinition.js} +43 -28
- package/system/TestFinder.js +11 -5
- package/system/TestFrame.js +16 -108
- package/system/TestRunner.js +4 -4
- package/system/TestStages.js +5 -13
- package/system/TotalCopier.js +28 -4
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
## What Risei is
|
|
5
5
|
|
|
6
6
|
**Risei is a new way to write unit tests that allows you to:**
|
|
7
|
-
* Whip up full test coverage of object-oriented or object-hosted JavaScript in no time.
|
|
7
|
+
* Whip up full test coverage of object-oriented or object-hosted JavaScript and TypeScript in no time.
|
|
8
8
|
* Refactor or replace existing designs without worrying about the cost in past or future test time.
|
|
9
9
|
* Create tests with immediate confidence, because you can't introduce mistakes in test code you write.
|
|
10
10
|
|
|
@@ -41,7 +41,11 @@ Test runs also feature a title bar at the top, as well as a summary bar at the b
|
|
|
41
41
|
|
|
42
42
|
## Using Risei
|
|
43
43
|
|
|
44
|
-
Risei is under active development. If you've been here before, check out [what's new in Risei](#whats-new-in-risei) for the latest. Also see [known
|
|
44
|
+
Risei is under active development. If you've been here before, check out [what's new in Risei](#whats-new-in-risei) for the latest. Also see [known issues and workarounds](#known-issues-and-workarounds) and [limitations in Risei](#limitations-in-risei).
|
|
45
|
+
|
|
46
|
+
There are a few additional or different steps for [using Typescript with Risei](#using-typescript-with-risei).
|
|
47
|
+
|
|
48
|
+
|
|
45
49
|
|
|
46
50
|
### Installation
|
|
47
51
|
|
|
@@ -65,6 +69,8 @@ And add Risei's metadata to `package.json`:
|
|
|
65
69
|
}
|
|
66
70
|
```
|
|
67
71
|
|
|
72
|
+
Just a [few extra steps](#using-typescript-with-risei) are required for Risei to work with TypeScript.
|
|
73
|
+
|
|
68
74
|
|
|
69
75
|
|
|
70
76
|
### Siting tests
|
|
@@ -117,13 +123,15 @@ You can save a lot of time by putting repeated test properties into an object on
|
|
|
117
123
|
{ of: "countOf", for: "Returns the number present.", in: [ "b" ], out: 2 }
|
|
118
124
|
```
|
|
119
125
|
|
|
120
|
-
This _collapsing forward_ works for just about every test property, but is reset when you change the class in `.on`, when you give the property a new value, or you erase it with an empty array `[ ]`.
|
|
126
|
+
- This _collapsing forward_ works for just about every test property, but is reset when you change the class in `.on`, when you give the property a new value, or you erase it with an empty array `[ ]`.
|
|
127
|
+
|
|
128
|
+
- Collapsing forward doesn't reduce test isolation — for instance, with mutable args — because Risei always runs a copy of the test definition, not the original.
|
|
121
129
|
|
|
122
130
|
|
|
123
131
|
|
|
124
132
|
#### Spoof away code dependencies:
|
|
125
133
|
|
|
126
|
-
When your
|
|
134
|
+
When your tests need certain results from code dependencies, just _spoof_ what you want using a `.plus` test property:
|
|
127
135
|
|
|
128
136
|
```javascript
|
|
129
137
|
{ on: CombinerClass, with: [ ],
|
|
@@ -145,7 +153,9 @@ When your code has dependencies on other code, just _spoof_ the results of that
|
|
|
145
153
|
in: [ "green" ], out: [ 7, 8, 9, 10, 10, 11, 12, { color: "green" } ] }
|
|
146
154
|
```
|
|
147
155
|
|
|
148
|
-
|
|
156
|
+
- Spoofing collapses forward across tests, but not across the elements within `.plus`.
|
|
157
|
+
|
|
158
|
+
- Spoofing is also fully isolated within tests.
|
|
149
159
|
|
|
150
160
|
|
|
151
161
|
|
|
@@ -171,15 +181,15 @@ And then run that script:
|
|
|
171
181
|
npm test
|
|
172
182
|
```
|
|
173
183
|
|
|
174
|
-
Risei can be used alongside other test frameworks
|
|
184
|
+
Risei can be used alongside other test frameworks, and even run with them from the same test script if you want.
|
|
175
185
|
|
|
176
186
|
|
|
177
187
|
|
|
178
188
|
### Learning more about Risei
|
|
179
189
|
|
|
180
|
-
|
|
190
|
+
Read through the rest of this doc to learn more about Risei's many capabilities, and about where Risei is headed.
|
|
181
191
|
|
|
182
|
-
- For instance, learn about using `.and` to test static
|
|
192
|
+
- For instance, learn about using `.and` to test static methods or throws.
|
|
183
193
|
- Or learn about using `.from` to test property results or other state.
|
|
184
194
|
- Don't miss out: Once you've tried the basics, read the rest...!
|
|
185
195
|
|
|
@@ -188,6 +198,11 @@ Be sure to read through the rest of this doc to learn more about Risei's many ca
|
|
|
188
198
|
|
|
189
199
|
## Risei in depth
|
|
190
200
|
|
|
201
|
+
<details>
|
|
202
|
+
<summary>
|
|
203
|
+
There's plenty more to learn about Risei and how it makes testing easy...
|
|
204
|
+
</summary>
|
|
205
|
+
|
|
191
206
|
### Installation
|
|
192
207
|
|
|
193
208
|
- You can use any file extension you want in Risei's metadata in `package.json`, and Risei will scan those files for tests.
|
|
@@ -211,6 +226,7 @@ Be sure to read through the rest of this doc to learn more about Risei's many ca
|
|
|
211
226
|
- The order and placement of test properties doesn't matter, although the order seen in the examples is probably most readable.
|
|
212
227
|
|
|
213
228
|
|
|
229
|
+
|
|
214
230
|
#### Basic test properties and options for each:
|
|
215
231
|
|
|
216
232
|
| Name | Contents |
|
|
@@ -226,25 +242,22 @@ Be sure to read through the rest of this doc to learn more about Risei's many ca
|
|
|
226
242
|
- The property names were chosen to be easy to remember and type, but longer alternatives are available, covered later.
|
|
227
243
|
|
|
228
244
|
|
|
229
|
-
</details>
|
|
230
|
-
|
|
231
245
|
|
|
232
246
|
### Test-property reuse _AKA_ Collapsing forward
|
|
233
247
|
|
|
234
248
|
- To save time and effort, any property you write is collapsed forward to subsequent tests unless you replace it or erase it with an empty array `[ ]`.
|
|
235
249
|
- Property values are gathered across partial test objects until they add up to a runnable test, which is then run.
|
|
236
250
|
- Changes to properties are combined with previous ones to produce intended new tests.
|
|
237
|
-
- For a rare and avoidable side-effect of this system, see [
|
|
251
|
+
- For a rare and avoidable side-effect of this system, see [known issues and workarounds](#known-issues-and-workarounds).
|
|
238
252
|
|
|
239
253
|
- Test contents, reused or not, are automatically reset when it makes the most sense:
|
|
240
254
|
- Changing the tested class in `.on` wipes out all prior test properties, so the new class has a fresh start.
|
|
241
255
|
- Changing the tested method in `.of` wipes out only test properties related to methods, to preserve class values you usually want.
|
|
242
256
|
|
|
257
|
+
- Individual tests remain fully isolated:
|
|
258
|
+
- Test args, including objects and functions in `.with`, `.plus`, and `.in`, are all copied for running in each test, so nothing is reused across tests.
|
|
259
|
+
- Class instances, spoofs (covered later), and so on are all created anew for each test.
|
|
243
260
|
|
|
244
|
-
- Individual tests remain isolated because class instances, spoofed methods (covered later) and so on are all created anew for each test.
|
|
245
|
-
- However, input (`.in`) and instantiation (`.with`) arguments that are mutated by tested code are not yet isolated.
|
|
246
|
-
- They will be fully isolated in a future release.
|
|
247
|
-
- In the meantime, calling a function to supply them to `.in` or `.with` does isolate them completely.
|
|
248
261
|
|
|
249
262
|
|
|
250
263
|
### Choosing test-only dependency inputs _AKA_ Spoofing
|
|
@@ -257,6 +270,7 @@ Be sure to read through the rest of this doc to learn more about Risei's many ca
|
|
|
257
270
|
- All classes whose members are being spoofed have to be imported.
|
|
258
271
|
|
|
259
272
|
|
|
273
|
+
|
|
260
274
|
#### Spoof-definition properties:
|
|
261
275
|
|
|
262
276
|
| Name | Necessary or Optional | Contents |
|
|
@@ -342,7 +356,7 @@ To test a value that isn't the exercised code's return value, you use `.out` nor
|
|
|
342
356
|
|
|
343
357
|
|
|
344
358
|
- Getting properties, mutated args, and other non-return values is known as _retrieving_.
|
|
345
|
-
- Retrieving definitions collapse forward across tests unless
|
|
359
|
+
- Retrieving definitions collapse forward across tests unless replaced with new definitions, or erased by setting `.from` to an empty array `[ ]`.
|
|
346
360
|
|
|
347
361
|
|
|
348
362
|
<details>
|
|
@@ -446,9 +460,72 @@ Constructors can be tested with no special test properties or keywords.
|
|
|
446
460
|
- Any `.with` args are completely ignored for a constructor test. Only those in the test's `.in` property are used.
|
|
447
461
|
- However, a `.with` must still be provided. It can simply be an empty array `[ ]`.
|
|
448
462
|
|
|
463
|
+
</details>
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
## Using TypeScript with Risei
|
|
469
|
+
|
|
470
|
+
Testing TypeScript code with Risei basically just means transpiling before running the tests, and being sure to point to its output JS files, not the TS ones.
|
|
471
|
+
|
|
472
|
+
- Anything beyond those basics is intended to keep JS files separate from TS files and the output of web frameworks' own, complex build processes.
|
|
473
|
+
|
|
474
|
+
If you follow the general Risei set-up, you can just make the following few modifications for TypeScript applications.
|
|
475
|
+
- These steps have worked with both Angular and React.
|
|
476
|
+
- Variant approaches are also sure to work, depending on the other technical choices in play.
|
|
477
|
+
|
|
449
478
|
|
|
450
479
|
|
|
451
|
-
###
|
|
480
|
+
### In `package.json`:
|
|
481
|
+
|
|
482
|
+
Add transpilation and deletion operations to the `test` script, with each operation conditional on completion of the preceding one:
|
|
483
|
+
|
|
484
|
+
```json
|
|
485
|
+
"scripts": {
|
|
486
|
+
"test": "tsc && node ./node_modules/risei/index.js && rm -r ./dist/out-tsc"
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
- Generally, you should use `tsc` or another plain transpiler, not web frameworks' complex processes with single output files.
|
|
491
|
+
- Deleting the files at the end prevents interference with web frameworks' bundling.
|
|
492
|
+
- The deletion path must match the `outDir` in `tsconfig.json`.
|
|
493
|
+
|
|
494
|
+
> You can run Risei manually with the same sequence of operations.
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
### In `tsconfig.json`:
|
|
499
|
+
|
|
500
|
+
You set up the transpiler to output files to a directory with these settings:
|
|
501
|
+
|
|
502
|
+
```json
|
|
503
|
+
{
|
|
504
|
+
"outDir": "dist/out-tsc",
|
|
505
|
+
"noEmit": false
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
- The `outDir` can be any location. It's best not to just use `dist`, where adding or deleting files may interfere with web frameworks' build steps.
|
|
510
|
+
- These settings are normally not near each other in the file (as seen here).
|
|
511
|
+
- You can also set the `target` to `es6` or higher, although Risei works fine with ES5.
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
### In test files:
|
|
517
|
+
|
|
518
|
+
All `import` statements have to point to the `outDir` path or subfolders there, using relative-path syntax:
|
|
519
|
+
|
|
520
|
+
```javascript
|
|
521
|
+
import { TestedClass } from "../../dist/out-tsc/SubPath/TestedClass.js";
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
- Output files may be in a folder tree parallel to the originals (Angular), or may all be in the `outDir` folder itself (React).
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
## Limitations in Risei
|
|
452
529
|
|
|
453
530
|
The following are not supported at present:
|
|
454
531
|
- Use of `async` syntax
|
|
@@ -468,52 +545,42 @@ Some of these are on the tentative future-development list. In the meanti
|
|
|
468
545
|
|
|
469
546
|
Most problems with using Risei are minor mistakes in syntax, or omissions in test definitions:
|
|
470
547
|
|
|
471
|
-
| Error condition or text
|
|
472
|
-
|
|
473
|
-
|
|
|
474
|
-
| `"Test loading failed for... SyntaxError: Unexpected token ':'"` | Missing comma in your tests in the named file
|
|
475
|
-
| `"Test loading failed for... SyntaxError: Unexpected token '.'"` | Using `this.tests = []` instead of `tests = []` in the file named
|
|
476
|
-
| Other `... Unexpected token ...` errors | Some other syntax error in the file named, most likely a missing or extra delimiter
|
|
477
|
-
| Unexpected actual values, or unexpected passes / fails in test runs | Spoofs, retrievals, or special conditions from previous tests not replaced or reset with `[ ]`<br>— or —<br>
|
|
548
|
+
| Error condition or text | Probable cause / fix |
|
|
549
|
+
|---------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
550
|
+
| Gold bar appears below the summary, and the number of tests run drops | A syntax error caused a test file not to load; error output in the gold bar explains why |
|
|
551
|
+
| `"Test loading failed for... SyntaxError: Unexpected token ':'"` | Missing comma in your tests in the named file |
|
|
552
|
+
| `"Test loading failed for... SyntaxError: Unexpected token '.'"` | Using `this.tests = []` instead of `tests = []` in the file named |
|
|
553
|
+
| Other `... Unexpected token ...` errors | Some other syntax error in the file named, most likely a missing or extra delimiter |
|
|
554
|
+
| Unexpected actual values, or unexpected passes / fails in test runs | Spoofs, retrievals, or special conditions from previous tests not replaced or reset with `[ ]`<br>— or —<br>Pre-listed test properties produce extra tests: preventable by restating class in `.on` |
|
|
478
555
|
|
|
479
556
|
|
|
480
557
|
|
|
481
558
|
|
|
482
|
-
## Known
|
|
559
|
+
## Known issues and workarounds
|
|
483
560
|
|
|
484
|
-
|
|
485
|
-
- When the args stated in `.with` or `.in` are mutated by the method under test (or by anything done within a test), the mutated values are carried forward to other tests.
|
|
486
|
-
- A workaround exists for now: just provide those args using a fixture function when they may be mutated. The function is called each time, isolating them completely.
|
|
561
|
+
- No bugs are known to exist at present.
|
|
487
562
|
|
|
563
|
+
- One unexpected result is known to exist:
|
|
564
|
+
- Changing one or more properties in objects by themselves in the middle of tests (perhaps to emphasize them) can create extra tests.
|
|
565
|
+
- The extra tests usually fail, because they have an unintended mix of old and new properties.
|
|
566
|
+
- In this case, Rs is actually working properly, running prior tests with the new properties swapped in.
|
|
567
|
+
- To avoid this problem, include changed properties in full tests to run, or restate `.of` along with the changed properties.
|
|
488
568
|
|
|
489
|
-
- This
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
One known unexpected result (not quite a bug) exists:
|
|
493
|
-
- Because test properties collapse forward to form whole tests, pre-stating new properties for upcoming tests without changing `.on` is treated as a new test like prior ones, with just those properties changed.
|
|
494
|
-
- Pre-stating properties might be done as a way to make them stand out when reading through the tests.
|
|
495
|
-
|
|
496
|
-
- This means you see an extra unexpected test that most likely fails, due to the mix of old and new properties.
|
|
497
|
-
|
|
498
|
-
- A workaround exists: if you pre-state new properties, also restate the class under test in `.on`, which erases all prior test properties.
|
|
499
|
-
- Restating `.on` doesn't cause the class name to be displayed again in output.
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
- This output is rarely an issue, and may be what is wanted in some cases, but options for preventing it are being considered.
|
|
569
|
+
- This situation is rarely an issue, but ways to optionally prevent it are being considered.
|
|
503
570
|
|
|
504
571
|
|
|
505
572
|
|
|
506
573
|
## What's new in Risei
|
|
507
574
|
|
|
508
|
-
- Release **1.
|
|
575
|
+
- Release **1.3.0** (February, 2024) moves the display of test-loading error messages to a new gold bar that appears at the bottom of the summary when there are any loading errors. A sorting error that occurs when no test files exist yet has also been fixed.
|
|
509
576
|
|
|
577
|
+
- Release **1.2.0** (January, 2024) changes sorting of test files. Previously they were displayed in the order found. Now the order remains the same, except that the last-edited file is moved to the bottom, making it easy to see the latest test results.
|
|
510
578
|
|
|
511
579
|
- Release **1.1.2** of Risei (January, 2024) fixes two problems:
|
|
512
580
|
- Classes were sometimes displayed in output as their entire definition. Now just the class name is displayed.
|
|
513
581
|
- All `Date` instances were considered equal, regardless of their actual value. Now they only are considered equal when they actually are.
|
|
514
582
|
|
|
515
|
-
|
|
516
|
-
> Don't use release **1.1.1**, which contains an internal path error.
|
|
583
|
+
- Don't use release **1.1.1**, which contains an internal path error.
|
|
517
584
|
|
|
518
585
|
|
|
519
586
|
|
|
@@ -534,7 +601,7 @@ Risei is published for use under the terms of the MIT license:
|
|
|
534
601
|
|
|
535
602
|
<div style="border: solid darkgray 1px; padding: 0.5rem;">
|
|
536
603
|
|
|
537
|
-
<b>Risei Copyright © 2023 Ed Fallin</b>
|
|
604
|
+
<b>Risei Copyright © 2023–2024 Ed Fallin</b>
|
|
538
605
|
|
|
539
606
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
540
607
|
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
|
-
/* Copyright (c) 2023 Ed Fallin. Published under the terms of the MIT license. */
|
|
3
|
+
/* Copyright (c) 2023-2024 Ed Fallin. Published under the terms of the MIT license. */
|
|
4
4
|
|
|
5
5
|
/* This index.js is the entry point for running Risei tests from
|
|
6
6
|
other code. It imports other modules to perform its work.
|
|
@@ -47,6 +47,7 @@ export * from "./system/ATestReporter.js";
|
|
|
47
47
|
|
|
48
48
|
/* Display styles for the start title and other general needs. */
|
|
49
49
|
const title = chalk.hex("FFFFFF").bgHex("191970").bold;
|
|
50
|
+
const fails = chalk.hex("000000").bgHex("FFD700").bold;
|
|
50
51
|
|
|
51
52
|
// endregion Named styles
|
|
52
53
|
|
|
@@ -61,7 +62,7 @@ let wide = (text) => {
|
|
|
61
62
|
|
|
62
63
|
// endregion Styling for color stripes
|
|
63
64
|
|
|
64
|
-
// region Key callable, its
|
|
65
|
+
// region Key callable, its scripted call, and its export
|
|
65
66
|
|
|
66
67
|
async function runRiseiTests(testFinderPath) {
|
|
67
68
|
// region Converting test-finder from path to class
|
|
@@ -90,7 +91,7 @@ async function runRiseiTests(testFinderPath) {
|
|
|
90
91
|
console.log();
|
|
91
92
|
|
|
92
93
|
// endregion Intro / title
|
|
93
|
-
|
|
94
|
+
|
|
94
95
|
// region Running tests
|
|
95
96
|
|
|
96
97
|
// Test-system objects and their relationships.
|
|
@@ -104,7 +105,19 @@ async function runRiseiTests(testFinderPath) {
|
|
|
104
105
|
await caller.runAllTests();
|
|
105
106
|
|
|
106
107
|
// endregion Running tests
|
|
107
|
-
|
|
108
|
+
|
|
109
|
+
// region Trailing display of test-loading issues
|
|
110
|
+
|
|
111
|
+
if (finder.thrown.length !== 0) {
|
|
112
|
+
let loadFails = finder.thrown;
|
|
113
|
+
|
|
114
|
+
for (let fail of loadFails) {
|
|
115
|
+
console.log(fails(wide(` ${ fail }`)));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// endregion Trailing display of test-loading issues
|
|
120
|
+
|
|
108
121
|
// region Trailing formatting
|
|
109
122
|
|
|
110
123
|
console.log();
|
|
@@ -118,5 +131,5 @@ await runRiseiTests();
|
|
|
118
131
|
|
|
119
132
|
export default runRiseiTests;
|
|
120
133
|
|
|
121
|
-
// endregion Key callable, its
|
|
134
|
+
// endregion Key callable, its scripted call, and its export
|
|
122
135
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "risei",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Risei is the framework that allows you to write unit tests as collections of values in JavaScript objects, so it's easy and fast, and tests don't serve as a drag on redesigns.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"unit test",
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
"test": "clear; node ./node_modules/risei/index.js"
|
|
29
29
|
},
|
|
30
30
|
"risei": {
|
|
31
|
-
"tests": "**.rt.js"
|
|
32
|
-
"sort": "normal"
|
|
31
|
+
"tests": "**.rt.js"
|
|
33
32
|
},
|
|
34
33
|
"exports": {
|
|
35
34
|
".": "./index.js",
|
|
@@ -49,6 +48,6 @@
|
|
|
49
48
|
"fs": "^0.0.1-security",
|
|
50
49
|
"mocha": "^10.0.0",
|
|
51
50
|
"morgan": "~1.9.1",
|
|
52
|
-
"risei": "1.
|
|
51
|
+
"risei": "1.2.0"
|
|
53
52
|
}
|
|
54
53
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
3
|
import { ATestFixture } from "./ATestFixture.js";
|
|
4
|
-
import {
|
|
4
|
+
import { SpoofDefinition } from "./SpoofDefinition.js";
|
|
5
5
|
|
|
6
6
|
export class ASpoofingFixture extends ATestFixture {
|
|
7
7
|
constructor(name, kind) {
|
|
@@ -25,8 +25,8 @@ export class ASpoofingFixture extends ATestFixture {
|
|
|
25
25
|
// Recursive case: Spoof defines a whole object
|
|
26
26
|
// tree to be returned as method output.
|
|
27
27
|
if (Array.isArray(spoofOutput)) {
|
|
28
|
-
if (spoofOutput.every(x =>
|
|
29
|
-
spoofOutput =
|
|
28
|
+
if (spoofOutput.every(x => SpoofDefinition.isASpoof(x))) {
|
|
29
|
+
spoofOutput = SpoofDefinition.fromNonceTuples(spoofOutput);
|
|
30
30
|
spoofOutput = this.spoofObjectTree(spoofOutput);
|
|
31
31
|
}
|
|
32
32
|
}
|
package/system/ATestFinder.js
CHANGED
|
@@ -5,7 +5,14 @@
|
|
|
5
5
|
import { ATestSource } from "./ATestSource.js";
|
|
6
6
|
|
|
7
7
|
export class ATestFinder {
|
|
8
|
+
// region Fields
|
|
9
|
+
|
|
8
10
|
#testSources;
|
|
11
|
+
#thrown = [];
|
|
12
|
+
|
|
13
|
+
// endregion Fields
|
|
14
|
+
|
|
15
|
+
// region Properties
|
|
9
16
|
|
|
10
17
|
get testSources() {
|
|
11
18
|
return this.#testSources;
|
|
@@ -15,6 +22,12 @@ export class ATestFinder {
|
|
|
15
22
|
this.#testSources = value;
|
|
16
23
|
}
|
|
17
24
|
|
|
25
|
+
get thrown() {
|
|
26
|
+
return this.#thrown;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// endregion Properties
|
|
30
|
+
|
|
18
31
|
constructor() {
|
|
19
32
|
this.#testSources = [];
|
|
20
33
|
}
|
package/system/Risei.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
|
-
/*
|
|
4
|
-
|
|
3
|
+
/* Copyright (c) 2023-2024 Ed Fallin. Published under the terms of the MIT license. */
|
|
4
|
+
|
|
5
|
+
/* This index.js is the entry point for running Risei tests from
|
|
6
|
+
other code. It imports other modules to perform its work.
|
|
7
|
+
It also exports modules that should / can be subclassed. */
|
|
8
|
+
|
|
9
|
+
// region Imports
|
|
5
10
|
|
|
6
11
|
// region Test-running dependencies
|
|
7
12
|
|
|
8
13
|
import { TestRunner } from "./TestRunner.js";
|
|
9
|
-
import { ChosenTestFinder } from "./ChosenTestFinder.js";
|
|
10
14
|
import { LocalCaller } from "./LocalCaller.js";
|
|
11
15
|
import { TerminalReporter } from "./TerminalReporter.js";
|
|
16
|
+
import { TestFinder } from "./TestFinder.js";
|
|
12
17
|
|
|
13
18
|
// endregion Test-running dependencies
|
|
14
19
|
|
|
@@ -19,19 +24,13 @@ import { Moment } from "./Moment.js";
|
|
|
19
24
|
|
|
20
25
|
// endregion Display dependencies
|
|
21
26
|
|
|
27
|
+
// endregion Imports
|
|
28
|
+
|
|
22
29
|
// region Named styles
|
|
23
30
|
|
|
24
31
|
/* Display styles for the start title and other general needs. */
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const onGreen = chalk.bgGreenBright;
|
|
28
|
-
|
|
29
|
-
const future = chalk.hex("FFFFFF").bgHex("191970").bold;
|
|
30
|
-
|
|
31
|
-
/* Display styles for tests. */
|
|
32
|
-
const group = chalk.hex("FFFFFF").bgHex("0000CD");
|
|
33
|
-
const passed = chalk.hex("000000").bgHex("90EE90");
|
|
34
|
-
const failed = chalk.hex("000000").bgHex("F08080");
|
|
32
|
+
const title = chalk.hex("FFFFFF").bgHex("191970").bold;
|
|
33
|
+
const fails = chalk.hex("000000").bgHex("FFD700").bold;
|
|
35
34
|
|
|
36
35
|
// endregion Named styles
|
|
37
36
|
|
|
@@ -46,43 +45,74 @@ let wide = (text) => {
|
|
|
46
45
|
|
|
47
46
|
// endregion Styling for color stripes
|
|
48
47
|
|
|
49
|
-
// region
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
let
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
48
|
+
// region Key callable and its scripted call
|
|
49
|
+
|
|
50
|
+
async function runRiseiMetaTests(testFinderPath) {
|
|
51
|
+
// region Converting test-finder from path to class
|
|
52
|
+
|
|
53
|
+
testFinderPath = testFinderPath || "./TestFinder.js";
|
|
54
|
+
let finderModule = await import(testFinderPath);
|
|
55
|
+
|
|
56
|
+
let moduleKeys = Object.keys(finderModule);
|
|
57
|
+
let classKey = moduleKeys[0];
|
|
58
|
+
let finderClass = finderModule[classKey];
|
|
59
|
+
|
|
60
|
+
// endregion Converting test-finder from path to class
|
|
61
|
+
|
|
62
|
+
// region Intro / title
|
|
63
|
+
|
|
64
|
+
console.clear();
|
|
65
|
+
console.log();
|
|
66
|
+
console.log(title(wide()));
|
|
67
|
+
|
|
68
|
+
let now = new Date();
|
|
69
|
+
now = new Moment(now);
|
|
70
|
+
|
|
71
|
+
console.log(title(wide(` Risei tests run on ${ now.asReadable() } local time.`)));
|
|
72
|
+
console.log(title(wide()));
|
|
73
|
+
|
|
74
|
+
console.log();
|
|
75
|
+
|
|
76
|
+
// endregion Intro / title
|
|
77
|
+
|
|
78
|
+
// region Running tests
|
|
79
|
+
|
|
80
|
+
// Test-system objects and their relationships.
|
|
81
|
+
const finder = new finderClass.prototype.constructor();
|
|
82
|
+
finder.sourceBySearch = () => { return { tests: "**.outward-rt.js" }; };
|
|
83
|
+
|
|
84
|
+
const runner = new TestRunner();
|
|
85
|
+
const reporter = new TerminalReporter();
|
|
86
|
+
|
|
87
|
+
const caller = new LocalCaller(finder, runner, reporter);
|
|
88
|
+
|
|
89
|
+
// Actually running the tests using this system.
|
|
90
|
+
await caller.runAllTests();
|
|
91
|
+
|
|
92
|
+
// endregion Running tests
|
|
93
|
+
|
|
94
|
+
// region Trailing display of test-loading issues
|
|
95
|
+
|
|
96
|
+
if (finder.thrown.length !== 0) {
|
|
97
|
+
let loadFails = finder.thrown;
|
|
98
|
+
|
|
99
|
+
for (let fail of loadFails) {
|
|
100
|
+
console.log(fails(wide(` ${ fail }`)));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// endregion Trailing display of test-loading issues
|
|
105
|
+
|
|
106
|
+
// region Trailing formatting
|
|
107
|
+
|
|
108
|
+
console.log();
|
|
109
|
+
console.log();
|
|
110
|
+
|
|
111
|
+
// endregion Trailing formatting
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Runs tests now. */
|
|
115
|
+
await runRiseiMetaTests();
|
|
116
|
+
|
|
117
|
+
// endregion Key callable and its scripted call
|
|
88
118
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
3
|
import { ASpoofingFixture } from "./ASpoofingFixture.js";
|
|
4
|
-
import {
|
|
4
|
+
import { SpoofDefinition } from "./SpoofDefinition.js";
|
|
5
5
|
|
|
6
6
|
export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
7
7
|
/* Algorithm: Forward method spoof() looks at spoof definitions in .plus and applies them
|
|
@@ -53,10 +53,10 @@ export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// Converting to scope object type.
|
|
56
|
-
let
|
|
56
|
+
let spoofDefinitionss = SpoofDefinition.fromNonceTuples(spoofNonces);
|
|
57
57
|
|
|
58
58
|
// Storing spoofing definitions.
|
|
59
|
-
this.#retainSpoofsByClass(type,
|
|
59
|
+
this.#retainSpoofsByClass(type, spoofDefinitionss);
|
|
60
60
|
|
|
61
61
|
// Storing originals for restoring later.
|
|
62
62
|
this.#reserveOriginalsByClass();
|
|
@@ -67,9 +67,9 @@ export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
|
67
67
|
|
|
68
68
|
// region Dependencies of spoof()
|
|
69
69
|
|
|
70
|
-
#retainSpoofsByClass(type,
|
|
70
|
+
#retainSpoofsByClass(type, spoofDefinitionss) {
|
|
71
71
|
// Map of Maps: by type, then by method.
|
|
72
|
-
for (let tuple of
|
|
72
|
+
for (let tuple of spoofDefinitionss) {
|
|
73
73
|
// If no .target, use `type`.
|
|
74
74
|
if (!tuple.target) {
|
|
75
75
|
tuple.target = type;
|