Skip to content

Commit 036ee9c

Browse files
authored
feat: add expectFailure enhancements proposal
1 parent 3bb7721 commit 036ee9c

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Feature proposal: `expectFailure` enhancements
2+
3+
## Summary
4+
Update the `expectFailure` option in `test()` to accept different types of values, enabling both **custom failure messages** and **error validation**. This aligns with `skip` and `todo` options while adding capabilities similar to `assert.throws`.
5+
6+
## API & Behavior
7+
8+
The behavior of `expectFailure` is determined by the type of value provided:
9+
10+
### 1. String: Failure Reason
11+
When a **non-empty string** is provided, it acts as a documentation message (reason), identical to `skip` and `todo` options.
12+
13+
```js
14+
test('fails with a specific reason', {
15+
expectFailure: 'Bug #123: Feature not implemented yet'
16+
}, () => {
17+
throw new Error('boom');
18+
});
19+
```
20+
- **Behavior**: The test is expected to fail. The string is treated as a label/reason.
21+
- **Validation**: None. It accepts *any* error.
22+
- **Output**: The reporter displays the string (e.g., `# EXPECTED FAILURE Bug #123...`).
23+
- **Rationale**: Maintains consistency with existing `test` options where a string implies a reason/description.
24+
25+
### 2. RegExp: Error Matcher
26+
When a **RegExp** is provided, it acts as a validator for the thrown error.
27+
28+
```js
29+
test('fails with matching error', {
30+
expectFailure: /expected error message/
31+
}, () => {
32+
throw new Error('this is the expected error message');
33+
});
34+
```
35+
- **Behavior**: The test passes **only if** the thrown error matches the regular expression.
36+
- **Validation**: Strict matching against the error message.
37+
- **Output**: Standard expected failure output.
38+
39+
## Ambiguity Resolution
40+
Potential ambiguity between "String as Reason" and "String as Matcher" is resolved by strict type separation:
41+
* `typeof value === 'string'`**Reason** (Documentation only)
42+
* `value instanceof RegExp`**Matcher** (Validation)
43+
44+
Users needing to match a specific string error message should use a RegExp (e.g., `/Error message/`) to avoid confusion.
45+
46+
## Edge Cases & Implementation Details
47+
48+
### Empty String (`expectFailure: ''`)
49+
Following standard JavaScript truthiness rules, an empty string should be treated as **falsy**.
50+
51+
* `expectFailure: ''` behaves exactly like `expectFailure: false`.
52+
* The feature is **disabled**, and the test is expected to pass normally.
53+
54+
### Type Safety for `this.passed`
55+
The implementation must ensure that `this.passed` remains a strict `boolean`.
56+
Assigning a string directly (e.g., `this.passed = this.expectFailure`) is unsafe as it introduces type pollution (assigning `""` or `"reason"` instead of `false`/`true`).
57+
58+
**Recommended Implementation Logic:**
59+
```javascript
60+
// When an error is caught:
61+
this.passed = !!this.expectFailure; // Forces conversion to boolean
62+
```
63+
* If `expectFailure` is `"reason"``true` (Test Passes)
64+
* If `expectFailure` is `""``false` (Test Fails, as expected failure was not active)

0 commit comments

Comments
 (0)