Skip to content

Commit 15d41e6

Browse files
committed
Profile settings update
1 parent 7805df7 commit 15d41e6

File tree

22 files changed

+2144
-16
lines changed

22 files changed

+2144
-16
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ __coverage__
44
dist
55
node_modules
66
_auto_doc_
7+
.vscode

__tests__/__snapshots__/index.js.snap

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ Object {
4848
"getGroupsDone": [Function],
4949
"getGroupsInit": [Function],
5050
},
51+
"lookup": Object {
52+
"getApprovedSkills": [Function],
53+
},
5154
"memberTasks": Object {
5255
"dropAll": [Function],
5356
"getDone": [Function],
@@ -64,19 +67,49 @@ Object {
6467
"getStatsInit": [Function],
6568
},
6669
"profile": Object {
70+
"addSkillDone": [Function],
71+
"addSkillInit": [Function],
72+
"addWebLinkDone": [Function],
73+
"addWebLinkInit": [Function],
74+
"deletePhotoDone": [Function],
75+
"deletePhotoInit": [Function],
76+
"deleteWebLinkDone": [Function],
77+
"deleteWebLinkInit": [Function],
6778
"getAchievementsDone": [Function],
6879
"getAchievementsInit": [Function],
80+
"getActiveChallengesCountDone": [Function],
81+
"getActiveChallengesCountInit": [Function],
82+
"getCredentialDone": [Function],
83+
"getCredentialInit": [Function],
84+
"getEmailPreferencesDone": [Function],
85+
"getEmailPreferencesInit": [Function],
6986
"getExternalAccountsDone": [Function],
7087
"getExternalAccountsInit": [Function],
7188
"getExternalLinksDone": [Function],
7289
"getExternalLinksInit": [Function],
7390
"getInfoDone": [Function],
7491
"getInfoInit": [Function],
92+
"getLinkedAccountsDone": [Function],
93+
"getLinkedAccountsInit": [Function],
7594
"getSkillsDone": [Function],
7695
"getSkillsInit": [Function],
7796
"getStatsDone": [Function],
7897
"getStatsInit": [Function],
98+
"hideSkillDone": [Function],
99+
"hideSkillInit": [Function],
100+
"linkExternalAccountDone": [Function],
101+
"linkExternalAccountInit": [Function],
79102
"loadProfile": [Function],
103+
"saveEmailPreferencesDone": [Function],
104+
"saveEmailPreferencesInit": [Function],
105+
"unlinkExternalAccountDone": [Function],
106+
"unlinkExternalAccountInit": [Function],
107+
"updatePasswordDone": [Function],
108+
"updatePasswordInit": [Function],
109+
"updateProfileDone": [Function],
110+
"updateProfileInit": [Function],
111+
"uploadPhotoDone": [Function],
112+
"uploadPhotoInit": [Function],
80113
},
81114
"reviewOpportunity": Object {
82115
"cancelApplicationsDone": [Function],
@@ -159,13 +192,29 @@ Object {
159192
"default": undefined,
160193
"mockAction": [Function],
161194
},
195+
"reducerFactories": Object {
196+
"authFactory": [Function],
197+
"challengeFactory": [Function],
198+
"directFactory": [Function],
199+
"errorsFactory": [Function],
200+
"groupsFactory": [Function],
201+
"lookupFactory": [Function],
202+
"memberTasksFactory": [Function],
203+
"membersFactory": [Function],
204+
"mySubmissionsManagementFactory": [Function],
205+
"profileFactory": [Function],
206+
"reviewOpportunityFactory": [Function],
207+
"statsFactory": [Function],
208+
"termsFactory": [Function],
209+
},
162210
"reducerFactory": [Function],
163211
"reducers": Object {
164212
"auth": [Function],
165213
"challenge": [Function],
166214
"direct": [Function],
167215
"errors": [Function],
168216
"groups": [Function],
217+
"lookup": [Function],
169218
"memberTasks": [Function],
170219
"members": [Function],
171220
"mySubmissionsManagement": [Function],
@@ -209,6 +258,10 @@ Object {
209258
"default": undefined,
210259
"getService": [Function],
211260
},
261+
"lookup": Object {
262+
"default": undefined,
263+
"getService": [Function],
264+
},
212265
"members": Object {
213266
"default": undefined,
214267
"getService": [Function],
@@ -242,6 +295,7 @@ Object {
242295
"Spec Review": "Specification Review",
243296
},
244297
"getApiResponsePayloadV3": [Function],
298+
"looseEqual": [Function],
245299
},
246300
"time": Object {
247301
"default": undefined,

__tests__/actions/lookup.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as LookupService from 'services/lookup';
2+
import actions from 'actions/lookup';
3+
4+
const tag = {
5+
domain: 'SKILLS',
6+
id: 251,
7+
name: 'Jekyll',
8+
status: 'APPROVED',
9+
};
10+
11+
// Mock services
12+
const mockLookupService = {
13+
getTags: jest.fn().mockReturnValue(Promise.resolve([tag])),
14+
};
15+
LookupService.getService = jest.fn().mockReturnValue(mockLookupService);
16+
17+
18+
describe('lookup.getApprovedSkills', () => {
19+
const a = actions.lookup.getApprovedSkills();
20+
21+
test('has expected type', () => {
22+
expect(a.type).toEqual('LOOKUP/GET_APPROVED_SKILLS');
23+
});
24+
25+
test('Approved skills should be returned', () =>
26+
a.payload.then((res) => {
27+
expect(res).toEqual([tag]);
28+
expect(mockLookupService.getTags).toBeCalled();
29+
}));
30+
});

__tests__/actions/profile.js

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
import * as ChallengesService from 'services/challenges';
2+
import * as MembersService from 'services/members';
3+
import * as UserService from 'services/user';
4+
5+
import actions from 'actions/profile';
6+
7+
const handle = 'tcscoder';
8+
const tokenV3 = 'tokenV3';
9+
const profile = { userId: 12345, handle };
10+
const skill = { tagId: 123, tagName: 'Node.js' };
11+
const weblink = 'https://www.google.com';
12+
const linkedAccounts = [{
13+
providerType: 'github',
14+
social: true,
15+
userId: '623633',
16+
}];
17+
18+
// Mock services
19+
const mockChanllengesService = {
20+
getUserChallenges: jest.fn().mockReturnValue(Promise.resolve({ totalCount: 3 })),
21+
getUserMarathonMatches: jest.fn().mockReturnValue(Promise.resolve({ totalCount: 5 })),
22+
};
23+
ChallengesService.getService = jest.fn().mockReturnValue(mockChanllengesService);
24+
25+
const mockMembersService = {
26+
getPresignedUrl: jest.fn().mockReturnValue(Promise.resolve()),
27+
uploadFileToS3: jest.fn().mockReturnValue(Promise.resolve()),
28+
updateMemberPhoto: jest.fn().mockReturnValue(Promise.resolve('url-of-photo')),
29+
updateMemberProfile: jest.fn().mockReturnValue(Promise.resolve(profile)),
30+
addSkill: jest.fn().mockReturnValue(Promise.resolve({ skills: [skill] })),
31+
hideSkill: jest.fn().mockReturnValue(Promise.resolve({ skills: [] })),
32+
addWebLink: jest.fn().mockReturnValue(Promise.resolve(weblink)),
33+
deleteWebLink: jest.fn().mockReturnValue(Promise.resolve(weblink)),
34+
};
35+
MembersService.getService = jest.fn().mockReturnValue(mockMembersService);
36+
37+
const mockUserService = {
38+
linkExternalAccount: jest.fn().mockReturnValue(Promise.resolve(linkedAccounts[0])),
39+
unlinkExternalAccount: jest.fn().mockReturnValue(Promise.resolve('unlinked')),
40+
getLinkedAccounts: jest.fn().mockReturnValue(Promise.resolve({ profiles: linkedAccounts })),
41+
getCredential: jest.fn().mockReturnValue(Promise.resolve({ credential: { hasPassword: true } })),
42+
getEmailPreferences:
43+
jest.fn().mockReturnValue(Promise.resolve({ subscriptions: { TOPCODER_NL_DATA: true } })),
44+
saveEmailPreferences:
45+
jest.fn().mockReturnValue(Promise.resolve({ subscriptions: { TOPCODER_NL_DATA: true } })),
46+
updatePassword: jest.fn().mockReturnValue(Promise.resolve({ update: true })),
47+
};
48+
UserService.getService = jest.fn().mockReturnValue(mockUserService);
49+
50+
51+
describe('profile.getActiveChallengesCountDone', () => {
52+
const a = actions.profile.getActiveChallengesCountDone(handle, tokenV3);
53+
54+
test('has expected type', () => {
55+
expect(a.type).toBe('PROFILE/GET_ACTIVE_CHALLENGES_COUNT_DONE');
56+
});
57+
58+
test('Sum of challenges and marathon matches should be returned', () =>
59+
a.payload.then((res) => {
60+
expect(res).toBe(8);
61+
expect(mockChanllengesService.getUserChallenges).toBeCalled();
62+
expect(mockChanllengesService.getUserMarathonMatches).toBeCalled();
63+
}));
64+
});
65+
66+
describe('profile.uploadPhotoDone', () => {
67+
const a = actions.profile.uploadPhotoDone(handle, tokenV3);
68+
69+
test('has expected type', () => {
70+
expect(a.type).toBe('PROFILE/UPLOAD_PHOTO_DONE');
71+
});
72+
73+
test('Photo URL should be returned', () =>
74+
a.payload.then((res) => {
75+
expect(res).toEqual({
76+
handle,
77+
photoURL: 'url-of-photo',
78+
});
79+
expect(mockMembersService.getPresignedUrl).toBeCalled();
80+
expect(mockMembersService.uploadFileToS3).toBeCalled();
81+
expect(mockMembersService.updateMemberPhoto).toBeCalled();
82+
}));
83+
});
84+
85+
describe('profile.updateProfileDone', () => {
86+
const a = actions.profile.updateProfileDone(profile, tokenV3);
87+
88+
test('has expected type', () => {
89+
expect(a.type).toBe('PROFILE/UPDATE_PROFILE_DONE');
90+
});
91+
92+
test('Profile should be updated', () =>
93+
a.payload.then((res) => {
94+
expect(res).toEqual(profile);
95+
expect(mockMembersService.updateMemberProfile).toBeCalled();
96+
}));
97+
});
98+
99+
describe('profile.addSkillDone', () => {
100+
const a = actions.profile.addSkillDone(handle, tokenV3, skill);
101+
102+
test('has expected type', () => {
103+
expect(a.type).toBe('PROFILE/ADD_SKILL_DONE');
104+
});
105+
106+
test('Skill should be added', () =>
107+
a.payload.then((res) => {
108+
expect(res).toEqual({ skills: [skill], handle, skill });
109+
expect(mockMembersService.addSkill).toBeCalled();
110+
}));
111+
});
112+
113+
describe('profile.hideSkillDone', () => {
114+
const a = actions.profile.hideSkillDone(handle, tokenV3, skill);
115+
116+
test('has expected type', () => {
117+
expect(a.type).toBe('PROFILE/HIDE_SKILL_DONE');
118+
});
119+
120+
test('Skill should be removed', () =>
121+
a.payload.then((res) => {
122+
expect(res).toEqual({ skills: [], handle, skill });
123+
expect(mockMembersService.hideSkill).toBeCalled();
124+
}));
125+
});
126+
127+
describe('profile.addWebLinkDone', () => {
128+
const a = actions.profile.addWebLinkDone(handle, tokenV3, weblink);
129+
130+
test('has expected type', () => {
131+
expect(a.type).toBe('PROFILE/ADD_WEB_LINK_DONE');
132+
});
133+
134+
test('Web link should be added', () =>
135+
a.payload.then((res) => {
136+
expect(res).toEqual({ data: weblink, handle });
137+
expect(mockMembersService.addWebLink).toBeCalled();
138+
}));
139+
});
140+
141+
describe('profile.deleteWebLinkDone', () => {
142+
const a = actions.profile.deleteWebLinkDone(handle, tokenV3, weblink);
143+
144+
test('has expected type', () => {
145+
expect(a.type).toBe('PROFILE/DELETE_WEB_LINK_DONE');
146+
});
147+
148+
test('Web link should be deleted', () =>
149+
a.payload.then((res) => {
150+
expect(res).toEqual({ data: weblink, handle });
151+
expect(mockMembersService.deleteWebLink).toBeCalled();
152+
}));
153+
});
154+
155+
describe('profile.linkExternalAccountDone', () => {
156+
const a = actions.profile.linkExternalAccountDone(profile, tokenV3, 'github');
157+
158+
test('has expected type', () => {
159+
expect(a.type).toBe('PROFILE/LINK_EXTERNAL_ACCOUNT_DONE');
160+
});
161+
162+
test('External account should be linked', () =>
163+
a.payload.then((res) => {
164+
expect(res).toEqual({ data: linkedAccounts[0], handle });
165+
expect(mockUserService.linkExternalAccount).toBeCalled();
166+
}));
167+
});
168+
169+
describe('profile.unlinkExternalAccountDone', () => {
170+
const a = actions.profile.unlinkExternalAccountDone(profile, tokenV3, 'github');
171+
172+
test('has expected type', () => {
173+
expect(a.type).toBe('PROFILE/UNLINK_EXTERNAL_ACCOUNT_DONE');
174+
});
175+
176+
test('External account should be unlinked', () =>
177+
a.payload.then((res) => {
178+
expect(res).toEqual({ handle, providerType: 'github' });
179+
expect(mockUserService.unlinkExternalAccount).toBeCalled();
180+
}));
181+
});
182+
183+
describe('profile.getLinkedAccountsDone', () => {
184+
const a = actions.profile.getLinkedAccountsDone(profile, tokenV3);
185+
186+
test('has expected type', () => {
187+
expect(a.type).toBe('PROFILE/GET_LINKED_ACCOUNTS_DONE');
188+
});
189+
190+
test('Linked account should be returned', () =>
191+
a.payload.then((res) => {
192+
expect(res).toEqual({ profiles: linkedAccounts });
193+
expect(mockUserService.getLinkedAccounts).toBeCalled();
194+
}));
195+
});
196+
197+
describe('profile.getCredentialDone', () => {
198+
const a = actions.profile.getCredentialDone(profile, tokenV3);
199+
200+
test('has expected type', () => {
201+
expect(a.type).toBe('PROFILE/GET_CREDENTIAL_DONE');
202+
});
203+
204+
test('Credential should be returned', () =>
205+
a.payload.then((res) => {
206+
expect(res).toEqual({ credential: { hasPassword: true } });
207+
expect(mockUserService.getCredential).toBeCalled();
208+
}));
209+
});
210+
211+
describe('profile.getEmailPreferencesDone', () => {
212+
const a = actions.profile.getEmailPreferencesDone(profile, tokenV3);
213+
214+
test('has expected type', () => {
215+
expect(a.type).toBe('PROFILE/GET_EMAIL_PREFERENCES_DONE');
216+
});
217+
218+
test('Email preferences should be returned', () =>
219+
a.payload.then((res) => {
220+
expect(res).toEqual({ subscriptions: { TOPCODER_NL_DATA: true } });
221+
expect(mockUserService.getEmailPreferences).toBeCalled();
222+
}));
223+
});
224+
225+
describe('profile.saveEmailPreferencesDone', () => {
226+
const a = actions.profile.saveEmailPreferencesDone(profile, tokenV3, {});
227+
228+
test('has expected type', () => {
229+
expect(a.type).toBe('PROFILE/SAVE_EMAIL_PREFERENCES_DONE');
230+
});
231+
232+
test('Email preferences should be updated', () =>
233+
a.payload.then((res) => {
234+
expect(res).toEqual({ handle, data: { subscriptions: { TOPCODER_NL_DATA: true } } });
235+
expect(mockUserService.saveEmailPreferences).toBeCalled();
236+
}));
237+
});
238+
239+
describe('profile.updatePasswordDone', () => {
240+
const a = actions.profile.updatePasswordDone(profile, tokenV3, 'newPassword', 'oldPassword');
241+
242+
test('has expected type', () => {
243+
expect(a.type).toBe('PROFILE/UPDATE_PASSWORD_DONE');
244+
});
245+
246+
test('User password should be updated', () =>
247+
a.payload.then((res) => {
248+
expect(res).toEqual({ handle, data: { update: true } });
249+
expect(mockUserService.updatePassword).toBeCalled();
250+
}));
251+
});
252+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy