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.
- package/README.md +142 -379
- package/Read-me reduced.md +294 -0
- package/Read-me redux.md +581 -0
- package/index.js +5 -5
- package/package.json +10 -11
- package/system/ASpoofingFixture.js +7 -8
- package/system/ATestCaller.js +3 -3
- package/system/ATestFinder.js +2 -2
- package/system/ATestReporter.js +2 -1
- package/system/ATestSource.js +5 -1
- package/system/ChosenTestFinder.js +4 -4
- package/system/ClassTestGroup.js +2 -2
- package/system/LocalCaller.js +5 -5
- package/system/{ClassMethodSpoofer.js → MethodSpoofer.js} +54 -48
- package/system/MethodTestGroup.js +2 -2
- package/system/Moment.js +1 -1
- package/system/NameAnalyzer.js +26 -0
- package/system/PropertySpoofer.js +156 -0
- package/system/Risei.js +5 -5
- package/system/SpoofDef.js +260 -0
- package/system/TerminalReporter.js +8 -8
- package/system/{TestDefinition.js → TestDef.js} +153 -107
- package/system/TestFinder.js +3 -3
- package/system/TestFrame.js +15 -52
- package/system/TestGroup.js +1 -1
- package/system/TestResult.js +2 -2
- package/system/TestRunner.js +23 -107
- package/system/TestStages.js +80 -76
- package/system/TestSummary.js +1 -1
- package/system/TotalComparer.js +60 -11
- package/system/TotalDisplayer.js +33 -12
- package/system/TypeAnalyzer.js +41 -79
- package/system/TypeIdentifier.js +18 -8
- package/system/Types.js +3 -1
- package/test-target-objects/ConditionalThrowTarget.js +11 -0
- package/test-target-objects/Counter.js +46 -0
- package/test-target-objects/DomTarget.js +37 -0
- package/test-target-objects/InterSpoofer.js +230 -0
- package/test-target-objects/MixedContents.js +33 -0
- package/test-target-objects/MutationTarget.js +37 -0
- package/test-target-objects/ObjectComposer.js +34 -0
- package/test-target-objects/PolySpoofableInner.js +29 -0
- package/test-target-objects/PolySpoofableOuter.js +52 -0
- package/test-target-objects/PropertiesTarget.js +98 -0
- package/test-target-objects/Returner.js +7 -0
- package/test-target-objects/Searcher.js +25 -0
- package/test-target-objects/Sorter.js +91 -0
- package/test-target-objects/Spoofable.js +36 -0
- package/test-target-objects/StateTarget.js +34 -0
- package/test-target-objects/StaticTarget.js +17 -0
- package/test-target-objects/TestableTarget.js +57 -0
- package/trial-tests/SelfTests.outward-rt.js +511 -0
- package/trial-tests/TopicTests.outward-rt.js +313 -0
- package/usage-examples/Gold-bar-example.png +0 -0
- package/usage-examples/Title-example.png +0 -0
- package/xternal-tests/ASpoofingFixture.tests.js +242 -0
- package/xternal-tests/MethodSpoofer.tests.js +130 -0
- package/xternal-tests/SpoofDef.tests.js +91 -0
- package/xternal-tests/TotalComparer.tests.js +1055 -0
- package/xternal-tests/package.json +7 -0
- package/system/AComparer.js +0 -9
- package/system/ATestFixture.js +0 -44
- package/system/ClassPropertySpoofer.js +0 -185
- package/system/ObjectMethodSpoofer.js +0 -58
- package/system/ObjectPropertySpoofer.js +0 -136
- package/system/SpoofDefinition.js +0 -243
- package/system/TestFrameChooser.js +0 -54
- package/system/TestFrames.js +0 -232
- package/system/TotalCopier.js +0 -106
package/README.md
CHANGED
|
@@ -4,16 +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
|
|
8
|
-
* Refactor or replace existing designs without worrying about
|
|
9
|
-
* Create tests with immediate confidence,
|
|
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.
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
## The Risei approach
|
|
15
15
|
|
|
16
|
-
Risei replaces coded tests with simple declarative syntax
|
|
16
|
+
Risei replaces coded tests with simple declarative syntax.
|
|
17
17
|
|
|
18
18
|
Here are two example tests. `SortModel.countSort()` is being tested using the inputs from `.in` and the expected output from `.out`:
|
|
19
19
|
|
|
@@ -25,12 +25,16 @@ Here is the terminal output of these two example tests. Tests are grouped
|
|
|
25
25
|

