risei 1.3.3 → 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 +149 -368
  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 +14 -12
  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 +79 -120
  29. package/system/TestSummary.js +1 -1
  30. package/system/TotalComparer.js +60 -11
  31. package/system/TotalDisplayer.js +34 -21
  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 -182
  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
package/README.md CHANGED
@@ -4,18 +4,16 @@
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 and TypeScript in no time.
8
- * Refactor or replace existing designs without worrying about the cost in past or future test time.
9
- * Create tests with immediate confidence, because you can't introduce mistakes in test code you write.
10
-
11
- Risei may be referred to as **Rs** here for brevity.
7
+ * Whip up full test coverage in no time for object-oriented (or object-hosted) JavaScript and TypeScript.
8
+ * Refactor or replace existing designs without worrying about about a heavy cost in past or future test construction.
9
+ * Create tests with immediate confidence, since you can't introduce mistakes when writing test code.
12
10
 
13
11
 
14
12
 
15
13
 
16
14
  ## The Risei approach
17
15
 
18
- Risei replaces coded tests with simple declarative syntax that's far easier to draft than any other unit-testing approach.
16
+ Risei replaces coded tests with simple declarative syntax.
19
17
 
20
18
  Here are two example tests.  `SortModel.countSort()` is being tested using the inputs from `.in` and the expected output from `.out`:
21
19
 
