fix useRequest error bug

This commit is contained in:
Keith Grant
2020-03-12 17:08:21 -07:00
parent eea80c45d1
commit ac9f526cf0
3 changed files with 174 additions and 89 deletions

View File

@@ -34,7 +34,7 @@ export function getQSConfig(
*/ */
export function parseQueryString(config, queryString) { export function parseQueryString(config, queryString) {
if (!queryString) { if (!queryString) {
return config.defaultParams; return config.defaultParams || {};
} }
const params = stringToObject(config, queryString); const params = stringToObject(config, queryString);
return addDefaultsToObject(config, params); return addDefaultsToObject(config, params);

View File

@@ -70,8 +70,10 @@ export function useDismissableError(error) {
}, [error]); }, [error]);
return { return {
error: showError && error, error: showError ? error : null,
dismissError: () => setShowError(false), dismissError: () => {
setShowError(false);
},
}; };
} }
@@ -81,7 +83,10 @@ export function useDeleteItems(
) { ) {
const location = useLocation(); const location = useLocation();
const history = useHistory(); const history = useHistory();
const { requestError, isLoading, request } = useRequest(makeRequest, null); const { error: requestError, isLoading, request } = useRequest(
makeRequest,
null
);
const { error, dismissError } = useDismissableError(requestError); const { error, dismissError } = useDismissableError(requestError);
const deleteItems = async () => { const deleteItems = async () => {

View File

@@ -1,7 +1,8 @@
import React from 'react'; import React from 'react';
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
import { mount } from 'enzyme'; import { mount } from 'enzyme';
import useRequest from './useRequest'; import { mountWithContexts } from '@testUtils/enzymeHelpers';
import useRequest, { useDeleteItems } from './useRequest';
function TestInner() { function TestInner() {
return <div />; return <div />;
@@ -10,100 +11,179 @@ function Test({ makeRequest, initialValue = {} }) {
const request = useRequest(makeRequest, initialValue); const request = useRequest(makeRequest, initialValue);
return <TestInner {...request} />; return <TestInner {...request} />;
} }
function DeleteTest({ makeRequest, args = {} }) {
const request = useDeleteItems(makeRequest, args);
return <TestInner {...request} />;
}
describe('useRequest', () => { describe('useRequest hooks', () => {
test('should return initial value as result', async () => { describe('useRequest', () => {
const makeRequest = jest.fn(); test('should return initial value as result', async () => {
makeRequest.mockResolvedValue({ data: 'foo' }); const makeRequest = jest.fn();
const wrapper = mount( makeRequest.mockResolvedValue({ data: 'foo' });
<Test const wrapper = mount(
makeRequest={makeRequest} <Test
initialValue={{ makeRequest={makeRequest}
initial: true, initialValue={{
}} initial: true,
/> }}
); />
);
expect(wrapper.find('TestInner').prop('result')).toEqual({ initial: true }); expect(wrapper.find('TestInner').prop('result')).toEqual({
initial: true,
});
});
test('should return result', async () => {
const makeRequest = jest.fn();
makeRequest.mockResolvedValue({ data: 'foo' });
const wrapper = mount(<Test makeRequest={makeRequest} />);
await act(async () => {
wrapper.find('TestInner').invoke('request')();
});
wrapper.update();
expect(wrapper.find('TestInner').prop('result')).toEqual({ data: 'foo' });
});
test('should is isLoading flag', async () => {
const makeRequest = jest.fn();
let resolve;
const promise = new Promise(r => {
resolve = r;
});
makeRequest.mockReturnValue(promise);
const wrapper = mount(<Test makeRequest={makeRequest} />);
await act(async () => {
wrapper.find('TestInner').invoke('request')();
});
wrapper.update();
expect(wrapper.find('TestInner').prop('isLoading')).toEqual(true);
await act(async () => {
resolve({ data: 'foo' });
});
wrapper.update();
expect(wrapper.find('TestInner').prop('isLoading')).toEqual(false);
expect(wrapper.find('TestInner').prop('result')).toEqual({ data: 'foo' });
});
test('should invoke request function', async () => {
const makeRequest = jest.fn();
makeRequest.mockResolvedValue({ data: 'foo' });
const wrapper = mount(<Test makeRequest={makeRequest} />);
expect(makeRequest).not.toHaveBeenCalled();
await act(async () => {
wrapper.find('TestInner').invoke('request')();
});
wrapper.update();
expect(makeRequest).toHaveBeenCalledTimes(1);
});
test('should return error thrown from request function', async () => {
const error = new Error('error');
const makeRequest = () => {
throw error;
};
const wrapper = mount(<Test makeRequest={makeRequest} />);
await act(async () => {
wrapper.find('TestInner').invoke('request')();
});
wrapper.update();
expect(wrapper.find('TestInner').prop('error')).toEqual(error);
});
test('should not update state after unmount', async () => {
const makeRequest = jest.fn();
let resolve;
const promise = new Promise(r => {
resolve = r;
});
makeRequest.mockReturnValue(promise);
const wrapper = mount(<Test makeRequest={makeRequest} />);
expect(makeRequest).not.toHaveBeenCalled();
await act(async () => {
wrapper.find('TestInner').invoke('request')();
});
wrapper.unmount();
await act(async () => {
resolve({ data: 'foo' });
});
});
}); });
test('should return result', async () => { describe('useDeleteItems', () => {
const makeRequest = jest.fn(); test('should invoke delete function', async () => {
makeRequest.mockResolvedValue({ data: 'foo' }); const makeRequest = jest.fn();
const wrapper = mount(<Test makeRequest={makeRequest} />); makeRequest.mockResolvedValue({ data: 'foo' });
const wrapper = mountWithContexts(
<DeleteTest
makeRequest={makeRequest}
args={{
qsConfig: {},
fetchItems: () => {},
}}
/>
);
await act(async () => { expect(makeRequest).not.toHaveBeenCalled();
wrapper.find('TestInner').invoke('request')(); await act(async () => {
wrapper.find('TestInner').invoke('deleteItems')();
});
wrapper.update();
expect(makeRequest).toHaveBeenCalledTimes(1);
}); });
wrapper.update();
expect(wrapper.find('TestInner').prop('result')).toEqual({ data: 'foo' });
});
test('should is isLoading flag', async () => { test('should return error object thrown by function', async () => {
const makeRequest = jest.fn(); const error = new Error('error');
let resolve; const makeRequest = () => {
const promise = new Promise(r => { throw error;
resolve = r; };
const wrapper = mountWithContexts(
<DeleteTest
makeRequest={makeRequest}
args={{
qsConfig: {},
fetchItems: () => {},
}}
/>
);
await act(async () => {
wrapper.find('TestInner').invoke('deleteItems')();
});
wrapper.update();
expect(wrapper.find('TestInner').prop('deletionError')).toEqual(error);
}); });
makeRequest.mockReturnValue(promise);
const wrapper = mount(<Test makeRequest={makeRequest} />);
await act(async () => { test('should dismiss error', async () => {
wrapper.find('TestInner').invoke('request')(); const error = new Error('error');
}); const makeRequest = () => {
wrapper.update(); throw error;
expect(wrapper.find('TestInner').prop('isLoading')).toEqual(true); };
await act(async () => { const wrapper = mountWithContexts(
resolve({ data: 'foo' }); <DeleteTest
}); makeRequest={makeRequest}
wrapper.update(); args={{
expect(wrapper.find('TestInner').prop('isLoading')).toEqual(false); qsConfig: {},
expect(wrapper.find('TestInner').prop('result')).toEqual({ data: 'foo' }); fetchItems: () => {},
}); }}
/>
);
test('should invoke request function', async () => { await act(async () => {
const makeRequest = jest.fn(); wrapper.find('TestInner').invoke('deleteItems')();
makeRequest.mockResolvedValue({ data: 'foo' }); });
const wrapper = mount(<Test makeRequest={makeRequest} />); wrapper.update();
await act(async () => {
expect(makeRequest).not.toHaveBeenCalled(); wrapper.find('TestInner').invoke('clearDeletionError')();
await act(async () => { });
wrapper.find('TestInner').invoke('request')(); wrapper.update();
}); expect(wrapper.find('TestInner').prop('deletionError')).toEqual(null);
wrapper.update();
expect(makeRequest).toHaveBeenCalledTimes(1);
});
test('should return error thrown from request function', async () => {
const error = new Error('error');
const makeRequest = () => {
throw error;
};
const wrapper = mount(<Test makeRequest={makeRequest} />);
await act(async () => {
wrapper.find('TestInner').invoke('request')();
});
wrapper.update();
expect(wrapper.find('TestInner').prop('error')).toEqual(error);
});
test('should not update state after unmount', async () => {
const makeRequest = jest.fn();
let resolve;
const promise = new Promise(r => {
resolve = r;
});
makeRequest.mockReturnValue(promise);
const wrapper = mount(<Test makeRequest={makeRequest} />);
expect(makeRequest).not.toHaveBeenCalled();
await act(async () => {
wrapper.find('TestInner').invoke('request')();
});
wrapper.unmount();
await act(async () => {
resolve({ data: 'foo' });
}); });
}); });
}); });