Skip to content
Snippets Groups Projects
Commit bd20aeb6 authored by Martin Hanzel's avatar Martin Hanzel Committed by Paul Slaughter
Browse files

Add helpers to wait for axios requests

Add two methods to the axios_utils Jest mock:

- `waitFor(url)`, which returns a Promise that resolves when the
  next request to `url` finishes.
- `waitForAll()`, which returns a Promise that resolves when all
  pending requests finish.
parent 914af2f5
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -10,21 +10,18 @@ axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.interceptors.request.use(config => {
window.activeVueResources = window.activeVueResources || 0;
window.activeVueResources += 1;
return config;
});
 
// Remove the global counter
axios.interceptors.response.use(
config => {
response => {
window.activeVueResources -= 1;
return config;
return response;
},
e => {
err => {
window.activeVueResources -= 1;
return Promise.reject(e);
return Promise.reject(err);
},
);
 
Loading
Loading
/* eslint-disable promise/catch-or-return */
import AxiosMockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
describe('axios_utils', () => {
let mock;
beforeEach(() => {
mock = new AxiosMockAdapter(axios);
mock.onAny('/ok').reply(200);
mock.onAny('/err').reply(500);
expect(axios.countActiveRequests()).toBe(0);
});
afterEach(() => axios.waitForAll().finally(() => mock.restore()));
describe('waitForAll', () => {
it('resolves if there are no requests', () => axios.waitForAll());
it('waits for all requests to finish', () => {
const handler = jest.fn();
axios.get('/ok').then(handler);
axios.get('/err').catch(handler);
return axios.waitForAll().finally(() => {
expect(handler).toHaveBeenCalledTimes(2);
expect(handler.mock.calls[0][0].status).toBe(200);
expect(handler.mock.calls[1][0].response.status).toBe(500);
});
});
});
describe('waitFor', () => {
it('waits for requests on a specific URL', () => {
const handler = jest.fn();
axios.get('/ok').finally(handler);
axios.waitFor('/err').finally(() => {
throw new Error('waitFor on /err should not be called');
});
return axios.waitFor('/ok');
});
});
});
import EventEmitter from 'events';
const axios = jest.requireActual('~/lib/utils/axios_utils').default;
 
axios.isMock = true;
Loading
Loading
@@ -13,4 +15,64 @@ axios.defaults.adapter = config => {
throw error;
};
 
// Count active requests and provide a way to wait for them
let activeRequests = 0;
const events = new EventEmitter();
const onRequest = () => {
activeRequests += 1;
};
// Use setImmediate to alloow the response interceptor to finish
const onResponse = config => {
activeRequests -= 1;
setImmediate(() => {
events.emit('response', config);
});
};
const subscribeToResponse = (predicate = () => true) =>
new Promise(resolve => {
const listener = (config = {}) => {
if (predicate(config)) {
events.off('response', listener);
resolve(config);
}
};
events.on('response', listener);
// If a request has been made synchronously, setImmediate waits for it to be
// processed and the counter incremented.
setImmediate(listener);
});
/**
* Registers a callback function to be run after a request to the given URL finishes.
*/
axios.waitFor = url => subscribeToResponse(({ url: configUrl }) => configUrl === url);
/**
* Registers a callback function to be run after all requests have finished. If there are no requests waiting, the callback is executed immediately.
*/
axios.waitForAll = () => subscribeToResponse(() => activeRequests === 0);
axios.countActiveRequests = () => activeRequests;
axios.interceptors.request.use(config => {
onRequest();
return config;
});
// Remove the global counter
axios.interceptors.response.use(
response => {
onResponse(response.config);
return response;
},
err => {
onResponse(err.config);
return Promise.reject(err);
},
);
export default axios;
Loading
Loading
@@ -49,17 +49,12 @@ describe('Old Notes (~/notes.js)', () => {
setTestTimeoutOnce(4000);
});
 
afterEach(done => {
afterEach(() => {
// The Notes component sets a polling interval. Clear it after every run.
// Make sure to use jest.runOnlyPendingTimers() instead of runAllTimers().
jest.clearAllTimers();
 
setImmediate(() => {
// Wait for any requests to resolve, otherwise we get failures about
// unmocked requests.
mockAxios.restore();
done();
});
return axios.waitForAll().finally(() => mockAxios.restore());
});
 
it('loads the Notes class into the DOM', () => {
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment