risei 3.1.0 → 3.2.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 CHANGED
@@ -46,7 +46,7 @@ And they have a summary bar at the bottom:
46
46
 
47
47
  ## Status
48
48
 
49
- Risei's major features are now complete, but new enhancements or fixes may appear from time to time.  The latest release, **3.1.0**, includes significant improvements and bug fixes, on top of the major improvements in releases **3.0.0** and **2.0.0**.
49
+ Risei's major features are now complete, but new enhancements or fixes may appear from time to time.  The latest release, **3.2.0**, includes significant improvements and bug fixes, on top of the major improvements in releases **3.0.0** and **2.0.0**.
50
50
 
51
51
  Check out the [full list of changes](#version-history).
52
52
 
@@ -219,10 +219,19 @@ If errors are thrown while testing, gold bars listing them appear at the bottom,
219
219
 
220
220
  ## Version history
221
221
 
222
+ - Release **3.2.0** (January, 2025) contains all the changes from **3.1.1** and **3.1.0**, plus this change:
223
+ - Risei's self-dependency for its own self-testing has been moved back to the development-only scope.
224
+
225
+
226
+ - Release **3.1.1** (January, 2025) contains these changes:
227
+ - Extra commas and non-objects in arrays of test objects are disregarded, and no longer cause a throw.
228
+ - Throws in wider scopes are now listed at the end, like others already found there.
229
+
230
+
222
231
  - Release **3.1.0** (January, 2025) contains these changes:
223
232
  - Accessor properties (formally _accessor descriptors_) are now compared for test results and displayed in test outputs.
224
233
  - Any accessor properties that throw errors during display are displayed as `(threw)`.
225
- - Throws in tested code and in test framing code are now listed at the end and displayed amid the tests.
234
+ - Throws in tested code and in test framing code are now listed at the end, and also displayed amid the tests.
226
235
  - `File` objects now have a succinct custom display in outputs.
227
236
  - **(Breaking change)**  In `constructor` tests, constructed instances are available in `.from` functions only as `actual` / `test.actual`.
228
237
  - **(Breaking change)**  In `constructor` tests, `test.target` is now the `prototype` of the tested class.
@@ -241,6 +250,7 @@ Older releases
241
250
  - If you need to work with the target of the test (usually an instance of the class being tested), it's available as `test.target`.
242
251
  - You can now call target code more than once in one test using an `.and` of `"poly"` (AKA _poly-calling_).
243
252
 
253
+
244
254
  - Release **2.0.0** / **2.0.1** (August, 2024) contained all of these changes:
245
255
  - Risei now can determine automatically if tested methods are static.
246
256
  - You can now directly test properties just like methods.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "risei",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Risei allows you to write unit tests as simple JavaScript objects, so it's easy and fast, with no drag on redesign.",
5
5
  "keywords": [
6
6
  "unit test",
@@ -42,8 +42,7 @@
42
42
  "chalk": "^5.0.0",
43
43
  "fs": "^0.0.1-security",
44
44
  "minimatch": "^9.0.1",
45
- "npm": "^11.0.0",
46
- "risei": "^3.0.0"
45
+ "npm": "^11.0.0"
47
46
  },
48
47
  "devDependencies": {
49
48
  "chai": "^4.3.6",
@@ -51,6 +50,7 @@
51
50
  "debug": "~2.6.9",
52
51
  "fs": "^0.0.1-security",
53
52
  "mocha": "^10.0.0",
54
- "morgan": "~1.9.1"
53
+ "morgan": "~1.9.1",
54
+ "risei": "^3.1.1"
55
55
  }
56
56
  }
