risei 1.3.4 → 2.0.1

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 (44) hide show
  1. package/README.md +134 -479
  2. package/index.js +5 -5
  3. package/package.json +10 -11
  4. package/system/ASpoofingFixture.js +7 -8
  5. package/system/ATestCaller.js +3 -3
  6. package/system/ATestFinder.js +2 -2
  7. package/system/ATestReporter.js +2 -1
  8. package/system/ATestSource.js +5 -1
  9. package/system/ChosenTestFinder.js +4 -4
  10. package/system/ClassTestGroup.js +2 -2
  11. package/system/LocalCaller.js +5 -5
  12. package/system/{ClassMethodSpoofer.js → MethodSpoofer.js} +54 -48
  13. package/system/MethodTestGroup.js +2 -2
  14. package/system/Moment.js +1 -1
  15. package/system/NameAnalyzer.js +26 -0
  16. package/system/PropertySpoofer.js +156 -0
  17. package/system/Risei.js +5 -5
  18. package/system/SpoofDef.js +260 -0
  19. package/system/TerminalReporter.js +8 -8
  20. package/system/{TestDefinition.js → TestDef.js} +153 -107
  21. package/system/TestFinder.js +3 -3
  22. package/system/TestFrame.js +15 -52
  23. package/system/TestGroup.js +1 -1
  24. package/system/TestResult.js +2 -2
  25. package/system/TestRunner.js +23 -107
  26. package/system/TestStages.js +80 -76
  27. package/system/TestSummary.js +1 -1
  28. package/system/TotalComparer.js +60 -11
  29. package/system/TotalDisplayer.js +33 -12
  30. package/system/TypeAnalyzer.js +41 -79
  31. package/system/TypeIdentifier.js +18 -8
  32. package/system/Types.js +3 -1
  33. package/system/AComparer.js +0 -9
  34. package/system/ATestFixture.js +0 -44
  35. package/system/ClassPropertySpoofer.js +0 -185
  36. package/system/ObjectMethodSpoofer.js +0 -58
  37. package/system/ObjectPropertySpoofer.js +0 -136
  38. package/system/SpoofDefinition.js +0 -243
  39. package/system/TestFrameChooser.js +0 -54
  40. package/system/TestFrames.js +0 -232
  41. package/system/TotalCopier.js +0 -106
  42. package/usage-examples/Output-example.png +0 -0
  43. package/usage-examples/Summary-example.png +0 -0
  44. package/usage-examples/Syntax-example.png +0 -0
package/README.md CHANGED
@@ -1,51 +1,73 @@
1
1
 
2
- # Risei
2
+ # Risei Read-Me
3
3
 
4
- ## What Risei is
4
+ ## Overview
5
5
 
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.
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.
10
7
 
8
+ Risei does all this by replacing hand-coded tests with simple declarative syntax.
11
9
 
