[NEW] Create useEndpointData for call endpoints using hooks (#4342)
* create basic useEndpointData for call endpoints using hooks * remove cache * create base for useEndpointData test * create basic useEndpointData for call endpoints using hooks * remove cache * create base for useEndpointData test * fix preset * update tests * change order * create ErrorResult and add error to return * update tests
This commit is contained in:
parent
2b08b683d7
commit
89820b2bec
|
@ -91,3 +91,5 @@ export type ResultFor<TMethod extends Method, TPathPattern extends PathPattern>
|
|||
| SuccessResult<OperationResult<TMethod, TPathPattern>>
|
||||
| FailureResult<unknown, unknown, unknown, unknown>
|
||||
| UnauthorizedResult<unknown>;
|
||||
|
||||
export type ErrorResult = FailureResult<unknown, unknown, unknown, unknown>;
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { render, waitFor } from '@testing-library/react-native';
|
||||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
|
||||
import { useEndpointData } from './useEndpointData';
|
||||
import sdk from '../services/sdk';
|
||||
|
||||
const url = 'chat.getMessage';
|
||||
|
||||
export const message = {
|
||||
_id: '9tYkmJ67wMwmvQouD',
|
||||
t: 'uj',
|
||||
rid: 'GENERAL',
|
||||
ts: '2022-07-05T19:34:30.146Z',
|
||||
msg: 'xdani',
|
||||
u: {
|
||||
_id: 'ombax8oEZnE7N3Mtt',
|
||||
username: 'xdani',
|
||||
name: 'xdani'
|
||||
},
|
||||
groupable: false,
|
||||
_updatedAt: '2022-07-05T19:34:30.146Z'
|
||||
};
|
||||
|
||||
// mock sdk
|
||||
jest.mock('../services/sdk', () => ({
|
||||
get: jest.fn(() => new Promise(resolve => setTimeout(() => resolve({ success: true, message }), 1000)))
|
||||
}));
|
||||
|
||||
function Render() {
|
||||
const { loading } = useEndpointData(url, { msgId: message._id });
|
||||
if (loading) {
|
||||
return (
|
||||
<View>
|
||||
<Text testID='loading'>loading</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<View>
|
||||
<Text testID='load complete'>load complete</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
describe('useFetch', () => {
|
||||
it('should return data after fetch', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useEndpointData(url, { msgId: message._id }));
|
||||
expect(result.current.loading).toEqual(true);
|
||||
expect(result.current.result).toEqual(undefined);
|
||||
await waitForNextUpdate();
|
||||
expect(result.current.loading).toEqual(false);
|
||||
expect(result.current.result).toEqual({ success: true, message });
|
||||
});
|
||||
|
||||
it('should component load correctly', async () => {
|
||||
const renderComponent = render(<Render />);
|
||||
const loading = await renderComponent.findByTestId('loading');
|
||||
expect(loading.props.children).toBe('loading');
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(renderComponent.getByText('load complete')).toBeTruthy();
|
||||
},
|
||||
{ timeout: 2000 }
|
||||
);
|
||||
});
|
||||
|
||||
it('should return error after fetch', async () => {
|
||||
const spy = jest
|
||||
.spyOn(sdk, 'get')
|
||||
.mockImplementation(
|
||||
jest.fn(() => new Promise(resolve => setTimeout(() => resolve({ success: false, error: null }), 1000)))
|
||||
);
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() => useEndpointData(url, { msgId: message._id }));
|
||||
expect(result.current.loading).toEqual(true);
|
||||
expect(result.current.result).toEqual(undefined);
|
||||
expect(result.current.error).toEqual(undefined);
|
||||
await waitForNextUpdate();
|
||||
expect(result.current.loading).toEqual(false);
|
||||
expect(result.current.result).toEqual(undefined);
|
||||
expect(result.current.error).toEqual({ success: false, error: null });
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,62 @@
|
|||
import isEqual from 'lodash/isEqual';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { ErrorResult, MatchPathPattern, OperationParams, PathFor, ResultFor, Serialized } from '../../definitions/rest/helpers';
|
||||
import sdk from '../services/sdk';
|
||||
|
||||
export const useEndpointData = <TPath extends PathFor<'GET'>>(
|
||||
endpoint: TPath,
|
||||
params: void extends OperationParams<'GET', MatchPathPattern<TPath>>
|
||||
? void
|
||||
: Serialized<OperationParams<'GET', MatchPathPattern<TPath>>> = undefined as void extends OperationParams<
|
||||
'GET',
|
||||
MatchPathPattern<TPath>
|
||||
>
|
||||
? void
|
||||
: Serialized<OperationParams<'GET', MatchPathPattern<TPath>>>
|
||||
): {
|
||||
result: Serialized<ResultFor<'GET', MatchPathPattern<TPath>>> | undefined;
|
||||
loading: boolean;
|
||||
reload: Function;
|
||||
error: ErrorResult | undefined;
|
||||
} => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [result, setResult] = useState<Serialized<ResultFor<'GET', MatchPathPattern<TPath>>> | undefined>();
|
||||
const [error, setError] = useState<ErrorResult | undefined>();
|
||||
|
||||
const paramsRef = useRef(params);
|
||||
|
||||
if (!isEqual(paramsRef.current, params)) {
|
||||
paramsRef.current = params;
|
||||
}
|
||||
|
||||
const fetchData = useCallback(() => {
|
||||
if (!endpoint) return;
|
||||
setLoading(true);
|
||||
sdk
|
||||
.get(endpoint, params)
|
||||
.then(e => {
|
||||
setLoading(false);
|
||||
if (e.success) {
|
||||
setResult(e);
|
||||
} else {
|
||||
setError(e as ErrorResult);
|
||||
}
|
||||
})
|
||||
.catch((e: ErrorResult) => {
|
||||
setLoading(false);
|
||||
setError(e);
|
||||
});
|
||||
}, [paramsRef.current]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
return {
|
||||
result,
|
||||
loading,
|
||||
reload: fetchData,
|
||||
error
|
||||
};
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
const jestRN = require('react-native/jest-preset');
|
||||
const jestRN = require('@testing-library/react-native/jest-preset/index.js');
|
||||
const jestExpo = require('jest-expo/jest-preset.js');
|
||||
|
||||
module.exports = {
|
||||
|
|
|
@ -154,6 +154,7 @@
|
|||
"@storybook/addon-storyshots": "5.3.21",
|
||||
"@storybook/react-native": "5.3.25",
|
||||
"@testing-library/jest-native": "^4.0.4",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@testing-library/react-native": "^9.0.0",
|
||||
"@types/bytebuffer": "^5.0.43",
|
||||
"@types/ejson": "^2.1.3",
|
||||
|
|
15
yarn.lock
15
yarn.lock
|
@ -5314,6 +5314,14 @@
|
|||
ramda "^0.26.1"
|
||||
redent "^2.0.0"
|
||||
|
||||
"@testing-library/react-hooks@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12"
|
||||
integrity sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
react-error-boundary "^3.1.0"
|
||||
|
||||
"@testing-library/react-native@^9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react-native/-/react-native-9.0.0.tgz#e9c63411e93d2e8e70d744b12aeb78c58025c5fc"
|
||||
|
@ -16424,6 +16432,13 @@ react-draggable@^4.0.3:
|
|||
classnames "^2.2.5"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-error-boundary@^3.1.0:
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
|
||||
integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
|
||||
react-error-overlay@^6.0.3:
|
||||
version "6.0.9"
|
||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
||||
|
|
Loading…
Reference in New Issue