risei 1.3.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +142 -379
  2. package/Read-me reduced.md +294 -0
  3. package/Read-me redux.md +581 -0
  4. package/index.js +5 -5
  5. package/package.json +10 -11
  6. package/system/ASpoofingFixture.js +7 -8
  7. package/system/ATestCaller.js +3 -3
  8. package/system/ATestFinder.js +2 -2
  9. package/system/ATestReporter.js +2 -1
  10. package/system/ATestSource.js +5 -1
  11. package/system/ChosenTestFinder.js +4 -4
  12. package/system/ClassTestGroup.js +2 -2
  13. package/system/LocalCaller.js +5 -5
  14. package/system/{ClassMethodSpoofer.js → MethodSpoofer.js} +54 -48
  15. package/system/MethodTestGroup.js +2 -2
  16. package/system/Moment.js +1 -1
  17. package/system/NameAnalyzer.js +26 -0
  18. package/system/PropertySpoofer.js +156 -0
  19. package/system/Risei.js +5 -5
  20. package/system/SpoofDef.js +260 -0
  21. package/system/TerminalReporter.js +8 -8
  22. package/system/{TestDefinition.js → TestDef.js} +153 -107
  23. package/system/TestFinder.js +3 -3
  24. package/system/TestFrame.js +15 -52
  25. package/system/TestGroup.js +1 -1
  26. package/system/TestResult.js +2 -2
  27. package/system/TestRunner.js +23 -107
  28. package/system/TestStages.js +80 -76
  29. package/system/TestSummary.js +1 -1
  30. package/system/TotalComparer.js +60 -11
  31. package/system/TotalDisplayer.js +33 -12
  32. package/system/TypeAnalyzer.js +41 -79
  33. package/system/TypeIdentifier.js +18 -8
  34. package/system/Types.js +3 -1
  35. package/test-target-objects/ConditionalThrowTarget.js +11 -0
  36. package/test-target-objects/Counter.js +46 -0
  37. package/test-target-objects/DomTarget.js +37 -0
  38. package/test-target-objects/InterSpoofer.js +230 -0
  39. package/test-target-objects/MixedContents.js +33 -0
  40. package/test-target-objects/MutationTarget.js +37 -0
  41. package/test-target-objects/ObjectComposer.js +34 -0
  42. package/test-target-objects/PolySpoofableInner.js +29 -0
  43. package/test-target-objects/PolySpoofableOuter.js +52 -0
  44. package/test-target-objects/PropertiesTarget.js +98 -0
  45. package/test-target-objects/Returner.js +7 -0
  46. package/test-target-objects/Searcher.js +25 -0
  47. package/test-target-objects/Sorter.js +91 -0
  48. package/test-target-objects/Spoofable.js +36 -0
  49. package/test-target-objects/StateTarget.js +34 -0
  50. package/test-target-objects/StaticTarget.js +17 -0
  51. package/test-target-objects/TestableTarget.js +57 -0
  52. package/trial-tests/SelfTests.outward-rt.js +511 -0
  53. package/trial-tests/TopicTests.outward-rt.js +313 -0
  54. package/usage-examples/Gold-bar-example.png +0 -0
  55. package/usage-examples/Title-example.png +0 -0
  56. package/xternal-tests/ASpoofingFixture.tests.js +242 -0
  57. package/xternal-tests/MethodSpoofer.tests.js +130 -0
  58. package/xternal-tests/SpoofDef.tests.js +91 -0
  59. package/xternal-tests/TotalComparer.tests.js +1055 -0
  60. package/xternal-tests/package.json +7 -0
  61. package/system/AComparer.js +0 -9
  62. package/system/ATestFixture.js +0 -44
  63. package/system/ClassPropertySpoofer.js +0 -185
  64. package/system/ObjectMethodSpoofer.js +0 -58
  65. package/system/ObjectPropertySpoofer.js +0 -136
  66. package/system/SpoofDefinition.js +0 -243
  67. package/system/TestFrameChooser.js +0 -54
  68. package/system/TestFrames.js +0 -232
  69. package/system/TotalCopier.js +0 -106
