risei 3.2.1 → 3.3.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.
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.2.1**, 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.3.1**, fixes an edge case with addressing properties.
50
50
 
51
51
  Check out the [full list of changes](#version-history).
52
52
 
@@ -91,33 +91,9 @@ And add Risei's metadata to `package.json`:
91
91
  }
92
92
  ```
93
93
 
94
- ## Testing Risei
95
-
96
- To test Risei, you clone it from a parallel [repository](https://gitlab.com/riseimaker/risei-public.git), install its dependencies, and run its self-tests.  See the full explanation [here](https://deusware.com/risei/index.html#self-testing).
97
-
98
-
99
- ## Running Tests
100
-
101
- Once you have some tests written, you can run them manually:
102
-
103
- ```bash
104
- node ./node_modules/risei/index.js
105
- ```
106
-
107
- Or write a script in `package.json` that does the same:
108
-
109
- ```json
110
- "scripts": {
111
- "test": "node ./node_modules/risei/index.js"
112
- }
113
- ```
114
-
115
- And then run that script:
116
-
117
- ```bash
118
- npm test
119
- ```
94
+ ## Testing Risei Itself
120
95
 
96
+ To test Risei itself, you clone it from a parallel [repository](https://gitlab.com/riseimaker/risei-public.git), install its dependencies, and run its self-tests.  See the full explanation [here](https://deusware.com/risei/index.html#self-testing).
121
97
 
122
98
 
123
99
  ## Writing Tests
@@ -150,9 +126,32 @@ tests = [ ...
150
126
  - You can use [long names](https://deusware.com/risei/index.html#long-names) for properties if you want.
151
127
 
152
128
 
129
+ ## Running Tests
130
+
131
+ Once you have some tests written, you can run them manually:
132
+
133
+ ```bash
134
+ node ./node_modules/risei/index.js
135
+ ```
136
+
137
+ Or write a script in `package.json` that does the same:
138
+
139
+ ```json
140
+ "scripts": {
141
+ "test": "node ./node_modules/risei/index.js"
142
+ }
143
+ ```
144
+
145
+ And then run that script:
146
+
147
+ ```bash
148
+ npm test
149
+ ```
150
+
151
+
153
152
  ## Basic collapsing forward example
154
153
 
155
- You can state test properties once and let them _collapse forward_ across subsequent tests to save time and make tests easier to read.
154
+ You can state repeated test properties just once, and let them _collapse forward_ across subsequent tests to save time and make tests easier to read.
156
155
 
157
156
  Risei collapses values together from partial or full test objects until it has a full test to run.  Every property collapses forward until it is changed or wiped out:
158
157
 
@@ -219,6 +218,20 @@ If errors are thrown while testing, gold bars listing them appear at the bottom,
219
218
 
220
219
  ## Version history
221
220
 
221
+ - Release **3.3.1** (February, 2025) contains this change:
222
+ - You can now spoof and otherwise address value properties (formally _data descriptors_) that don't have an initial value, whether they are static or instance class members.
223
+
224
+
225
+ - Release **3.3.0** (January, 2025) adds this change to those of other recent releases:
226
+ - You can now test instance members with the same names as static members using a new `.and` option of `"instance"`.
227
+
228
+
229
+
230
+ <details>
231
+ <summary>
232
+ Older releases
233
+ </summary>
234
+
222
235
  - Release **3.2.1** (January, 2025) contains all the changes from **3.2.0**, **3.1.1**, and **3.1.0**, plus this change:
223
236
  - Risei's mistaken nominal dependency on **npm** has been removed.
224
237
 
@@ -242,34 +255,6 @@ If errors are thrown while testing, gold bars listing them appear at the bottom,
242
255
  - Widespread internal reengineering of other kinds.
243
256
 
244
257
 
245
-
246
- <details>
247
- <summary>
248
- Older releases
249
- </summary>
250
-
251
- - Release **3.0.0** (August, 2024) contained all of these changes:
252
- - Asynchronous code with `async` syntax is now supported, with no special test syntax.
253
- - **(Breaking change)**&nbsp; `.from` functions now take `test` and `actual` as parameters, rather than `target` and `test`.
254
- - 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`.
255
- - You can now call target code more than once in one test using an `.and` of `"poly"` (AKA _poly-calling_).
256
-
257
-
258
- - Release **2.0.0** / **2.0.1** (August, 2024) contained all of these changes:
259
- - Risei now can determine automatically if tested methods are static.
260
- - You can now directly test properties just like methods.
261
- - Risei can also determine automatically if these are static.
262
- - Directly tested properties appear in the output in the form `.name`.
263
- - You can now spoof properties on the targeted class instance, and static properties on the target class itself.
264
- - You can now perform arbitrary operations, if needed, with the two-part `.do` property and one-part `.undo` property.
265
- - You can now change test properties without accidentally creating a new test using `.just`.
266
- - You can now directly test for `undefined` in `.out` using `this.undef` / `ATestSource.undefSymbol`.
267
- - `Error` objects are now compared accurately.
268
- - You can now identify member types with `.`, `:`, and `()` in any of `.of`, `.plus`, and `.from`, though it isn't necessary.
269
- - **(Breaking change)**&nbsp; The actual for throw tests is now the entire thrown object (usually an `Error`), rather than the `Error`'s message text.
270
- - **(Breaking change)**&nbsp; `ATestSource` is now a default export, changing its imports from `import { ATestSource } from` to `import ATestSource from`.
271
- - Major internal re-engineering.
272
-
273
258
  > Older releases are dropped from this list progressively over time.&nbsp; Using the latest release is recommended.