@@ -27,12 +25,16 @@ Here is the terminal output of these two example tests.  Tests are grouped
27
25
  ![https://deusware.com/Output-example.png](https://deusware.com/Output-example.png)
28
26
 
29
27
 
30
- - An individual test may appear on one line or multiple lines, depending on how wide the terminal window is.
31
28
  - Any failing tests appear in light red.
32
- - Your latest-edited tests always sort to the bottom, so you can see your current test results at a glance.
29
+ - Your latest tests always sort to the bottom so it's easy to find their results.
30
+
31
+
32
+ Test runs also feature a title bar at the top:
33
+
34
+ ![https://deusware.com/Title-example.png](https://deusware.com/Title-example.png)
33
35
 
34
36
 
35
- Test runs also feature a title bar at the top, as well as a summary bar at the bottom:
37
+ As well as a summary bar at the bottom:
36
38
 
37
39
  ![https://deusware.com/Summary-example.png](https://deusware.com/Summary-example.png)
38
40
 
@@ -41,9 +43,30 @@ Test runs also feature a title bar at the top, as well as a summary bar at the b
41
43
 
42
44
  ## Using Risei
43
45
 
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).
46
+ Risei is under active development.  The newest release, **2.0.0**, brings many major improvements:
47
+
48
+ - You can now test properties just like methods.
49
+ - You can now spoof properties on the targeted class instance.
50
+ - Risei now can determine automatically if tested or spoofed methods and properties are static.
51
+ - You can now perform arbitrary operations if needed.
52
+ - You can now change a test property without accidentally creating a new test.
53
+ - `Error` objects are now compared accurately.
54
+ - Outputs for `throw` tests are now the entire `Error` objects (breaking change).
55
+
56
+ Risei has been reengineered internally along with these improvements.
57
+
58
+ - In addition, `ATestSource` is now a default export (breaking change).
59
+ - This means a simple adjustment from `import { ATestSource }` to `import ATestSource`.
60
+
61
+ These changes and others are detailed at the new external Risei documentation website:
62
+
63
+ &cruft, new site
64
+ [https://deusware.com/risei-docs/index.html](https://deusware.com/risei-docs/index.html)
65
+
66
+ 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).
67
+
68
+ Risei works with Typescript, requiring only a few additional or different steps, described in [using Typescript with Risei](#using-typescript-with-risei).
45
69
 
46
- There are a few additional or different steps for [using Typescript with Risei](#using-typescript-with-risei).
47
70
 
48
71
 
49
72
 
@@ -55,7 +78,7 @@ Install Risei for development time only:
55
78
  npm install --save-dev risei
56
79
  ```
57
80
 
58
- Make sure your `package.json` specifies that ESM is in use:
81
+ Make sure your `package.json` specifies that ECMAScript modules are in use:
59
82
 
60
83
  ```json
61
84
  "type": "module"
@@ -69,99 +92,20 @@ And add Risei's metadata to `package.json`:
69
92
  }
70
93
  ```
71
94
 
72
- Just a [few extra steps](#using-typescript-with-risei) are required for Risei to work with TypeScript.
73
-
74
-
75
-
76
- ### Siting tests
77
-
78
- Add tests in files ending in `.rt.js` like this:
79
-
80
- ```javascript
81
- import { ATestSource } from "risei/ATestSource";
82
- import { ClassToBeTested } from "somewhere";
83
-
84
- export class SomeTests extends ATestSource {
85
- tests = [ ... ]; // This array is where test definitions are written.
86
- }
87
- ```
88
-
89
-
90
-
91
- ### Writing tests
92
-
93
- Write tests with Risei's easy syntax:
94
-
95
- ```javascript
96
- tests = [ ...
97
- { on: ContainerModelClass, with: [ "a", "b", "c" ], // Target class and constructor args.
98
- of: "doesContain", // Target method.
99
- for: "When the input arg is present, returns true.", // Description of test.
100
- in: [ "c" ], // Inputs.
101
- out: true }, // Expected output.
102
- ...];
103
- ```
104
-
105
-
106
-
107
- #### Write more tests with less syntax:
108
-
109
- You can save a lot of time by putting repeated test properties into an object once, just before the related tests:
110
-
111
- ```javascript
112
- /* All of the following tests are of ContainerModelClass. */
113
- { on: ContainerModelClass, with: [ "a", "b", "c", "a", "b" ] },
114
-
115
- /* Two tests for ContainerModelClass .doesContain(). */
116
- { of: "doesContain" },
117
- { for: "When the input arg is present, returns true.",
118
- in: [ "c" ], out: true },
119
- { for: "When the input arg is not present, returns false.",
120
- in: [ "d" ], out: false },
121
-
122
- /* First test for ContainerModelClass .countOf(). */
123
- { of: "countOf", for: "Returns the number present.", in: [ "b" ], out: 2 }
124
- ```
125
-
126
- - This _collapsing forward_ 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 `[]`.
95
+ > Just a [few extra steps](#using-typescript-with-risei) are required for Risei to work with TypeScript.
127
96
 
128
- - Tests are isolated in general, but if the code you're testing mutates its arguments, you have to state them in each test so the mutations aren't carried forward.
97
+ &cruft, new site / section
98
+ - Further general options can be found [here](https://deusware.com/risei-docs/index.html#installation).
129
99
 
100
+ &cruft, new site / section
101
+ - Further Typescript details can be found [here](https://deusware.com/risei-docs/index.html#using-typescript).
130
102
 
131
103
 
132
- #### Spoof away code dependencies:
133
-
134
- When your tests need certain results from code dependencies, just _spoof_ what you want using a `.plus` test property:
135
-
136
- ```javascript
137
- { on: CombinerClass, with: [],
138
- of: "combineResults",
139
- plus: [
140
- { on: ClassA, of: "someMethod", as: 10 }, // Spoof this ClassA method to return 10.
141
- { on: ClassB, of: "someMethod" }, // Spoof this ClassB method not to return (or do) anything.
142
- { of: "firstMethod", as: [ 7, 8, 9, 10 ] }, // Spoof a method on the tested class (CombinerClass).
143
- { of: "secondMethod" }, // Spoof a method on CombinerClass not to do anything.
144
- { on: ClassC, // Spoof this ClassC method to be this nonce code.
145
- of: "someMethod",
146
- as: (arg) => { return { color: arg }; } },
147
- { on: ClassD, as: [ // Spoof two methods on ClassD at the same time.
148
- { of: "firstMethod", as: 11 },
149
- { of: "secondMethod", as: 12 }
150
- ] },
151
- ],
152
- for: "When called, returns an array of values from sources.",
153
- in: [ "green" ], out: [ 7, 8, 9, 10, 10, 11, 12, { color: "green" } ] }
154
- ```
155
-
156
- - It's just like _fakes_, _mocks_, or _test doubles_ in other test systems, but much easier to write and read.
157
-
158
- - Spoofed code is fully isolated within tests, even though spoof definitions collapse forward across tests (and within `.plus`).
159
-
160
104
 
161
105
 
162
106
  ### Running tests
163
107
 
164
- Run your tests by invoking Risei's `index.js` file:
108
+ Once you've written your tests, run them by invoking Risei's `index.js` file:
165
109
 
166
110
  ```bash
167
111
  node ./node_modules/risei/index.js
@@ -181,298 +125,132 @@ And then run that script:
181
125
  npm test
182
126
  ```
183
127
 
184
- Risei can be used alongside other test frameworks, and even run with them from the same test script if you want.
185
-
186
-
128
+ - Risei can be used alongside other test frameworks, and even run with them from the same test script if you want.
187
129
 
188
- ### Learning more about Risei
130
+ &cruft, new site / section
131
+ - Find more information about this mixed testing and other config / run options [here](https://deusware.com/risei-docs/index.html#running-tests).
189
132
 
190
- Read through the rest of this doc to learn more about Risei's many capabilities, and about where Risei is headed.
191
-
192
- - For instance, learn about using `.and` to test static methods or throws.
193
- - Or learn about using `.from` to test property results or other state.
194
- - Don't miss out:  Once you've tried the basics, read the rest...!
195
-
196
-
197
-
198
-
199
- ## Risei in depth
200
-
201
- <details>
202
- <summary>
203
- There's plenty more to learn about Risei and how it makes testing easy...
204
- </summary>
205
-
206
- ### Installation
207
-
208
- - You can use any file extension you want in Risei's metadata in `package.json`, and Risei will scan those files for tests.
209
-
210
- - You can install Risei outside of development time the usual way, but as with any test system, this is definitely not recommended.
211
-
212
- - Risei uses ESM syntax, and may not work in older environments where that's not available or is patched in.
213
133
 
214
134
 
215
135
 
216
136
  ### Siting tests
217
137
 
218
- - Match your Risei test file's extensions to whatever you choose in the metadata in `package.json`.
219
-
220
- - Test classes must inherit from `ATestSource` in `"risei/ATestSource"`: this type name is looked for specifically, so duck-typing doesn't work.
221
-
222
-
223
-
224
- ### Writing tests
225
-
226
- - The order and placement of test properties doesn't matter, although the order seen in the examples is probably most readable.
227
-
228
-
229
-
230
- #### Basic test properties and options for each:
231
-
232
- | Name | Contents |
233
- |--------|-----------------------------------------------------------------------------------------------------------|
234
- | `on` | The class under test, as a symbol / name (already imported into the test file) |
235
- | `with` | An array of any arguments to pass to the constructor of the tested class, or an empty array `[]` if none |
236
- | `of` | The name of the method under test, as a string, no `()` needed |
237
- | `for` | A description of what the test proves, for test output |
238
- | `in` | An array of the input arguments to pass to the tested method, or an empty array `[]` if none |
239
- | `out` | The expected return value, not in an array |
240
-
241
- - There are additional properties for extended functionality, covered later.
242
- - The property names were chosen to be easy to remember and type, but longer alternatives are available, covered later.
243
-
244
-
245
-
246
- ### Test-property reuse _AKA_ Collapsing forward
247
-
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 `[]`.
249
- - Property values are gathered across partial test objects until they add up to a runnable test, which is then run.
250
- - Changes to properties are combined with previous ones to produce intended new tests.
251
- - For a rare and avoidable side-effect of this system, see [known issues and workarounds](#known-issues-and-workarounds).
252
-
253
- - Test contents, reused or not, are automatically reset when it makes the most sense:
254
- - Changing the tested class in `.on` wipes out all prior test properties, so the new class has a fresh start.
255
- - Changing the tested method in `.of` wipes out only test properties related to methods, to preserve class values you usually want.
256
-
257
- - Individual tests remain isolated, except for when args are mutated by the code under test.
258
- - Restate args for each test when the code mutates them.
259
- - This limitation is the result of limits on what can be copied reliably in JavaScript.
260
-
261
-
262
- ### Choosing test-only dependency inputs _AKA_ Spoofing
263
-
264
- - Spoofing is Risei's way of providing test-only inputs from dependencies the tested code uses, written in simple declarative syntax.
265
- - It's therefore the equivalent of test doubles, mocks, fakes, and so on.
266
-
267
-
268
- - As the earlier examples and this table show, you can spoof in many ways, both on the dependencies, and on the class being tested.
269
- - All classes whose members are being spoofed have to be imported.
270
-
271
-
272
-
273
- #### Spoof-definition properties:
274
-
275
- | Name | Necessary or Optional | Contents |
276
- |------|-----------------------|----------------------------------------------------------------------------|
277
- | `on` | Optional | Symbol for a type (class); if omitted, the targeted model class is assumed |
278
- | `of` | Necessary | Name of the method to spoof, as a string, trailing `()` not needed |
279
- | `as` | Optional | Value to return or nonce implementation; if omitted, an empty method with no return value is used<br> &mdash; or &mdash;<br>A list of partial spoof definitions for the same class |
280
-
281
-
282
- - You can spoof multiple methods of a class individually, or list them together with partial definitions as seen in the example, with the same effect either way.
283
-
284
-
285
- #### Partial spoof-definition properties:
286
-
287
- | Name | Necessary or Optional | Contents |
288
- |------|-----------------------|---------------------------------------------------------------------------------------------------|
289
- | `of` | Necessary | Name of the method to spoof, as a string, trailing `()` not needed |
290
- | `as` | Optional | Value to return or nonce implementation; if omitted, an empty method with no return value is used |
291
-
292
-
293
- - Defining new spoofing wipes out all old definitions.
294
-
295
-
296
- - Spoofing is done at the start of each test and undone at the end of each test, keeping all tests isolated.
297
-
298
-
299
-
300
-
301
- ## Advanced Risei usage
302
-
303
- ### Testing special test conditions with `.and`
304
-
305
- You can use the special test property `.and`, always a string, to indicate special conditions that apply to your test.
306
- - At present, the values available are `"static"` and `"throw"` / `"throws"` (either one works).
307
- - You can list `static` and `throw` / `throws` together if needed, separated by a space.
308
-
309
- The `.and` property is an expansion point for supporting more special conditions in the future.&nbsp; Values will always be listable together (as long as any particular grouping makes sense).
310
-
311
-
312
-
313
- #### Testing static methods
314
-
315
- To test a static method, use an `.and` of `"static"`:
138
+ Add tests in files ending in `.rt.js` like this:
316
139
 
317
140
  ```javascript
318
- { on: StaticTextProfileModel, with: [] },
141
+ import ATestSource from "risei/ATestSource";
142
+ import { ClassToBeTested } from "somewhere";
319
143
 
320
- { of: "getTextProfile",
321
- for: "Returns accurate profile of arg text.",
322
- and: "static",
323
- in: [ "This is a short sentence." ],
324
- out: { isFullSentence: true, characters: 25, words: 5 }
144
+ export class SomeTests extends ATestSource {
145
+ tests = [ ... ]; // Test definitions are added here.
325
146
  }
326
147
  ```
327
148
 
328
149
 
329
150
 
330
- #### Testing throws
151
+ ### Writing tests
331
152
 
332
- To test a throw, use an `.and` of `"throw"` or `"throws"`:
153
+ Write tests with Risei's simple syntax:
333
154
 
334
155
  ```javascript
335
- { on: InstanceTextProfileModel, with: [] },
336
-
337
- { of: "getTextProfile",
338
- for: "Throws with a helpful message when there is no arg text.",
339
- and: "throws",
340
- in: [],
341
- out: "Could not build a profile. Did you forget to provide a text?"
342
- }
156
+ tests = [ ...
157
+ { on: ContainerModelClass, with: [ "a", "b", "c" ], // Target class and constructor args.
158
+ of: "doesContain", // Target method name.
159
+ for: "When the arg is present, returns true.", // Description of test.
160
+ in: [ "c" ], // Inputs to method.
161
+ out: true }, // Expected output.
162
+ ...];
343
163
  ```
344
164
 
165
+ - To test a throw path in a method, add an `.and` test property with the text value `"throws"`.
345
166
 
167
+ - To test a property of the target instance after running code, add a `.from` property with the property's name as a string.
346
168
 
347
- ### Testing object properties and other non-`return` results
169
+ - To test a value derived from the initial actual value, or otherwise from any available context, add a `from` property that's an arrow function taking (at present) `target` and `test` parameters: `(target, test) => { return test.actual.someProperty; }`.
348
170
 
349
- To test a value that isn't the exercised code's return value, you use `.out` normally, and you add a `.from` property to your test, which can be one of two things:
171
+ - To perform operations like creating files temporarily, use the `.do` property (encompassing two stages, `.before` and `.after`) to set up isolated test state, and `.undo` to restore normal state.
172
+ - The `.do`-`.before` steps are taken before the target class instance is created, the `.do`-`.after steps are taken after that but before the target method / property is run.
173
+ - The `.undo` is an arrow function taking a `test` arg.&nbsp; It is run after all other steps of the test have been run.&nbsp; **(2.0.0)**
350
174
 
351
- | Contents of `.from` | Usage |
352
- |--------------------------------|-------------------------------------------------------------------------|
353
- | Property name as string | Retrieves the actual from the named property on the test's target class |
354
- | Specialized function | Retrieves the actual from either its `target` or `test` parameter |
175
+ - To maintain the benefits of using Risei's declarative style, avoid arbitrary options as much as possible.
355
176
 
177
+ - If you prefer test property names that aren't JavaScript keywords, alternatives are available for all of them.
356
178
 
357
- - Getting properties, mutated args, and other non-return values is known as _retrieving_.
358
- - Retrieving definitions collapse forward across tests unless replaced with new definitions, or erased by setting `.from` to an empty array `[]`.
179
+ - Further details about syntax options can be found [here](https://deusware.com/risei-docs/index.html#test-syntax).
359
180
 
360
181
 
361
- <details>
362
- <summary>
363
- &nbsp; More information
364
- </summary>
365
- <br>
366
182
 
367
- - Use of `.from` with a property name looks like this:
183
+
184
+ #### Write more tests with less syntax:
185
+
186
+ To save a lot of time, state repeated test values just once, and let them _collapse forward_ into following tests:
368
187
 
369
188
  ```javascript
370
- { on: StatefulModel, with: [] },
189
+ /* All of the following tests are of ContainerModelClass. */
190
+ { on: ContainerModelClass, with: [ "a", "b", "c", "a", "b" ] },
371
191
 
372
- { of: "storePolyProduct",
373
- for: "The result of the calculation is stored as .result.",
374
- in: [ 10, 8, 9, 6 ], out: 4320, from: "result" },
192
+ /* Two tests for ContainerModelClass .doesContain(). */
193
+ { of: "doesContain" },
194
+ { for: "When the input arg is present, returns true.",
195
+ in: [ "c" ], out: true },
196
+ { for: "When the input arg is not present, returns false.",
197
+ in: [ "d" ], out: false },
198
+
199
+ /* First test for ContainerModelClass .countOf(). */
200
+ { of: "countOf", for: "Returns the number present.", in: [ "b" ], out: 2 }
375
201
  ```
376
202
 
377
- - Only instance properties can be retrieved by name.&nbsp; For static properties, use `.and` (covered earlier), plus a function as `.from` (covered next).
203
+ - When you change the class in `.on`, all test properties are wiped away, and when you change the method in `.of`, only test properties about the class (like `.with`) are retained.
378
204
 
379
- When the contents of `.from` are a function, these are the two parameters:
205
+ - Tests remain isolated, in effect, except when a test mutates input arguments.&nbsp; In that case, restate them in each test so the mutations aren't carried forward.
380
206
 
381
- | Name | Contents |
382
- |----------|---------------------------------------------------------------------------------------------------|
383
- | `target` | The instance of the class being tested |
384
- | `test` | The test definition itself, whose properties may have been mutated by the tested method |
207
+ - Change test contents without possibly adding an unintended new test by adding a `.just` property (with any value, such as `true`) alongside the changed properties.&nbsp; **(2.0.0)**
385
208
 
209
+ &cruft, new site / details
210
+ - Further options and details can be found [here](https://deusware.com/risei-docs/index.html#collapsing-forward).
386
211
 
387
- - The `test` parameter to a `.from` function contains all of the properties of your test definition, including those that collapsed forward.
388
- - These properties are available by both short or long names (covered later).
389
- - The `test.on` property always references the class under test, rather than an instance of it.
390
212
 
391
213
 
392
- - You can write a function for `.from` that uses `test.on` to get the values of static properties, in conjunction with `and: "static"` in the encompassing test.
393
214
 
215
+ #### Ensure desired inputs from dependencies
394
216
 
395
- - Another usage of a `.from` function is to look at an input to see if it was changed as expected:
217
+ To make code dependencies return what your tests need, just _spoof_ what you want using a `.plus` test property:
396
218
 
397
219
  ```javascript
398
- { on: SecurityModel, with: [] },
399
-
400
- { of: "addHash",
401
- for: "The content's hash is added to the input arg a new property.",
402
- in: [ { content: "SecretValue" }, iterations: 8 ],
403
- out: { content: "SecretValue", hash: "FasBdQ-fljk%asPcdf" },
404
- from: (target, test) => { return test.in[0]; }
405
- },
220
+ { on: CombinerClass, with: [],
221
+ of: "combineResults",
222
+ plus: [
223
+ { on: ClassA, of: "someMethod", as: 10 }, // Spoofing one method to return 10.
224
+ { on: ClassB, of: "someMethod" }, // Spoofing one method not to return anything.
225
+ { on: ClassC, as: [ // Spoofing two class methods together.
226
+ { of: "firstMethod", as: 11 },
227
+ { of: "secondMethod", as: 12 }
228
+ ] },
229
+ ],
230
+ for: "When called, returns an array of values from sources.",
231
+ in: [ "green" ], out: [ 7, 8, 9, 10, 10, 11, 12, { color: "green" } ] }
406
232
  ```
407
233
 
408
- </details>
409
-
410
-
411
-
412
- ### Property long names
413
-
414
- Property names are short so they're easy to use.&nbsp; Some of them overlap with JavaScript keywords, but this causes no harm.
415
-
416
- All test properties have long names that you can use instead of the short ones if you prefer, mixed together as much as you want.&nbsp; None of the long names are JavaScript keywords.
417
-
418
-
419
- <details>
420
- <summary>
421
- &nbsp; Test properties' short and long names
422
- </summary>
423
-
424
- | Short Name | Long Name |
425
- |------------|-----------|
426
- | `on` | `type` |
427
- | `with` | `initors` |
428
- | `of` | `method` |
429
- | `for` | `nature` |
430
- | `in` | `inputs` |
431
- | `out` | `output` |
432
- | `plus` | `spoofed` |
433
- | `from` | `source` |
434
- | `and` | `factors` |
435
-
436
- </details>
437
-
438
- <br>
234
+ - It's just like _fakes_, _mocks_, or _test doubles_ in other test systems, but easier to write and read.
439
235
 
440
- <details>
441
- <summary>
442
- &nbsp; Spoof properties' short and long names
443
- </summary>
236
+ &cruft, site / section
237
+ - There are many further spoofing options that save effort, including using nonce methods as spoofs and spoofing target-instance properties.&nbsp; **(2.0.0)**&nbsp; Check out all your options [here](https://deusware.com/risei-docs/index.html#collapsing-forward).
444
238
 
445
- | Short Name | Long Name |
446
- |------------|-----------|
447
- | `on` | `target` |
448
- | `of` | `method` |
449
- | `as` | `output` |
450
239
 
451
- </details>
452
-
453
-
454
-
455
- ### Further capabilities of Risei
456
-
457
- Constructors can be tested with no special test properties or keywords.
458
- - The method name in `.of` is simply `"constructor"`.
459
- - Any `.with` args are completely ignored for a constructor test.&nbsp; Only those in the test's `.in` property are used.
460
- - However, a `.with` must still be provided.&nbsp; It can simply be an empty array `[]`.
461
-
462
- </details>
240
+ - Spoofed code is fully isolated within tests, even though spoof definitions collapse forward across tests (and within `.plus`).
463
241
 
464
242
 
465
243
 
466
244
 
467
245
  ## Using TypeScript with Risei
468
246
 
469
- 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.
247
+ Testing TypeScript code with Risei basically just means transpiling before running the tests, and pointing Risei to the transpiled JS files.
470
248
 
471
249
  - Anything beyond those basics is intended to keep JS files separate from TS files and the output of web frameworks' own, complex build processes.
472
250
 
473
251
  If you follow the general Risei set-up, you can just make the following few modifications for TypeScript applications.
474
252
  - These steps have worked with both Angular and React.
475
- - Variant approaches are also sure to work, depending on the other technical choices in play.
253
+ - Varying other approaches are also sure to work, depending on the other technical choices in play.
476
254
 
477
255
 
478
256
 
@@ -511,7 +289,6 @@ You set up the transpiler to output files to a directory with these settings:
511
289
 
512
290
 
513
291
 
514
-
515
292
  ### In test files:
516
293
 
517
294
  All `import` statements have to point to the Javascript (`.js`) files in the `outDir` path or subfolders there, using relative-path syntax:
@@ -525,70 +302,72 @@ import { TestedClass } from "../../dist/out-tsc/SubPath/TestedClass.js";
525
302
 
526
303
 
527
304
 
528
- ## Limitations in Risei
305
+ ## What's new in Risei
529
306
 
530
- The following are not supported at present:
531
- - Use of `async` syntax
532
- - Code written in ESM `export` modules, but not within classes
533
- - Standalone functions and other functionality not built into classes, AKA _loose code_
534
- - CJS syntax using `require()`
535
- - Spoofing mixes of properties and methods, such as `something.method.property.method`
536
- - Debugging model code during tests
537
- - Comparing rare JS object types like `Proxy` or `ArrayBuffer` in test assertions
307
+ - Release **2.0.0** (month, 2024) introduces many [improvements](#using-risei), including new capabilities, bug fixes, and two breaking changes with only minor impacts on consuming code.
538
308
 
539
- Some of these are on the tentative future-development list.&nbsp; In the meantime, Risei can be used to save development time for most of your JavaScript code, while these can be tested using another framework invoked alongside Risei.
309
+ - Release **1.3.4** (March, 2024) fixed a bug that caused class display problems in some cases.
540
310
 
311
+ - Release **1.3.3** (March, 2024) fixed a major bug that prevented tests from running in Windows.
541
312
 
313
+ - Release **1.3.2** (February, 2024) only improved this read-me's contents.
542
314
 
315
+ - Release **1.3.1** (February, 2024) reversed some changes in 1.3.0 that did not work as hoped.
543
316
 
544
- ## Troubleshooting
317
+ - Release **1.3.0** (February, 2024) added the loading-error gold bar and fixed a test-sorting bug.
545
318
 
546
- Most problems with using Risei are minor mistakes in syntax, or omissions in test definitions:
319
+ - Release **1.2.0** (January, 2024) changed test sorting to move last-edited tests to the end.
547
320
 
548
- | Error condition or text | Probable cause |
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 extra, failing test/s | Partial test properties in a mid-list object have produced extra tests |
555
- | 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> Args mutated by tested code were not restated in following tests to isolate them |
321
+ - Release **1.1.2** of Risei (January, 2024) fixed class displays and inaccurate `Date` comparisons.
556
322
 
323
+ - The oldest releases are not listed here, and old releases are dropped progressively over time.&nbsp; Using the latest release is recommended.
557
324
 
558
325
 
559
326
 
560
- ## Known issues and workarounds
561
327
 
562
- Two issues are known to exist:
328
+ ## Troubleshooting
563
329
 
564
- - When code mutates its args in test definitions, the mutated forms are used in subsequent tests unless those args are restated.
565
- - To avoid this problem, just restate the args in each test of this code.
566
- - The workaround for this &mdash; copying and initing objects to bypass mutation &mdash; requires too many assumptions to be reliable.
330
+ Problems loading tests are almost always a missing or extra comma, brace, or similar.&nbsp; When a test file can't be loaded, loading continues with the next file.&nbsp; The number of tests drops (or doesn't increase as expected), and a gold bar appears naming the file and problem:
567
331
 
332
+ ![https://deusware.com/Gold-bar-example.png](https://deusware.com/Gold-bar-example.png)
568
333
 
569
- - When a few properties are changed in separate objects, they are treated as whole new tests, which usually fail because of their unintended mix of old and new properties.
570
- - To avoid this problem, just change properties as part of whole new tests, or else restate `.of` along with the changed properties.
571
- - Rs is actually working as intended when this happens, but ways to optionally prevent it are being considered.
334
+ - Unfortunately, there is no way to list the problem line number.
335
+ - A sudden fail of many test files is usually due to a problem in the tested code, not the tests themselves.
572
336
 
337
+ Problems with test results themselves are usually due to omissions or other mistakes in test definitions.
573
338
 
339
+ For far more information about troubleshooting, including some specific error messages, check out the documentation [here](https://deusware.com/risei-docs/index.html#troubleshooting).
574
340
 
575
- ## What's new in Risei
576
341
 
577
- - Release **1.3.3** (March, 2024) fixes a major bug related to file paths that prevented any tests from loading or running in Windows environments.
578
342
 
579
- - Release **1.3.2** (February, 2024) does not change the code at all, but improves this read-me, notably explaining the easiest way to deal with mutable args (which is just restating the args), and correcting a few mistakes.
580
343
 
581
- - Release **1.3.1** (February, 2024) reverses some changes in 1.3.0 that were intended to fully isolate tests against mutable args, but which caused incomplete or inaccurate object contents in some cases.&nbsp; This sort of built-in total isolation is not feasible, and in fact is rarely needed.
344
+ ## Known issues and workarounds
345
+
346
+ At present, there are two known issues, both with simple workarounds:
347
+
348
+ - When tested code mutates its args, the mutated forms are used in subsequent tests if collapsed forward.
349
+ - To avoid this, simply restate the args for each test that mutates them.
350
+
351
+
352
+ - When a few properties are changed in separate objects, they are treated as whole new tests, which usually fail because of their unintended mix of old and new properties.
353
+ - To avoid this problem, just add a `.just` or `.only` property, of any value, in the same objects as those tests.change properties as part of whole new tests, or else restate `.of` along with the changed properties.
354
+ - You can also clear existing properties with `.on` or `.of` and then do this, since then there aren't enough test properties present yet to comprise a full test.
582
355
 
583
- - 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.&nbsp; A sorting error that occurs when no test files exist yet has also been fixed.
584
356
 
585
- - Release **1.2.0** (January, 2024) changes sorting of test files.&nbsp; Previously they were displayed in the order found.&nbsp; 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.
586
357
 
587
- - Release **1.1.2** of Risei (January, 2024) fixes two problems:
588
- - Classes were sometimes displayed in output as their entire definition.&nbsp; Now just the class name is displayed.
589
- - All `Date` instances were considered equal, regardless of their actual value.&nbsp; Now they only are considered equal when they actually are.
358
+ ## Limitations in Risei
359
+
360
+ The following are not supported at present:
361
+ - Use of `async` syntax
362
+ - Code written in ESM `export` modules, but not within classes
363
+ - Standalone functions and other functionality not built into classes, AKA _loose code_
364
+ - CJS syntax using `require()`
365
+ - Debugging model code during tests
366
+ - Comparing rare JS object types like `Proxy` or `ArrayBuffer` in test assertions
367
+
368
+ Some of these are on the tentative future-development list.
369
+ - In the meantime, Risei can be used to save development time for most of your JavaScript code, while these cases can be tested using another framework invoked alongside Risei.
590
370
 
591
- - Don't use release **1.1.1**, which contains an internal path error.
592
371
 
593
372
 
594
373
 
@@ -620,3 +399,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
620
399
 
621
400
 
622
401
  &nbsp;
402
+
403
+