@@ -0,0 +1,581 @@
1
+
2
+ # Risei Read-Me
3
+
4
+ ## Overview
5
+
6
+ Risei is a new way to write unit tests that's easier and faster, more dependable, and keeps your tests from standing in the way of redesigns.
7
+
8
+ Risei does all this by replacing coded tests with simple declarative syntax.
9
+
10
+ - Risei works with object-oriented JavaScript in modules.
11
+
12
+ - Risei works with TypeScript after just a few tweaks.
13
+
14
+
15
+
16
+ ## Examples
17
+
18
+ Here are two example tests, in which `SortModel.countSort()` is being tested using the inputs from `.in` and the expected output from `.out`:
19
+
20
+ ![https://deusware.com/risei/images/Syntax-example.png](https://deusware.com/risei/images/Syntax-example.png)
21
+
22
+
23
+ Here are the example test results for those two tests:
24
+
25
+ ![https://deusware.com/risei/images/Output-example.png](https://deusware.com/risei/images/Output-example.png)
26
+
27
+ - Outputs are always listed, even on passing tests, which makes code usage much clearer.
28
+ - Any failing tests appear in light red.
29
+ - Your latest tests always sort to the bottom so it's easy to find their results.
30
+
31
+
32
+ Test runs have a title bar so the starting point is easy to find:
33
+
34
+ ![https://deusware.com/risei/images/Title-example.png](https://deusware.com/risei/images/Title-example.png)
35
+
36
+
37
+ And they have a summary bar at the bottom:
38
+
39
+ ![https://deusware.com/risei/images/Summary-example.png](https://deusware.com/risei/images/Summary-example.png)
40
+
41
+ - This bar is red when any tests fail, much as you'd expect.
42
+
43
+
44
+
45
+ ## Status
46
+
47
+ Risei is under active development and new enhancements appear often.  The latest release, **2.0.0**, has many [major improvements](#version-history), including broader capabilities and simpler syntax, and a few minor breaking changes.
48
+
49
+ Check out the [list of the changes](#version-history).
50
+
51
+
52
+
53
+ ## Installation
54
+
55
+ Install Risei for development time only:
56
+
57
+ ```bash
58
+ npm install --save-dev risei
59
+ ```
60
+
61
+ Ensure that `package.json` specifies ECMAScript modules:
62
+
63
+ ```json
64
+ "type": "module"
65
+ ```
66
+
67
+ And add Risei's metadata to `package.json`:
68
+
69
+ ```json
70
+ "risei": {
71
+ "tests": "**.rt.js"
72
+ }
73
+ ```
74
+
75
+
76
+
77
+ ## Running Tests
78
+
79
+ Once you have some tests written, you can run them manually:
80
+
81
+ ```bash
82
+ node ./node_modules/risei/index.js
83
+ ```
84
+
85
+ Or write a script in `package.json` that does the same:
86
+
87
+ ```json
88
+ "scripts": {
89
+ "test": "node ./node_modules/risei/index.js"
90
+ }
91
+ ```
92
+
93
+ And then run that script:
94
+
95
+ ```bash
96
+ npm test
97
+ ```
98
+
99
+
100
+
101
+ ## Writing Tests
102
+
103
+ You write tests in `.rt.js` files like this:
104
+
105
+ ```javascript
106
+ import ATestSource from "risei/ATestSource";
107
+ import ClassToTest from "ClassToTest.js";
108
+
109
+ export class SomeTests extends ATestSource {
110
+ tests = [ ... ];
111
+ }
112
+ ```
113
+
114
+ Write individual tests as plain JavaScript objects with Risei's simple syntax:
115
+
116
+ ```javascript
117
+ tests = [ ...
118
+ { on: ContainerClass, with: [ "a", "b", "c" ], // Target class and constructor args.
119
+ of: "doesContain", // Target method name.
120
+ for: "When the arg is present, returns true.", // Description of test.
121
+ in: [ "c" ], // Inputs to method.
122
+ out: true }, // Expected output.
123
+ ... ];
124
+ ```
125
+
126
+ - To run, a test must have `.on`, `.with`, `.of`, `.for`, `.in`, and `.out` defined.
127
+ - When there are no constructor or method args, you can use empty arrays for `.in` or `.with`.
128
+ - Some of these properties' names are harmlessly the same as JS keywords.  [Long names](#property-long-names) exist if you want to use them instead.
129
+
130
+
131
+
132
+ ## Collapsing forward for lighter tests
133
+
134
+ You can write more tests with less syntax by stating test properties once and letting them _collapse forward_ across subsequent tests.
135
+
136
+ Risei collapses values together until it has a full test to run, as seen in this typical example:
137
+
138
+
139
+ ```javascript
140
+ { on: ContainerClass, with: [ "a", "b", "c" ] }, // Following tests are of this class.
141
+
142
+ { of: "doesContain" }, // Following tests are of this method.
143
+ { for: "Returns true when arg present.", in: [ "c" ], out: true }, // First test: now Risei has enough to run on.
144
+ { for: "Returns false when arg absent.", in: [ "d" ], out: false }, // Next test: same method, different test case.
145
+
146
+ { of: "countOf" }, // Change of tested method. Method-related props are wiped out.
147
+ ...
148
+
149
+ { on: SortingClass, with: [ ] }, // Change of tested class. All existing props are wiped out.
150
+ ```
151
+
152
+ Every property collapses forward until it is set to something else or wiped out with a target shift:
153
+
154
+ - Changing `.on` (the target class) wipes out all other test properties.
155
+ - Changing `.of` (the target method) wipes out all except `.on`, `.with`, and `.plus` (described [later](#spoofing-for-test-isolation-using-plus)).
156
+ - To drop any optional property starting with the current test, you can set it to an empty array `[]`.
157
+
158
+
159
+ ### Preventing extra tests using `.just`:
160
+
161
+ You may want to pre-set a property for an upcoming group of tests, even when fully defined tests already exist.  However, this creates an accidental extra test (which often fails), because Risei always collapses old and new values together to make a new fully defined test.
162
+
163
+ It's easy to avoid this problem with the `.just` property:
164
+
165
+ ```javascript
166
+ { on: ContainerClass, with: [ "a", "b", "c", ] }, // A section of tests using these values.
167
+ { ... },
168
+ { ... },
169
+
170
+ { just: true, with: [ "t", "u", "v" ] }, // Changing .with without creating an extra test.
171
+ { ... }, // Tests using the new .with start here.
172
+ { ... },
173
+ ```
174
+
175
+ - The value of `.just` doesn't have to be `true`, or any value in particular.  The property just has to be defined.
176
+
177
+
178
+ ### Avoiding mutable-arg problems by restating them:
179
+
180
+ Collapsing forward reuses test property contents directly.  Tests are isolated unless your code mutates its arguments.  If so, the mutated values are used, throwing off test results.
181
+
182
+ To prevent this problem, simply restate mutable args in each test to keep them independent.
183
+
184
+
185
+
186
+ ## Testing properties and static methods
187
+
188
+ To test properties of instances, or to test static methods and properties, you use exactly the same syntax you would for instance methods, and Risei figures out the rest:
189
+
190
+ ```javascript
191
+ tests = [
192
+ { on: VariegatedClass, with: [ ] },
193
+ { of: "instanceMethod", for: "Returns true.", in: [ ], out: true }, // Typical use: instance method.
194
+ { of: "staticMethod", for: "Returns false.", in: [ ], out: false }, // Static method: same syntax. Empty .with needed.
195
+ { of: "instanceProperty", for: "Returns 47.", in: [ ], out: 47 }, // Instance prop: same. Empty .in needed.
196
+ { of: "staticProperty", for: "Returns 98.", in: [ ], out: 98 } // Static prop: same. Empty .in needed.
197
+ ];
198
+ ```
199
+
200
+ - When testing statics or properties, tests still need a `.with` and `.in`.  You can set them to empty arrays `[]` if needed.
201
+
202
+ Although Risei figures out what it needs to, you can explicitly state these factors if you want, and Risei will treat them as you specify:
203
+
204
+ ```javascript
205
+ { of: "instanceMethod()", ... }, // Trailing parens specify method.
206
+ { of: ".someProperty", ... }, { of: "someProperty:", ... } // Leading dot or trailing colon specify property.
207
+ { of: "something", and: "static", ... }, // You add an .and of "static" for statics.
208
+ ```
209
+
210
+ - This syntax can be used in `.of`, `.plus`, and `.from` (all covered later).
211
+ - When a property is tested directly, it is listed in test output as `.name`.
212
+
213
+
214
+
215
+ ## Spoofing for test isolation using `.plus`
216
+
217
+ To make code dependencies return what your tests need, just _spoof_ what you want using a `.plus` test property:
218
+
219
+ ```javascript
220
+ {
221
+ on: TestedClass,
222
+ ...
223
+ plus: [
224
+ { on: Dependency, of: "someMethod", as: 10 }, // Dependency.someMethod() returns 10 in this test.
225
+ { of: "testedClassMethod", as: 11 } // TestedClass.testedClassMethod returns 11 in this test.
226
+ ],
227
+ ...
228
+ }
229
+ ```
230
+
231
+ - It's just like _fakes_, _mocks_, or _test doubles_ in other test systems, but easier to write and read.
232
+
233
+ There are many options available for spoofing, all laid out together in this example:
234
+
235
+ ```javascript
236
+ { on: CombinerClass,
237
+ ...
238
+ plus: [
239
+ /* Mono-spoofing. */
240
+ { on: ClassA, of: "someMethod", as: 10 }, // Spoof this ClassA method to return 10.
241
+ { on: ClassB, of: "someMethod" }, // Spoof this ClassB method not to return (or do) anything.
242
+
243
+ { of: "firstMethod", as: [ 7, 8, 9, 10 ] }, // Spoof a method on the tested class (CombinerClass).
244
+ { of: "secondMethod" }, // Spoof a method on the tested class not to do anything.
245
+
246
+ { on: ClassC, // Spoof this ClassC method to be this nonce code using a runtime arg.
247
+ of: "someMethod",
248
+ as: (arg) => { return { color: arg }; } },
249
+
250
+ /* Poly-spoofing. */
251
+ { on: ClassD, as: [ // Spoof two methods on ClassD at the same time.
252
+ { of: "firstMethod", as: 11 },
253
+ { of: "secondMethod", as: 12 }
254
+ ] },
255
+ { as: [ // Spoof two methods on the tested class at the same time.
256
+ { of: "firstMethod", as: 11 },
257
+ { of: "secondMethod", as: 12 }
258
+ ] },
259
+ ],
260
+ ...
261
+ }
262
+ ```
263
+
264
+ - These individual types of spoofing can be mixed however needed.
265
+ - You can spoof multiple class methods at the same time with either mono- or poly-spoofing syntax.
266
+ - A spoof nonce function can use args provided to it, but not `this` of the tested instance.
267
+ - You can spoof properties only for the class under test.
268
+
269
+
270
+ ## Special test conditions
271
+
272
+ ### Testing throws with `.and`:
273
+
274
+ You can test for a value thrown in code by adding an `.and` property of `"throw"` or `"throws"`:
275
+
276
+ ```javascript
277
+ {
278
+ on: TestedClass, of: "throwsWhenNoArgsGiven", and: "throws",
279
+ for: "When not given any args, throws an Error stating \"Argless.\".",
280
+ in: [ ], out: new Error("Argless.")
281
+ }
282
+ ```
283
+
284
+ - The `.and` property is an extension point for special test conditions.
285
+
286
+
287
+ ### Testing for `undefined` actuals with `this.undef`:
288
+
289
+ You can test for an `undefined` value by setting `.out` to `this.undef` (or `ATestSource.undefSymbol`):
290
+
291
+ ```javascript
292
+ {
293
+ on: TestedClass, of: "returnsArgGiven",
294
+ for: "When the arg is undefined, returns undefined.",
295
+ in: [ undefined ], out: this.undef
296
+ }
297
+ ```
298
+
299
+ - You can't use `undefined` itself directly for `.out`, because Risei treats it as a missing prop.
300
+
301
+
302
+
303
+ ## Changing actual with `.from`
304
+
305
+ You can refine the test's actual using the `.from` property, for instance for method side-effects or derivatives of the original actual.
306
+
307
+ The `.from` can be the name of a property on the target class or its instance created for the test:
308
+
309
+ ```javascript
310
+ {
311
+ on: TestedClass, of: "makeInstanceReady",
312
+ for: "When method is run, the .ready flag is set.",
313
+ in: [ ], out: true,
314
+ from: "ready"
315
+ }
316
+ ```
317
+
318
+ - Both instance and static props can be retrieved this way.
319
+ - You can't retrieve an instance property for a test of a static method, because no instance is created.
320
+
321
+ The `.from` can be a nonce function, which must always return a new actual:
322
+
323
+ ```javascript
324
+ {
325
+ on: TestedClass, of: "initDerivedObject",
326
+ for: "When method is run, output's .flag is cleared.",
327
+ in: [ ], out: false,
328
+ from: (target, test) => { return test.actual.flag; }
329
+ }
330
+ ```
331
+
332
+ - The `test` parameter is the assemblage of test properties you've provided, plus the test's actual value as `.actual`.
333
+ - The `target` parameter is the instance created for the test, or the tested class itself for statics.
334
+
335
+
336
+
337
+ ## Changing external state with `.do.early`, `.do.late`, and `.undo`
338
+
339
+ If test state you need can't be created declaratively, you can set it up and then tear it down using `.do` and `.undo`.  The `.do` property has two stages, `.early` and `.late`.
340
+
341
+ You set these properties to nonce functions:
342
+
343
+ ```javascript
344
+ {
345
+ on: TestedClass, for: "When the file to read is not text, returns first ten bytes as hex.",
346
+ do: {
347
+ early: () => { writeRandomTestFile(); }, // Steps before any test target instance is created.
348
+ late: (test) => { test.out = readTestFileHex(10); } // Steps after any instance is created, here altering a test property.
349
+ },
350
+ undo: { () => { eraseRandomTestFile(); }, // Steps after everything else in the test.
351
+ in: [ ... ], out: 0x00, // .out is replaced with varying data in .undo.
352
+ }
353
+ ```
354
+
355
+ - You're better off using Risei's declarative syntax whenever it can do what you need.
356
+ - You don't need to include both `do.early` and `do.late` if you only need one, which is normally the case.
357
+ - You can use the `test` parameter to alter the test itself if needed, though this is rare.
358
+ - If you do, it's best not to change any added at runtime by Risei.
359
+
360
+
361
+
362
+ ## Using TypeScript with Risei
363
+
364
+ To test TypeScript code with Risei, you make sure the code is transpiled before the tests are run, and you point Risei to the transpiled `.js` files.
365
+
366
+
367
+ ### In `tsconfig.json`:
368
+
369
+ You set up the transpiler to output files to a separate directory with these two settings:
370
+
371
+ ```json
372
+ {
373
+ "outDir": "dist/out-tsc",
374
+ "noEmit": false
375
+ }
376
+ ```
377
+
378
+ - Any folder can be `outDir`, but it's best to avoid `dist`, which can interfere with frameworks' build steps.
379
+
380
+
381
+ ### In `package.json`:
382
+
383
+ In the `test` script, add transpilation before the test run, and file deletion after it, each one conditional on the previous:
384
+
385
+ ```json
386
+ "scripts": {
387
+ "test": "tsc && node ./node_modules/risei/index.js && rm -r ./dist/out-tsc"
388
+ }
389
+ ```
390
+
391
+ - Using `tsc` or an equivalent produces individually testable JavaScript files.
392
+ - Deleting files at the end prevents interference with web frameworks' bundling.
393
+ - The deletion path must match the `outDir` in `tsconfig.json`.
394
+
395
+ > You can run Risei manually with the same sequence of operations.
396
+
397
+
398
+ ### In test files:
399
+
400
+ All `import` statements have to point to the JavaScript (`.js`) files in the `outDir` path or its subfolders:
401
+
402
+ ```javascript
403
+ import { TestedClass } from "../../dist/out-tsc/SubPath/TestedClass.js";
404
+ ```
405
+
406
+ - Output files may be in a folder tree parallel to the TypeScript originals (Angular), or may all be in the `outDir` folder itself (React).
407
+
408
+
409
+
410
+ ## Troubleshooting
411
+
412
+ ### When a gold bar appears and some tests disappear:
413
+
414
+ When problems cause test files not to load, you see a gold bar listing the syntax errors at fault:
415
+
416
+ ![https://deusware.com/risei/images/Gold-bar-example.png](https://deusware.com/risei/images/Gold-bar-example.png)
417
+
418
+ - Test files without syntax errors are still loaded and run, so you also see a lower total number of tests.
419
+
420
+ Here are the most common problems:
421
+
422
+ | Error condition | Probable cause |
423
+ |-------------------|------------------|
424
+ | Gold bar text `"Test loading failed for... SyntaxError: Unexpected token ':'"` | Missing comma in your tests in the named file, either between tests or between test props |
425
+ | Gold bar text `"Test loading failed for... SyntaxError: Unexpected token '.'"` | Stating the test list as `this.tests = []` instead of `tests = []` in the file named |
426
+ | Other `... Unexpected token ...` errors in gold bar | Some other syntax error in the file named, most likely a missing or extra delimiter |
427
+ | Many test files failing all at once | Syntax error in the code targeted in those test files, or a dependency of it |
428
+
429
+
430
+ ## When the listed tests or their results are unexpected:
431
+
432
+ | Error condition | Probable cause |
433
+ |-------------------|------------------|
434
+ | Unexpected extra, failing test/s | An object intended only to change test properties lacks a `.just` / `.only` |
435
+ | Unexpected actual values, or unexpected passes / fails in test runs | Test properties from previous tests not replaced or reset with `[]` <br>&mdash; or &mdash;<br> Mutated args for tested code not restated in following tests to isolate them |
436
+ | Tests written not appearing in runs | Not all properties needed to run tests stated before or in those tests |
437
+
438
+
439
+
440
+ ## Property long names
441
+
442
+ Test properties have longer names that you can use interchangeably with their short names.
443
+
444
+ <details>
445
+ <summary>
446
+ Test definition names
447
+ </summary>
448
+
449
+ | Short Name | Long Name |
450
+ |------------|-----------|
451
+ | `on` | `type` |
452
+ | `with` | `initors` |
453
+ | `of` | `method` |
454
+ | `for` | `nature` |
455
+ | `in` | `inputs` |
456
+ | `out` | `output` |
457
+ | `plus` | `spoofed` |
458
+ | `from` | `source` |
459
+ | `and` | `factors` |
460
+ | `do` | `enact` |
461
+ | `undo` | `counteract` |
462
+ | `just` | `only` |
463
+
464
+ - There are no long names for the `.early` and `.late` properties of `.do` / `.enact`.
465
+
466
+ </details>
467
+
468
+ <br>
469
+
470
+ <details>
471
+ <summary>
472
+ Spoof definition names
473
+ </summary>
474
+
475
+ | Short Name | Long Name |
476
+ |------|------|
477
+ | `on` | `target` |
478
+ | `of` | `method` |
479
+ | `as` | `output` |
480
+
481
+ </details>
482
+
483
+
484
+
485
+ ## Version history
486
+
487
+ - Release **2.0.0** (August, 2024) contains all of these changes:
488
+ - Risei now can determine automatically if tested methods are static.
489
+ - You can now directly test properties just like methods.
490
+ - Risei can also determine automatically if these are static.
491
+ - Directly tested properties appear in the output in the form `.name`.
492
+ - You can now spoof properties on the targeted class instance, and static properties on the target class itself.
493
+ - You can now perform arbitrary operations, if needed, with the two-part `.do` property and one-part `.undo` property.
494
+ - You can now change test properties without accidentally creating a new test using `.just`.
495
+ - You can now directly test for `undefined` in `.out` using `this.undef` / `ATestSource.undefSymbol`.
496
+ - `Error` objects are now compared accurately.
497
+ - You can now identify member types with sigils (`.` / `:` / `()`) in `.of`, `.plus`, and `.from`, though they aren't necessary.
498
+ - **(Breaking change)**&nbsp; The `actual` for throw tests is now the entire thrown object (usually an `Error`), rather than the `Error`'s message text.
499
+ - **(Breaking change)**&nbsp; `ATestSource` is now a default export, changing its imports from `import { ATestSource } from` to `import ATestSource from`.
500
+
501
+ > Risei has been massively re-engineered internally along with these improvements.
502
+
503
+
504
+
505
+ <details>
506
+ <summary>
507
+ Older releases
508
+ </summary>
509
+
510
+ - Release **1.3.4** (March, 2024) fixed a bug that caused class display problems in some cases.
511
+
512
+ - Release **1.3.3** (March, 2024) fixed a major bug that prevented tests from running in Windows.
513
+
514
+ - Release **1.3.2** (February, 2024) only improved this read-me's contents.
515
+
516
+ - Release **1.3.1** (February, 2024) reversed some changes in 1.3.0 that did not work as hoped.
517
+
518
+ - Release **1.3.0** (February, 2024) added the loading-error gold bar and fixed a test-sorting bug.
519
+
520
+ - Release **1.2.0** (January, 2024) changed test sorting to move last-edited tests to the end.
521
+
522
+ - Release **1.1.2** of Risei (January, 2024) fixed class displays and inaccurate `Date` comparisons.
523
+
524
+ > The oldest releases are no longer listed here, and old releases are dropped progressively over time.&nbsp; Using the latest release is recommended.
525
+
526
+ </details>
527
+
528
+
529
+ ## Known issues and workarounds
530
+
531
+ The only issue at present is the use of mutated args when tested code mutates them, when collapsing forward.
532
+
533
+ - The workaround is simply to restate the args for each test.
534
+
535
+
536
+ ## Exclusions from Risei
537
+
538
+ The following are not supported at present:
539
+
540
+ - Use of `async` syntax
541
+ - Any code not in classes, even in ESM `export` modules, AKA _loose code_
542
+ - CJS syntax using `require()`
543
+ - Performing step-through debugging of tests and tested code
544
+ - Comparing rare JS object types like `Proxy` or `ArrayBuffer` in test assertions
545
+ - Testing for inequality of values
546
+
547
+ Some of these may be supported in the future.
548
+
549
+ - You can save a lot of time by using Risei for most of your code, but another framework for whatever it doesn't support.
550
+
551
+
552
+
553
+ ## Maker
554
+
555
+ Risei is written by myself, Ed Fallin.&nbsp; I'm a longtime software developer who likes to find better ways to do things.
556
+
557
+ If you find Risei useful, consider spreading the word to other devs, making a donation, suggesting enhancements, or proposing sponsorships.
558
+
559
+ You can get in touch about Risei at **riseimaker@gmail.com**.
560
+
561
+
562
+
563
+ ## License
564
+
565
+ Risei is published for use under the terms of the MIT license:
566
+
567
+ <div style="border: solid darkgray 1px; padding: 0.5rem;">
568
+
569
+ <b>Risei Copyright &copy; 2023&ndash;2024 Ed Fallin</b>
570
+
571
+ 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:
572
+
573
+ The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
574
+
575
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.&nbsp; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
576
+ </div>
577
+
578
+
579
+ &nbsp;
580
+
581
+
package/index.js CHANGED
@@ -10,17 +10,17 @@
10
10
 
11
11
  // region Test-running dependencies
12
12
 
13
- import { TestRunner } from "./system/TestRunner.js";
14
- import { LocalCaller } from "./system/LocalCaller.js";
15
- import { TerminalReporter } from "./system/TerminalReporter.js";
16
- import { TestFinder } from "./system/TestFinder.js";
13
+ import TestRunner from "./system/TestRunner.js";
14
+ import LocalCaller from "./system/LocalCaller.js";
15
+ import TerminalReporter from "./system/TerminalReporter.js";
16
+ import TestFinder from "./system/TestFinder.js";
17
17
 
18
18
  // endregion Test-running dependencies
19
19
 
20
20
  // region Display dependencies
21
21
 
22
22
  import chalk from "chalk";
23
- import { Moment } from "./system/Moment.js";
23
+ import Moment from "./system/Moment.js";
24
24
 
25
25
  // endregion Display dependencies
26
26
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "risei",
3
- "version": "1.3.4",
4
- "description": "Risei is the framework that allows you to write unit tests as simple JavaScript objects, so it's easy and fast, and tests don't serve as a drag on redesigns.",
3
+ "version": "2.0.0",
4
+ "description": "Risei allows you to write unit tests as simple JavaScript objects, so it's easy and fast, with no drag on redesign.",
5
5
  "keywords": [
6
6
  "unit test",
7
7
  "test",
@@ -19,16 +19,17 @@
19
19
  ],
20
20
  "author": "Ed Fallin <riseimaker@gmail.com>",
21
21
  "license": "MIT",
22
+ "homepage": "https://deusware.com/risei",
22
23
  "type": "module",
23
24
  "private": false,
24
25
  "scripts": {
25
26
  "start": "node ./bin/www",
26
- "rself": "clear; node system/Risei.js",
27
- "rtest": "clear; node ./node_modules/risei/index.js",
28
- "xtest": "clear; mocha **/*.tests.js",
29
- "mixedtest": "clear; mocha **/*.tests.js; node ./node_modules/risei/index.js",
30
- "alltest": "clear; mocha **/*.tests.js; node ./node_modules/risei/index.js; node system/Risei.js",
31
- "test": "clear; node ./node_modules/risei/index.js"
27
+ "rself": "clear && node system/Risei.js",
28
+ "rtest": "clear && node ./node_modules/risei/index.js",
29
+ "xtest": "clear && mocha **/*.tests.js",
30
+ "mixedtest": "clear && mocha **/*.tests.js; node ./node_modules/risei/index.js",
31
+ "alltest": "clear && mocha **/*.tests.js; node ./node_modules/risei/index.js; node system/Risei.js",
32
+ "test": "clear && node ./node_modules/risei/index.js"
32
33
  },
33
34
  "risei": {
34
35
  "tests": "**.rt.js"
@@ -45,12 +46,10 @@
45
46
  "devDependencies": {
46
47
  "chai": "^4.3.6",
47
48
  "chalk": "^5.0.0",
48
- "cookie-parser": "~1.4.4",
49
49
  "debug": "~2.6.9",
50
- "express": "^4.18.2",
51
50
  "fs": "^0.0.1-security",
52
51
  "mocha": "^10.0.0",
53
52
  "morgan": "~1.9.1",
54
- "risei": "1.3.3"
53
+ "risei": "^1.3.4"
55
54
  }
56
55
  }
@@ -1,11 +1,10 @@
1
1
  /**/
2
2
 
3
- import { ATestFixture } from "./ATestFixture.js";
4
- import { SpoofDefinition } from "./SpoofDefinition.js";
3
+ import SpoofDef from "./SpoofDef.js";
5
4
 
6
- export class ASpoofingFixture extends ATestFixture {
7
- constructor(name, kind) {
8
- super(name, kind);
5
+ export default class ASpoofingFixture {
6
+ constructor() {
7
+ /* No operations. */
9
8
  }
10
9
 
11
10
  /* A spoof might be supplied as a custom function,
@@ -25,8 +24,8 @@ export class ASpoofingFixture extends ATestFixture {
25
24
  // Recursive case: Spoof defines a whole object
26
25
  // tree to be returned as method output.
27
26
  if (Array.isArray(spoofOutput)) {
28
- if (spoofOutput.every(x => SpoofDefinition.isASpoof(x))) {
29
- spoofOutput = SpoofDefinition.fromNonceTuples(spoofOutput);
27
+ if (spoofOutput.every(x => SpoofDef.isASpoof(x))) {
28
+ spoofOutput = SpoofDef.fromNonceTuples(spoofOutput);
30
29
  spoofOutput = this.spoofObjectTree(spoofOutput);
31
30
  }
32
31
  }
@@ -40,7 +39,7 @@ export class ASpoofingFixture extends ATestFixture {
40
39
  possibly with intermediate objects. */
41
40
  spoofObjectTree(ofAsPairs) {
42
41
  let spoof = {};
43
-
42
+
44
43
  for (let pair of ofAsPairs) {
45
44
  let chain = pair.of;
46
45
  let output = pair.as;