Open SunnyWind opened 4 years ago
There isn't a similar method at the moment but it sounds like a feature that could be implemented.
Could you please provide me with a code example of how you'd use it? Is this for testing a component render?
I'm writing UT for React components which mostly do an HTTP request after mounted. I need to check the state of components after the request was finished. Without the flush
method, I have to wait a few milliseconds to proceed with the check.
Thanks for explaining it in more detail! Could you please you provide a minimal code example that demonstrates how the feature should work which we can use as a test?
import React, { useState, useEffect } from 'react';
import Enzyme, { mount } from 'enzyme';
import EnzymeAdapter from 'enzyme-adapter-react-16';
import { expect } from 'chai';
import { request } from "mithril/request";
import xhrMock from 'xhr-mock';
Enzyme.configure({ adapter: new EnzymeAdapter() });
describe('The component', () => {
it('should update its state after it got a responce from the server', async () => {
xhrMock.get('/count', {
status: 200,
body: 1
});
const wrapper = mount(
<TestComp />,
);
// This method should wait until the request is finished
// await xhrMock.flush();
expect(wrapper.state('count')).to.be.equal(1);
});
});
const TestComp = () => {
const [count, setCount] = useState<number>(0);
useEffect(() => {
const res = await request({
method: 'GET',
url: '/count'
});
setCount(res);
}, []);
return (
<p>{count}</p>
);
};
I'm not sure the code is runnable...
BTW, Is there a hacky and easy way to meet my requirements? I tried to modify the XMLHttpRequest and could not find a way to wrap the process into a Promise object.
An API "wait for all" in XHRMock
would be nice, but it will not be as simple as in your example, if it should work in more complicated tests. Mocks may get registered among making requests. A mocked request can be executed multiple times. Maybe a scope object would help to group the mocked calls to wait for all?
As long as there is no API for this, you can use your own promises to wait just for the calls that you need. (If the mock was called multiple times, or if it was in other script as a shared utility, you could use an event emitter instead of the promise to inform the test about the finished request.)
For example:
let respond;
const responded = new Promise(resolve => (respond = resolve));
xhrMock.get('/count', (request, response) => {
// switch context to let the component update by the promise
setTimeout(respond);
return response.status(200).body(1);
});
const wrapper = mount(
<TestComp />
);
await responded;
expect(wrapper.state('count')).to.be.equal(1);
Alternatively, you could try watching for updates of the React
component.
@SunnyWind I don't believe there's an easy way to implement the functionality in the current version (v2.5.1
) though it will be easy to implement in the next major version (v3
) which is (very slowly) under development.
I was thinking the .flush()
* method would resolve when all incomplete requests are completed (that includes any requests that were initiated after .flush()
is called while waiting for the original requests).
@prantlf What would the API for a scope object look like? Can you provide a theoretical example? Thanks for the interim work around!
*I'm keen to hear people's opinion on the method name! e.g. .wait|flush|settle()
etc
The method description is as follows: