From 99216e5fec8a10c3868cb7f911265eaea1faddda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Stani=C3=B3w?= Date: Mon, 5 Feb 2018 22:11:52 +0100 Subject: [PATCH] test(Auth): Fix UTs for Auth --- src/matches/matches.sagas.test.js | 14 +-- src/settings/settings.sagas.test.js | 31 ++---- src/shared/auth/auth.sagas.test.js | 112 ++----------------- src/test/auth.sagas.test.js | 160 ++++++++++++++++++++++++++++ src/test/settings.sagas.test.js | 81 ++++++++++++++ 5 files changed, 262 insertions(+), 136 deletions(-) create mode 100644 src/test/auth.sagas.test.js create mode 100644 src/test/settings.sagas.test.js diff --git a/src/matches/matches.sagas.test.js b/src/matches/matches.sagas.test.js index b7c3fb6..70f3acf 100644 --- a/src/matches/matches.sagas.test.js +++ b/src/matches/matches.sagas.test.js @@ -3,8 +3,9 @@ import api from '../api/index'; import * as MatchActions from './match.actions'; import * as MatchTypes from './match.types'; import { raiseError, showInfo } from '../shared/notifier.actions'; -import { publish, removeMatch, listMatches, stateTeamsSelectedSelector } from './matches.sagas'; +import { publish, removeMatch, listMatches } from './matches.sagas'; import { fetchUpdateUsers } from '../users/users.sagas'; +import { getSelectedTeamId } from "../teams/teams.reducer"; describe('Publish match saga', () => { @@ -36,7 +37,8 @@ describe('Publish match saga', () => { }); it('should select team id', () => { - expect(JSON.stringify(iterator.next(MatchActions.publish(matchData, callback)).value)).toEqual(JSON.stringify(select(() => 1))); + const iter = iterator.next(MatchActions.publish(matchData, callback)).value; + expect(iter).toEqual(select(getSelectedTeamId)); }); it('should call api to publish match', () => { @@ -87,8 +89,8 @@ describe('Publish match saga', () => { }); it('should select team id', () => { - const iter = JSON.stringify(iterator.next(MatchActions.publish(matchData, callback)).value); - expect(iter).toEqual(JSON.stringify(select(() => currentTeamId))); + const iter = iterator.next(MatchActions.publish(matchData, callback)).value; + expect(iter).toEqual(select(getSelectedTeamId)); }); it('should call api to publish match', () => { @@ -175,7 +177,7 @@ describe('ListMatches saga', () => { const iterator = listMatches(params); it('should select team selected from store', () => { - expect(iterator.next(currentTeamId).value).toEqual(select(stateTeamsSelectedSelector)); + expect(iterator.next(currentTeamId).value).toEqual(select(getSelectedTeamId)); }); it('should call fetch data from API', () => { expect(iterator.next(currentTeamId).value).toEqual(call(api.requests.get, url, params, errorMsg)); @@ -192,7 +194,7 @@ describe('ListMatches saga', () => { const iterator = listMatches(params); it('should select team selected from store', () => { - expect(iterator.next(currentTeamId).value).toEqual(select(stateTeamsSelectedSelector)); + expect(iterator.next(currentTeamId).value).toEqual(select(getSelectedTeamId)); }); it('should call fetch data from API', () => { expect(iterator.next(currentTeamId).value).toEqual(call(api.requests.get, url, params, errorMsg)); diff --git a/src/settings/settings.sagas.test.js b/src/settings/settings.sagas.test.js index efdc98d..0a1d50e 100644 --- a/src/settings/settings.sagas.test.js +++ b/src/settings/settings.sagas.test.js @@ -1,35 +1,16 @@ -import { call, put, takeLatest, select } from 'redux-saga/effects'; +import { call, put, select } from 'redux-saga/effects'; import api from '../api/index'; -import { showInfo } from '../shared/notifier.actions'; -import { - saveSettings, onRequestSaveSettings, validateMember -} from './settings.sagas'; +import { showInfo } from '../shared/notifier.actions'; +import { saveSettings, validateMember } from './settings.sagas'; import { settingsSaved } from './settings.actions'; import { browserHistory } from 'react-router' - -import { - REQUEST_SAVE_SETTINGS, - requestSaveSettings, -} from './settings.actions'; +import { requestSaveSettings } from './settings.actions'; import { getSelectedTeam } from "../teams/teams.reducer"; - -describe('onRequestSaveSettings saga', () => { - const iterator = onRequestSaveSettings(); - - it('should take latest REQUEST_SAVE_SETTINGS', () => { - expect(iterator.next().value).toEqual(takeLatest(REQUEST_SAVE_SETTINGS, saveSettings)); - }); - - it('should return from the saga', () => { - expect(iterator.next().done).toBe(true); - }); -}); - describe('Save settings saga', () => { - const settings = { first_name: 'ABC', last_name: '123', username: 'ABC123', hidden: true}; - const currentTeam = { id: 1, member_id: 15, }; + const settings = {first_name: 'ABC', last_name: '123', username: 'ABC123', hidden: true}; + const currentTeam = {id: 1, member_id: 15,}; const successMsg = 'Your settings were saved'; const errorMsg = 'Failed to save settings'; diff --git a/src/shared/auth/auth.sagas.test.js b/src/shared/auth/auth.sagas.test.js index 5a7ed56..5024e91 100644 --- a/src/shared/auth/auth.sagas.test.js +++ b/src/shared/auth/auth.sagas.test.js @@ -4,7 +4,7 @@ import { prepareWindow } from '../../api/oauth'; import api from '../../api/index'; import * as AuthActions from './auth.actions'; import { clean, raiseError } from '../notifier.actions'; -import { authenticate, loginFlow, signIn, fetchProfile } from './auth.sagas'; +import { authenticate, onSignIn, fetchProfile } from './auth.sagas'; import { getOAuthErrorMsg } from './auth.utils'; import { fetchTeams, initTeam } from '../../teams/teams.sagas'; import { removeState } from '../../persistence'; @@ -34,7 +34,7 @@ describe('Authenticate saga', () => { it('should return token and complete', () => { const iter = iterator.next(fixture.token).value; - expect(iter).toEqual(fixture); + expect(iter).toEqual(fixture.token); expect(iterator.next().done).toEqual(true); }); }); @@ -78,7 +78,7 @@ describe('Authenticate saga', () => { it('should complete', () => { const iter = iterator.next('some-token').value; - expect(iter).toEqual({}); + expect(iter).toEqual(''); expect(iterator.next().done).toEqual(true); }); }); @@ -87,22 +87,18 @@ describe('Authenticate saga', () => { describe('SignIn saga', () => { describe('Scenario 1: Typical [Success]', () => { - const iterator = signIn(); + const iterator = onSignIn(); const fixtureTeam = { id: 1, member_id: 7, }; - it('should wait for action SIGN_IN', () => { - expect(iterator.next(AuthActions.signIn()).value).toEqual(take(AuthActions.signIn().type)); - }); - it('should call Authenticate saga', () => { expect(iterator.next().value).toEqual(call(authenticate)); }); it('should call FetchTeams saga', () => { - expect(iterator.next().value).toEqual(call(fetchTeams)); + expect(iterator.next('token').value).toEqual(call(fetchTeams)); }); it('should call InitTeam saga', () => { @@ -120,17 +116,14 @@ describe('SignIn saga', () => { }); describe('Scenario 2: User not assigned to any team', () => { - const iterator = signIn(); - it('should wait for action SIGN_IN', () => { - expect(iterator.next(AuthActions.signIn()).value).toEqual(take(AuthActions.signIn().type)); - }); + const iterator = onSignIn(); it('should call Authenticate saga', () => { expect(iterator.next().value).toEqual(call(authenticate)); }); it('should call FetchTeams saga', () => { - expect(iterator.next().value).toEqual(call(fetchTeams)); + expect(iterator.next('token').value).toEqual(call(fetchTeams)); }); it('should call InitTeam saga', () => { @@ -144,97 +137,6 @@ describe('SignIn saga', () => { }); -describe('LoginFlow saga', () => { - describe('Scenario 1: Typical success', () => { - const iterator = loginFlow(); - let signInSaga; - it('should fork SignIn saga', () => { - signInSaga = fork(signIn); - expect(iterator.next().value).toEqual(signInSaga); - }); - - it('should wait for SIGN_OUT action', () => { - expect(iterator.next(createMockTask()).value).toEqual(take(AuthActions.signOut().type)); - }); - - it('should cancel SignIn saga', () => { - expect(JSON.stringify(iterator.next().value)).toEqual(JSON.stringify(cancel(createMockTask()))); - }); - - it('should call API sign out', () => { - const logout_url = api.urls.logout(); - const expected = call(api.requests.get, logout_url, null, 'Failed to sign out. Please try again.'); - expect(iterator.next().value).toEqual(expected) - }); - - it('should dispatch SIGNED_OUT action', () => { - expect(iterator.next().value).toEqual(put(AuthActions.signedOut())); - }); - - it('should clean notifications', () => { - expect(iterator.next().value).toEqual(put(clean())); - }); - - it('should clean localStorage', () => { - expect(iterator.next().value).toEqual(call(removeState)); - }); - - it('should redirect to home page', () => { - expect(iterator.next().value).toEqual(call([browserHistory, browserHistory.push], '/')); - }); - - it('should not complete the saga', () => { - expect(iterator.next().done).toEqual(false); // Fork signIn again - }); - }); - - describe('Scenario 2: Failed to sign out', () => { - const iterator = loginFlow(); - const error_msg = 'Failed to sign out. Please try again.'; - let signInSaga; - it('should fork SignIn saga', () => { - signInSaga = fork(signIn); - expect(iterator.next().value).toEqual(signInSaga); - }); - - it('should wait for SIGN_OUT action', () => { - expect(iterator.next(createMockTask()).value).toEqual(take(AuthActions.signOut().type)); - }); - - it('should cancel SignIn saga', () => { - expect(JSON.stringify(iterator.next().value)).toEqual(JSON.stringify(cancel(createMockTask()))); - }); - - it('should call API sign out', () => { - const logout_url = api.urls.logout(); - const expected = call(api.requests.get, logout_url, null, error_msg); - expect(iterator.next().value).toEqual(expected) - }); - - it('should dispatch SIGNED_OUT action', () => { - expect(iterator.next().value).toEqual(put(AuthActions.signedOut())); - }); - - it('should clean notifications', () => { - expect(iterator.next().value).toEqual(put(clean())); - }); - - it('should clean localStorage', () => { - expect(iterator.next().value).toEqual(call(removeState)); - }); - - it('should redirect to home page', () => { - expect(iterator.next().value).toEqual(call([browserHistory, browserHistory.push], '/')); - }); - - it('should restart the saga', () => { - const iter = iterator.next(); - expect(iter.done).toEqual(false); - expect(iter.value).toEqual(fork(signIn)); - }) - }) -}); - describe('Fetch profile saga', () => { const team = {id: 1, member_id: 7}; const iterator = fetchProfile(team.id, team.member_id); diff --git a/src/test/auth.sagas.test.js b/src/test/auth.sagas.test.js new file mode 100644 index 0000000..25aee35 --- /dev/null +++ b/src/test/auth.sagas.test.js @@ -0,0 +1,160 @@ +import { call, put, take, select, fork, cancel } from 'redux-saga/effects'; +import { createMockTask } from 'redux-saga/utils'; +import { prepareWindow } from '../api/oauth'; +import api from '../api'; +import * as AuthActions from '../shared/auth/auth.actions'; +import { clean, raiseError } from '../shared/notifier.actions'; +import { authenticate, onSignIn, onSignOut, fetchProfile } from '../shared/auth/auth.sagas'; +import { getOAuthErrorMsg } from '../shared/auth/auth.utils'; +import { fetchTeams, initTeam } from '../teams/teams.sagas'; +import { removeState } from '../persistence'; +import { browserHistory } from 'react-router' +import { getToken } from "../shared/auth/auth.reducer"; + + +describe('Authenticate saga', () => { + describe('Scenario 1: OAuth window - success', () => { + const iterator = authenticate(); + const fixture = { token: 'some_token_value' }; + + it('should check if token exists', () => { + const iter = iterator.next().value; + expect(iter).toEqual(select(getToken)); + }); + + it('should yield an effect call([promptWindow, open])', () => { + const promptWindow = prepareWindow(); + const iter1 = iterator.next().value; + const call1 = call([promptWindow, promptWindow.open]); + expect(JSON.stringify(iter1)).toEqual(JSON.stringify(call1)); + }); + + it('should yield an effect put(setToken(token))', () => { + expect(iterator.next(fixture).value).toEqual(put(AuthActions.setToken(fixture.token))); + }); + + it('should return token and complete', () => { + const iter = iterator.next(fixture.token).value; + expect(iter).toEqual(fixture.token); + expect(iterator.next().done).toEqual(true); + }); + }); + + describe('Scenario 2: OAuth window - already authenticated', () => { + const iterator = authenticate(); + const fixture = { token: 'some_token_value' }; + + it('should check if token exists', () => { + const iter = iterator.next(fixture).value; + expect(iter).toEqual(select(getToken)); + }); + + it('should return token and complete', () => { + const iter = iterator.next(fixture.token).value; + expect(iter).toEqual(fixture); + expect(iterator.next().done).toEqual(true); + }); + }); + + describe('Scenario 3: OAuth window - failure scenario', () => { + const iterator = authenticate(); + const fixture = { error: 'failure' }; + + it('should check if token exists', () => { + const iter = iterator.next(fixture).value; + expect(iter).toEqual(select(getToken)); + }); + + it('should yield an effect call([promptWindow, open])', () => { + const promptWindow = prepareWindow(); + const iter = iterator.next().value; + const called = call([promptWindow, promptWindow.open]); + expect(JSON.stringify(iter)).toEqual(JSON.stringify(called)); + }); + + it('should yield an effect put(raiseError(errorMsg))', () => { + const errorMsg = getOAuthErrorMsg(fixture); + expect(iterator.throw(fixture).value).toEqual(put(raiseError(errorMsg))); + }); + + it('should complete', () => { + const iter = iterator.next('some-token').value; + expect(iter).toEqual(''); + expect(iterator.next().done).toEqual(true); + }); + }); +}); + + +describe('SignIn saga', () => { + describe('Scenario 1: Typical [Success]', () => { + const iterator = onSignIn(); + const fixtureTeam = { + id: 1, + member_id: 7, + }; + + it('should call Authenticate saga', () => { + expect(iterator.next().value).toEqual(call(authenticate)); + }); + + it('should call FetchTeams saga', () => { + expect(iterator.next('token').value).toEqual(call(fetchTeams)); + }); + + it('should call InitTeam saga', () => { + expect(iterator.next().value).toEqual(call(initTeam)); + }); + + it('should call FetchProfile saga', () => { + expect(iterator.next(fixtureTeam).value).toEqual(call(fetchProfile, fixtureTeam.id, fixtureTeam.member_id)); + }); + + it('should navigate to root and finish', () => { + expect(iterator.next().value).toEqual(call([browserHistory, browserHistory.push], `/match`)); + expect(iterator.next().done).toEqual(true); + }); + }); + + describe('Scenario 2: User not assigned to any team', () => { + const iterator = onSignIn(); + + it('should call Authenticate saga', () => { + expect(iterator.next().value).toEqual(call(authenticate)); + }); + + it('should call FetchTeams saga', () => { + expect(iterator.next('token').value).toEqual(call(fetchTeams)); + }); + + it('should call InitTeam saga', () => { + expect(iterator.next().value).toEqual(call(initTeam)); + }); + + it('should return from saga', () => { + expect(iterator.next().done).toEqual(true); + }); + }); +}); + +describe('Fetch profile saga', () => { + const team = {id: 1, member_id: 7}; + const iterator = fetchProfile(team.id, team.member_id); + const profile_url = api.urls.teamMemberEntity(team.id, team.member_id); + const profile = { username: 'Heniek' }; + + it('should fetch profile from API', () => { + const iter = iterator.next().value; + expect(iter).toEqual(call(api.requests.get, profile_url, {}, 'Failed to load user profile')); + }); + + it('should set profile in store', () => { + const iter = iterator.next(profile).value; + expect(iter).toEqual(put(AuthActions.setProfile(profile))); + }); + + it('should return from saga', () => { + const iter = iterator.next(); + expect(iter.done).toEqual(true); + }); +}); diff --git a/src/test/settings.sagas.test.js b/src/test/settings.sagas.test.js new file mode 100644 index 0000000..413f360 --- /dev/null +++ b/src/test/settings.sagas.test.js @@ -0,0 +1,81 @@ +import { call, put, takeLatest, select } from 'redux-saga/effects'; +import api from '../api'; +import { showInfo } from '../shared/notifier.actions'; +import { saveSettings, validateMember } from '../settings/settings.sagas'; +import { settingsSaved } from '../settings/settings.actions'; +import { browserHistory } from 'react-router' + +import { + REQUEST_SAVE_SETTINGS, + requestSaveSettings, +} from '../settings/settings.actions'; +import { getSelectedTeam } from "../teams/teams.reducer"; + + +describe('Save settings saga', () => { + const settings = {first_name: 'ABC', last_name: '123', username: 'ABC123', hidden: true}; + const currentTeam = {id: 1, member_id: 15,}; + const successMsg = 'Your settings were saved'; + const errorMsg = 'Failed to save settings'; + + + describe('Scenario 1: Should save settings', () => { + const action = requestSaveSettings({}, settings); + const iterator = saveSettings(action); + const memberUrl = api.urls.teamMemberEntity(currentTeam.id, currentTeam.member_id); + + it('should get current team', () => { + expect(iterator.next().value).toEqual(select(getSelectedTeam)); + }); + + it('should call API with PATCH request to save profile', () => { + const iter = iterator.next(currentTeam).value; + expect(iter).toEqual(call(api.requests.patch, memberUrl, action.values, errorMsg)) + }); + + it('should show info about success', () => { + expect(iterator.next().value).toEqual(put(showInfo(successMsg))); + }); + + it('should dispatch action SETTINGS_SAVED', () => { + expect(iterator.next().value).toEqual(put(settingsSaved(action.values))); + }); + + it('should redir to new profile url', () => { + const expected = call([browserHistory, browserHistory.push], '/profile/ABC123/settings'); + expect(iterator.next().value).toEqual(expected); + }); + }); +}); + +describe('Validate member profile data', () => { + it('should return data when username has length >=3', () => { + const validData = { + username: 'exe', + }; + expect(() => validateMember(validData)).not.toThrowError(); + expect(validateMember(validData)).toEqual(validData); + }); + + it('should return data when username has length <= 14', () => { + const validData = { + username: 'executive12345', + }; + expect(() => validateMember(validData)).not.toThrowError(); + expect(validateMember(validData)).toEqual(validData); + }); + + it('should throw error when username consists of more than 14 characters', () => { + const invalidData = { + username: 'anatomopatomorfolog', + }; + expect(() => validateMember(invalidData)).toThrowError(); + }); + + it('should throw error when username consists of no more than 3 characters', () => { + const invalidData = { + username: 'dx', + }; + expect(() => validateMember(invalidData)).toThrowError(); + }); +});