|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
- An individual test may appear on one line or multiple lines, depending on how wide the terminal window is.
|
|
29
28
|
- Any failing tests appear in light red.
|
|
30
|
-
- Your latest
|
|
29
|
+
- Your latest tests always sort to the bottom so it's easy to find their results.
|
|
31
30
|
|
|
32
31
|
|
|
33
|
-
Test runs also feature a title bar at the top
|
|
32
|
+
Test runs also feature a title bar at the top:
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
As well as a summary bar at the bottom:
|
|
34
38
|
|
|
35
39
|

|
|
36
40
|
|
|
@@ -39,9 +43,30 @@ Test runs also feature a title bar at the top, as well as a summary bar at the b
|
|
|
39
43
|
|
|
40
44
|
## Using Risei
|
|
41
45
|
|
|
42
|
-
Risei is under active development.
|
|
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).
|
|
43
69
|
|
|
44
|
-
There are a few additional or different steps for [using Typescript with Risei](#using-typescript-with-risei).
|
|
45
70
|
|
|
46
71
|
|
|
47
72
|
|
|
@@ -53,7 +78,7 @@ Install Risei for development time only:
|
|
|
53
78
|
npm install --save-dev risei
|
|
54
79
|
```
|
|
55
80
|
|
|
56
|
-
Make sure your `package.json` specifies that
|
|
81
|
+
Make sure your `package.json` specifies that ECMAScript modules are in use:
|
|
57
82
|
|
|
58
83
|
```json
|
|
59
84
|
"type": "module"
|
|
@@ -67,99 +92,20 @@ And add Risei's metadata to `package.json`:
|
|
|
67
92
|
}
|
|
68
93
|
```
|
|
69
94
|
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
#### Write more tests with less syntax:
|
|
106
|
-
|
|
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" ] },
|
|
95
|
+
> Just a [few extra steps](#using-typescript-with-risei) are required for Risei to work with TypeScript.
|
|
112
96
|
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
```
|
|
97
|
+
&cruft, new site / section
|
|
98
|
+
- Further general options can be found [here](https://deusware.com/risei-docs/index.html#installation).
|
|
123
99
|
|
|
124
|
-
|
|
100
|
+
&cruft, new site / section
|
|
101
|
+
- Further Typescript details can be found [here](https://deusware.com/risei-docs/index.html#using-typescript).
|
|
125
102
|
|
|
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
103
|
|
|
158
104
|
|
|
159
105
|
|
|
160
106
|
### Running tests
|
|
161
107
|
|
|
162
|
-
|
|
108
|
+
Once you've written your tests, run them by invoking Risei's `index.js` file:
|
|
163
109
|
|
|
164
110
|
```bash
|
|
165
111
|
node ./node_modules/risei/index.js
|
|
@@ -179,292 +125,126 @@ And then run that script:
|
|
|
179
125
|
npm test
|
|
180
126
|
```
|
|
181
127
|
|
|
182
|
-
Risei can be used alongside other test frameworks, and even run with them from the same test script if you want.
|
|
183
|
-
|
|
128
|
+
- Risei can be used alongside other test frameworks, and even run with them from the same test script if you want.
|
|
184
129
|
|
|
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).
|
|
185
132
|
|
|
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
133
|
|
|
212
134
|
|
|
213
135
|
|
|
214
136
|
### Siting tests
|
|
215
137
|
|
|
216
|
-
|
|
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> — or —<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
|
-
|
|
301
|
-
### Testing special test conditions with `.and`
|
|
302
|
-
|
|
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.
|
|
306
|
-
|
|
307
|
-
The `.and` property is an expansion point for supporting more special conditions in the future. 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"`:
|
|
138
|
+
Add tests in files ending in `.rt.js` like this:
|
|
314
139
|
|
|
315
140
|
```javascript
|
|
316
|
-
|
|
141
|
+
import ATestSource from "risei/ATestSource";
|
|
142
|
+
import { ClassToBeTested } from "somewhere";
|
|
317
143
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
and: "static",
|
|
321
|
-
in: [ "This is a short sentence." ],
|
|
322
|
-
out: { isFullSentence: true, characters: 25, words: 5 }
|
|
144
|
+
export class SomeTests extends ATestSource {
|
|
145
|
+
tests = [ ... ]; // Test definitions are added here.
|
|
323
146
|
}
|
|
324
147
|
```
|
|
325
148
|
|
|
326
149
|
|
|
327
150
|
|
|
328
|
-
|
|
151
|
+
### Writing tests
|
|
329
152
|
|
|
330
|
-
|
|
153
|
+
Write tests with Risei's simple syntax:
|
|
331
154
|
|
|
332
155
|
```javascript
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
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
|
+
...];
|
|
341
163
|
```
|
|
342
164
|
|
|
165
|
+
- To test a throw path in a method, add an `.and` test property with the text value `"throws"`.
|
|
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.
|
|
343
168
|
|
|
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; }`.
|
|
344
170
|
|
|
345
|
-
|
|
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. It is run after all other steps of the test have been run. **(2.0.0)**
|
|
346
174
|
|
|
347
|
-
To
|
|
175
|
+
- To maintain the benefits of using Risei's declarative style, avoid arbitrary options as much as possible.
|
|
348
176
|
|
|
349
|
-
|
|
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 |
|
|
177
|
+
- If you prefer test property names that aren't JavaScript keywords, alternatives are available for all of them.
|
|
353
178
|
|
|
179
|
+
- Further details about syntax options can be found [here](https://deusware.com/risei-docs/index.html#test-syntax).
|
|
354
180
|
|
|
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
181
|
|
|
358
182
|
|
|
359
|
-
<details>
|
|
360
|
-
<summary>
|
|
361
|
-
More information
|
|
362
|
-
</summary>
|
|
363
|
-
<br>
|
|
364
183
|
|
|
365
|
-
|
|
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:
|
|
366
187
|
|
|
367
188
|
```javascript
|
|
368
|
-
|
|
189
|
+
/* All of the following tests are of ContainerModelClass. */
|
|
190
|
+
{ on: ContainerModelClass, with: [ "a", "b", "c", "a", "b" ] },
|
|
369
191
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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 }
|
|
373
201
|
```
|
|
374
202
|
|
|
375
|
-
-
|
|
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.
|
|
376
204
|
|
|
377
|
-
|
|
205
|
+
- Tests remain isolated, in effect, except when a test mutates input arguments. In that case, restate them in each test so the mutations aren't carried forward.
|
|
378
206
|
|
|
379
|
-
|
|
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 |
|
|
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. **(2.0.0)**
|
|
383
208
|
|
|
209
|
+
&cruft, new site / details
|
|
210
|
+
- Further options and details can be found [here](https://deusware.com/risei-docs/index.html#collapsing-forward).
|
|
384
211
|
|
|
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
212
|
|
|
389
213
|
|
|
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.
|
|
391
214
|
|
|
215
|
+
#### Ensure desired inputs from dependencies
|
|
392
216
|
|
|
393
|
-
|
|
217
|
+
To make code dependencies return what your tests need, just _spoof_ what you want using a `.plus` test property:
|
|
394
218
|
|
|
395
219
|
```javascript
|
|
396
|
-
{ on:
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
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" } ] }
|
|
404
232
|
```
|
|
405
233
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
### Property long names
|
|
411
|
-
|
|
412
|
-
Property names are short so they're easy to use. 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. None of the long names are JavaScript keywords.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
<details>
|
|
418
|
-
<summary>
|
|
419
|
-
Test properties' short and long names
|
|
420
|
-
</summary>
|
|
234
|
+
- It's just like _fakes_, _mocks_, or _test doubles_ in other test systems, but easier to write and read.
|
|
421
235
|
|
|
422
|
-
|
|
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` |
|
|
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. **(2.0.0)** Check out all your options [here](https://deusware.com/risei-docs/index.html#collapsing-forward).
|
|
433
238
|
|
|
434
|
-
</details>
|
|
435
239
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
<details>
|
|
439
|
-
<summary>
|
|
440
|
-
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. Only those in the test's `.in` property are used.
|
|
458
|
-
- However, a `.with` must still be provided. It can simply be an empty array `[]`.
|
|
459
|
-
|
|
460
|
-
</details>
|
|
240
|
+
- Spoofed code is fully isolated within tests, even though spoof definitions collapse forward across tests (and within `.plus`).
|
|
461
241
|
|
|
462
242
|
|
|
463
243
|
|
|
464
244
|
|
|
465
245
|
## Using TypeScript with Risei
|
|
466
246
|
|
|
467
|
-
Testing TypeScript code with Risei basically just means transpiling before running the tests, and
|
|
247
|
+
Testing TypeScript code with Risei basically just means transpiling before running the tests, and pointing Risei to the transpiled JS files.
|
|
468
248
|
|
|
469
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.
|
|
470
250
|
|
|
@@ -509,7 +289,6 @@ You set up the transpiler to output files to a directory with these settings:
|
|
|
509
289
|
|
|
510
290
|
|
|
511
291
|
|
|
512
|
-
|
|
513
292
|
### In test files:
|
|
514
293
|
|
|
515
294
|
All `import` statements have to point to the Javascript (`.js`) files in the `outDir` path or subfolders there, using relative-path syntax:
|
|
@@ -523,90 +302,72 @@ import { TestedClass } from "../../dist/out-tsc/SubPath/TestedClass.js";
|
|
|
523
302
|
|
|
524
303
|
|
|
525
304
|
|
|
526
|
-
##
|
|
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. 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.
|
|
305
|
+
## What's new in Risei
|
|
538
306
|
|
|
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.
|
|
539
308
|
|
|
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
|
|
|
542
|
-
|
|
313
|
+
- Release **1.3.2** (February, 2024) only improved this read-me's contents.
|
|
543
314
|
|
|
544
|
-
|
|
315
|
+
- Release **1.3.1** (February, 2024) reversed some changes in 1.3.0 that did not work as hoped.
|
|
545
316
|
|
|
546
|
-
|
|
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>— or —<br> Args mutated by tested code were not restated in following tests to isolate them |
|
|
317
|
+
- Release **1.3.0** (February, 2024) added the loading-error gold bar and fixed a test-sorting bug.
|
|
554
318
|
|
|
319
|
+
- Release **1.2.0** (January, 2024) changed test sorting to move last-edited tests to the end.
|
|
555
320
|
|
|
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. Using the latest release is recommended.
|
|
557
324
|
|
|
558
|
-
## Known issues and workarounds
|
|
559
325
|
|
|
560
|
-
Two issues are known to exist:
|
|
561
326
|
|
|
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 — copying and initing objects to bypass mutation — requires too many assumptions to be reliable.
|
|
565
327
|
|
|
328
|
+
## Troubleshooting
|
|
566
329
|
|
|
567
|
-
|
|
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.
|
|
330
|
+
Problems loading tests are almost always a missing or extra comma, brace, or similar. When a test file can't be loaded, loading continues with the next file. The number of tests drops (or doesn't increase as expected), and a gold bar appears naming the file and problem:
|
|
570
331
|
|
|
332
|
+

|
|
571
333
|
|
|
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
|
|
|
573
|
-
|
|
337
|
+
Problems with test results themselves are usually due to omissions or other mistakes in test definitions.
|
|
574
338
|
|
|
575
|
-
|
|
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.
|
|
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).
|
|
577
340
|
|
|
578
341
|
|
|
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
342
|
|
|
582
343
|
|
|
583
|
-
|
|
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.
|
|
344
|
+
## Known issues and workarounds
|
|
586
345
|
|
|
346
|
+
At present, there are two known issues, both with simple workarounds:
|
|
587
347
|
|
|
588
|
-
-
|
|
589
|
-
-
|
|
590
|
-
- In contrast, collapsing forward is both highly beneficial and frequently used.
|
|
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.
|
|
591
350
|
|
|
592
351
|
|
|
593
|
-
-
|
|
594
|
-
-
|
|
595
|
-
-
|
|
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.
|
|
596
355
|
|
|
597
356
|
|
|
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.
|
|
602
357
|
|
|
358
|
+
## Limitations in Risei
|
|
603
359
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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
|
|
607
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.
|
|
608
370
|
|
|
609
|
-
- Don't use release **1.1.1**, which contains an internal path error.
|
|
610
371
|
|
|
611
372
|
|
|
612
373
|
|
|
@@ -638,3 +399,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
638
399
|
|
|
639
400
|
|
|
640
401
|
|
|
402
|
+
|
|
403
|
+
|