274
259
 
275
260
  </details>
@@ -278,7 +263,7 @@ Older releases
278
263
 
279
264
  ## Known issues and workarounds
280
265
 
281
- There are two minor issues at present:
266
+ There are the known minor issues:
282
267
 
283
268
  - If args for a test are mutated by tested code, the mutated args are used when collapsing forward.
284
269
  - The workaround is just to restate those args for each test.
@@ -288,6 +273,10 @@ There are two minor issues at present:
288
273
  - The workaround is to find another way to produce the property values you need.
289
274
 
290
275
 
276
+ - Predefined JavaScript methods like `toString()` may not be recognized, nor any instance method that has the same name as a static method.
277
+ - The workaround is to use an `.and` value of `"instance"` for any methods like these that you test.
278
+
279
+
291
280
 
292
281
  ## Exclusions from Risei
293
282
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "risei",
3
- "version": "3.2.1",
3
+ "version": "3.3.1",
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",
@@ -50,6 +50,6 @@
50
50
  "fs": "^0.0.1-security",
51
51
  "mocha": "^10.0.0",
52
52
  "morgan": "~1.9.1",
53
- "risei": "^3.2.0"
53
+ "risei": "^3.3.0"
54
54
  }
55
55
  }
@@ -80,7 +80,7 @@ export default class MethodSpoofer extends ASpoofingFixture {
80
80
  // Map of Maps: by type, then by method.
81
81
  for (let def of spoofDefs) {
82
82
  let spoofsByTarget = this.#supplyMemberMap(this.#spoofsByClass, def.target);
83
-
83
+
84
84
  // A single-method spoof is set for later use.
85
85
  if (def.method) {
86
86
  spoofsByTarget.set(def.method, def.output);
@@ -104,7 +104,7 @@ export default class MethodSpoofer extends ASpoofingFixture {
104
104
 
105
105
  // Saving originals in the Map for later.
106
106
  for (let name of names) {
107
- let original = TypeAnalyzer.isInstanceMember(type, name)
107
+ let original = TypeAnalyzer.isInstanceMember(type, name)
108
108
  ? type.prototype[name]
109
109
  : type[name];
110
110
 
package/system/TestDef.js CHANGED
@@ -14,6 +14,7 @@ export default class TestDef {
14
14
  // region Definitions
15
15
 
16
16
  static staticName = "static";
17
+ static instanceName = "instance";
17
18
  static throwName = "throw";
18
19
  static polyName = "poly";
19
20
  static constructorName = "constructor";
@@ -173,16 +174,19 @@ export default class TestDef {
173
174
  }
174
175
 
175
176
  get isInstanceTest() /* passed */ {
176
- return !this.isStaticTest || this.isConstructorTest;
177
+ return this.#isNamedTypeTest(
178
+ TestDef.instanceName,
179
+ TestDef.staticName,
180
+ TypeAnalyzer.isInstanceMember
181
+ );
177
182
  }
178
183
 
179
184
  get isStaticTest() /* passed */ {
180
- let plainName = NameAnalyzer.plainNameOf(this.of);
181
-
182
- let is = TypeAnalyzer.isStaticMember(this.on, plainName);
183
- let stated = this.andStringContains(TestDef.staticName);
184
-
185
- return is || stated;
185
+ return this.#isNamedTypeTest(
186
+ TestDef.staticName,
187
+ TestDef.instanceName,
188
+ TypeAnalyzer.isStaticMember
189
+ );
186
190
  }
187
191
 
188
192
  get isThrowTest() /* passed */ {
@@ -308,6 +312,25 @@ export default class TestDef {
308
312
 
309
313
  // region State methods
310
314
 
315
+ /* Dependency of .isInstanceTest and .isStaticTest. */
316
+ #isNamedTypeTest(type, antiType, analyzer) /* verified */ {
317
+ // If stated to be the opposite type, not this type.
318
+ if (this.andStringContains(antiType)) {
319
+ return false;
320
+ }
321
+
322
+ // Analysis of what the type probably is.
323
+ let plainName = NameAnalyzer.plainNameOf(this.of);
324
+ let is = analyzer(this.on, plainName);
325
+
326
+ // If states to be this type, then this type.
327
+ let stated = this.andStringContains(type);
328
+
329
+ // Whichever may apply.
330
+ return is || stated;
331
+ }
332
+
333
+
311
334
  /* Needed externally, and dependency
312
335
  of all .and-based properties. */
313
336
  andStringContains(keyword) /* passed */ {
@@ -42,7 +42,7 @@ export default class TestStages {
42
42
  return;
43
43
  }
44
44
 
45
- let target = test.isInstanceTest
45
+ let target = test.isInstanceTest
46
46
  ? new test.on.prototype.constructor(...test.with)
47
47
  : test.on;
48
48
 
@@ -105,10 +105,8 @@ export default class TypeAnalyzer {
105
105
  return false;
106
106
  }
107
107
 
108
- // Members with any other values are properties.
109
- if (named.value !== undefined) {
110
- return true;
111
- }
108
+ // Any other members are properties.
109
+ return true;
112
110
  }
113
111
 
114
112
  static #typeTextContainsNameAsProperty(type, name) /* verified */ {