Skip to content

Commit 254be59

Browse files
committed
Convert class equivlance tests to flushSync
There's an old collection of test suites that test class component behavior across ES6 (regular JavaScript classes), CoffeeScript classes, and TypeScript classes. They work by running the same tests in all environments and comparing the results. Rather than use `act` or `waitFor` in these, I've changed them to use `flushSync` instead so that they can flush synchronously. The reason is that CoffeeScript doesn't have async/await, so we'd have to write those tests differently than how they are written in the corresponding modules. Since none of these tests cover any concurrent behavior, I believe it's fine in this case to do everything synchronously; they don't use any concurrent features, anyway, so effectively it's just skipping a microtask.
1 parent 978fae4 commit 254be59

File tree

4 files changed

+32
-35
lines changed

4 files changed

+32
-35
lines changed

packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ describe 'ReactCoffeeScriptClass', ->
2222
React = require 'react'
2323
ReactDOM = require 'react-dom'
2424
ReactDOMClient = require 'react-dom/client'
25-
act = require('jest-react').act
2625
PropTypes = require 'prop-types'
2726
container = document.createElement 'div'
2827
root = ReactDOMClient.createRoot container
@@ -36,7 +35,7 @@ describe 'ReactCoffeeScriptClass', ->
3635
return React.createElement('div', className: this.props.name)
3736

3837
test = (element, expectedTag, expectedClassName) ->
39-
act ->
38+
ReactDOM.flushSync ->
4039
root.render(element)
4140
expect(container.firstChild).not.toBeNull()
4241
expect(container.firstChild.tagName).toBe(expectedTag)
@@ -50,7 +49,7 @@ describe 'ReactCoffeeScriptClass', ->
5049
class Foo extends React.Component
5150
expect(->
5251
expect(->
53-
act ->
52+
ReactDOM.flushSync ->
5453
root.render React.createElement(Foo)
5554
).toThrow()
5655
).toErrorDev([
@@ -103,7 +102,8 @@ describe 'ReactCoffeeScriptClass', ->
103102

104103
ref = React.createRef()
105104
test React.createElement(Foo, initialValue: 'foo', ref: ref), 'DIV', 'foo'
106-
ref.current.changeState()
105+
ReactDOM.flushSync ->
106+
ref.current.changeState()
107107
test React.createElement(Foo), 'SPAN', 'bar'
108108

109109
it 'sets initial state with value returned by static getDerivedStateFromProps', ->
@@ -129,7 +129,7 @@ describe 'ReactCoffeeScriptClass', ->
129129
getDerivedStateFromProps: ->
130130
{}
131131
expect(->
132-
act ->
132+
ReactDOM.flushSync ->
133133
root.render React.createElement(Foo, foo: 'foo')
134134
return
135135
).toErrorDev 'Foo: getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method.'
@@ -141,7 +141,7 @@ describe 'ReactCoffeeScriptClass', ->
141141
getDerivedStateFromError: ->
142142
{}
143143
expect(->
144-
act ->
144+
ReactDOM.flushSync ->
145145
root.render React.createElement(Foo, foo: 'foo')
146146
return
147147
).toErrorDev 'Foo: getDerivedStateFromError() is defined as an instance method and will be ignored. Instead, declare it as a static method.'
@@ -153,7 +153,7 @@ describe 'ReactCoffeeScriptClass', ->
153153
Foo.getSnapshotBeforeUpdate = () ->
154154
{}
155155
expect(->
156-
act ->
156+
ReactDOM.flushSync ->
157157
root.render React.createElement(Foo, foo: 'foo')
158158
return
159159
).toErrorDev 'Foo: getSnapshotBeforeUpdate() is defined as a static method and will be ignored. Instead, declare it as an instance method.'
@@ -170,7 +170,7 @@ describe 'ReactCoffeeScriptClass', ->
170170
bar: 'bar'
171171
}
172172
expect(->
173-
act ->
173+
ReactDOM.flushSync ->
174174
root.render React.createElement(Foo, foo: 'foo')
175175
return
176176
).toErrorDev (
@@ -303,7 +303,7 @@ describe 'ReactCoffeeScriptClass', ->
303303
)
304304

305305
test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
306-
act ->
306+
ReactDOM.flushSync ->
307307
attachedListener()
308308
expect(renderedName).toBe 'bar'
309309

@@ -340,7 +340,7 @@ describe 'ReactCoffeeScriptClass', ->
340340
)
341341

342342
test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
343-
act ->
343+
ReactDOM.flushSync ->
344344
attachedListener()
345345
expect(renderedName).toBe 'bar'
346346

