Skip to content

Commit

Permalink
Merge e0f44bc into 8cceda7
Browse files Browse the repository at this point in the history
  • Loading branch information
swain committed Nov 7, 2023
2 parents 8cceda7 + e0f44bc commit 62eabf2
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 51 deletions.
10 changes: 6 additions & 4 deletions src/hooks/useSetUserProfileEffect.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { renderHook } from '@testing-library/react-native';
import { useUser } from './useUser';
import { useUpdateUser, useUser } from './useUser';
import { useActiveProject } from './useActiveProject';
import { useSetUserProfileEffect } from './useSetUserProfileEffect';

Expand All @@ -8,9 +8,11 @@ jest.mock('./useActiveProject', () => ({
}));
jest.mock('./useUser', () => ({
useUser: jest.fn(),
useUpdateUser: jest.fn(),
}));

const useUserMock = useUser as jest.Mock;
const useUpdateUserMock = useUpdateUser as jest.Mock;
const useActiveProjectMock = useActiveProject as jest.Mock;
const updateUser = jest.fn();

Expand All @@ -20,6 +22,9 @@ beforeEach(() => {
isLoading: true,
updateUser,
});
useUpdateUserMock.mockReturnValue({
mutate: updateUser,
});
useActiveProjectMock.mockReturnValue({});
});

Expand All @@ -32,7 +37,6 @@ test('should update the user once all hooks load and the user does not have data
isLoading: false,
isFetched: true,
data: { profile: {} },
updateUser,
});

result.rerender({});
Expand Down Expand Up @@ -65,7 +69,6 @@ test('should use the first official name', () => {
isLoading: false,
isFetched: true,
data: { profile: {} },
updateUser,
});
useActiveProjectMock.mockReturnValue({
activeSubject: {
Expand Down Expand Up @@ -103,7 +106,6 @@ test('not set the username if it is already set', () => {
familyName: 'AlreadySet',
},
},
updateUser,
});
useActiveProjectMock.mockReturnValue({
activeSubject: {
Expand Down
5 changes: 3 additions & 2 deletions src/hooks/useSetUserProfileEffect.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useEffect } from 'react';
import { useActiveProject } from './useActiveProject';
import { useUser } from './useUser';
import { useUpdateUser, useUser } from './useUser';

export const useSetUserProfileEffect = () => {
const { isLoading, isFetched, data: user, updateUser } = useUser();
const { isLoading, isFetched, data: user } = useUser();
const { mutate: updateUser } = useUpdateUser();
const { activeSubject } = useActiveProject();

useEffect(() => {
Expand Down
50 changes: 27 additions & 23 deletions src/hooks/useUser.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React from 'react';
import { renderHook, waitFor, act } from '@testing-library/react-native';
import { useAuth } from './useAuth';
import { useUser } from './useUser';
import { useUpdateUser, useUser } from './useUser';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';
import { useHttpClient } from './useHttpClient';
import { createRestAPIMock } from '../test-utils/rest-api-mocking';

const queryClient = new QueryClient({
defaultOptions: {
Expand All @@ -18,41 +16,37 @@ const queryClient = new QueryClient({
jest.mock('./useAuth', () => ({
useAuth: jest.fn(),
}));
jest.mock('./useHttpClient', () => ({
useHttpClient: jest.fn(),
}));

const useAuthMock = useAuth as jest.Mock;
const useHttpClientMock = useHttpClient as jest.Mock;

const renderHookInContext = async () => {
return renderHook(() => useUser(), {
// This second generic is required to tell the parser that it isn't
// JSX syntax
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const renderInContext = async <T, _ = never>(hook: () => T) => {
return renderHook(() => hook(), {
wrapper: ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
),
});
};

const axiosInstance = axios.create();
const axiosMock = new MockAdapter(axiosInstance);
const api = createRestAPIMock();

beforeEach(() => {
useAuthMock.mockReturnValue({
authResult: { accessToken: 'accessToken' },
});
useHttpClientMock.mockReturnValue({ httpClient: axiosInstance });
});

test('fetches and parses user', async () => {
const userProfile = { id: 'id', profile: {} };
axiosMock.onGet('/v1/user').reply(200, userProfile);
const { result } = await renderHookInContext();
api.mock('GET /v1/user', { status: 200, data: userProfile });
const { result } = await renderInContext(() => useUser());
await waitFor(() => result.current.isSuccess);
expect(axiosMock.history.get[0].url).toBe('/v1/user');
await waitFor(() => expect(result.current.data).toEqual(userProfile));
});

test('can update a user', async () => {
test('useUpdateUser can update a user', async () => {
const userProfile = { id: 'id', profile: { email: 'email' } };
const updatedProfile = {
...userProfile,
Expand All @@ -61,15 +55,25 @@ test('can update a user', async () => {
familyName: 'test',
},
};
axiosMock.onGet('/v1/user').reply(200, userProfile);
axiosMock.onPatch('/v1/user').reply(200, updatedProfile);
api.mock('GET /v1/user', { status: 200, data: userProfile });
api.mock('PATCH /v1/user', { status: 200, data: updatedProfile });

const { result } = await renderHookInContext();
const { result } = await renderInContext(() => {
const query = useUser();
const mutation = useUpdateUser();

await waitFor(() => result.current.isSuccess);
return {
data: query.data,
mutate: mutation.mutate,
};
});

await waitFor(() => {
expect(result.current.data).toStrictEqual(userProfile);
});

await act(async () => {
await result.current.updateUser({
act(() => {
result.current.mutate({
profile: {
familyName: 'test',
},
Expand Down
34 changes: 12 additions & 22 deletions src/hooks/useUser.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useHttpClient } from './useHttpClient';
import { useAuth } from './useAuth';
import { useRestMutation } from './rest-api';
import { User } from '../types';
import { useRestCache, useRestMutation, useRestQuery } from './rest-api';

export function useUser() {
const { authResult } = useAuth();
const client = useQueryClient();
const { httpClient } = useHttpClient();

const result = useQuery(
['user'],
() => httpClient.get<User>('/v1/user').then((res) => res.data),
{
enabled: !!authResult?.accessToken,
},
return useRestQuery(
'GET /v1/user',
{},
{ enabled: !!authResult?.accessToken },
);
}

const { mutateAsync: updateUser } = useRestMutation('PATCH /v1/user', {
onSuccess: (updatedUser) => {
client.setQueryData(['user'], () => updatedUser);
export const useUpdateUser = () => {
const cache = useRestCache();
return useRestMutation('PATCH /v1/user', {
onSuccess: (user) => {
cache.updateCache('GET /v1/user', {}, user);
},
});

return {
...result,
updateUser,
};
}
};
5 changes: 5 additions & 0 deletions src/types/rest-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export type RestAPIEndpoints = FhirAPIEndpoints & {
};
};

'GET /v1/user': {
Request: {};
Response: User;
};

'GET /v1/features': {
Request: {
project?: string;
Expand Down

0 comments on commit 62eabf2

Please sign in to comment.