-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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
How to test async componentDidMount() #14687
Comments
I have a question. When do you use async |
I'm not directly calling componentDidMount() in the test, I expect it to be called by the react test renderer when I call create(...). The Applications component looks like this: export default class Applications extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
applications: null,
failedToFetchApplications: false,
};
}
async componentDidMount() {
this.logService.debug("Applications->componentDidMount()");
this.setState({
loading: true,
});
if (this.props.currentUser) {
await this.loadApplicationsIntoState();
}
this.setState({
loading: false,
});
}
// ...
// loadApplicationsIntostate() fetches from an API
// ... |
How about this? you can async test using export default class Applications extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
applications: null,
failedToFetchApplications: false,
};
}
componentDidMount() {
wrapFunc();
}
// wrapping function.
async wrapFunc() {
this.logService.debug("Applications->componentDidMount()");
this.setState({
loading: true,
});
if (this.props.currentUser) {
await this.loadApplicationsIntoState();
}
this.setState({
loading: false,
});
}
// ...
// loadApplicationsIntostate() fetches from an API
// ... |
Actually I'm not trying to test the code within componentDidMount(), I just can't get over the "Invariant Violation" error. Basically I need sort of an away to await componentDidMount() in the test. The only way I found yet is: const renderComponent = (props = {}) => {
const component = create(<Applications {...props} />);
return component.root;
}
const delay = async (miliseconds = 0) => {
await new Promise(resolve => { setTimeout(resolve, miliseconds); });
};
it("renders applications", async () => {
const instance = renderComponent();
await delay(2000); // this is a workaround for leaving async componentDidMount() finish
}); Sorry for the misleading title. |
Here's how we handle async we have a spec helper called // in spec/helpers/defer
export default () => {
const d = {};
d.promise = new Promise((resolve, _reject) => {
d.resolve = (result) => {
setTimeout(resolve, 0);
return Promise.resolve(result);
};
d.reject = (rejection) => {
setTimeout(resolve, 0);
return Promise.reject(rejection);
};
});
d.then = d.promise.then.bind(d.promise);
d.catch = d.promise.catch.bind(d.promise);
return d;
}; and then let's say that the component to be tested are something like: class MyComponent extends Component {
static propTypes = {
asyncApiCall: PropTypes.func,
}
componentDidMount() {
const { asyncApiCall } = this.props;
asyncApiCall().then(
() => /* do something */
);
}
// etc...
} in test, we'll use the helper function like: it('test async componentDidMount', (done) => {
const deferredApi = defer();
const asyncApiCall = () => deferredApi.resolve();
const wrapper = mount(<MyComponent asyncApiCall={asyncApiCall} />);
deferredApiCall.then(() => {
wrapper.update();
// run some expect...
done();
});
}); |
Thanks. |
Do you want to request a feature or report a bug?
Question.
What is the current behavior?
I'm trying to test a statefull component (Applications) that has async componentDidMount();
I tried to provide a callback (done()) to the test and use setImmediate(() => { done(); }, but I still get the error. If I don't call setImmediate() but use the callback variant of the test, I get "Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL." error.
The text was updated successfully, but these errors were encountered: