Skip to content

Commit ecdf2e2

Browse files
Merge
2 parents 3c2833a + 8789275 commit ecdf2e2

File tree

3 files changed

+122
-99
lines changed

3 files changed

+122
-99
lines changed

src/auth/auth.ts

+19-16
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ import {
99
OidcUser,
1010
} from 'src/auth/oidc-broker';
1111
import { cookiesAcceptedKey } from 'src/components/CookieWarning';
12-
import { Ajax } from 'src/libs/ajax';
1312
import { fetchOk } from 'src/libs/ajax/ajax-common';
14-
import { SamUserAttributes } from 'src/libs/ajax/User';
13+
import { ExternalCredentials } from 'src/libs/ajax/ExternalCredentials';
14+
import { Groups } from 'src/libs/ajax/Groups';
15+
import { Metrics } from 'src/libs/ajax/Metrics';
16+
import { TermsOfService } from 'src/libs/ajax/TermsOfService';
17+
import { SamUserAttributes, User } from 'src/libs/ajax/User';
1518
import { withErrorIgnoring, withErrorReporting } from 'src/libs/error';
1619
import Events, { captureAppcuesEvent, MetricsEventName } from 'src/libs/events';
1720
import * as Nav from 'src/libs/nav';
@@ -50,7 +53,7 @@ export const getAuthTokenFromLocalStorage = async (): Promise<string | undefined
5053
};
5154

5255
export const sendRetryMetric = () => {
53-
Ajax().Metrics.captureEvent(Events.user.authToken.load.retry, {});
56+
Metrics().captureEvent(Events.user.authToken.load.retry, {});
5457
};
5558

5659
export const signIn = async (includeBillingScope = false): Promise<OidcUser> => {
@@ -71,13 +74,13 @@ export const signIn = async (includeBillingScope = false): Promise<OidcUser> =>
7174
sessionId,
7275
sessionStartTime,
7376
}));
74-
Ajax().Metrics.captureEvent(Events.user.login.success, {
77+
Metrics().captureEvent(Events.user.login.success, {
7578
sessionStartTime: Utils.makeCompleteDate(sessionStartTime),
7679
});
7780
return authTokenState.oidcUser;
7881
}
7982
if (authTokenState.status === 'error') {
80-
Ajax().Metrics.captureEvent(Events.user.login.error, {});
83+
Metrics().captureEvent(Events.user.login.error, {});
8184
}
8285
throw new Error('Auth token failed to load when signing in');
8386
};
@@ -170,7 +173,7 @@ export const loadAuthToken = async (
170173
}));
171174
const { refreshTokenMetadata: currentRefreshTokenMetadata } = metricStore.get();
172175

