-
Notifications
You must be signed in to change notification settings - Fork 47.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flush act() only on exiting outermost call #15519
Changes from all commits
c35e37a
dc605c1
a09bd0f
48ffcee
7cc1379
e86d051
fda3a14
d2c26ee
f7aa6ca
8f88e96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -285,14 +285,13 @@ describe('ReactTestUtils.act()', () => { | |
return ctr; | ||
} | ||
const el = document.createElement('div'); | ||
act(() => { | ||
ReactDOM.render(<App />, el); | ||
}); | ||
await act(async () => { | ||
act(() => { | ||
ReactDOM.render(<App />, el); | ||
}); | ||
|
||
await sleep(100); | ||
expect(el.innerHTML).toBe('1'); | ||
}); | ||
expect(el.innerHTML).toBe('1'); | ||
}); | ||
|
||
it('can handle async/await', async () => { | ||
|
@@ -371,18 +370,23 @@ describe('ReactTestUtils.act()', () => { | |
let ctr = 0; | ||
const div = document.createElement('div'); | ||
|
||
await act(async () => { | ||
act(() => { | ||
ReactDOM.render(<App callback={() => ctr++} />, div); | ||
}); | ||
expect(div.innerHTML).toBe('0'); | ||
expect(ctr).toBe(1); | ||
act(() => { | ||
ReactDOM.render(<App callback={() => ctr++} />, div); | ||
}); | ||
// this may seem odd, but it matches user behaviour - | ||
// a flash of "0" followed by "1" | ||
expect(div.innerHTML).toBe('0'); | ||
expect(ctr).toBe(1); | ||
|
||
await act(async () => {}); // #just-react-things | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to specifically test the intermediate sync state. this test is named badly (and frankly on looking at it now, it doesn't seem super useful). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not clear to me at all what behavior you're actually trying to test. More comments could help. |
||
|
||
expect(div.innerHTML).toBe('1'); | ||
expect(ctr).toBe(2); | ||
|
||
// this may seem odd, but it matches browser behaviour - | ||
// a flash of "0" followed by "1" | ||
|
||
// now you probably wouldn't write a test like this for your app | ||
// you'd await act(async () => { ReactDOM.render(<App/> }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So then why did you write it this way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. like mentioned, just wanted to make sure the intermediate state was what I'd expected. |
||
// and assert on final render | ||
}); | ||
|
||
it('propagates errors', async () => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,16 +60,15 @@ function flushEffectsAndMicroTasks(onDone: (err: ?Error) => void) { | |
} | ||
|
||
function act(callback: () => Thenable) { | ||
let previousActingUpdatesScopeDepth; | ||
let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; | ||
actingUpdatesScopeDepth++; | ||
if (__DEV__) { | ||
previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; | ||
actingUpdatesScopeDepth++; | ||
ReactShouldWarnActingUpdates.current = true; | ||
} | ||
|
||
function onDone() { | ||
actingUpdatesScopeDepth--; | ||
if (__DEV__) { | ||
actingUpdatesScopeDepth--; | ||
if (actingUpdatesScopeDepth === 0) { | ||
ReactShouldWarnActingUpdates.current = false; | ||
} | ||
|
@@ -119,6 +118,13 @@ function act(callback: () => Thenable) { | |
called = true; | ||
result.then( | ||
() => { | ||
if (actingUpdatesScopeDepth !== 1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any scenario where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rather, actingUpdatesScopeDepth > 1 |
||
onDone(); | ||
resolve(); | ||
return; | ||
} | ||
// we're about to exit the act() scope, | ||
// now's the time to flush tasks/effects | ||
flushEffectsAndMicroTasks((err: ?Error) => { | ||
onDone(); | ||
if (err) { | ||
|
@@ -145,9 +151,12 @@ function act(callback: () => Thenable) { | |
); | ||
} | ||
|
||
// flush effects until none remain, and cleanup | ||
try { | ||
while (flushPassiveEffects()) {} | ||
if (actingUpdatesScopeDepth === 1) { | ||
// we're about to exit the act() scope, | ||
// now's the time to flush effects | ||
while (flushPassiveEffects()) {} | ||
} | ||
onDone(); | ||
} catch (err) { | ||
onDone(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you move this to a separate
act
? I would expect moving the assertion outsideact
is sufficient.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the effect wouldn't flush effects until the act exits, only after which the timeout in the component would start, failing the assertion. hence, 2 act()s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you remove the
await
then?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't?