I have a React JS component MyComponent
and I would like to test the following use case:
It should call
updateSomething()
when component on mount
And I've come up with the following code:
System Under Test (SUT)
export class MyComponent extends React.Component<Props, State> {
public componentDidMount() {
console.log("componentDidMount"); // Debug purpose.
this.fetchSomething()
.then(() => {
console.log("fetchSomething"); // Debug purpose.
this.updateSomething();
});
}
// These are public for simplicity
public async fetchSomething(): Promise<any> { }
public updateSomething() {
console.log("updateSomething"); // Debug purpose.
}
}
Test
it("should update something, when on mount", () => {
const props = { ...baseProps };
sinon.stub(MyComponent.prototype, "fetchSomething").resolves();
const spy = sinon.spy(MyComponent.prototype, "updateSomething");
shallow(<MyComponent {...props} />);
sinon.assert.calledOnce(spy);
});
The result is the test failed with AssertError: expected updateSomething to be called once but was called 0 times
but all three console.log()
printed.
My understanding is since I want to test the event when on mount, I have to spy/stub it before it's even created, therefore I have to spy on MyComponent.Prototype
. Also, for fetchSomething()
, I have to stub the async call and make it .resolves()
to let it progress.
But I couldn't understand how it can still console.log("updateSomething")
without being spied.
According to the comments/answer from this post, the assertion comes before .updateSomething
have been called. To solve this problem, I would've to await the componentDidMount
lifecycle method.
So the fixed program is as below:
// SUT
public async componentDidMount() {
//...
return this.fetchSomething()
.then(() => {
//...
});
}
// Test
it("should update something, when on mount", () => {
const props = { ...baseProps };
// Disable lifecycle here to enable stub in between.
const wrapper = shallow(<MyComponent {...props} />, { disableLifecycleMethods: true });
sinon.stub(wrapper.instance(), "fetchSomething").resolves();
const stub = sinon.stub(wrapper.instance(), "updateSomething");
// Actually call component did mount.
wrapper.instance().componentDidMount().then(() => {
sinon.assert.calledOnce(stub);
});
});