-
Notifications
You must be signed in to change notification settings - Fork 46.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Warn when rendering tests in concurrent/batched mode without a mocked…
… scheduler (#16207) Concurrent/Batched mode tests should always be run with a mocked scheduler (v17 or not). This PR adds a warning for the same. I'll put up a separate PR to the docs with a page detailing how to mock the scheduler.
- Loading branch information
Sunil Pai
authored
Jul 30, 2019
1 parent
e276a5e
commit e6a0473
Showing
18 changed files
with
441 additions
and
319 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @emails react-core | ||
*/ | ||
|
||
let React; | ||
let TestUtils; | ||
let TestRenderer; | ||
|
||
global.__DEV__ = process.env.NODE_ENV !== 'production'; | ||
|
||
expect.extend(require('../toWarnDev')); | ||
|
||
describe('unmocked scheduler', () => { | ||
beforeEach(() => { | ||
jest.resetModules(); | ||
React = require('react'); | ||
TestUtils = require('react-dom/test-utils'); | ||
TestRenderer = require('react-test-renderer'); | ||
}); | ||
|
||
it('flushes work only outside the outermost act() corresponding to its own renderer', () => { | ||
let log = []; | ||
function Effecty() { | ||
React.useEffect(() => { | ||
log.push('called'); | ||
}, []); | ||
return null; | ||
} | ||
// in legacy mode, this tests whether an act only flushes its own effects | ||
TestRenderer.act(() => { | ||
TestUtils.act(() => { | ||
TestRenderer.create(<Effecty />); | ||
}); | ||
expect(log).toEqual([]); | ||
}); | ||
expect(log).toEqual(['called']); | ||
|
||
log = []; | ||
// for doublechecking, we flip it inside out, and assert on the outermost | ||
TestUtils.act(() => { | ||
TestRenderer.act(() => { | ||
TestRenderer.create(<Effecty />); | ||
}); | ||
expect(log).toEqual(['called']); | ||
}); | ||
expect(log).toEqual(['called']); | ||
}); | ||
}); | ||
|
||
describe('mocked scheduler', () => { | ||
beforeEach(() => { | ||
jest.resetModules(); | ||
jest.mock('scheduler', () => | ||
require.requireActual('scheduler/unstable_mock') | ||
); | ||
React = require('react'); | ||
TestUtils = require('react-dom/test-utils'); | ||
TestRenderer = require('react-test-renderer'); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.unmock('scheduler'); | ||
}); | ||
|
||
it('flushes work only outside the outermost act()', () => { | ||
let log = []; | ||
function Effecty() { | ||
React.useEffect(() => { | ||
log.push('called'); | ||
}, []); | ||
return null; | ||
} | ||
// with a mocked scheduler, this tests whether it flushes all work only on the outermost act | ||
TestRenderer.act(() => { | ||
TestUtils.act(() => { | ||
TestRenderer.create(<Effecty />); | ||
}); | ||
expect(log).toEqual([]); | ||
}); | ||
expect(log).toEqual(['called']); | ||
|
||
log = []; | ||
// for doublechecking, we flip it inside out, and assert on the outermost | ||
TestUtils.act(() => { | ||
TestRenderer.act(() => { | ||
TestRenderer.create(<Effecty />); | ||
}); | ||
expect(log).toEqual([]); | ||
}); | ||
expect(log).toEqual(['called']); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
/** | ||
* Copyright (c) Facebook, Inc. and its affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @emails react-core | ||
*/ | ||
|
||
let React; | ||
let ReactDOM; | ||
let ReactART; | ||
let ARTSVGMode; | ||
let ARTCurrentMode; | ||
let TestUtils; | ||
let TestRenderer; | ||
let ARTTest; | ||
|
||
global.__DEV__ = process.env.NODE_ENV !== 'production'; | ||
|
||
expect.extend(require('../toWarnDev')); | ||
|
||
function App(props) { | ||
return 'hello world'; | ||
} | ||
|
||
beforeEach(() => { | ||
jest.resetModules(); | ||
React = require('react'); | ||
ReactDOM = require('react-dom'); | ||
ReactART = require('react-art'); | ||
ARTSVGMode = require('art/modes/svg'); | ||
ARTCurrentMode = require('art/modes/current'); | ||
TestUtils = require('react-dom/test-utils'); | ||
TestRenderer = require('react-test-renderer'); | ||
|
||
ARTCurrentMode.setCurrent(ARTSVGMode); | ||
|
||
ARTTest = function ARTTestComponent(props) { | ||
return ( | ||
<ReactART.Surface width={150} height={200}> | ||
<ReactART.Group> | ||
<ReactART.Shape | ||
d="M0,0l50,0l0,50l-50,0z" | ||
fill={new ReactART.LinearGradient(['black', 'white'])} | ||
key="a" | ||
width={50} | ||
height={50} | ||
x={50} | ||
y={50} | ||
opacity={0.1} | ||
/> | ||
<ReactART.Shape | ||
fill="#3C5A99" | ||
key="b" | ||
scale={0.5} | ||
x={50} | ||
y={50} | ||
title="This is an F" | ||
cursor="pointer"> | ||
M64.564,38.583H54l0.008-5.834c0-3.035,0.293-4.666,4.657-4.666 | ||
h5.833V16.429h-9.33c-11.213,0-15.159,5.654-15.159,15.16v6.994 | ||
h-6.99v11.652h6.99v33.815H54V50.235h9.331L64.564,38.583z | ||
</ReactART.Shape> | ||
</ReactART.Group> | ||
</ReactART.Surface> | ||
); | ||
}; | ||
}); | ||
|
||
it("doesn't warn when you use the right act + renderer: dom", () => { | ||
TestUtils.act(() => { | ||
TestUtils.renderIntoDocument(<App />); | ||
}); | ||
}); | ||
|
||
it("doesn't warn when you use the right act + renderer: test", () => { | ||
TestRenderer.act(() => { | ||
TestRenderer.create(<App />); | ||
}); | ||
}); | ||
|
||
it('resets correctly across renderers', () => { | ||
function Effecty() { | ||
React.useEffect(() => {}, []); | ||
return null; | ||
} | ||
TestUtils.act(() => { | ||
TestRenderer.act(() => {}); | ||
expect(() => { | ||
TestRenderer.create(<Effecty />); | ||
}).toWarnDev(["It looks like you're using the wrong act()"], { | ||
withoutStack: true, | ||
}); | ||
}); | ||
}); | ||
|
||
it('warns when using the wrong act version - test + dom: render', () => { | ||
expect(() => { | ||
TestRenderer.act(() => { | ||
TestUtils.renderIntoDocument(<App />); | ||
}); | ||
}).toWarnDev(["It looks like you're using the wrong act()"], { | ||
withoutStack: true, | ||
}); | ||
}); | ||
|
||
it('warns when using the wrong act version - test + dom: updates', () => { | ||
let setCtr; | ||
function Counter(props) { | ||
const [ctr, _setCtr] = React.useState(0); | ||
setCtr = _setCtr; | ||
return ctr; | ||
} | ||
TestUtils.renderIntoDocument(<Counter />); | ||
expect(() => { | ||
TestRenderer.act(() => { | ||
setCtr(1); | ||
}); | ||
}).toWarnDev(["It looks like you're using the wrong act()"]); | ||
}); | ||
|
||
it('warns when using the wrong act version - dom + test: .create()', () => { | ||
expect(() => { | ||
TestUtils.act(() => { | ||
TestRenderer.create(<App />); | ||
}); | ||
}).toWarnDev(["It looks like you're using the wrong act()"], { | ||
withoutStack: true, | ||
}); | ||
}); | ||
|
||
it('warns when using the wrong act version - dom + test: .update()', () => { | ||
const root = TestRenderer.create(<App key="one" />); | ||
expect(() => { | ||
TestUtils.act(() => { | ||
root.update(<App key="two" />); | ||
}); | ||
}).toWarnDev(["It looks like you're using the wrong act()"], { | ||
withoutStack: true, | ||
}); | ||
}); | ||
|
||
it('warns when using the wrong act version - dom + test: updates', () => { | ||
let setCtr; | ||
function Counter(props) { | ||
const [ctr, _setCtr] = React.useState(0); | ||
setCtr = _setCtr; | ||
return ctr; | ||
} | ||
TestRenderer.create(<Counter />); | ||
expect(() => { | ||
TestUtils.act(() => { | ||
setCtr(1); | ||
}); | ||
}).toWarnDev(["It looks like you're using the wrong act()"]); | ||
}); | ||
|
||
it('does not warn when nesting react-act inside react-dom', () => { | ||
TestUtils.act(() => { | ||
TestUtils.renderIntoDocument(<ARTTest />); | ||
}); | ||
}); | ||
|
||
it('does not warn when nesting react-act inside react-test-renderer', () => { | ||
TestRenderer.act(() => { | ||
TestRenderer.create(<ARTTest />); | ||
}); | ||
}); | ||
|
||
it("doesn't warn if you use nested acts from different renderers", () => { | ||
TestRenderer.act(() => { | ||
TestUtils.act(() => { | ||
TestRenderer.create(<App />); | ||
}); | ||
}); | ||
}); | ||
|
||
it('warns when using createRoot() + .render', () => { | ||
const root = ReactDOM.unstable_createRoot(document.createElement('div')); | ||
expect(() => { | ||
TestRenderer.act(() => { | ||
root.render(<App />); | ||
}); | ||
}).toWarnDev( | ||
[ | ||
'In Concurrent or Sync modes, the "scheduler" module needs to be mocked', | ||
"It looks like you're using the wrong act()", | ||
], | ||
{ | ||
withoutStack: true, | ||
} | ||
); | ||
}); |
Oops, something went wrong.