Skip to content
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

Is there a method similar with fetchMock.flush? #102

Open
SunnyWind opened this issue Dec 16, 2019 · 8 comments
Open

Is there a method similar with fetchMock.flush? #102

SunnyWind opened this issue Dec 16, 2019 · 8 comments
Milestone

Comments

@SunnyWind
Copy link

The method description is as follows:

.flush(waitForBody)
Returns a Promise that resolves once all fetches handled by fetch-mock have resolved
Useful for testing code that uses fetch but doesn’t return a promise.
If waitForBody is true, the promise will wait for all body parsing methods (res.json(), res.text(), etc.) to resolve too.

@jameslnewell
Copy link
Owner

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?

@SunnyWind
Copy link
Author

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.

@jameslnewell
Copy link
Owner

jameslnewell commented Dec 18, 2019

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?

@SunnyWind
Copy link
Author

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...

@SunnyWind
Copy link
Author

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.

@prantlf
Copy link

prantlf commented Mar 7, 2020

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.

@jameslnewell
Copy link
Owner

@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.

@jameslnewell
Copy link
Owner

jameslnewell commented Mar 11, 2020

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

@jameslnewell jameslnewell added this to the v3 milestone Mar 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants