Skip to content

Commit f6c0660

Browse files
authored
Add act() eslint rule and upgrade eslint (#1054)
* Prevent warning about missing plugin * Upgrade eslint, fix errors * Fix conditional hook call * Add eslint plugin for act() in tests * Don't require act for userEvent * Actually use the imported act name * Apply autofixes * Remove unneeded acts around events * Update lint rule...
1 parent dc6d787 commit f6c0660

File tree

63 files changed

+1389
-1219
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1389
-1219
lines changed

.eslintrc.js

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ let rulesDirPlugin = require('eslint-plugin-rulesdir');
55
rulesDirPlugin.RULES_DIR = './bin';
66

77
module.exports = {
8-
plugins: ['react', 'rulesdir', 'jsx-a11y', 'react-hooks', 'jest', 'monorepo'],
8+
plugins: ['react', 'rulesdir', 'jsx-a11y', 'react-hooks', 'jest', 'monorepo', 'eslint-plugin-test-act'],
99
extends: ['eslint:recommended'],
1010
parser: 'babel-eslint',
1111
parserOptions: {
1212
ecmaFeatures: {
13-
"legacyDecorators": true
13+
'legacyDecorators': true
1414
},
1515
sourceType: 'module'
1616
},
@@ -20,17 +20,24 @@ module.exports = {
2020
parser: '@typescript-eslint/parser',
2121
parserOptions: {
2222
ecmaFeatures: {
23-
"jsx": true,
24-
"legacyDecorators": true
23+
'jsx': true,
24+
'legacyDecorators': true
2525
},
26-
"useJSXTextNode": true,
27-
"project": "./tsconfig.json",
26+
'useJSXTextNode': true,
27+
'project': './tsconfig.json',
2828
sourceType: 'module'
2929
},
3030
rules: {
31-
"no-unused-vars": OFF,
32-
"@typescript-eslint/no-unused-vars": ERROR,
33-
"@typescript-eslint/member-delimiter-style": [ERROR, {
31+
'jsdoc/require-description-complete-sentence': [ERROR, {abbreviations: ['e.g', 'etc']}],
32+
'jsdoc/check-alignment': ERROR,
33+
'jsdoc/check-indentation': ERROR,
34+
'jsdoc/check-tag-names': ERROR,
35+
// enable this rule to see literally everything missing jsdocs, this rule needs some refinement but is good as a sanity check.
36+
// 'jsdoc/require-jsdoc': [ERROR, {contexts:['TSInterfaceDeclaration TSPropertySignature', 'TSInterfaceDeclaration TSMethodSignature']}],
37+
'jsdoc/require-description': [ERROR, {exemptedBy: ['deprecated'], checkConstructors: false}],
38+
'no-unused-vars': OFF,
39+
'@typescript-eslint/no-unused-vars': ERROR,
40+
'@typescript-eslint/member-delimiter-style': [ERROR, {
3441
multiline: {
3542
delimiter: 'comma',
3643
requireLast: false
@@ -39,11 +46,12 @@ module.exports = {
3946
delimiter: 'comma',
4047
requireLast: false
4148
}
42-
}],
49+
}]
4350
}
4451
}, {
4552
files: ['**/test/**', '**/stories/**', '**/docs/**', '**/chromatic/**'],
4653
rules: {
54+
'test-act/act-events-test': ERROR,
4755
'rulesdir/imports': OFF,
4856
'monorepo/no-internal-import': OFF,
4957
'jsdoc/require-jsdoc': OFF
@@ -65,22 +73,19 @@ module.exports = {
6573
globals: {
6674
'importSpectrumCSS': 'readonly',
6775
'jest': true,
68-
'expect': true
76+
'expect': true,
77+
'JSX': 'readonly'
6978
},
7079
settings: {
7180
jsdoc: {
7281
ignorePrivate: true,
7382
publicFunctionsOnly: true
83+
},
84+
react: {
85+
version: 'detect'
7486
}
7587
},
7688
rules: {
77-
'jsdoc/require-description-complete-sentence': [ERROR, {abbreviations: ['e.g', 'etc']}],
78-
'jsdoc/check-alignment': ERROR,
79-
'jsdoc/check-indentation': ERROR,
80-
'jsdoc/check-tag-names': ERROR,
81-
// enable this rule to see literally everything missing jsdocs, this rule needs some refinement but is good as a sanity check.
82-
// 'jsdoc/require-jsdoc': [ERROR, {contexts:['TSInterfaceDeclaration TSPropertySignature', 'TSInterfaceDeclaration TSMethodSignature']}],
83-
'jsdoc/require-description': [ERROR, {exemptedBy: ['deprecated'], checkConstructors: false}],
8489
'comma-dangle': ERROR,
8590
'indent': OFF,
8691
'indent-legacy': [ERROR, ERROR, {SwitchCase: 1}],
@@ -234,8 +239,8 @@ module.exports = {
234239
],
235240
li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
236241
table: ['grid'],
237-
td: ['gridcell','columnheader','rowheader'],
238-
th: ['columnheader','rowheader']
242+
td: ['gridcell', 'columnheader', 'rowheader'],
243+
th: ['columnheader', 'rowheader']
239244
}
240245
],
241246
'jsx-a11y/no-noninteractive-tabindex': [

package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@
8484
"@testing-library/user-event": "^12.1.3",
8585
"@types/react": "^16.9.23",
8686
"@types/storybook__react": "^4.0.1",
87-
"@typescript-eslint/eslint-plugin": "^2.28.0",
88-
"@typescript-eslint/parser": "^2.28.0",
87+
"@typescript-eslint/eslint-plugin": "^4.3.0",
88+
"@typescript-eslint/parser": "^4.3.0",
8989
"autoprefixer": "^9.6.0",
9090
"axe-core": "^3.0.3",
91-
"babel-eslint": "^10.0.0",
91+
"babel-eslint": "^10.1.0",
9292
"babel-loader": "^8.0.5",
9393
"babel-plugin-istanbul": "^5.0.0",
9494
"babel-plugin-macros": "^2.5.0",
@@ -102,14 +102,14 @@
102102
"cross-env": "^7.0.2",
103103
"cross-spawn": "^7.0.3",
104104
"css-loader": "^2.1.1",
105-
"eslint": "^5.0.0",
106-
"eslint-plugin-import": "^2.18.2",
107-
"eslint-plugin-jest": "^22.5.1",
108-
"eslint-plugin-jsdoc": "^27.1.1",
109-
"eslint-plugin-jsx-a11y": "^6.2.1",
105+
"eslint": "^7.10.0",
106+
"eslint-plugin-import": "^2.22.1",
107+
"eslint-plugin-jest": "^24.0.2",
108+
"eslint-plugin-jsdoc": "^30.6.2",
109+
"eslint-plugin-jsx-a11y": "^6.3.1",
110110
"eslint-plugin-monorepo": "^0.2.1",
111-
"eslint-plugin-react": "^7.12.4",
112-
"eslint-plugin-react-hooks": "^1.6.0",
111+
"eslint-plugin-react": "^7.21.2",
112+
"eslint-plugin-react-hooks": "^4.1.2",
113113
"eslint-plugin-rulesdir": "^0.1.0",
114114
"fast-glob": "^3.1.0",
115115
"file-loader": "^0.9.0",

packages/@react-aria/checkbox/test/useCheckboxGroup.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {act, render} from '@testing-library/react';
1413
import {AriaCheckboxGroupProps, AriaCheckboxProps} from '@react-types/checkbox';
1514
import {CheckboxGroupState, useCheckboxGroupState} from '@react-stately/checkbox';
1615
import React, {useRef} from 'react';
16+
import {render} from '@testing-library/react';
1717
import {useCheckboxGroup, useCheckboxGroupItem} from '../';
1818
import userEvent from '@testing-library/user-event';
1919

@@ -68,7 +68,7 @@ describe('useCheckboxGroup', () => {
6868
expect(checkboxes[2].checked).toBe(false);
6969

7070
let dragons = getByLabelText('Dragons');
71-
act(() => {userEvent.click(dragons);});
71+
userEvent.click(dragons);
7272
expect(onChangeSpy).toHaveBeenCalledTimes(1);
7373
expect(onChangeSpy).toHaveBeenCalledWith(['dragons']);
7474

@@ -251,7 +251,7 @@ describe('useCheckboxGroup', () => {
251251
let checkboxes = getAllByRole('checkbox') as HTMLInputElement[];
252252
let dragons = getByLabelText('Dragons');
253253

254-
act(() => {userEvent.click(dragons);});
254+
userEvent.click(dragons);
255255

256256
expect(groupOnChangeSpy).toHaveBeenCalledTimes(0);
257257
expect(checkboxOnChangeSpy).toHaveBeenCalledTimes(0);

packages/@react-aria/focus/test/FocusScope.test.js

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {fireEvent, render} from '@testing-library/react';
13+
import {act, fireEvent, render} from '@testing-library/react';
1414
import {FocusScope, useFocusManager} from '../';
1515
import React from 'react';
1616
import ReactDOM from 'react-dom';
@@ -38,7 +38,7 @@ describe('FocusScope', function () {
3838
let input2 = getByTestId('input2');
3939
let input3 = getByTestId('input3');
4040

41-
input1.focus();
41+
act(() => {input1.focus();});
4242
expect(document.activeElement).toBe(input1);
4343

4444
fireEvent.keyDown(document.activeElement, {key: 'Tab'});
@@ -77,7 +77,7 @@ describe('FocusScope', function () {
7777
let input2 = getByTestId('input2');
7878
let input3 = getByTestId('input3');
7979

80-
input1.focus();
80+
act(() => {input1.focus();});
8181
expect(document.activeElement).toBe(input1);
8282

8383
fireEvent.keyDown(document.activeElement, {key: 'Tab'});
@@ -114,7 +114,7 @@ describe('FocusScope', function () {
114114
let input2 = getByTestId('input2');
115115
let input3 = getByTestId('input3');
116116

117-
input1.focus();
117+
act(() => {input1.focus();});
118118
expect(document.activeElement).toBe(input1);
119119

120120
fireEvent.keyDown(document.activeElement, {key: 'Tab'});
@@ -147,7 +147,7 @@ describe('FocusScope', function () {
147147

148148
let input1 = getByTestId('input1');
149149

150-
input1.focus();
150+
act(() => {input1.focus();});
151151
expect(document.activeElement).toBe(input1);
152152

153153
fireEvent.keyDown(document.activeElement, {key: 'Tab', altKey: true});
@@ -177,7 +177,7 @@ describe('FocusScope', function () {
177177
let input5 = getByTestId('input5');
178178
let input6 = getByTestId('input6');
179179

180-
input1.focus();
180+
act(() => {input1.focus();});
181181
expect(document.activeElement).toBe(input1);
182182

183183
fireEvent.keyDown(document.activeElement, {key: 'Tab'});
@@ -198,7 +198,7 @@ describe('FocusScope', function () {
198198
fireEvent.keyDown(document.activeElement, {key: 'Tab', shiftKey: true});
199199
expect(document.activeElement).toBe(input1);
200200

201-
input4.focus();
201+
act(() => {input4.focus();});
202202
expect(document.activeElement).toBe(input4);
203203

204204
fireEvent.keyDown(document.activeElement, {key: 'Tab'});
@@ -236,18 +236,18 @@ describe('FocusScope', function () {
236236
let input2 = getByTestId('input2');
237237
let outside = getByTestId('outside');
238238

239-
input1.focus();
239+
act(() => {input1.focus();});
240240
fireEvent.focusIn(input1); // jsdom doesn't fire this automatically
241241
expect(document.activeElement).toBe(input1);
242242

243243
fireEvent.keyDown(document.activeElement, {key: 'Tab'});
244244
fireEvent.focusIn(input2);
245245
expect(document.activeElement).toBe(input2);
246246

247-
input2.blur();
247+
act(() => {input2.blur();});
248248
expect(document.activeElement).toBe(input2);
249249

250-
outside.focus();
250+
act(() => {outside.focus();});
251251
fireEvent.focusIn(outside);
252252
expect(document.activeElement).toBe(input2);
253253
});
@@ -265,15 +265,15 @@ describe('FocusScope', function () {
265265
let input1 = getByTestId('input1');
266266
let input2 = getByTestId('input2');
267267

268-
input1.focus();
268+
act(() => {input1.focus();});
269269
fireEvent.focusIn(input1); // jsdom doesn't fire this automatically
270270
expect(document.activeElement).toBe(input1);
271271

272272
fireEvent.keyDown(document.activeElement, {key: 'Tab'});
273273
fireEvent.focusIn(input2);
274274
expect(document.activeElement).toBe(input2);
275275

276-
input2.blur();
276+
act(() => {input2.blur();});
277277
expect(document.activeElement).toBe(input2);
278278
fireEvent.focusOut(input2);
279279
expect(document.activeElement).toBe(input2);
@@ -300,7 +300,7 @@ describe('FocusScope', function () {
300300
let {getByTestId, rerender} = render(<Test />);
301301

302302
let outside = getByTestId('outside');
303-
outside.focus();
303+
act(() => {outside.focus();});
304304

305305
rerender(<Test show />);
306306

@@ -333,15 +333,15 @@ describe('FocusScope', function () {
333333
let {getByTestId, rerender} = render(<Test />);
334334

335335
let trigger = getByTestId('trigger');
336-
trigger.focus();
336+
act(() => {trigger.focus();});
337337

338338
rerender(<Test show />);
339339

340340
let input1 = getByTestId('input1');
341341
expect(document.activeElement).toBe(input1);
342342

343343
let input3 = getByTestId('input3');
344-
input3.focus();
344+
act(() => {input3.focus();});
345345

346346
fireEvent.keyDown(input3, {key: 'Tab'});
347347
expect(document.activeElement).toBe(getByTestId('after'));
@@ -368,7 +368,7 @@ describe('FocusScope', function () {
368368
let {getByTestId, rerender} = render(<Test />);
369369

370370
let trigger = getByTestId('trigger');
371-
trigger.focus();
371+
act(() => {trigger.focus();});
372372

373373
rerender(<Test show />);
374374

@@ -400,15 +400,15 @@ describe('FocusScope', function () {
400400
let {getByTestId, rerender} = render(<Test />);
401401

402402
let trigger = getByTestId('trigger');
403-
trigger.focus();
403+
act(() => {trigger.focus();});
404404

405405
rerender(<Test show />);
406406

407407
let input1 = getByTestId('input1');
408408
expect(document.activeElement).toBe(input1);
409409

410410
let input3 = getByTestId('input3');
411-
input3.focus();
411+
act(() => {input3.focus();});
412412

413413
fireEvent.keyDown(input3, {key: 'Tab'});
414414
expect(document.activeElement).toBe(getByTestId('after'));
@@ -471,7 +471,7 @@ describe('FocusScope', function () {
471471
let item2 = getByTestId('item2');
472472
let item3 = getByTestId('item3');
473473

474-
item1.focus();
474+
act(() => {item1.focus();});
475475

476476
fireEvent.click(item1);
477477
expect(document.activeElement).toBe(item2);
@@ -508,7 +508,7 @@ describe('FocusScope', function () {
508508
let item2 = getByTestId('item2');
509509
let item3 = getByTestId('item3');
510510

511-
item1.focus();
511+
act(() => {item1.focus();});
512512

513513
fireEvent.click(item1);
514514
expect(document.activeElement).toBe(item2);
@@ -544,7 +544,7 @@ describe('FocusScope', function () {
544544
let item1 = getByTestId('item1');
545545
let item3 = getByTestId('item3');
546546

547-
item1.focus();
547+
act(() => {item1.focus();});
548548

549549
fireEvent.click(item1);
550550
expect(document.activeElement).toBe(item3);
@@ -575,7 +575,7 @@ describe('FocusScope', function () {
575575
let item2 = getByTestId('item2');
576576
let item3 = getByTestId('item3');
577577

578-
item3.focus();
578+
act(() => {item3.focus();});
579579

580580
fireEvent.click(item3);
581581
expect(document.activeElement).toBe(item2);
@@ -612,7 +612,7 @@ describe('FocusScope', function () {
612612
let item2 = getByTestId('item2');
613613
let item3 = getByTestId('item3');
614614

615-
item3.focus();
615+
act(() => {item3.focus();});
616616

617617
fireEvent.click(item3);
618618
expect(document.activeElement).toBe(item2);
@@ -648,7 +648,7 @@ describe('FocusScope', function () {
648648
let item1 = getByTestId('item1');
649649
let item3 = getByTestId('item3');
650650

651-
item3.focus();
651+
act(() => {item3.focus();});
652652

653653
fireEvent.click(item3);
654654
expect(document.activeElement).toBe(item1);
@@ -681,14 +681,14 @@ describe('FocusScope', function () {
681681
let {getByTestId, rerender} = render(<Test />);
682682
// Set a focused node and make first FocusScope the active scope
683683
let input1 = getByTestId('input1');
684-
input1.focus();
684+
act(() => {input1.focus();});
685685
fireEvent.focusIn(input1);
686686
expect(document.activeElement).toBe(input1);
687687

688688
rerender(<Test show />);
689689
expect(document.activeElement).toBe(input1);
690690
let input3 = getByTestId('input3');
691-
input3.focus();
691+
act(() => {input3.focus();});
692692
fireEvent.focusIn(input3);
693693
expect(document.activeElement).toBe(input3);
694694
});

0 commit comments

Comments
 (0)