Skip to content

Commit

Permalink
test: hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
Dtesch9 committed Jul 16, 2020
1 parent f7ea1b2 commit 527cabe
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 5 deletions.
1 change: 1 addition & 0 deletions mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@babel/core": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@react-native-community/eslint-config": "^1.0.0",
"@testing-library/react-hooks": "^3.3.0",
"@types/jest": "^24.0.24",
"@types/react-native": "^0.62.0",
"@types/react-native-vector-icons": "^6.4.5",
Expand Down
187 changes: 187 additions & 0 deletions mobile/src/__tests__/hooks/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import { renderHook, act } from '@testing-library/react-hooks';
import AsyncStorage from '@react-native-community/async-storage';
import MockAdapter from 'axios-mock-adapter';

import { useAuth, AuthProvider } from '../../hooks/auth';
import api from '../../services/api';

const setItemSpy = jest.spyOn(AsyncStorage, 'setItem');
const multiSetSpy = jest.spyOn(AsyncStorage, 'multiSet');
const multiGetSpy = jest.spyOn(AsyncStorage, 'multiGet');
const multiRemoveSpy = jest.spyOn(AsyncStorage, 'multiRemove');

const mockApi = new MockAdapter(api);

describe('Auth hook', () => {
it('should be able get context', async () => {
const { result } = renderHook(() => useAuth(), {
wrapper: AuthProvider,
});

await act(async () => {
expect(result.current.user).toBeUndefined();
expect(result.current.loading).toBe(true);
expect(typeof result.current.signIn).toBe('function');
expect(typeof result.current.signOut).toBe('function');
});
});

it('should be able to sign in', async () => {
const apiResponse = {
user: {
id: 'user-id',
name: 'user-name',
email: '[email protected]',
avatar_url: 'user-avatar.png',
},
token: 'user-token',
};

mockApi.onPost('/sessions').reply(200, apiResponse);

const { result, waitForNextUpdate } = renderHook(() => useAuth(), {
wrapper: AuthProvider,
});

result.current.signIn({
email: '[email protected]',
password: 'user-password',
});

await waitForNextUpdate();

expect(result.current.user.email).toEqual('[email protected]');

expect(multiSetSpy).toHaveBeenCalledWith(
expect.arrayContaining([
['@GoBarber:token', apiResponse.token],
['@GoBarber:user', JSON.stringify(apiResponse.user)],
]),
);
});

it('should be able recover data from AsyncStorage', async () => {
const mockData = {
user: {
id: 'user-id',
name: 'user-name',
email: '[email protected]',
avatar_url: 'user-avatar.png',
},
token: 'user-token',
};

multiGetSpy.mockImplementation(
(keys: string[]): Promise<[string, string | null][]> => {
return new Promise(resolve => {
const values = keys.map(key => {
switch (key) {
case '@GoBarber:user':
return ['@GoBarber:user', JSON.stringify(mockData.user)];

case '@GoBarber:token':
return ['@GoBarber:token', JSON.stringify(mockData.token)];

default:
return [key, null];
}
});

const returningValue = values as [string, string | null][];

setTimeout(() => {
resolve(returningValue);
}, 200);
});
},
);

const { result, waitForNextUpdate } = renderHook(() => useAuth(), {
wrapper: AuthProvider,
});

await waitForNextUpdate();

expect(result.current.user).toEqual(expect.objectContaining(mockData.user));
});

it('should be able to sign out', async () => {
const mockData = {
user: {
id: 'user-id',
name: 'user-name',
email: '[email protected]',
avatar_url: 'user-avatar.png',
},
token: 'user-token',
};

multiGetSpy.mockImplementation(
(keys: string[]): Promise<[string, string | null][]> => {
return new Promise(resolve => {
const values = keys.map(key => {
switch (key) {
case '@GoBarber:user':
return ['@GoBarber:user', JSON.stringify(mockData.user)];

case '@GoBarber:token':
return ['@GoBarber:token', JSON.stringify(mockData.token)];

default:
return [key, null];
}
});

const returningValue = values as [string, string | null][];

setTimeout(() => {
resolve(returningValue);
}, 200);
});
},
);

const { result, waitForNextUpdate } = renderHook(() => useAuth(), {
wrapper: AuthProvider,
});

await waitForNextUpdate();

expect(result.current.user).toEqual(expect.objectContaining(mockData.user));

result.current.signOut();

expect(multiRemoveSpy).toHaveBeenCalledWith([
'@GoBarber:token',
'@GoBarber:user',
]);

await waitForNextUpdate();

expect(result.current.user).toBeUndefined();
});

it('should be able to sign out', async () => {
const user = {
id: 'user-id',
name: 'user-name',
email: '[email protected]',
avatar_url: 'user-avatar.png',
};

const { result, waitForNextUpdate } = renderHook(() => useAuth(), {
wrapper: AuthProvider,
});

result.current.updateUser(user);

expect(setItemSpy).toHaveBeenCalledWith(
'@GoBarber:user',
JSON.stringify(user),
);

await waitForNextUpdate();

expect(result.current.user).toEqual(expect.objectContaining(user));
});
});
4 changes: 0 additions & 4 deletions mobile/src/hooks/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,6 @@ const AuthProvider: React.FC = ({ children }) => {
function useAuth(): AuthContextData {
const context = useContext(AuthContext);

if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}

return context;
}

Expand Down
25 changes: 24 additions & 1 deletion mobile/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,13 @@
dependencies:
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.5.4":
version "7.10.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c"
integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==
dependencies:
regenerator-runtime "^0.13.4"

"@babel/template@^7.0.0", "@babel/template@^7.4.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
version "7.8.6"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
Expand Down Expand Up @@ -1090,6 +1097,14 @@
ramda "^0.26.1"
redent "^2.0.0"

"@testing-library/react-hooks@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-3.3.0.tgz#dc217bfce8e7c34a99c811d73d23feef957b7c1d"
integrity sha512-rE9geI1+HJ6jqXkzzJ6abREbeud6bLF8OmF+Vyc7gBoPwZAEVBYjbC1up5nNoVfYBhO5HUwdD4u9mTehAUeiyw==
dependencies:
"@babel/runtime" "^7.5.4"
"@types/testing-library__react-hooks" "^3.0.0"

"@types/babel__core@^7.1.0":
version "7.1.7"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89"
Expand Down Expand Up @@ -1203,7 +1218,7 @@
dependencies:
"@types/react" "*"

"@types/[email protected]":
"@types/react-test-renderer@*", "@types/react-test-renderer@16.9.2":
version "16.9.2"
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.2.tgz#e1c408831e8183e5ad748fdece02214a7c2ab6c5"
integrity sha512-4eJr1JFLIAlWhzDkBCkhrOIWOvOxcCAfQh+jiKg7l/nNZcCIL2MHl2dZhogIFKyHzedVWHaVP1Yydq/Ruu4agw==
Expand Down Expand Up @@ -1233,6 +1248,14 @@
"@types/react-native" "*"
csstype "^2.2.0"

"@types/testing-library__react-hooks@^3.0.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@types/testing-library__react-hooks/-/testing-library__react-hooks-3.2.0.tgz#52f3a109bef06080e3b1e3ae7ea1c014ce859897"
integrity sha512-dE8iMTuR5lzB+MqnxlzORlXzXyCL0EKfzH0w/lau20OpkHD37EaWjZDz0iNG8b71iEtxT4XKGmSKAGVEqk46mw==
dependencies:
"@types/react" "*"
"@types/react-test-renderer" "*"

"@types/yargs-parser@*":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
Expand Down

0 comments on commit 527cabe

Please sign in to comment.