Skip to content

Commit ff8e482

Browse files
eryue0220SimenBG-Rath
authored
feat: add no-confusing-set-time rule (#1425)
* feat: add no-confusing-set-time rule * fix: cr problems * fix: ci * feat: reactor rule * chore: fix lint * fix: ci problems * fix: cr problems * fix: ci * docs: regenerate --------- Co-authored-by: Simen Bekkhus <[email protected]> Co-authored-by: Gareth Jones <[email protected]>
1 parent 1b96756 commit ff8e482

File tree

6 files changed

+393
-1
lines changed

6 files changed

+393
-1
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ set to warn in.\
220220
| [no-commented-out-tests](docs/rules/no-commented-out-tests.md) | Disallow commented out tests | || | | |
221221
| [no-conditional-expect](docs/rules/no-conditional-expect.md) | Disallow calling `expect` conditionally || | | | |
222222
| [no-conditional-in-test](docs/rules/no-conditional-in-test.md) | Disallow conditional logic in tests | | | | | |
223+
| [no-confusing-set-timeout](docs/rules/no-confusing-set-timeout.md) | Disallow confusing usages of jest.setTimeout | | | | | |
223224
| [no-deprecated-functions](docs/rules/no-deprecated-functions.md) | Disallow use of deprecated functions || | 🔧 | | |
224225
| [no-disabled-tests](docs/rules/no-disabled-tests.md) | Disallow disabled tests | || | | |
225226
| [no-done-callback](docs/rules/no-done-callback.md) | Disallow using a callback in asynchronous tests and hooks || | | 💡 | |
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Disallow confusing usages of jest.setTimeout (`no-confusing-set-timeout`)
2+
3+
<!-- end auto-generated rule header -->
4+
5+
While `jest.setTimeout` can be called multiple times anywhere within a single
6+
test file only the last call before any test functions run will have an effect.
7+
8+
## Rule details
9+
10+
this rule checks for several confusing usages of `jest.setTimeout` that looks
11+
like it applies to specific tests within the same file, such as:
12+
13+
- being called anywhere other than in global scope
14+
- being called multiple times
15+
- being called after other Jest functions like hooks, `describe`, `test`, or
16+
`it`
17+
18+
Examples of **incorrect** code for this rule:
19+
20+
```js
21+
describe('test foo', () => {
22+
jest.setTimeout(1000);
23+
it('test-description', () => {
24+
// test logic;
25+
});
26+
});
27+
28+
describe('test bar', () => {
29+
it('test-description', () => {
30+
jest.setTimeout(1000);
31+
// test logic;
32+
});
33+
});
34+
35+
test('foo-bar', () => {
36+
jest.setTimeout(1000);
37+
});
38+
39+
describe('unit test', () => {
40+
beforeEach(() => {
41+
jest.setTimeout(1000);
42+
});
43+
});
44+
```
45+
46+
Examples of **correct** code for this rule:
47+
48+
```js
49+
jest.setTimeout(500);
50+
test('test test', () => {
51+
// do some stuff
52+
});
53+
```
54+
55+
```js
56+
jest.setTimeout(1000);
57+
describe('test bar bar', () => {
58+
it('test-description', () => {
59+
// test logic;
60+
});
61+
});
62+
```

src/__tests__/__snapshots__/rules.test.ts.snap

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ exports[`rules should export configs that refer to actual rules 1`] = `
1818
"jest/no-commented-out-tests": "error",
1919
"jest/no-conditional-expect": "error",
2020
"jest/no-conditional-in-test": "error",
21+
"jest/no-confusing-set-timeout": "error",
2122
"jest/no-deprecated-functions": "error",
2223
"jest/no-disabled-tests": "error",
2324
"jest/no-done-callback": "error",

src/__tests__/rules.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { existsSync } from 'fs';
22
import { resolve } from 'path';
33
import plugin from '../';
44

5-
const numberOfRules = 52;
5+
const numberOfRules = 53;
66
const ruleNames = Object.keys(plugin.rules);
77
const deprecatedRules = Object.entries(plugin.rules)
88
.filter(([, rule]) => rule.meta.deprecated)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
import { TSESLint } from '@typescript-eslint/utils';
2+
import dedent from 'dedent';
3+
import rule from '../no-confusing-set-timeout';
4+
import { espreeParser } from './test-utils';
5+
6+
const ruleTester = new TSESLint.RuleTester({
7+
parser: espreeParser,
8+
parserOptions: {
9+
ecmaVersion: 2020,
10+
},
11+
});
12+
13+
ruleTester.run('no-confusing-set-timeout', rule, {
14+
valid: [
15+
dedent`
16+
jest.setTimeout(1000);
17+
describe('A', () => {
18+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
19+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
20+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
21+
});
22+
`,
23+
dedent`
24+
jest.setTimeout(1000);
25+
window.setTimeout(6000)
26+
describe('A', () => {
27+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
28+
it('test foo', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
29+
});
30+
`,
31+
{
32+
code: dedent`
33+
import { handler } from 'dep/mod';
34+
jest.setTimeout(800);
35+
describe('A', () => {
36+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
37+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
38+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
39+
});
40+
`,
41+
parserOptions: { sourceType: 'module' },
42+
},
43+
dedent`
44+
function handler() {}
45+
jest.setTimeout(800);
46+
describe('A', () => {
47+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
48+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
49+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
50+
});
51+
`,
52+
dedent`
53+
const { handler } = require('dep/mod');
54+
jest.setTimeout(800);
55+
describe('A', () => {
56+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
57+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
58+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
59+
});
60+
`,
61+
dedent`
62+
jest.setTimeout(1000);
63+
window.setTimeout(60000);
64+
`,
65+
'window.setTimeout(60000);',
66+
'setTimeout(1000);',
67+
dedent`
68+
jest.setTimeout(1000);
69+
test('test case', () => {
70+
setTimeout(() => {
71+
Promise.resolv();
72+
}, 5000);
73+
});
74+
`,
75+
dedent`
76+
test('test case', () => {
77+
setTimeout(() => {
78+
Promise.resolv();
79+
}, 5000);
80+
});
81+
`,
82+
],
83+
invalid: [
84+
{
85+
code: dedent`
86+
jest.setTimeout(1000);
87+
setTimeout(1000);
88+
window.setTimeout(1000);
89+
describe('A', () => {
90+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
91+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
92+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
93+
});
94+
jest.setTimeout(800);
95+
`,
96+
errors: [
97+
{
98+
messageId: 'orderSetTimeout',
99+
line: 9,
100+
column: 1,
101+
},
102+
{
103+
messageId: 'multipleSetTimeouts',
104+
line: 9,
105+
column: 1,
106+
},
107+
],
108+
},
109+
{
110+
code: dedent`
111+
describe('A', () => {
112+
jest.setTimeout(800);
113+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
114+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
115+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
116+
});
117+
`,
118+
errors: [
119+
{
120+
messageId: 'globalSetTimeout',
121+
line: 2,
122+
column: 3,
123+
},
124+
{
125+
messageId: 'orderSetTimeout',
126+
line: 2,
127+
column: 3,
128+
},
129+
],
130+
},
131+
{
132+
code: dedent`
133+
describe('B', () => {
134+
it('B.1', async () => {
135+
await new Promise((resolve) => {
136+
jest.setTimeout(1000);
137+
setTimeout(resolve, 10000).unref();
138+
});
139+
});
140+
it('B.2', async () => {
141+
await new Promise((resolve) => { setTimeout(resolve, 10000).unref(); });
142+
});
143+
});
144+
`,
145+
errors: [
146+
{
147+
messageId: 'globalSetTimeout',
148+
line: 4,
149+
column: 7,
150+
},
151+
{
152+
messageId: 'orderSetTimeout',
153+
line: 4,
154+
column: 7,
155+
},
156+
],
157+
},
158+
{
159+
code: dedent`
160+
test('test-suite', () => {
161+
jest.setTimeout(1000);
162+
});
163+
`,
164+
errors: [
165+
{
166+
messageId: 'globalSetTimeout',
167+
line: 2,
168+
column: 3,
169+
},
170+
{
171+
messageId: 'orderSetTimeout',
172+
line: 2,
173+
column: 3,
174+
},
175+
],
176+
},
177+
{
178+
code: dedent`
179+
describe('A', () => {
180+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
181+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
182+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
183+
});
184+
jest.setTimeout(1000);
185+
`,
186+
errors: [
187+
{
188+
messageId: 'orderSetTimeout',
189+
line: 6,
190+
column: 1,
191+
},
192+
],
193+
},
194+
{
195+
code: dedent`
196+
import { jest } from '@jest/globals';
197+
{
198+
jest.setTimeout(800);
199+
}
200+
describe('A', () => {
201+
beforeEach(async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
202+
it('A.1', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
203+
it('A.2', async () => { await new Promise(resolve => { setTimeout(resolve, 10000).unref(); });});
204+
});
205+
`,
206+
parserOptions: { sourceType: 'module' },
207+
errors: [
208+
{
209+
messageId: 'globalSetTimeout',
210+
line: 3,
211+
column: 3,
212+
},
213+
],
214+
},
215+
{
216+
code: dedent`
217+
jest.setTimeout(800);
218+
jest.setTimeout(900);
219+
`,
220+
errors: [
221+
{
222+
messageId: 'multipleSetTimeouts',
223+
line: 2,
224+
column: 1,
225+
},
226+
],
227+
},
228+
{
229+
code: dedent`
230+
expect(1 + 2).toEqual(3);
231+
jest.setTimeout(800);
232+
`,
233+
errors: [
234+
{
235+
messageId: 'orderSetTimeout',
236+
line: 2,
237+
column: 1,
238+
},
239+
],
240+
},
241+
{
242+
code: dedent`
243+
import { jest as Jest } from '@jest/globals';
244+
{
245+
Jest.setTimeout(800);
246+
}
247+
`,
248+
parserOptions: { sourceType: 'module' },
249+
errors: [
250+
{
251+
messageId: 'globalSetTimeout',
252+
line: 3,
253+
column: 3,
254+
},
255+
],
256+
},
257+
],
258+
});

0 commit comments

Comments
 (0)