@@ -289,18 +289,25 @@ export default class TerminalReporter {
289
289
 
290
290
  console.log(this.#summary(this.#toFullWidth(` ${ summary.summary }`)));
291
291
 
292
- /* Post-summary reporting of unsought throws. */
292
+ /* Post-summary reporting of any throws. */
293
293
 
294
+ // Unsought throws in tested code.
294
295
  if (summary.anyThrows.length !== 0) {
295
296
  console.log();
296
297
  console.log(this.#problems(summary.anyThrows.join("\n")));
297
298
  }
298
299
 
299
- // And/or reporting of outer-scope throws.
300
+ // Throws in code in scope of test frame.
300
301
  if (summary.anyTroubles.length !== 0) {
301
302
  console.log();
302
303
  console.log(this.#problems(summary.anyTroubles.join("\n")));
303
304
  }
305
+
306
+ // Throws in code in scope of test runner.
307
+ if (summary.anyCaught.length !== 0) {
308
+ console.log();
309
+ console.log(this.#problems(summary.anyCaught.join("\n")));
310
+ }
304
311
  }
305
312
 
306
313
  // endregion Summary dependency of reportNext()
package/system/TestDef.js CHANGED
@@ -344,6 +344,11 @@ export default class TestDef {
344
344
 
345
345
  // Looping over all.
346
346
  for (let nonce of nonces) {
347
+ // No possible test definition to output.
348
+ if (!TestDef.isANonce(nonce)) {
349
+ continue;
350
+ }
351
+
347
352
  // Get latest test definition.
348
353
  let latest = TestDef.fromNonceTuple(nonce);
349
354
 
@@ -398,6 +403,11 @@ export default class TestDef {
398
403
 
399
404
  // region Dependencies of nonce-tuple initing methods
400
405
 
406
+ static isANonce(topic) /* passed */ {
407
+ let type = TypeIdentifier.identify(topic);
408
+ return type === Types.isObject;
409
+ }
410
+
401
411
  /* Replaces some or all of the 'full' that gathers test
402
412
  props for reuse when targeting changes significantly
403
413
  in the middle of the collapsing-forward process. */
@@ -26,8 +26,10 @@ export default class TestRunner {
26
26
  #numberPassed;
27
27
  #numberFailed;
28
28
 
29
- #thrown;
30
- #trouble;
29
+ // Problems in different scopes.
30
+ #thrown; // In tested code.
31
+ #trouble; // In framing code.
32
+ #caught; // In outer system.
31
33
 
32
34
  #allDidPass;
33
35
 
@@ -100,6 +102,7 @@ export default class TestRunner {
100
102
 
101
103
  this.#thrown = [];
102
104
  this.#trouble = [];
105
+ this.#caught = [];
103
106
 
104
107
  this.#allDidPass = true;
105
108
  }
@@ -124,37 +127,43 @@ export default class TestRunner {
124
127
  );
125
128
  }
126
129
 
127
- // Converting so that property names can be relied on.
128
- this.#tests = TestDef.fromNonceTuples(this.tests);
129
-
130
- // Needed for displaying classes and methods as groups.
131
- let classGroup = new ClassTestGroup();
132
- let methodGroup = new MethodTestGroup();
133
- let atFirstClassMethod = false;
134
-
135
- // Iterative running of all tests in current order.
136
- for (let test of this.#tests) {
137
- // Each new class should be a group, and its start
138
- // should be retained for grouping of methods.
139
- if (test.on.name !== classGroup.group) {
140
- classGroup.group = test.on.name;
141
- atFirstClassMethod = true;
142
- yield classGroup;
130
+ try {
131
+ // Converting so that property names can be relied on.
132
+ this.#tests = TestDef.fromNonceTuples(this.tests);
133
+
134
+ // Needed for displaying classes and methods as groups.
135
+ let classGroup = new ClassTestGroup();
136
+ let methodGroup = new MethodTestGroup();
137
+ let atFirstClassMethod = false;
138
+
139
+ // Iterative running of all tests in current order.
140
+ for (let test of this.#tests) {
141
+ // Each new class should be a group, and its start
142
+ // should be retained for grouping of methods.
143
+ if (test.on.name !== classGroup.group) {
144
+ classGroup.group = test.on.name;
145
+ atFirstClassMethod = true;
146
+ yield classGroup;
147
+ }
148
+
149
+ // Each new method / prop name should be a group,
150
+ // and so should the first method for a class.
151
+ let runName = test.runName;
152
+
153
+ if (runName !== methodGroup.group || atFirstClassMethod) {
154
+ methodGroup.group = runName;
155
+ atFirstClassMethod = false;
156
+ yield methodGroup;
157
+ }
158
+
159
+ let result = await this.#runOneTest(test);
160
+
161
+ yield result;
143
162
  }
144
-
145
- // Each new method / prop name should be a group,
146
- // and so should the first method for a class.
147
- let runName = test.runName;
148
-
149
- if (runName !== methodGroup.group || atFirstClassMethod) {
150
- methodGroup.group = runName;
151
- atFirstClassMethod = false;
152
- yield methodGroup;
153
- }
154
-
155
- let result = await this.#runOneTest(test);
156
-
157
- yield result;
163
+ }
164
+ catch (caught) {
165
+ // Top of .stack is .message.
166
+ this.#caught.push(caught.stack);
158
167
  }
159
168
 
160
169
  // Iterative returning of final results summary.
@@ -217,7 +226,7 @@ export default class TestRunner {
217
226
 
218
227
  let anyWereRun = this.#numberRun > 0;
219
228
 
220
- return new TestSummary(summary, this.#allDidPass, anyWereRun, this.#thrown, this.#trouble);
229
+ return new TestSummary(summary, this.#allDidPass, anyWereRun, this.#thrown, this.#trouble, this.#caught);
221
230
  }
222
231
 
223
232
  // endregion Running tests
@@ -7,6 +7,7 @@ export default class TestSummary {
7
7
 
8
8
  #anyThrows;
9
9
  #anyTroubles;
10
+ #anyCaught;
10
11
 
11
12
  get summary() {
12
13
  return this.#summary;
@@ -28,11 +29,16 @@ export default class TestSummary {
28
29
  return this.#anyTroubles;
29
30
  }
30
31
 
31
- constructor(summary, allDidPass, anyWereRun, anyThrows, anyTroubles) {
32
+ get anyCaught() {
33
+ return this.#anyCaught;
34
+ }
35
+
36
+ constructor(summary, allDidPass, anyWereRun, anyThrows, anyTroubles, anyCaught) {
32
37
  this.#summary = summary;
33
38
  this.#allDidPass = allDidPass;
34
39
  this.#anyWereRun = anyWereRun;
35
40
  this.#anyThrows = anyThrows;
36
41
  this.#anyTroubles = anyTroubles;
42
+ this.#anyCaught = anyCaught;
37
43
  }
38
44
  }