173-
Ajax().Metrics.captureEvent(Events.user.authToken.load.success, {
176+
Metrics().captureEvent(Events.user.authToken.load.success, {
174177
authProvider: oidcUser.profile.idp,
175178
...getOldAuthTokenLabels(oldAuthTokenMetadata),
176179
authTokenCreatedAt: getTimestampMetricLabel(authTokenCreatedAt),
@@ -182,7 +185,7 @@ export const loadAuthToken = async (
182185
jwtExpiresAt: getTimestampMetricLabel(jwtExpiresAt),
183186
});
184187
} else if (loadedAuthTokenState.status === 'error') {
185-
Ajax().Metrics.captureEvent(Events.user.authToken.load.error, {
188+
Metrics().captureEvent(Events.user.authToken.load.error, {
186189
// we could potentially log the reason, but I don't know if that data is safe to log
187190
...getOldAuthTokenLabels(oldAuthTokenMetadata),
188191
refreshTokenId: oldRefreshTokenMetadata.id,
@@ -460,27 +463,27 @@ authStore.subscribe((state: AuthState) => {
460463
authStore.subscribe(
461464
withErrorReporting('Error checking groups for timeout status')(async (state: AuthState, oldState: AuthState) => {
462465
if (userCanNowUseTerra(oldState, state)) {
463-
const isTimeoutEnabled = _.some({ groupName: 'session_timeout' }, await Ajax().Groups.list());
466+
const isTimeoutEnabled = _.some({ groupName: 'session_timeout' }, await Groups().list());
464467
authStore.update((state) => ({ ...state, isTimeoutEnabled }));
465468
}
466469
})
467470
);
468471

469472
export const refreshTerraProfile = async () => {
470-
const profile: TerraUserProfile = await Ajax().User.profile.get();
473+
const profile: TerraUserProfile = await User().profile.get();
471474
userStore.update((state: TerraUserState) => ({ ...state, profile }));
472475
};
473476

474477
export const refreshSamUserAttributes = async (): Promise<void> => {
475-
const terraUserAttributes: SamUserAttributes = await Ajax().User.getUserAttributes();
478+
const terraUserAttributes: SamUserAttributes = await User().getUserAttributes();
476479
userStore.update((state: TerraUserState) => ({ ...state, terraUserAttributes }));
477480
};
478481

479482
export const loadTerraUser = async (): Promise<void> => {
480483
try {
481484
const signInStatus = 'userLoaded';
482-
const getProfile = Ajax().User.profile.get();
483-
const getCombinedState = Ajax().User.getSamUserCombinedState();
485+
const getProfile = User().profile.get();
486+
const getCombinedState = User().getSamUserCombinedState();
484487
const [profile, terraUserCombinedState] = await Promise.all([getProfile, getCombinedState]);
485488
const { terraUserAttributes, enterpriseFeatures, samUser, terraUserAllowances, termsOfService } =
486489
terraUserCombinedState;
@@ -534,7 +537,7 @@ authStore.subscribe(
534537
authStore.subscribe(
535538
withErrorReporting('Error loading NIH account link status')(async (state: AuthState, oldState: AuthState) => {
536539
if (userCanNowUseTerra(oldState, state)) {
537-
const nihStatus = await Ajax().User.getNihStatus();
540+
const nihStatus = await User().getNihStatus();
538541
authStore.update((state: AuthState) => ({ ...state, nihStatus, nihStatusLoaded: true }));
539542
}
540543
})
@@ -543,7 +546,7 @@ authStore.subscribe(
543546
authStore.subscribe(
544547
withErrorIgnoring(async (state: AuthState, oldState: AuthState) => {
545548
if (userCanNowUseTerra(oldState, state)) {
546-
await Ajax().Metrics.syncProfile();
549+
await Metrics().syncProfile();
547550
}
548551
})
549552
);
@@ -553,7 +556,7 @@ authStore.subscribe(
553556
if (userCanNowUseTerra(oldState, state)) {
554557
const { anonymousId } = metricStore.get();
555558
if (anonymousId) {
556-
return await Ajax().Metrics.identify(anonymousId);
559+
return await Metrics().identify(anonymousId);
557560
}
558561
}
559562
})
@@ -564,7 +567,7 @@ authStore.subscribe(
564567
if (userCanNowUseTerra(oldState, state)) {
565568
await Promise.all(
566569
_.map(async (provider) => {
567-
const status = await Ajax().ExternalCredentials(provider).getAccountLinkStatus();
570+
const status = await ExternalCredentials()(provider).getAccountLinkStatus();
568571
authStore.update(_.set(['oAuth2AccountStatus', provider.key], status));
569572
}, allOAuth2Providers)
570573
);

src/auth/login.test.ts

+68-55
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ import { DeepPartial } from '@terra-ui-packages/core-utils';
22
import { asMockedFn } from '@terra-ui-packages/test-utils';
33
import { act } from '@testing-library/react';
44
import { loadTerraUser } from 'src/auth/auth';
5-
import { Ajax } from 'src/libs/ajax';
6-
import { GroupRole } from 'src/libs/ajax/Groups';
7-
import { SamUserTermsOfServiceDetails } from 'src/libs/ajax/TermsOfService';
8-
import { SamUserCombinedStateResponse, SamUserResponse } from 'src/libs/ajax/User';
9-
import { userStore } from 'src/libs/state';
5+
import { Groups, GroupsContract } from 'src/libs/ajax/Groups';
6+
import { Metrics, MetricsContract } from 'src/libs/ajax/Metrics';
7+
import { SamUserTermsOfServiceDetails, TermsOfService, TermsOfServiceContract } from 'src/libs/ajax/TermsOfService';
8+
import { SamUserResponse, User, UserContract } from 'src/libs/ajax/User';
9+
import { oidcStore, TerraUserState, userStore } from 'src/libs/state';
1010

11-
jest.mock('src/libs/ajax');
12-
13-
type AjaxExports = typeof import('src/libs/ajax');
14-
type AjaxContract = ReturnType<AjaxExports['Ajax']>;
11+
jest.mock('src/libs/ajax/TermsOfService');
12+
jest.mock('src/libs/ajax/User');
13+
jest.mock('src/libs/ajax/Groups');
14+
jest.mock('src/libs/ajax/Metrics');
1515

1616
jest.mock('react-notifications-component', () => {
1717
return {
@@ -22,6 +22,12 @@ jest.mock('react-notifications-component', () => {
2222
};
2323
});
2424

25+
jest.spyOn(oidcStore, 'get').mockImplementation(
26+
jest.fn().mockReturnValue({
27+
userManager: { getUser: jest.fn() },
28+
})
29+
);
30+
2531
const samUserDate = new Date('1970-01-01');
2632

2733
const mockSamUserResponse: SamUserResponse = {
@@ -86,43 +92,50 @@ const mockOrchestrationNihStatusResponse = {
8692
linkExpireTime: 1234,
8793
};
8894

89-
const mockCurrentUserGroupMembership = {
90-
groupEmail: 'testGroupEmail',
91-
groupName: 'testGroupName',
92-
role: 'member' as GroupRole,
93-
};
94-
9595
// TODO centralize Ajax mock setup so it can be reused across tests
9696
describe('a request to load a terra user', () => {
97-
// reset userStore state before each test
97+
// Arrange (shared between tests for the success case)
98+
const getUserAllowancesFunction = jest.fn().mockResolvedValue(testSamUserAllowances);
99+
const getUserAttributesFunction = jest.fn().mockResolvedValue({ marketingConsent: false });
100+
const getUserTermsOfServiceDetailsFunction = jest.fn().mockResolvedValue(mockSamUserTermsOfServiceDetails);
101+
const getEnterpriseFeaturesFunction = jest.fn().mockResolvedValue([]);
102+
const getSamUserResponseFunction = jest.fn().mockResolvedValue(mockSamUserResponse);
103+
const getNihStatusFunction = jest.fn().mockResolvedValue(mockOrchestrationNihStatusResponse);
104+
const getFenceStatusFunction = jest.fn().mockResolvedValue({});
105+
const getSamUserCombinedStateMock = jest.fn().mockResolvedValue(mockSamUserCombinedState);
106+
98107
beforeEach(() => {
99-
userStore.reset;
108+
userStore.reset();
109+
});
110+
111+
// reset userStore state before each test
112+
beforeAll(() => {
113+
asMockedFn(Metrics).mockReturnValue({
114+
captureEvent: jest.fn(),
115+
} as Partial<MetricsContract> as MetricsContract);
116+
asMockedFn(User).mockReturnValue({
117+
getSamUserCombinedState: getSamUserCombinedStateMock,
118+
getUserAllowances: getUserAllowancesFunction,
119+
getUserAttributes: getUserAttributesFunction,
120+
getUserTermsOfServiceDetails: getUserTermsOfServiceDetailsFunction,
121+
getEnterpriseFeatures: getEnterpriseFeaturesFunction,
122+
getSamUserResponse: getSamUserResponseFunction,
123+
getNihStatus: getNihStatusFunction,
124+
getFenceStatus: getFenceStatusFunction,
125+
profile: {
126+
get: jest.fn().mockReturnValue(mockTerraUserProfile),
127+
},
128+
} as DeepPartial<UserContract> as UserContract);
129+
130+
asMockedFn(Groups).mockReturnValue({
131+
list: jest.fn(),
132+
} as Partial<GroupsContract> as GroupsContract);
133+
134+
asMockedFn(TermsOfService).mockReturnValue({
135+
getUserTermsOfServiceDetails: jest.fn().mockReturnValue({}),
136+
} as Partial<TermsOfServiceContract> as TermsOfServiceContract);
100137
});
101138
describe('when successful', () => {
102-
// Arrange (shared between tests for the success case)
103-
const getSamUserCombinedStateMock = jest.fn().mockResolvedValue(mockSamUserCombinedState);
104-
const getNihStatusMock = jest.fn().mockResolvedValue(mockOrchestrationNihStatusResponse);
105-
const getFenceStatusMock = jest.fn().mockResolvedValue({});
106-
107-
asMockedFn(Ajax).mockImplementation(
108-
() =>
109-
({
110-
User: {
111-
getSamUserCombinedState: getSamUserCombinedStateMock,
112-
getNihStatus: getNihStatusMock,
113-
getFenceStatus: getFenceStatusMock,
114-
profile: {
115-
get: jest.fn().mockReturnValue(mockTerraUserProfile),
116-
},
117-
},
118-
TermsOfService: {
119-
getUserTermsOfServiceDetails: jest.fn().mockReturnValue({}),
120-
},
121-
Groups: {
122-
list: jest.fn().mockReturnValue([mockCurrentUserGroupMembership]),
123-
},
124-
} as DeepPartial<AjaxContract> as AjaxContract)
125-
);
126139
it('should include a samUserResponse', async () => {
127140
// Act
128141
await act(() => loadTerraUser());
@@ -144,20 +157,20 @@ describe('a request to load a terra user', () => {
144157
// mock a failure to get samUserResponse
145158
const getSamUserCombinedStateMockFailure = jest.fn().mockRejectedValue(new Error('unknown'));
146159

147-
asMockedFn(Ajax).mockImplementation(
148-
() =>
149-
({
150-
User: {
151-
getSamUserCombinedState: getSamUserCombinedStateMockFailure,
152-
profile: {
153-
get: jest.fn().mockReturnValue(mockTerraUserProfile),
154-
},
155-
},
156-
TermsOfService: {
157-
getUserTermsOfServiceDetails: jest.fn().mockReturnValue({}),
158-
},
159-
} as DeepPartial<AjaxContract> as AjaxContract)
160-
);
160+
asMockedFn(User).mockReturnValue({
161+
getUserAllowances: getUserAllowancesFunction,
162+
getUserAttributes: getUserAttributesFunction,
163+
getUserTermsOfServiceDetails: getUserTermsOfServiceDetailsFunction,
164+
getEnterpriseFeatures: getEnterpriseFeaturesFunction,
165+
getSamUserResponse: getSamUserResponseFunction,
166+
getSamUserCombinedState: getSamUserCombinedStateMockFailure,
167+
168+
profile: {
169+
get: jest.fn().mockReturnValue(mockTerraUserProfile),
170+
},
171+
getNihStatus: getNihStatusFunction,
172+
} as DeepPartial<UserContract> as UserContract);
173+
161174
// Act, Assert
162175
// this expect.assertions is here to prevent the test from passing if the error is not thrown
163176
expect.assertions(1);

src/registration/terms-of-service/TermsOfServicePage.test.ts

+35-28
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import { DeepPartial } from '@terra-ui-packages/core-utils';
22
import { act, fireEvent, screen } from '@testing-library/react';
33
import { h } from 'react-hyperscript-helpers';
44
import { Ajax } from 'src/libs/ajax';
5-
import { SamUserTermsOfServiceDetails } from 'src/libs/ajax/TermsOfService';
6-
import { SamUserAllowances, SamUserCombinedStateResponse, SamUserResponse } from 'src/libs/ajax/User';
5+
import { Groups, GroupsContract } from 'src/libs/ajax/Groups';
6+
import { Metrics, MetricsContract } from 'src/libs/ajax/Metrics';
7+
import { SamUserTermsOfServiceDetails, TermsOfService, TermsOfServiceContract } from 'src/libs/ajax/TermsOfService';
8+
import { SamUserAllowances, SamUserResponse, User, UserContract } from 'src/libs/ajax/User';
79
import { AuthState, authStore } from 'src/libs/state';
810
import { TermsOfServicePage } from 'src/registration/terms-of-service/TermsOfServicePage';
911
import { asMockedFn, renderWithAppContexts as render } from 'src/testing/test-utils';
1012

13+
jest.mock('src/libs/ajax/Metrics');
14+
jest.mock('src/libs/ajax/TermsOfService');
15+
jest.mock('src/libs/ajax/User');
16+
jest.mock('src/libs/ajax/Groups');
1117
jest.mock('src/libs/ajax');
1218
jest.mock('react-notifications-component', () => {
1319
return {
@@ -27,8 +33,6 @@ jest.mock(
2733
})
2834
);
2935

30-
type AuthExports = typeof import('src/auth/auth');
31-
3236
type SignOutExports = typeof import('src/auth/signout/sign-out');
3337
jest.mock(
3438
'src/auth/signout/sign-out',
@@ -38,13 +42,6 @@ jest.mock(
3842
})
3943
);
4044

41-
jest.mock(
42-
'src/auth/auth',
43-
(): AuthExports => ({
44-
...jest.requireActual<AuthExports>('src/auth/auth'),
45-
})
46-
);
47-
4845
interface TermsOfServiceSetupResult {
4946
getTosFn: jest.Mock;
5047
getTermsOfServiceComplianceStatusFn: jest.Mock;
@@ -92,31 +89,41 @@ const setupMockAjax = async (
9289
asMockedFn(Ajax).mockImplementation(
9390
() =>
9491
({
95-
Metrics: {
96-
captureEvent: jest.fn(),
97-
},
98-
User: {
99-
getSamUserCombinedState: jest.fn().mockResolvedValue(mockSamUserCombinedState),
100-
profile: {
101-
get: jest.fn().mockResolvedValue({ keyValuePairs: [] }),
102-
update: jest.fn().mockResolvedValue({ keyValuePairs: [] }),
103-
setPreferences: jest.fn().mockResolvedValue({}),
104-
preferLegacyFirecloud: jest.fn().mockResolvedValue({}),
105-
},
106-
getNihStatus,
107-
},
10892
TermsOfService: {
109-
getUserTermsOfServiceDetails,
11093
acceptTermsOfService,
11194
rejectTermsOfService,
11295
getTermsOfServiceText,
11396
},
114-
Groups: {
115-
list: jest.fn(),
116-
},
11797
} as DeepPartial<AjaxContract> as AjaxContract)
11898
);
11999

100+
asMockedFn(Metrics).mockReturnValue({
101+
captureEvent: jest.fn(),
102+
} as Partial<MetricsContract> as MetricsContract);
103+
104+
asMockedFn(User).mockReturnValue({
105+
getSamUserCombinedState: jest.fn().mockResolvedValue(mockSamUserCombinedState),
106+
getUserAttributes: jest.fn().mockResolvedValue({ marketingConsent: true }),
107+
getUserAllowances: jest.fn().mockResolvedValue(terraUserAllowances),
108+
getEnterpriseFeatures: jest.fn().mockResolvedValue([]),
109+
getSamUserResponse: jest.fn().mockResolvedValue(mockSamUserResponse),
110+
profile: {
111+
get: jest.fn().mockResolvedValue({ keyValuePairs: [] }),
112+
update: jest.fn().mockResolvedValue({ keyValuePairs: [] }),
113+
setPreferences: jest.fn().mockResolvedValue({}),
114+
preferLegacyFirecloud: jest.fn().mockResolvedValue({}),
115+
},
116+
getNihStatus,
117+
} as Partial<UserContract> as UserContract);
118+
119+
asMockedFn(Groups).mockReturnValue({
120+
list: jest.fn(),
121+
} as Partial<GroupsContract> as GroupsContract);
122+
123+
asMockedFn(TermsOfService).mockReturnValue({
124+
getUserTermsOfServiceDetails,
125+
} as Partial<TermsOfServiceContract> as TermsOfServiceContract);
126+
120127
await act(async () => {
121128
authStore.update((state: AuthState) => ({ ...state, termsOfService, signInStatus, terraUserAllowances }));
122129
});

0 commit comments

Comments
 (0)