Skip to content

Commit b1abeaf

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 8a9f82e commit b1abeaf

File tree

4 files changed

+30
-34
lines changed

4 files changed

+30
-34
lines changed

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

Lines changed: 9 additions & 10 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([
@@ -129,7 +128,7 @@ describe 'ReactCoffeeScriptClass', ->
129128
getDerivedStateFromProps: ->
130129
{}
131130
expect(->
132-
act ->
131+
ReactDOM.flushSync ->
133132
root.render React.createElement(Foo, foo: 'foo')
134133
return
135134
).toErrorDev 'Foo: getDerivedStateFromProps() is defined as an instance method and will be ignored. Instead, declare it as a static method.'
@@ -141,7 +140,7 @@ describe 'ReactCoffeeScriptClass', ->
141140
getDerivedStateFromError: ->
142141
{}
143142
expect(->
144-
act ->
143+
ReactDOM.flushSync ->
145144
root.render React.createElement(Foo, foo: 'foo')
146145
return
147146
).toErrorDev 'Foo: getDerivedStateFromError() is defined as an instance method and will be ignored. Instead, declare it as a static method.'
@@ -153,7 +152,7 @@ describe 'ReactCoffeeScriptClass', ->
153152
Foo.getSnapshotBeforeUpdate = () ->
154153
{}
155154
expect(->
156-
act ->
155+
ReactDOM.flushSync ->
157156
root.render React.createElement(Foo, foo: 'foo')
158157
return
159158
).toErrorDev 'Foo: getSnapshotBeforeUpdate() is defined as a static method and will be ignored. Instead, declare it as an instance method.'
@@ -170,7 +169,7 @@ describe 'ReactCoffeeScriptClass', ->
170169
bar: 'bar'
171170
}
172171
expect(->
173-
act ->
172+
ReactDOM.flushSync ->
174173
root.render React.createElement(Foo, foo: 'foo')
175174
return
176175
).toErrorDev (
@@ -303,7 +302,7 @@ describe 'ReactCoffeeScriptClass', ->
303302
)
304303

305304
test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
306-
act ->
305+
ReactDOM.flushSync ->
307306
attachedListener()
308307
expect(renderedName).toBe 'bar'
309308

@@ -340,7 +339,7 @@ describe 'ReactCoffeeScriptClass', ->
340339
)
341340

342341
test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
343-
act ->
342+
ReactDOM.flushSync ->
344343
attachedListener()
345344
expect(renderedName).toBe 'bar'
346345

@@ -391,7 +390,7 @@ describe 'ReactCoffeeScriptClass', ->
391390
'did-update', { value: 'foo' }, {}
392391
]
393392
lifeCycles = [] # reset
394-
act ->
393+
ReactDOM.flushSync ->
395394
root.unmount()
396395
expect(lifeCycles).toEqual ['will-unmount']
397396

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)