-
Notifications
You must be signed in to change notification settings - Fork 137
Don't setTimeout if component is unmounted. #169
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
Changes from all commits
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 |
|---|---|---|
|
|
@@ -203,7 +203,7 @@ describe('React', () => { | |
| const pending = TestUtils.findRenderedComponentWithType(container, Container) | ||
| const startedAt = pending.state.startedAts.testFetch | ||
| setImmediate(() => { | ||
| expect(startedAt.getTime()).toBeLessThan(new Date().getTime()) | ||
| expect(startedAt.getTime()).toBeLessThanOrEqualTo(new Date().getTime()) | ||
| const fulfilled = TestUtils.findRenderedComponentWithType(container, Container) | ||
| expect(fulfilled.state.startedAts.testFetch).toEqual(startedAt) | ||
| done() | ||
|
|
@@ -801,7 +801,7 @@ describe('React', () => { | |
| }) | ||
|
|
||
| it('should refresh when refreshInterval is provided', (done) => { | ||
| const interval = 100000 // set sufficently far out to not happen during test | ||
| const interval = 100000 // set sufficiently far out to not happen during test | ||
|
|
||
| @connect(() => ({ testFetch: { url: `/example`, refreshInterval: interval } })) | ||
| class Container extends Component { | ||
|
|
@@ -856,6 +856,77 @@ describe('React', () => { | |
| }) | ||
| }) | ||
|
|
||
| it('should not set refreshTimeouts when component is unmounted', (done) => { | ||
| const interval = 100000 // set sufficiently far out to not happen during test | ||
|
|
||
| @connect(() => ({ testFetch: { url: `/example`, refreshInterval: interval } })) | ||
| class WithProps extends Component { | ||
| render() { | ||
| return <Passthrough {...this.props}/> | ||
| } | ||
| } | ||
|
|
||
| class OuterComponent extends Component { | ||
| constructor() { | ||
| super() | ||
| this.state = { render: true } | ||
| } | ||
|
|
||
| setRender(render) { | ||
| this.setState({ render }) | ||
| } | ||
|
|
||
| render() { | ||
| if (this.state.render) { | ||
| return ( | ||
| <div> | ||
| <WithProps {...this.state} /> | ||
| </div> | ||
| ) | ||
| } else { | ||
| return <div /> | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const outerComponent = TestUtils.renderIntoDocument( | ||
| <OuterComponent /> | ||
| ) | ||
|
|
||
| const container = TestUtils.findRenderedComponentWithType(outerComponent, WithProps) | ||
|
|
||
| expect(container.state.data.testFetch).toIncludeKeyValues({ | ||
| fulfilled: false, pending: true, reason: null, refreshing: false, rejected: false, settled: false, value: null | ||
| }) | ||
| expect(container.state.mappings.testFetch.refreshInterval).toEqual(interval) | ||
| expect(container.state.refreshTimeouts.testFetch).toEqual(undefined) | ||
|
|
||
| setImmediate(() => { | ||
| expect(container.state.data.testFetch).toIncludeKeyValues({ | ||
| fulfilled: true, pending: false, reason: null, refreshing: false, rejected: false, settled: true, value: { T: 't' } | ||
| }) | ||
| expect(container.state.mappings.testFetch.refreshInterval).toEqual(interval) | ||
| const refreshTimeout = container.state.refreshTimeouts.testFetch | ||
| expect(refreshTimeout).toBeTruthy() | ||
| const after = refreshTimeout._onTimeout | ||
|
|
||
| // Cancel scheduled refresh | ||
| clearTimeout(refreshTimeout) | ||
|
|
||
| outerComponent.setRender(false) | ||
|
|
||
| // force the refresh to happen now after it has been unmounted | ||
| after() | ||
|
|
||
| const spy = expect.spyOn(window, 'setTimeout') | ||
|
Contributor
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. shouldn't this happen before
Contributor
Author
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. Hmm.. You're right that it is strange that it is after but I was following the I was having a hard time coming up with a better test than this. If you have any ideas that would be great.
Contributor
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 just tested this (and the other test) with the |
||
| setImmediate(() => { | ||
| spy.destroy() | ||
| expect(spy.calls.length).toBe(0) | ||
| done() | ||
| }) | ||
| }) | ||
| }) | ||
|
|
||
| it('should not set refreshTimeouts when refreshInterval is not provided', (done) => { | ||
| @connect(() => ({ testFetch: `/example` })) | ||
| class Container extends Component { | ||
|
|
||
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.
can you explain what this is doing? it appears that it's just forcing the call the the
refreshTimeout._onTimeout, but doesn't seem like that would actually test the code you added.Uh oh!
There was an error while loading. Please reload this page.
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'm forcing the refreshTimeout._onTimeout after the component has been unmounted. If
_onTimeoutis called without thesetRender(false), thesetTimeoutgets called and the refresh continues indefinitely even though the component has unmounted.If you remove the code I added, this test does indeed fail. I'm not sure this is the proper fix, but it seems to be working for the issues I've been having.
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.
makes sense