-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Id 367 get user registration from sam #4716
Merged
Merged
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
2ec08f8
wip get registered date from sam
Shakespeared 1b71e1e
get registration date from sam
Shakespeared e720f8d
streamline and store samUser in state
Shakespeared 1de9e4b
wip add unit tests
Shakespeared bcce5cf
Merge branch 'dev' into id-367-get-user-registration-from-sam
Shakespeared 36e3096
add test for failure case
Shakespeared 24c9125
remove leftover rex code
Shakespeared 0c43b3c
Merge branch 'dev' into id-367-get-user-registration-from-sam
Shakespeared b4ddadc
reorder const for consistency
Shakespeared 6223873
fix tests after merge from dev
Shakespeared ef7e880
fix wonky imports
Shakespeared b964235
fix one more test
Shakespeared ce22711
make mock return values more realistic
Shakespeared 0218e8d
fully initialize samUserResponse in state
Shakespeared a4479d5
Merge branch 'dev' into id-367-get-user-registration-from-sam
Shakespeared a1bef94
add explanatory comment
Shakespeared bb7bd0a
handle if registeredAt is null in the sam db
Shakespeared b7dd27f
simplify after updates in Sam
Shakespeared 5dbf432
put back ui default to epoch
Shakespeared 6815a64
allow initialization of samuser with undefined
Shakespeared dcb76f4
Merge branch 'dev' into id-367-get-user-registration-from-sam
Shakespeared 534a5a9
nit remove extra undefined on optional fields
Shakespeared d00f514
Merge branch 'dev' into id-367-get-user-registration-from-sam
Shakespeared File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import { DeepPartial } from '@terra-ui-packages/core-utils'; | ||
import { asMockedFn } from '@terra-ui-packages/test-utils'; | ||
import { act } from '@testing-library/react'; | ||
import { loadTerraUser } from 'src/auth/auth'; | ||
import { Ajax } from 'src/libs/ajax'; | ||
import { GroupRole } from 'src/libs/ajax/Groups'; | ||
import { SamUserTermsOfServiceDetails } from 'src/libs/ajax/TermsOfService'; | ||
import { SamUserResponse } from 'src/libs/ajax/User'; | ||
import { TerraUserState, userStore } from 'src/libs/state'; | ||
|
||
jest.mock('src/libs/ajax'); | ||
|
||
type AjaxExports = typeof import('src/libs/ajax'); | ||
type AjaxContract = ReturnType<AjaxExports['Ajax']>; | ||
|
||
jest.mock('react-notifications-component', () => { | ||
return { | ||
Store: { | ||
addNotification: jest.fn(), | ||
removeNotification: jest.fn(), | ||
}, | ||
}; | ||
}); | ||
|
||
const samUserDate = new Date('1970-01-01'); | ||
|
||
const mockSamUserResponse: SamUserResponse = { | ||
id: 'testId', | ||
googleSubjectId: 'testGoogleSubjectId', | ||
email: 'testEmail', | ||
azureB2CId: 'testAzureB2CId', | ||
allowed: true, | ||
createdAt: samUserDate, | ||
registeredAt: samUserDate, | ||
updatedAt: samUserDate, | ||
}; | ||
|
||
const mockSamUserTermsOfServiceDetails: SamUserTermsOfServiceDetails = { | ||
latestAcceptedVersion: '1234', | ||
acceptedOn: samUserDate, | ||
permitsSystemUsage: true, | ||
isCurrentVersion: true, | ||
}; | ||
|
||
const mockTerraUserProfile = { | ||
firstName: 'testFirstName', | ||
lastName: 'testLastName', | ||
institute: 'testInstitute', | ||
contactEmail: 'testContactEmail', | ||
title: 'testTitle', | ||
department: 'testDepartment', | ||
interestInTerra: 'testInterestInTerra', | ||
programLocationCity: 'testProgramLocationCity', | ||
programLocationState: 'testProgramLocationState', | ||
programLocationCountry: 'testProgramLocationCountry', | ||
researchArea: 'testResearchArea', | ||
starredWorkspaces: 'testStarredWorkspaces', | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks good! |
||
|
||
const testSamUserAllowancesDetails = { | ||
enabled: true, | ||
termsOfService: true, | ||
}; | ||
|
||
const testSamUserAllowances = { | ||
allowed: true, | ||
details: testSamUserAllowancesDetails, | ||
}; | ||
|
||
const mockNihDatasetPermission = { | ||
name: 'testNihDatasetPermissionName', | ||
authorized: true, | ||
}; | ||
|
||
const mockOrchestrationNihStatusResponse = { | ||
linkedNihUsername: 'testLinkedNihUsername', | ||
datasetPermissions: mockNihDatasetPermission, | ||
linkExpireTime: 1234, | ||
}; | ||
|
||
const mockCurrentUserGroupMembership = { | ||
groupEmail: 'testGroupEmail', | ||
groupName: 'testGroupName', | ||
role: 'member' as GroupRole, | ||
}; | ||
|
||
// TODO centralize Ajax mock setup so it can be reused across tests | ||
describe('a request to load a terra user', () => { | ||
// reset userStore state before each test | ||
beforeEach(() => { | ||
userStore.reset; | ||
}); | ||
describe('when successful', () => { | ||
// Arrange (shared between tests for the success case) | ||
const getUserAllowancesFunction = jest.fn().mockResolvedValue(testSamUserAllowances); | ||
const getUserAttributesFunction = jest.fn().mockResolvedValue({ marketingConsent: false }); | ||
const getUserTermsOfServiceDetailsFunction = jest.fn().mockResolvedValue(mockSamUserTermsOfServiceDetails); | ||
const getEnterpriseFeaturesFunction = jest.fn().mockResolvedValue([]); | ||
const getSamUserResponseFunction = jest.fn().mockResolvedValue(mockSamUserResponse); | ||
const getNihStatusFunction = jest.fn().mockResolvedValue(mockOrchestrationNihStatusResponse); | ||
const getFenceStatusFunction = jest.fn().mockResolvedValue({}); | ||
|
||
asMockedFn(Ajax).mockImplementation( | ||
() => | ||
({ | ||
User: { | ||
getUserAllowances: getUserAllowancesFunction, | ||
getUserAttributes: getUserAttributesFunction, | ||
getUserTermsOfServiceDetails: getUserTermsOfServiceDetailsFunction, | ||
getEnterpriseFeatures: getEnterpriseFeaturesFunction, | ||
getSamUserResponse: getSamUserResponseFunction, | ||
getNihStatus: getNihStatusFunction, | ||
getFenceStatus: getFenceStatusFunction, | ||
profile: { | ||
get: jest.fn().mockReturnValue(mockTerraUserProfile), | ||
}, | ||
}, | ||
TermsOfService: { | ||
getUserTermsOfServiceDetails: jest.fn().mockReturnValue({}), | ||
}, | ||
Groups: { | ||
list: jest.fn().mockReturnValue([mockCurrentUserGroupMembership]), | ||
}, | ||
} as DeepPartial<AjaxContract> as AjaxContract) | ||
); | ||
Shakespeared marked this conversation as resolved.
Show resolved
Hide resolved
|
||
it('should include a samUserResponse', async () => { | ||
// Act | ||
await act(() => loadTerraUser()); | ||
|
||
// Assert | ||
expect(getSamUserResponseFunction).toHaveBeenCalled(); | ||
}); | ||
it('should update the samUser in state', async () => { | ||
// Act | ||
await act(() => loadTerraUser()); | ||
|
||
let samUser; | ||
await act(async () => { | ||
samUser = await getSamUserResponseFunction.mock.results[0].value; | ||
}); | ||
userStore.update((state: TerraUserState) => ({ | ||
...state, | ||
samUser, | ||
})); | ||
// Assert | ||
expect(getSamUserResponseFunction).toHaveBeenCalled(); | ||
expect(userStore.get().samUser).toEqual(mockSamUserResponse); | ||
}); | ||
describe('when not successful', () => { | ||
it('should fail with an error', async () => { | ||
// // Arrange | ||
// mock a failure to get samUserResponse | ||
const getSamUserResponseFunction = jest.fn().mockRejectedValue(new Error('unknown')); | ||
|
||
asMockedFn(Ajax).mockImplementation( | ||
() => | ||
({ | ||
User: { | ||
getUserAllowances: getUserAllowancesFunction, | ||
getUserAttributes: getUserAttributesFunction, | ||
getUserTermsOfServiceDetails: getUserTermsOfServiceDetailsFunction, | ||
getEnterpriseFeatures: getEnterpriseFeaturesFunction, | ||
getSamUserResponse: getSamUserResponseFunction, | ||
profile: { | ||
get: jest.fn().mockReturnValue(mockTerraUserProfile), | ||
}, | ||
}, | ||
TermsOfService: { | ||
getUserTermsOfServiceDetails: jest.fn().mockReturnValue({}), | ||
}, | ||
} as DeepPartial<AjaxContract> as AjaxContract) | ||
); | ||
// Act, Assert | ||
// this expect.assertions is here to prevent the test from passing if the error is not thrown | ||
expect.assertions(1); | ||
Shakespeared marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
await act(() => loadTerraUser()); | ||
} catch (error) { | ||
expect(error).toEqual(new Error('unknown')); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,7 @@ | ||
import _ from 'lodash/fp'; | ||
import * as qs from 'qs'; | ||
import { authOpts, fetchBond, fetchOrchestration, fetchRex, fetchSam, jsonBody } from 'src/libs/ajax/ajax-common'; | ||
import { getTerraUser, TerraUserProfile } from 'src/libs/state'; | ||
import * as Utils from 'src/libs/utils'; | ||
import { authOpts, fetchBond, fetchOrchestration, fetchSam, jsonBody } from 'src/libs/ajax/ajax-common'; | ||
import { TerraUserProfile } from 'src/libs/state'; | ||
|
||
export interface SamUserRegistrationStatusResponse { | ||
userSubjectId: string; | ||
|
@@ -154,19 +153,15 @@ export interface SamInviteUserResponse { | |
userEmail: string; | ||
} | ||
|
||
export interface RexFirstTimestampResponse { | ||
timestamp: Date; | ||
} | ||
|
||
export interface SamUserResponse { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added the undefined so we can initialize with an empty object in state |
||
id: string; | ||
googleSubjectId?: string; | ||
email: string; | ||
azureB2CId?: string; | ||
allowed: boolean; | ||
createdAt: Date; | ||
registeredAt?: Date; | ||
updatedAt: Date; | ||
id: string | undefined; | ||
googleSubjectId?: string | undefined; | ||
email: string | undefined; | ||
azureB2CId?: string | undefined; | ||
allowed: boolean | undefined; | ||
createdAt: Date | undefined; | ||
registeredAt?: Date | undefined; | ||
updatedAt: Date | undefined; | ||
} | ||
|
||
export type SamUserAttributes = { | ||
|
@@ -179,15 +174,6 @@ export type SamUserAttributesRequest = { | |
|
||
export type OrchestrationUserRegistrationRequest = object; | ||
|
||
// TODO: Remove this as a part of https://broadworkbench.atlassian.net/browse/ID-460 | ||
const getFirstTimeStamp = Utils.memoizeAsync( | ||
async (token): Promise<RexFirstTimestampResponse> => { | ||
const res = await fetchRex('firstTimestamps/record', _.mergeAll([authOpts(token), { method: 'POST' }])); | ||
return res.json(); | ||
}, | ||
{ keyFn: (...args) => JSON.stringify(args) } | ||
) as (token: string) => Promise<RexFirstTimestampResponse>; | ||
|
||
export const User = (signal?: AbortSignal) => { | ||
return { | ||
getStatus: async (): Promise<SamUserRegistrationStatusResponse> => { | ||
|
@@ -281,8 +267,9 @@ export const User = (signal?: AbortSignal) => { | |
return res.json(); | ||
}, | ||
|
||
firstTimestamp: (): Promise<RexFirstTimestampResponse> => { | ||
return getFirstTimeStamp(getTerraUser().token!); | ||
getSamUserResponse: async (): Promise<SamUserResponse> => { | ||
const res = await fetchSam('api/users/v2/self', _.mergeAll([authOpts(), { method: 'GET' }])); | ||
return res.json(); | ||
}, | ||
|
||
getNihStatus: async (): Promise<OrchestrationNihStatusResponse | undefined> => { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also just rely on the
createdAt
date, since its not nullable in Sam's DB. That might be preferable, just in case there's a realcreatedAt
, but not aregisteredAt
, for some reason.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to user
createdAt
because then a user who is invited, waits a month to register, then comes to Terra would immediately be shown the survey