Skip to content

Commit bf39075

Browse files
committed
feat: create new prefer-ending-with-an-expect rule
1 parent aa64936 commit bf39075

File tree

4 files changed

+769
-0
lines changed

4 files changed

+769
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ Manually fixable by
363363
| [prefer-called-with](docs/rules/prefer-called-with.md) | Suggest using `toBeCalledWith()` or `toHaveBeenCalledWith()` | | | | |
364364
| [prefer-comparison-matcher](docs/rules/prefer-comparison-matcher.md) | Suggest using the built-in comparison matchers | | | 🔧 | |
365365
| [prefer-each](docs/rules/prefer-each.md) | Prefer using `.each` rather than manual loops | | | | |
366+
| [prefer-ending-with-an-expect](docs/rules/prefer-ending-with-an-expect.md) | Prefer having the last statement in a test be an assertion | | | | |
366367
| [prefer-equality-matcher](docs/rules/prefer-equality-matcher.md) | Suggest using the built-in equality matchers | | | | 💡 |
367368
| [prefer-expect-assertions](docs/rules/prefer-expect-assertions.md) | Suggest using `expect.assertions()` OR `expect.hasAssertions()` | | | | 💡 |
368369
| [prefer-expect-resolves](docs/rules/prefer-expect-resolves.md) | Prefer `await expect(...).resolves` over `expect(await ...)` syntax | | | 🔧 | |
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Prefer having the last statement in a test be an assertion (`prefer-ending-with-an-expect`)
2+
3+
<!-- end auto-generated rule header -->
4+
5+
Prefer ending tests with an `expect` assertion.
6+
7+
## Rule details
8+
9+
This rule triggers when a test body does not end with an `expect` call, which
10+
can indicate an unfinished test.
11+
12+
Examples of **incorrect** code for this rule:
13+
14+
```js
15+
it('lets me change the selected option', () => {
16+
const container = render(MySelect, {
17+
props: { options: [1, 2, 3], selected: 1 },
18+
});
19+
20+
expect(container).toBeDefined();
21+
expect(container.toHTML()).toContain('<option value="1" selected>');
22+
23+
container.setProp('selected', 2);
24+
});
25+
```
26+
27+
Examples of **correct** code for this rule:
28+
29+
```js
30+
it('lets me change the selected option', () => {
31+
const container = render(MySelect, {
32+
props: { options: [1, 2, 3], selected: 1 },
33+
});
34+
35+
expect(container).toBeDefined();
36+
expect(container.toHTML()).toContain('<option value="1" selected>');
37+
38+
container.setProp('selected', 2);
39+
40+
expect(container.toHTML()).not.toContain('<option value="1" selected>');
41+
expect(container.toHTML()).toContain('<option value="2" selected>');
42+
});
43+
```
44+
45+
## Options
46+
47+
```json
48+
{
49+
"jest/prefer-ending-with-an-expect": [
50+
"error",
51+
{
52+
"assertFunctionNames": ["expect"],
53+
"additionalTestBlockFunctions": []
54+
}
55+
]
56+
}
57+
```
58+
59+
### `assertFunctionNames`
60+
61+
This array option specifies the names of functions that should be considered to
62+
be asserting functions. Function names can use wildcards i.e `request.*.expect`,
63+
`request.**.expect`, `request.*.expect*`
64+
65+
Examples of **incorrect** code for the `{ "assertFunctionNames": ["expect"] }`
66+
option:
67+
68+
```js
69+
/* eslint jest/prefer-ending-with-an-expect: ["error", { "assertFunctionNames": ["expect"] }] */
70+
71+
import { expectSaga } from 'redux-saga-test-plan';
72+
import { addSaga } from '../src/sagas';
73+
74+
test('returns sum', () => {
75+
expectSaga(addSaga, 1, 1).returns(2).run();
76+
});
77+
```
78+
79+
Examples of **correct** code for the
80+
`{ "assertFunctionNames": ["expect", "expectSaga"] }` option:
81+
82+
```js
83+
/* eslint jest/prefer-ending-with-an-expect: ["error", { "assertFunctionNames": ["expect", "expectSaga"] }] */
84+
85+
import { expectSaga } from 'redux-saga-test-plan';
86+
import { addSaga } from '../src/sagas';
87+
88+
test('returns sum', () => {
89+
expectSaga(addSaga, 1, 1).returns(2).run();
90+
});
91+
```
92+
93+
Since the string is compiled into a regular expression, you'll need to escape
94+
special characters such as `$` with a double backslash:
95+
96+
```js
97+
/* eslint jest/prefer-ending-with-an-expect: ["error", { "assertFunctionNames": ["expect\\$"] }] */
98+
99+
it('is money-like', () => {
100+
expect$(1.0);
101+
});
102+
```
103+
104+
Examples of **correct** code for working with the HTTP assertions library
105+
[SuperTest](https://www.npmjs.com/package/supertest) with the
106+
`{ "assertFunctionNames": ["expect", "request.**.expect"] }` option:
107+
108+
```js
109+
/* eslint jest/prefer-ending-with-an-expect: ["error", { "assertFunctionNames": ["expect", "request.**.expect"] }] */
110+
const request = require('supertest');
111+
const express = require('express');
112+
113+
const app = express();
114+
115+
describe('GET /user', function () {
116+
it('responds with json', function (done) {
117+
doSomething();
118+
119+
request(app).get('/user').expect('Content-Type', /json/).expect(200, done);
120+
});
121+
});
122+
```
123+
124+
### `additionalTestBlockFunctions`
125+
126+
This array can be used to specify the names of functions that should also be
127+
treated as test blocks:
128+
129+
```json
130+
{
131+
"rules": {
132+
"jest/prefer-ending-with-an-expect": [
133+
"error",
134+
{ "additionalTestBlockFunctions": ["each.test"] }
135+
]
136+
}
137+
}
138+
```
139+
140+
The following is _correct_ when using the above configuration:
141+
142+
```js
143+
each([
144+
[2, 3],
145+
[1, 3],
146+
]).test(
147+
'the selection can change from %d to %d',
148+
(firstSelection, secondSelection) => {
149+
const container = render(MySelect, {
150+
props: { options: [1, 2, 3], selected: firstSelection },
151+
});
152+
153+
expect(container).toBeDefined();
154+
expect(container.toHTML()).toContain(
155+
`<option value="${firstSelection}" selected>`,
156+
);
157+
158+
container.setProp('selected', secondSelection);
159+
160+
expect(container.toHTML()).not.toContain(
161+
`<option value="${firstSelection}" selected>`,
162+
);
163+
expect(container.toHTML()).toContain(
164+
`<option value="${secondSelection}" selected>`,
165+
);
166+
},
167+
);
168+
```

0 commit comments

Comments
 (0)