@@ -391,7 +391,7 @@ describe 'ReactCoffeeScriptClass', ->
391391
'did-update', { value: 'foo' }, {}
392392
]
393393
lifeCycles = [] # reset
394-
act ->
394+
ReactDOM.flushSync ->
395395
root.unmount()
396396
expect(lifeCycles).toEqual ['will-unmount']
397397

packages/react/src/__tests__/ReactES6Class-test.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ let PropTypes;
1313
let React;
1414
let ReactDOM;
1515
let ReactDOMClient;
16-
let act;
1716

1817
describe('ReactES6Class', () => {
1918
let container;
@@ -31,7 +30,6 @@ describe('ReactES6Class', () => {
3130
React = require('react');
3231
ReactDOM = require('react-dom');
3332
ReactDOMClient = require('react-dom/client');
34-
act = require('jest-react').act;
3533
container = document.createElement('div');
3634
root = ReactDOMClient.createRoot(container);
3735
attachedListener = null;
@@ -49,7 +47,7 @@ describe('ReactES6Class', () => {
4947
});
5048

5149
function test(element, expectedTag, expectedClassName) {
52-
act(() => root.render(element));
50+
ReactDOM.flushSync(() => root.render(element));
5351
expect(container.firstChild).not.toBeNull();
5452
expect(container.firstChild.tagName).toBe(expectedTag);
5553
expect(container.firstChild.className).toBe(expectedClassName);
@@ -63,7 +61,7 @@ describe('ReactES6Class', () => {
6361
it('throws if no render function is defined', () => {
6462
class Foo extends React.Component {}
6563
expect(() => {
66-
expect(() => act(() => root.render(<Foo />))).toThrow();
64+
expect(() => ReactDOM.flushSync(() => root.render(<Foo />))).toThrow();
6765
}).toErrorDev([
6866
// A failed component renders four times in DEV in concurrent mode
6967
'Warning: Foo(...): No `render` method found on the returned component ' +
@@ -118,7 +116,7 @@ describe('ReactES6Class', () => {
118116
}
119117
const ref = React.createRef();
120118
test(<Foo initialValue="foo" ref={ref} />, 'DIV', 'foo');
121-
act(() => ref.current.changeState());
119+
ReactDOM.flushSync(() => ref.current.changeState());
122120
test(<Foo />, 'SPAN', 'bar');
123121
});
124122

@@ -148,7 +146,7 @@ describe('ReactES6Class', () => {
148146
}
149147
}
150148
expect(() => {
151-
act(() => root.render(<Foo foo="foo" />));
149+
ReactDOM.flushSync(() => root.render(<Foo foo="foo" />));
152150
}).toErrorDev(
153151
'Foo: getDerivedStateFromProps() is defined as an instance method ' +
154152
'and will be ignored. Instead, declare it as a static method.',
@@ -165,7 +163,7 @@ describe('ReactES6Class', () => {
165163
}
166164
}
167165
expect(() => {
168-
act(() => root.render(<Foo foo="foo" />));
166+
ReactDOM.flushSync(() => root.render(<Foo foo="foo" />));
169167
}).toErrorDev(
170168
'Foo: getDerivedStateFromError() is defined as an instance method ' +
171169
'and will be ignored. Instead, declare it as a static method.',
@@ -180,7 +178,7 @@ describe('ReactES6Class', () => {
180178
}
181179
}
182180
expect(() => {
183-
act(() => root.render(<Foo foo="foo" />));
181+
ReactDOM.flushSync(() => root.render(<Foo foo="foo" />));
184182
}).toErrorDev(
185183
'Foo: getSnapshotBeforeUpdate() is defined as a static method ' +
186184
'and will be ignored. Instead, declare it as an instance method.',
@@ -200,7 +198,7 @@ describe('ReactES6Class', () => {
200198
}
201199
}
202200
expect(() => {
203-
act(() => root.render(<Foo foo="foo" />));
201+
ReactDOM.flushSync(() => root.render(<Foo foo="foo" />));
204202
}).toErrorDev(
205203
'`Foo` uses `getDerivedStateFromProps` but its initial state is ' +
206204
'undefined. This is not recommended. Instead, define the initial state by ' +
@@ -347,7 +345,7 @@ describe('ReactES6Class', () => {
347345
}
348346
test(<Foo initialValue="foo" />, 'DIV', 'foo');
349347

350-
act(() => attachedListener());
348+
ReactDOM.flushSync(() => attachedListener());
351349
expect(renderedName).toBe('bar');
352350
});
353351

@@ -388,7 +386,7 @@ describe('ReactES6Class', () => {
388386
}
389387
}
390388
test(<Foo initialValue="foo" />, 'DIV', 'foo');
391-
act(() => attachedListener());
389+
ReactDOM.flushSync(() => attachedListener());
392390
expect(renderedName).toBe('bar');
393391
});
394392

@@ -437,7 +435,7 @@ describe('ReactES6Class', () => {
437435
'did-update', freeze({value: 'foo'}), {},
438436
]);
439437
lifeCycles = []; // reset
440-
act(() => root.unmount());
438+
ReactDOM.flushSync(() => root.unmount());
441439
expect(lifeCycles).toEqual(['will-unmount']);
442440
});
443441

packages/react/src/__tests__/ReactTypeScriptClass-test.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@ import ReactDOM = require('react-dom');
1616
import ReactDOMClient = require('react-dom/client');
1717
import ReactDOMTestUtils = require('react-dom/test-utils');
1818
import PropTypes = require('prop-types');
19-
import internalAct = require('jest-react');
2019

2120
// Before Each
2221

2322
let container;
2423
let root;
2524
let attachedListener = null;
2625
let renderedName = null;
27-
let act = internalAct.act;
2826

2927
class Inner extends React.Component {
3028
getName() {
@@ -38,7 +36,7 @@ class Inner extends React.Component {
3836
}
3937

4038
function test(element, expectedTag, expectedClassName) {
41-
act(() => root.render(element));
39+
ReactDOM.flushSync(() => root.render(element));
4240
expect(container.firstChild).not.toBeNull();
4341
expect(container.firstChild.tagName).toBe(expectedTag);
4442
expect(container.firstChild.className).toBe(expectedClassName);
@@ -331,7 +329,7 @@ describe('ReactTypeScriptClass', function() {
331329
it('throws if no render function is defined', function() {
332330
expect(() => {
333331
expect(() =>
334-
act(() => root.render(React.createElement(Empty)))
332+
ReactDOM.flushSync(() => root.render(React.createElement(Empty)))
335333
).toThrow();
336334
}).toErrorDev([
337335
// A failed component renders four times in DEV in concurrent mode
@@ -366,7 +364,7 @@ describe('ReactTypeScriptClass', function() {
366364
'DIV',
367365
'foo'
368366
);
369-
act(() => ref.current.changeState());
367+
ReactDOM.flushSync(() => ref.current.changeState());
370368
test(React.createElement(StateBasedOnProps), 'SPAN', 'bar');
371369
});
372370

@@ -401,7 +399,7 @@ describe('ReactTypeScriptClass', function() {
401399
}
402400
}
403401
expect(function() {
404-
act(() =>
402+
ReactDOM.flushSync(() =>
405403
root.render(React.createElement(Foo, {foo: 'foo'}))
406404
);
407405
}).toErrorDev(
@@ -420,7 +418,7 @@ describe('ReactTypeScriptClass', function() {
420418
}
421419
}
422420
expect(function() {
423-
act(() =>
421+
ReactDOM.flushSync(() =>
424422
root.render(React.createElement(Foo, {foo: 'foo'}))
425423
);
426424
}).toErrorDev(
@@ -437,7 +435,7 @@ describe('ReactTypeScriptClass', function() {
437435
}
438436
}
439437
expect(function() {
440-
act(() =>
438+
ReactDOM.flushSync(() =>
441439
root.render(React.createElement(Foo, {foo: 'foo'}))
442440
);
443441
}).toErrorDev(
@@ -461,7 +459,7 @@ describe('ReactTypeScriptClass', function() {
461459
}
462460
}
463461
expect(function() {
464-
act(() =>
462+
ReactDOM.flushSync(() =>
465463
root.render(React.createElement(Foo, {foo: 'foo'}))
466464
);
467465
}).toErrorDev(
@@ -547,7 +545,7 @@ describe('ReactTypeScriptClass', function() {
547545
'DIV',
548546
'foo'
549547
);
550-
act(() => attachedListener());
548+
ReactDOM.flushSync(() => attachedListener());
551549
expect(renderedName).toBe('bar');
552550
});
553551

@@ -566,7 +564,7 @@ describe('ReactTypeScriptClass', function() {
566564
'DIV',
567565
'foo'
568566
);
569-
act(() => attachedListener());
567+
ReactDOM.flushSync(() => attachedListener());
570568
expect(renderedName).toBe('bar');
571569
});
572570

@@ -590,7 +588,7 @@ describe('ReactTypeScriptClass', function() {
590588
{},
591589
]);
592590
lifeCycles = []; // reset
593-
act(() => root.unmount(container));
591+
ReactDOM.flushSync(() => root.unmount(container));
594592
expect(lifeCycles).toEqual(['will-unmount']);
595593
});
596594

packages/react/src/__tests__/testDefinitions/ReactDOM.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ declare module 'react-dom' {
1616
export function render(element : any, container : any) : any
1717
export function unmountComponentAtNode(container : any) : void
1818
export function findDOMNode(instance : any) : any
19+
export function flushSync(cb : any) : any
1920
}

0 commit comments

Comments
 (0)