10
+ - Risei has many convenient and time-saving [features](#features-of-risei).
11
+ - Risei works with object-oriented JavaScript in modules.
12
+ - Risei works with TypeScript after just a few [tweaks](https://deusware.com/risei/index.html#typescript-with-risei).
12
13
 
14
+ You can find a longer version of this read-me at [https://deusware.com/risei](https://deusware.com/risei/index.html).  It expands greatly on the information here.
13
15
 
14
- ## The Risei approach
15
16
 
16
- Risei replaces coded tests with simple declarative syntax that's far easier to draft than any other unit-testing approach.
17
17
 
18
- Here are two example tests.  `SortModel.countSort()` is being tested using the inputs from `.in` and the expected output from `.out`:
18
+ ## Examples
19
19
 
20
- ![https://deusware.com/Syntax-example.png](https://deusware.com/Syntax-example.png)
20
+ Here are two example tests, in which `SortModel.countSort()` is being tested using the inputs from `.in` and the expected output from `.out`:
21
21
 
22
+ ![https://deusware.com/risei/images/Syntax-example.png](https://deusware.com/risei/images/Syntax-example.png)
22
23
 
23
- Here is the terminal output of these two example tests.  Tests are grouped by class and method.  Inputs, expected, and actual values are displayed for all tests, to make intended usage obvious at a glance:
24
24
 
25
- ![https://deusware.com/Output-example.png](https://deusware.com/Output-example.png)
25
+ Here are the example test results for those two tests:
26
26
 
27
+ ![https://deusware.com/risei/images/Output-example.png](https://deusware.com/risei/images/Output-example.png)
27
28
 
28
- - An individual test may appear on one line or multiple lines, depending on how wide the terminal window is.
29
+ - Outputs are always listed, even on passing tests, which makes code usage much clearer.
29
30
  - Any failing tests appear in light red.
30
- - Your latest-edited tests always sort to the bottom, so you can see your current test results at a glance.
31
+ - Your latest tests always sort to the bottom so it's easy to find their results.
31
32
 
32
33
 
33
- Test runs also feature a title bar at the top, as well as a summary bar at the bottom:
34
+ Test runs have a title bar so the starting point is easy to find:
34
35
 
35
- ![https://deusware.com/Summary-example.png](https://deusware.com/Summary-example.png)
36
+ ![https://deusware.com/risei/images/Title-example.png](https://deusware.com/risei/images/Title-example.png)
36
37
 
37
38
 
39
+ And they have a summary bar at the bottom:
38
40
 
41
+ ![https://deusware.com/risei/images/Summary-example.png](https://deusware.com/risei/images/Summary-example.png)
39
42
 
40
- ## Using Risei
43
+ - This bar is red when any tests fail, much as you'd expect.
41
44
 
42
- 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).
43
45
 
44
- There are a few additional or different steps for [using Typescript with Risei](#using-typescript-with-risei).
45
46
 
47
+ ## Status
46
48
 
49
+ Risei is under active development and new enhancements appear often.  The latest release, **2.0.1**, brings many major improvements, including broader capabilities and simpler syntax, and a few minor breaking changes.
47
50
 
48
- ### Installation
51
+ Check out the [full list of changes](#version-history).
52
+
53
+
54
+
55
+ ## Features of Risei
56
+
57
+ - #### Declarative syntax to write tests simply and quickly.    ►  [Writing tests](https://deusware.com/risei/index.html#writing-tests)  (basics below)
58
+ - #### Easy-to-read test definitions and test outputs.    ►  [Test and output examples](https://deusware.com/risei/index.html#examples)  (also above)
59
+ - #### Even less to write by stating reused test properties only once.    ►  [Collapsing forward](https://deusware.com/risei/index.html#collapsing-forward)  (basics below)
60
+ - #### Built-in declarative syntax to fake test-time values from dependencies.    ►  [Spoofing using `.plus`](https://deusware.com/risei/index.html#spoofing)  (basics below)
61
+ - #### Testing properties, methods, static and instance members all the same way.    ►  [Properties and statics](https://deusware.com/risei/index.html#testing-properties-and-static-methods)
62
+ - #### Testing `throw` paths effortlessly.    ►  [Using `.and: "throws"`](https://deusware.com/risei/index.html#using-and-throws)
63
+ - #### Deriving actual values to test from raw outputs or property retrieval.    ►  [Using `.from`](https://deusware.com/risei/index.html#using-from)
64
+ - #### Setting up and tearing down arbitrary test state.    ►  [Using `.do` and `.undo`](https://deusware.com/risei/index.html#using-do-and-undo)
65
+ - #### Testing for `undefined` as output.    ►  [Using `this.undef`](https://deusware.com/risei/index.html#using-undef)
66
+
67
+ - And more!  Check out the full [Risei home page](https://deusware.com/risei).
68
+
69
+
70
+ ## Installation
49
71
 
50
72
  Install Risei for development time only:
51
73
 
@@ -53,7 +75,7 @@ Install Risei for development time only:
53
75
  npm install --save-dev risei
54
76
  ```
55
77
 
56
- Make sure your `package.json` specifies that ESM is in use:
78
+ Ensure that `package.json` specifies ECMAScript modules:
57
79
 
58
80
  ```json
59
81
  "type": "module"
@@ -67,105 +89,17 @@ And add Risei's metadata to `package.json`:
67
89
  }
68
90
  ```
69
91
 
70
- Just a [few extra steps](#using-typescript-with-risei) are required for Risei to work with TypeScript.
71
-
72
-
73
-
74
- ### Siting tests
75
-
76
- Add tests in files ending in `.rt.js` like this:
77
-
78
- ```javascript
79
- import { ATestSource } from "risei/ATestSource";
80
- import { ClassToBeTested } from "somewhere";
81
-
82
- export class SomeTests extends ATestSource {
83
- tests = [ ... ]; // This array is where test definitions are written.
84
- }
85
- ```
86
-
87
-
88
-
89
- ### Writing tests
90
-
91
- Write tests with Risei's easy syntax:
92
-
93
- ```javascript
94
- tests = [ ...
95
- { on: ContainerModelClass, with: [ "a", "b", "c" ], // Target class and constructor args.
96
- of: "doesContain", // Target method.
97
- for: "When the input arg is present, returns true.", // Description of test.
98
- in: [ "c" ], // Inputs.
99
- out: true }, // Expected output.
100
- ...];
101
- ```
102
-
103
92
 
104
93
 
105
- #### Write more tests with less syntax:
94
+ ## Running Tests
106
95
 
107
- You can save a lot of time by putting repeated test properties into an object once, just before the related tests:
108
-
109
- ```javascript
110
- /* All of the following tests are of ContainerModelClass. */
111
- { on: ContainerModelClass, with: [ "a", "b", "c", "a", "b" ] },
112
-
113
- /* Two tests for ContainerModelClass .doesContain(). */
114
- { of: "doesContain" },
115
- { for: "When the input arg is present, returns true.",
116
- in: [ "c" ], out: true },
117
- { for: "When the input arg is not present, returns false.",
118
- in: [ "d" ], out: false },
119
-
120
- /* First test for ContainerModelClass .countOf(). */
121
- { of: "countOf", for: "Returns the number present.", in: [ "b" ], out: 2 }
122
- ```
123
-
124
- - 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 `[]`.
125
-
126
- - 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.
127
-
128
-
129
-
130
- #### Spoof away code dependencies:
131
-
132
- When your tests need certain results from code dependencies, just _spoof_ what you want using a `.plus` test property:
133
-
134
- ```javascript
135
- { on: CombinerClass, with: [],
136
- of: "combineResults",
137
- plus: [
138
- { on: ClassA, of: "someMethod", as: 10 }, // Spoof this ClassA method to return 10.
139
- { on: ClassB, of: "someMethod" }, // Spoof this ClassB method not to return (or do) anything.
140
- { of: "firstMethod", as: [ 7, 8, 9, 10 ] }, // Spoof a method on the tested class (CombinerClass).
141
- { of: "secondMethod" }, // Spoof a method on CombinerClass not to do anything.
142
- { on: ClassC, // Spoof this ClassC method to be this nonce code.
143
- of: "someMethod",
144
- as: (arg) => { return { color: arg }; } },
145
- { on: ClassD, as: [ // Spoof two methods on ClassD at the same time.
146
- { of: "firstMethod", as: 11 },
147
- { of: "secondMethod", as: 12 }
148
- ] },
149
- ],
150
- for: "When called, returns an array of values from sources.",
151
- in: [ "green" ], out: [ 7, 8, 9, 10, 10, 11, 12, { color: "green" } ] }
152
- ```
153
-
154
- - It's just like _fakes_, _mocks_, or _test doubles_ in other test systems, but much easier to write and read.
155
-
156
- - Spoofed code is fully isolated within tests, even though spoof definitions collapse forward across tests (and within `.plus`).
157
-
158
-
159
-
160
- ### Running tests
161
-
162
- Run your tests by invoking Risei's `index.js` file:
96
+ Once you have some tests written, you can run them manually:
163
97
 
164
98
  ```bash
165
99
  node ./node_modules/risei/index.js
166
100
  ```
167
101
 
168
- Or write a `package.json` script that does the same:
102
+ Or write a script in `package.json` that does the same:
169
103
 
170
104
  ```json
171
105
  "scripts": {
@@ -179,438 +113,158 @@ And then run that script:
179
113
  npm test
180
114
  ```
181
115
 
182
- Risei can be used alongside other test frameworks, and even run with them from the same test script if you want.
183
-
184
-
185
-
186
- ### Learning more about Risei
187
-
188
- Read through the rest of this doc to learn more about Risei's many capabilities, and about where Risei is headed.
189
-
190
- - For instance, learn about using `.and` to test static methods or throws.
191
- - Or learn about using `.from` to test property results or other state.
192
- - Don't miss out:  Once you've tried the basics, read the rest...!
193
-
194
-
195
-
196
-
197
- ## Risei in depth
198
-
199
- <details>
200
- <summary>
201
- There's plenty more to learn about Risei and how it makes testing easy...
202
- </summary>
203
-
204
- ### Installation
205
-
206
- - You can use any file extension you want in Risei's metadata in `package.json`, and Risei will scan those files for tests.
207
-
208
- - You can install Risei outside of development time the usual way, but as with any test system, this is definitely not recommended.
209
-
210
- - Risei uses ESM syntax, and may not work in older environments where that's not available or is patched in.
211
-
212
-
213
-
214
- ### Siting tests
215
-
216
- - Match your Risei test file's extensions to whatever you choose in the metadata in `package.json`.
217
-
218
- - Test classes must inherit from `ATestSource` in `"risei/ATestSource"`: this type name is looked for specifically, so duck-typing doesn't work.
219
-
220
-
221
-
222
- ### Writing tests
223
-
224
- - The order and placement of test properties doesn't matter, although the order seen in the examples is probably most readable.
225
-
226
-
227
-
228
- #### Basic test properties and options for each:
229
-
230
- | Name | Contents |
231
- |--------|-----------------------------------------------------------------------------------------------------------|
232
- | `on` | The class under test, as a symbol / name (already imported into the test file) |
233
- | `with` | An array of any arguments to pass to the constructor of the tested class, or an empty array `[]` if none |
234
- | `of` | The name of the method under test, as a string, no `()` needed |
235
- | `for` | A description of what the test proves, for test output |
236
- | `in` | An array of the input arguments to pass to the tested method, or an empty array `[]` if none |
237
- | `out` | The expected return value, not in an array |
238
-
239
- - There are additional properties for extended functionality, covered later.
240
- - The property names were chosen to be easy to remember and type, but longer alternatives are available, covered later.
241
-
242
-
243
-
244
- ### Test-property reuse _AKA_ Collapsing forward
245
-
246
- - 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 `[]`.
247
- - Property values are gathered across partial test objects until they add up to a runnable test, which is then run.
248
- - Changes to properties are combined with previous ones to produce intended new tests.
249
- - For a rare and avoidable side-effect of this system, see [known issues and workarounds](#known-issues-and-workarounds).
250
-
251
- - Test contents, reused or not, are automatically reset when it makes the most sense:
252
- - Changing the tested class in `.on` wipes out all prior test properties, so the new class has a fresh start.
253
- - Changing the tested method in `.of` wipes out only test properties related to methods, to preserve class values you usually want.
254
-
255
- - Individual tests remain isolated, except for when args are mutated by the code under test.
256
- - Restate args for each test when the code mutates them.
257
- - This limitation is the result of limits on what can be copied reliably in JavaScript.
258
-
259
-
260
- ### Choosing test-only dependency inputs _AKA_ Spoofing
261
-
262
- - Spoofing is Risei's way of providing test-only inputs from dependencies the tested code uses, written in simple declarative syntax.
263
- - It's therefore the equivalent of test doubles, mocks, fakes, and so on.
264
-
265
-
266
- - As the earlier examples and this table show, you can spoof in many ways, both on the dependencies, and on the class being tested.
267
- - All classes whose members are being spoofed have to be imported.
268
-
269
-
270
-
271
- #### Spoof-definition properties:
272
-
273
- | Name | Necessary or Optional | Contents |
274
- |------|-----------------------|----------------------------------------------------------------------------|
275
- | `on` | Optional | Symbol for a type (class); if omitted, the targeted model class is assumed |
276
- | `of` | Necessary | Name of the method to spoof, as a string, trailing `()` not needed |
277
- | `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 |
278
-
279
-
280
- - 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.
281
-
282
-
283
- #### Partial spoof-definition properties:
284
-
285
- | Name | Necessary or Optional | Contents |
286
- |------|-----------------------|---------------------------------------------------------------------------------------------------|
287
- | `of` | Necessary | Name of the method to spoof, as a string, trailing `()` not needed |
288
- | `as` | Optional | Value to return or nonce implementation; if omitted, an empty method with no return value is used |
289
-
290
-
291
- - Defining new spoofing wipes out all old definitions.
292
-
293
-
294
- - Spoofing is done at the start of each test and undone at the end of each test, keeping all tests isolated.
295
-
296
-
297
-
298
-
299
- ## Advanced Risei usage
300
116
 
301
- ### Testing special test conditions with `.and`
302
117
 
303
- You can use the special test property `.and`, always a string, to indicate special conditions that apply to your test.
304
- - At present, the values available are `"static"` and `"throw"` / `"throws"` (either one works).
305
- - You can list `static` and `throw` / `throws` together if needed, separated by a space.
118
+ ## Writing Tests
306
119
 
307
- 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).
308
-
309
-
310
-
311
- #### Testing static methods
312
-
313
- To test a static method, use an `.and` of `"static"`:
314
-
315
- ```javascript
316
- { on: StaticTextProfileModel, with: [] },
317
-
318
- { of: "getTextProfile",
319
- for: "Returns accurate profile of arg text.",
320
- and: "static",
321
- in: [ "This is a short sentence." ],
322
- out: { isFullSentence: true, characters: 25, words: 5 }
323
- }
324
- ```
325
-
326
-
327
-
328
- #### Testing throws
329
-
330
- To test a throw, use an `.and` of `"throw"` or `"throws"`:
120
+ You write tests in `.rt.js` files like this:
331
121
 
332
122
  ```javascript
333
- { on: InstanceTextProfileModel, with: [] },
123
+ import ATestSource from "risei/ATestSource";
124
+ import ClassToTest from "ClassToTest.js";
334
125
 
335
- { of: "getTextProfile",
336
- for: "Throws with a helpful message when there is no arg text.",
337
- and: "throws",
338
- in: [],
339
- out: "Could not build a profile. Did you forget to provide a text?"
126
+ export class SomeTests extends ATestSource {
127
+ tests = [ ... ];
340
128
  }
341
129
  ```
342
130
 
343
-
344
-
345
- ### Testing object properties and other non-`return` results
346
-
347
- 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:
348
-
349
- | Contents of `.from` | Usage |
350
- |--------------------------------|-------------------------------------------------------------------------|
351
- | Property name as string | Retrieves the actual from the named property on the test's target class |
352
- | Specialized function | Retrieves the actual from either its `target` or `test` parameter |
353
-
354
-
355
- - Getting properties, mutated args, and other non-return values is known as _retrieving_.
356
- - Retrieving definitions collapse forward across tests unless replaced with new definitions, or erased by setting `.from` to an empty array `[]`.
357
-
358
-
359
- <details>
360
- <summary>
361
- &nbsp; More information
362
- </summary>
363
- <br>
364
-
365
- - Use of `.from` with a property name looks like this:
131
+ Write individual tests as plain JavaScript objects with Risei's simple syntax:
366
132
 
367
133
  ```javascript
368
- { on: StatefulModel, with: [] },
369
-
370
- { of: "storePolyProduct",
371
- for: "The result of the calculation is stored as .result.",
372
- in: [ 10, 8, 9, 6 ], out: 4320, from: "result" },
134
+ tests = [ ...
135
+ { on: ContainerClass, with: [ "a", "b", "c" ], // Target class and constructor args.
136
+ of: "doesContain", // Target method name.
137
+ for: "When the arg is present, returns true.", // Description of test.
138
+ in: [ "c" ], // Inputs to method.
139
+ out: true }, // Expected output.
140
+ ... ];
373
141
  ```
374
142
 
375
- - Only instance properties can be retrieved by name.&nbsp; For static properties, use `.and` (covered earlier), plus a function as `.from` (covered next).
376
-
377
- When the contents of `.from` are a function, these are the two parameters:
378
-
379
- | Name | Contents |
380
- |----------|---------------------------------------------------------------------------------------------------|
381
- | `target` | The instance of the class being tested |
382
- | `test` | The test definition itself, whose properties may have been mutated by the tested method |
143
+ - Use empty arrays for `.in` or `.with` when there are no args to pass.
144
+ - You can use [long names](https://deusware.com/risei/index.html#long-names) for properties if you want.
383
145
 
384
146
 
385
- - The `test` parameter to a `.from` function contains all of the properties of your test definition, including those that collapsed forward.
386
- - These properties are available by both short or long names (covered later).
387
- - The `test.on` property always references the class under test, rather than an instance of it.
388
147
 
148
+ ## Basic collapsing forward example
389
149
 
390
- - 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.
150
+ You can state test properties once and let them _collapse forward_ across subsequent tests to save time and make tests easier to read.
391
151
 
392
-
393
- - Another usage of a `.from` function is to look at an input to see if it was changed as expected:
152
+ Risei collapses values together from partial or full test objects until it has a full test to run.&nbsp; Every property collapses forward until it is changed or wiped out:
394
153
 
395
154
  ```javascript
396
- { on: SecurityModel, with: [] },
397
-
398
- { of: "addHash",
399
- for: "The content's hash is added to the input arg a new property.",
400
- in: [ { content: "SecretValue" }, iterations: 8 ],
401
- out: { content: "SecretValue", hash: "FasBdQ-fljk%asPcdf" },
402
- from: (target, test) => { return test.in[0]; }
403
- },
404
- ```
405
-
406
- </details>
407
-
408
-
409
-
410
- ### Property long names
411
-
412
- Property names are short so they're easy to use.&nbsp; Some of them overlap with JavaScript keywords, but this causes no harm.
413
-
414
- 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.
415
-
416
-
417
- <details>
418
- <summary>
419
- &nbsp; Test properties' short and long names
420
- </summary>
421
-
422
- | Short Name | Long Name |
423
- |------------|-----------|
424
- | `on` | `type` |
425
- | `with` | `initors` |
426
- | `of` | `method` |
427
- | `for` | `nature` |
428
- | `in` | `inputs` |
429
- | `out` | `output` |
430
- | `plus` | `spoofed` |
431
- | `from` | `source` |
432
- | `and` | `factors` |
433
-
434
- </details>
435
-
436
- <br>
437
-
438
- <details>
439
- <summary>
440
- &nbsp; Spoof properties' short and long names
441
- </summary>
442
-
443
- | Short Name | Long Name |
444
- |------------|-----------|
445
- | `on` | `target` |
446
- | `of` | `method` |
447
- | `as` | `output` |
448
-
449
- </details>
450
-
451
-
452
-
453
- ### Further capabilities of Risei
454
-
455
- Constructors can be tested with no special test properties or keywords.
456
- - The method name in `.of` is simply `"constructor"`.
457
- - Any `.with` args are completely ignored for a constructor test.&nbsp; Only those in the test's `.in` property are used.
458
- - However, a `.with` must still be provided.&nbsp; It can simply be an empty array `[]`.
459
-
460
- </details>
461
-
462
-
463
-
155
+ { on: ContainerClass, with: [ "a", "b", "c" ] }, // Following tests are of this class.
464
156
 
465
- ## Using TypeScript with Risei
157
+ { of: "doesContain" }, // Following tests are of this method.
158
+ { for: "Returns true when arg present.", in: [ "c" ], out: true }, // First test: now Risei has enough to run on.
159
+ { for: "Returns false when arg absent.", in: [ "d" ], out: false }, // Next test: same method, different test case.
466
160
 
467
- 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.
161
+ { of: "countOf" }, // Change of tested method. Method-related props are wiped out.
162
+ ...
468
163
 
469
- - Anything beyond those basics is intended to keep JS files separate from TS files and the output of web frameworks' own, complex build processes.
470
-
471
- If you follow the general Risei set-up, you can just make the following few modifications for TypeScript applications.
472
- - These steps have worked with both Angular and React.
473
- - Varying other approaches are also sure to work, depending on the other technical choices in play.
474
-
475
-
476
-
477
- ### In `package.json`:
478
-
479
- Add transpilation and deletion operations to the `test` script, with each operation conditional on completion of the preceding one:
480
-
481
- ```json
482
- "scripts": {
483
- "test": "tsc && node ./node_modules/risei/index.js && rm -r ./dist/out-tsc"
484
- }
164
+ { on: SortingClass, with: [ ] }, // Change of tested class. All existing props are wiped out.
485
165
  ```
486
166
 
487
- - Generally, you should use `tsc` or another plain transpiler, not web frameworks' complex processes with single output files.
488
- - Deleting the files at the end prevents interference with web frameworks' bundling.
489
- - The deletion path must match the `outDir` in `tsconfig.json`.
490
-
491
- > You can run Risei manually with the same sequence of operations.
167
+ - There are more options available, and an exclusion for mutated args.
168
+ - Learn all the details [here](https://deusware.com/risei/index.html#collapsing-forward).
492
169
 
493
170
 
494
171
 
495
- ### In `tsconfig.json`:
172
+ ## Basic spoofing example
496
173
 
497
- You set up the transpiler to output files to a directory with these settings:
174
+ You can use declarative _spoofing_ syntax to define what dependencies of your targeted code return for it to use.
498
175
 
499
- ```json
500
- {
501
- "outDir": "dist/out-tsc",
502
- "noEmit": false
503
- }
504
- ```
505
-
506
- - The `outDir` can be any location.&nbsp; It's best not to just use `dist`, where adding or deleting files may interfere with web frameworks' build steps.
507
- - These settings are normally not near each other in the file (as seen here).
508
- - You can also set the `target` to `es6` or higher, although Risei works fine with ES5.
509
-
510
-
511
-
512
-
513
- ### In test files:
514
-
515
- All `import` statements have to point to the Javascript (`.js`) files in the `outDir` path or subfolders there, using relative-path syntax:
176
+ The most basic spoofing looks like this:
516
177
 
517
178
  ```javascript
518
- import { TestedClass } from "../../dist/out-tsc/SubPath/TestedClass.js";
179
+ {
180
+ on: TestedClass,
181
+ ...
182
+ plus: [
183
+ { on: Dependency, of: "someMethod", as: 10 }, // Dependency.someMethod() returns 10 in this test.
184
+ { of: "testedClassMethod", as: 11 } // TestedClass.testedClassMethod() returns 11 in this test.
185
+ ],
186
+ ...
187
+ }
519
188
  ```
520
189
 
521
- - Output files may be in a folder tree parallel to the originals (Angular), or may all be in the `outDir` folder itself (React).
190
+ - Numerous additional capabilities, as well as compressed syntax, can be mixed freely in many ways.
191
+ - Learn more [here](https://deusware.com/risei/index.html#spoofing).
522
192
 
523
193
 
524
194
 
195
+ ## TypeScript with Risei
525
196
 
526
- ## Limitations in Risei
527
-
528
- The following are not supported at present:
529
- - Use of `async` syntax
530
- - Code written in ESM `export` modules, but not within classes
531
- - Standalone functions and other functionality not built into classes, AKA _loose code_
532
- - CJS syntax using `require()`
533
- - Spoofing mixes of properties and methods, such as `something.method.property.method`
534
- - Debugging model code during tests
535
- - Comparing rare JS object types like `Proxy` or `ArrayBuffer` in test assertions
536
-
537
- 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.
197
+ 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.
538
198
 
199
+ - Learn all about it [here](https://deusware.com/risei/index.html#typescript-with-risei).
539
200
 
540
201
 
541
202
 
542
203
  ## Troubleshooting
543
204
 
544
- Most problems with using Risei are minor mistakes in syntax, or omissions in test definitions:
545
-
546
- | Error condition or text | Probable cause |
547
- |---------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
548
- | 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 |
549
- | `"Test loading failed for... SyntaxError: Unexpected token ':'"` | Missing comma in your tests in the named file |
550
- | `"Test loading failed for... SyntaxError: Unexpected token '.'"` | Using `this.tests = []` instead of `tests = []` in the file named |
551
- | Other `... Unexpected token ...` errors | Some other syntax error in the file named, most likely a missing or extra delimiter |
552
- | Unexpected extra, failing test/s | Partial test properties in a mid-list object have produced extra tests |
553
- | 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 |
205
+ If problems cause test files not to load, a gold bar appears and tests in those files disappear from output:
554
206
 
207
+ ![https://deusware.com/risei/images/Gold-bar-example.png](https://deusware.com/risei/images/Gold-bar-example.png)
555
208
 
209
+ - Those and other problems can be solved with the help of this [troubleshooting guide](https://deusware.com/risei/index.html#troubleshooting).
556
210
 
557
211
 
558
- ## Known issues and workarounds
559
-
560
- Two issues are known to exist:
561
-
562
- - When code mutates its args in test definitions, the mutated forms are used in subsequent tests unless those args are restated.
563
- - To avoid this problem, just restate the args in each test of this code.
564
- - The workaround for this &mdash; copying and initing objects to bypass mutation &mdash; requires too many assumptions to be reliable.
212
+ ## Version history
565
213
 
214
+ - Release **2.0.1** (August, 2024) contains all of these changes:
215
+ - Risei now can determine automatically if tested methods are static.
216
+ - You can now directly test properties just like methods.
217
+ - Risei can also determine automatically if these are static.
218
+ - Directly tested properties appear in the output in the form `.name`.
219
+ - You can now spoof properties on the targeted class instance, and static properties on the target class itself.
220
+ - You can now perform arbitrary operations, if needed, with the two-part `.do` property and one-part `.undo` property.
221
+ - You can now change test properties without accidentally creating a new test using `.just`.
222
+ - You can now directly test for `undefined` in `.out` using `this.undef` / `ATestSource.undefSymbol`.
223
+ - `Error` objects are now compared accurately.
224
+ - You can now identify member types with `.`, `:`, and `()` in `.of`, `.plus`, and `.from`, though they aren't necessary.
225
+ - **(Breaking change)**&nbsp; The actual for throw tests is now the entire thrown object (usually an `Error`), rather than the `Error`'s message text.
226
+ - **(Breaking change)**&nbsp; `ATestSource` is now a default export, changing its imports from `import { ATestSource } from` to `import ATestSource from`.
566
227
 
567
- - 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.
568
- - To avoid this problem, just change properties as part of whole new tests, or else restate `.of` along with the changed properties.
569
- - Risei is actually working as intended when this happens, but ways to optionally prevent it are being considered.
228
+ > Risei has been massively re-engineered internally along with these improvements.
570
229
 
571
230
 
572
231
 
573
- ## What's new in Risei
574
-
575
- - Release **1.3.4** (March, 2024) fixes a bug that caused class definitions still to appear instead of class names when classes were used as object properties.
576
- - As a side effect of this change, objects' own `toString()` is never used in onscreen test output any longer, but all of Risei's output display is now handled the same.
577
-
578
-
579
- - 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.
580
- - Risei is now fully usable in Windows environments again.
581
-
232
+ <details>
233
+ <summary>
234
+ Older releases
235
+ </summary>
582
236
 
583
- - Release **1.3.2** (February, 2024) does not change the code at all, but improves this read-me.
584
- - It now explains the easiest way to deal with mutable args (which is just restating the args).
585
- - A few mistakes in the text were also fixed.
237
+ - Release **2.0.0** (August, 2024) is identical to 2.0.1 except for some unneeded extra files.
238
+ - Release **1.3.4** (March, 2024) fixed a bug that caused class display problems in some cases.
239
+ - Release **1.3.3** (March, 2024) fixed a major bug that prevented tests from running in Windows.
240
+ - Release **1.3.2** (February, 2024) only improved this read-me's contents.
241
+ - Release **1.3.1** (February, 2024) reversed some changes in 1.3.0 that did not work as hoped.
242
+ - Release **1.3.0** (February, 2024) added the loading-error gold bar and fixed a test-sorting bug.
243
+ - Release **1.2.0** (January, 2024) changed test sorting to move last-edited tests to the end.
244
+ - Release **1.1.2** of Risei (January, 2024) fixed class displays and inaccurate `Date` comparisons.
586
245
 
246
+ > The oldest releases are no longer listed here, and old releases are dropped progressively over time.&nbsp; Using the latest release is recommended.
587
247
 
588
- - 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.
589
- - Supporting built-in total test isolation is not feasible with collapsing forward, nor is it usually necessary given easy usage alternatives.
590
- - In contrast, collapsing forward is both highly beneficial and frequently used.
248
+ </details>
591
249
 
592
250
 
593
- - Release **1.3.0** (February, 2024) makes two changes:
594
- - If there are any test-loading errors, their messages now appear in a new gold bar that appears below the summary of the test run.
595
- - A test-sorting error has also been fixed that occurred when no test files existed yet.
251
+ ## Known issues and workarounds
596
252
 
253
+ The only issue at present is reuse of method args mutated by tested code when collapsing forward.
597
254
 
598
- - Release **1.2.0** (January, 2024) changes sorting of test files to make tests you're working on now appear at the bottom.
599
- - Previously tests were displayed in the order found, which is always alphabetical (though is not guaranteed to be so).
600
- - The order for all files except one remains the same.
601
- - The last-edited file is moved to the bottom, making it easy to see the latest test results.
255
+ - The workaround is just to restate those args for each test.
602
256
 
603
257
 
604
- - Release **1.1.2** of Risei (January, 2024) fixes two problems:
605
- - Classes were sometimes displayed in output as their entire definition.&nbsp; Now just the class name is displayed.
606
- - All `Date` instances were considered equal, regardless of their actual value.&nbsp; Now they only are considered equal when they actually are.
258
+ ## Exclusions from Risei
607
259
 
260
+ At present, there are a few things Risei doesn't support, such as `async` syntax.&nbsp; Some of these may be supported in the future.
608
261
 
609
- - Don't use release **1.1.1**, which contains an internal path error.
262
+ - You can see the whole list [here](https://deusware.com/risei/index.html#exclusions-from-risei).
263
+ - You can save a lot of time by using Risei for most of your code, and another framework for whatever it doesn't support.
610
264
 
611
265
 
612
266
 
613
- ## Who makes Risei
267
+ ## Maker
614
268
 
615
269
  Risei is written by myself, Ed Fallin.&nbsp; I'm a longtime software developer who likes to find better ways to do things.
616
270
 
@@ -620,8 +274,7 @@ You can get in touch about Risei at **riseimaker@gmail.com**.
620
274
 
621
275
 
622
276
 
623
-
624
- ## Risei license
277
+ ## License
625
278
 
626
279
  Risei is published for use under the terms of the MIT license:
627
280
 
@@ -638,3 +291,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
638
291
 
639
292
 
640
293
  &nbsp;
294
+
295
+