Repository navigation
fix(settings-users): resolve a deep-linked user by exact uid #529
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -242,7 +242,7 @@ describe('SettingsViewUsers.vue', () => { | |
| const zoe = { uid: 'zoe@example.org', name: 'Zoe', email: 'zoe@example.org', permissions: [] } | ||
|
|
||
| beforeEach(() => { | ||
| api.getUsers.mockImplementation(async ({ q }) => (q === zoe.uid ? { items: [zoe], pagination: { total: 1 } } : usersResponse)) | ||
| api.getUsers.mockImplementation(async ({ uid }) => (uid === zoe.uid ? { items: [zoe], pagination: { total: 1 } } : usersResponse)) | ||
| }) | ||
|
|
||
| it.each([ | ||
|
|
@@ -256,11 +256,23 @@ describe('SettingsViewUsers.vue', () => { | |
| expect(wrapper.findComponent(modal).props()).toMatchObject({ modelValue: true, user: zoe, notFound: false }) | ||
| }) | ||
|
|
||
| // A uid search by q only matches a substring, so a short uid could fall outside the page and | ||
| // the modal would claim the user does not exist (ICIJ/datashare#2434). | ||
| it('looks the routed user up by exact uid, not with a q search over a page of hits', async () => { | ||
| await core.router.push(`/settings/users/edit/${zoe.uid}`) | ||
| shallowMountComponent() | ||
| await flushPromises() | ||
| // noRole stays on: a user holding no role in the scope must still resolve | ||
| expect(api.getUsers).toHaveBeenCalledWith(expect.objectContaining({ uid: zoe.uid, noRole: true })) | ||
| expect(api.getUsers).not.toHaveBeenCalledWith(expect.objectContaining({ q: zoe.uid })) | ||
| }) | ||
|
|
||
| it.each([ | ||
| ['manage', SettingsViewUsersRolesModal], | ||
| ['edit', SettingsViewUsersEditModal], | ||
| ['delete', SettingsViewUsersDeleteModal] | ||
| ])('flags the %s modal as not found when the URL names an unknown user', async (action, modal) => { | ||
| api.getUsers.mockImplementation(async ({ uid }) => (uid ? { items: [], pagination: { total: 0 } } : usersResponse)) | ||
|
Member
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. important: this mock had to change to return no items because with items?.[0] the default response would resolve ghost to the first listed user. Nothing tests that case any more. Could we keep the original mock and add a case where the uid lookup returns |
||
| await core.router.push(`/settings/users/${action}/ghost`) | ||
| const wrapper = shallowMountComponent() | ||
| await flushPromises() | ||
|
|
@@ -310,8 +322,8 @@ describe('SettingsViewUsers.vue', () => { | |
| }) | ||
|
|
||
| it('reports a failed lookup and goes back to the list, instead of saying the user does not exist', async () => { | ||
| api.getUsers.mockImplementation(async ({ q }) => { | ||
| if (q === zoe.uid) throw new Error('timeout') | ||
| api.getUsers.mockImplementation(async ({ uid }) => { | ||
| if (uid === zoe.uid) throw new Error('timeout') | ||
| return usersResponse | ||
| }) | ||
| await core.router.push(`/settings/users/manage/${zoe.uid}`) | ||
|
|
@@ -414,13 +426,13 @@ describe('SettingsViewUsers.vue', () => { | |
|
|
||
| // Save then close: the refetch started by user:updated is dropped once the modal closes | ||
| const renamed = { ...zoe, name: 'Zoe Renamed' } | ||
| api.getUsers.mockImplementation(async ({ q }) => (q === zoe.uid ? { items: [renamed] } : usersResponse)) | ||
| api.getUsers.mockImplementation(async ({ uid }) => (uid === zoe.uid ? { items: [renamed] } : usersResponse)) | ||
| wrapper.findComponent(SettingsViewUsersEditModal).vm.$emit('user:updated', { uid: zoe.uid }) | ||
| wrapper.findComponent(SettingsViewUsersEditModal).vm.$emit('update:modelValue', false) | ||
| await flushPromises() | ||
|
|
||
| let resolveLookup | ||
| api.getUsers.mockImplementation(({ q }) => (q === zoe.uid | ||
| api.getUsers.mockImplementation(({ uid }) => (uid === zoe.uid | ||
| ? new Promise((resolve) => { | ||
| resolveLookup = () => resolve({ items: [renamed] }) | ||
| }) | ||
|
|
@@ -451,12 +463,12 @@ describe('SettingsViewUsers.vue', () => { | |
| await flushPromises() | ||
|
|
||
| const granted = { ...zoe, permissions: [{ v1: 'PROJECT_MEMBER', v2: 'default::project-a' }] } | ||
| api.getUsers.mockImplementation(async ({ q }) => (q === zoe.uid ? { items: [granted] } : usersResponse)) | ||
| api.getUsers.mockImplementation(async ({ uid }) => (uid === zoe.uid ? { items: [granted] } : usersResponse)) | ||
| api.getUsers.mockClear() | ||
| wrapper.findComponent(SettingsViewUsersRolesModal).vm.$emit('user:updated', { uid: zoe.uid }) | ||
| await flushPromises() | ||
|
|
||
| expect(api.getUsers).toHaveBeenCalledWith(expect.objectContaining({ q: zoe.uid })) | ||
| expect(api.getUsers).toHaveBeenCalledWith(expect.objectContaining({ uid: zoe.uid })) | ||
| expect(api.getUsers).toHaveBeenCalledWith(expect.objectContaining({ q: null })) | ||
| expect(wrapper.findComponent(SettingsViewUsersRolesModal).props('user')).toEqual(granted) | ||
| }) | ||
|
|
||
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.
crucial: with items?.[0], any backend that doesn't support uid yet ignores the param and returns the first page of all users, so
/settings/users/delete/zoe@example.orgwould open the delete modal on whoever comes first and delete them. Keeping the exact-match find costs nothing once the backend honours uid and keeps the wrong account from being picked: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.
Never mind, I checked the backend!