Skip to content

Commit

Permalink
Fix credentials redirect url (#1258)
Browse files Browse the repository at this point in the history
* Add username to credentials url

* Add username to credentials url for fhir user management

* Move test to create new user to own file

facing a jest-fetch-mock-error that isMocking is not a function
  • Loading branch information
peterMuriuki authored Sep 8, 2023
1 parent b29146f commit e5d206a
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,9 @@ export const practitionerUpdater =
})
.catch(() => sendErrorNotification(practitionerErrorMessage))
.finally(() => {
if (!isEditMode) history.push(`${URL_USER_CREDENTIALS}/${userId}`);
if (!isEditMode) {
history.push(`${URL_USER_CREDENTIALS}/${userId}/${values.username}`);
}
})
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,55 @@ export const keycloakUser = {
},
};

export const newPractitioner = {
resourceType: 'Practitioner',
id: 'acb9d47e-7247-448f-be93-7a193a5312da',
identifier: [
{ use: 'official', value: 'acb9d47e-7247-448f-be93-7a193a5312da' },
{ use: 'secondary', value: 'cab07278-c77b-4bc7-b154-bcbf01b7d35b' },
],
active: true,
name: [{ use: 'official', family: 'plotus', given: ['flotus', ''] }],
telecom: [{ system: 'email', value: '[email protected]' }],
};
export const newPractitionerRole = {
resourceType: 'PractitionerRole',
id: 'acb9d47e-7247-448f-be93-7a193a5312da',
identifier: [
{ use: 'official', value: 'acb9d47e-7247-448f-be93-7a193a5312da' },
{ use: 'secondary', value: 'cab07278-c77b-4bc7-b154-bcbf01b7d35b' },
],
active: true,
practitioner: {
reference: 'Practitioner/c1d36d9a-b771-410b-959e-af2c04d132a2',
display: 'Demoflotus kenyaplotus',
},
code: [
{
coding: [
{ system: 'http://snomed.info/sct', code: '236321002', display: 'Supervisor (occupation)' },
],
},
],
};
export const newGroup = {
resourceType: 'Group',
id: 'acb9d47e-7247-448f-be93-7a193a5312da',
identifier: [
{ use: 'official', value: 'acb9d47e-7247-448f-be93-7a193a5312da' },
{ use: 'secondary', value: 'cab07278-c77b-4bc7-b154-bcbf01b7d35b' },
],
active: true,
type: 'practitioner',
actual: true,
code: {
coding: [
{ system: 'http://snomed.info/sct', code: '405623001', display: 'Assigned practitioner' },
],
},
name: 'flotus plotus',
member: [{ entity: { reference: 'Practitioner/c1d36d9a-b771-410b-959e-af2c04d132a2' } }],
};
export const practitioner = {
resourceType: 'Bundle',
id: '30c8715d-c661-4c58-b7f1-303f6e6251c6',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
/* eslint-disable @typescript-eslint/naming-convention */
import React from 'react';
import { Route, Router, Switch } from 'react-router';
import { QueryClient, QueryClientProvider } from 'react-query';
import { CreateEditUser, practitionerUpdater, getPractitioner, getPractitionerRole } from '..';
import { Provider } from 'react-redux';
import { store } from '@opensrp/store';
import nock from 'nock';
import { cleanup, fireEvent, render } from '@testing-library/react';
import { waitFor } from '@testing-library/dom';
import { authenticateUser } from '@onaio/session-reducer';
import fetch from 'jest-fetch-mock';
import {
keycloakUser,
practitioner,
updatedPractitioner,
userGroup,
group,
practitionerRoleBundle,
compositionResource,
newPractitioner,
newPractitionerRole,
newGroup,
} from './fixtures';
import userEvent from '@testing-library/user-event';
import * as notifications from '@opensrp/notifications';
import { practitionerResourceType, practitionerRoleResourceType } from '../../../constants';
import { fetchKeycloakUsers } from '@opensrp/user-management';
import { history } from '@onaio/connected-reducer-registry';
import { opensrpI18nInstance } from '@opensrp/i18n';

jest.setTimeout(10000);

jest.mock('fhirclient', () => {
return jest.requireActual('fhirclient/lib/entry/browser');
});

jest.mock('@opensrp/notifications', () => ({
__esModule: true,
...Object.assign({}, jest.requireActual('@opensrp/notifications')),
}));

const mockId = 'acb9d47e-7247-448f-be93-7a193a5312da';

jest.mock('uuid', () => {
const actual = jest.requireActual('uuid');
return {
...actual,
v4: () => mockId,
};
});

const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
cacheTime: 0,
},
},
});

const props = {
baseUrl: 'http://test.server.org',
keycloakBaseURL: 'http://test-keycloak.server.org',
history,
location: {
hash: '',
pathname: '/users/edit',
search: '',
state: '',
},
match: {
isExact: true,
params: { userId: keycloakUser.id },
path: `/add/:id`,
url: `/add/${keycloakUser.id}`,
},
keycloakUser,
extraData: {},
fetchKeycloakUsersCreator: fetchKeycloakUsers,
getPractitionerFun: getPractitioner,
getPractitionerRoleFun: getPractitionerRole,
postPutPractitionerFactory: practitionerUpdater,
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const AppWrapper = (props: any) => {
return (
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<Switch>
<Route exact path="/add">
<CreateEditUser {...props} />
</Route>
<Route exact path="/add/:id">
<CreateEditUser {...props} />
</Route>
<Route exact path="/">
I love oof!
</Route>
</Switch>
</QueryClientProvider>
</Provider>
);
};

afterEach(() => {
cleanup();
nock.cleanAll();
fetch.resetMocks();
jest.resetAllMocks();
});

beforeAll(async () => {
await opensrpI18nInstance.init();
nock.disableNetConnect();
store.dispatch(
authenticateUser(
true,
{
email: '[email protected]',
name: 'Bobbie',
username: 'RobertBaratheon',
},
{ api_token: 'hunter2', oAuth2Data: { access_token: 'sometoken', state: 'abcde' } }
)
);
});

afterAll(() => {
nock.enableNetConnect();
});

test('renders correctly for new user', async () => {
history.push('/add');

const thisProps = {
...props,
history,
location: {
hash: '',
pathname: '/add',
search: '',
state: '',
},
match: {
isExact: true,
params: {},
path: `/add`,
url: `/add`,
},
keycloakUser: null,
};

fetch.once(JSON.stringify(userGroup));
fetch.once(JSON.stringify(keycloakUser), { headers: { location: `/${keycloakUser.id}` } });

nock(props.baseUrl)
.get(`/${practitionerResourceType}/_search`)
.query({
identifier: keycloakUser.id,
})
.reply(200, practitioner);

nock(props.baseUrl)
.get('/PractitionerRole/_search')
.query({
identifier: keycloakUser.id,
})
.reply(200, practitionerRoleBundle);

nock(props.baseUrl)
.put(`/${practitionerResourceType}/${mockId}`, newPractitioner)
.reply(200, updatedPractitioner);

nock(props.baseUrl)
.put(`/${practitionerRoleResourceType}/${mockId}`, newPractitionerRole)
.reply(200, {});

nock(props.baseUrl)
.get(`/Group/_search`)
.query({
identifier: keycloakUser.id,
})
.reply(200, group);

nock(props.baseUrl).put(`/Group/${mockId}`, newGroup).reply(200, {});

nock(props.baseUrl)
.get(`/Composition/_search`)
.query({
_getpagesoffset: '0',
_count: '20',
type: `http://snomed.info/sct|1156600005`,
_elements: 'identifier,title',
})
.reply(200, compositionResource)
.persist();

const successStub = jest
.spyOn(notifications, 'sendSuccessNotification')
.mockImplementation(jest.fn);

const errorStub = jest.spyOn(notifications, 'sendErrorNotification').mockImplementation(jest.fn);

const { getByTestId, getByText, queryByTitle } = render(
<Router history={history}>
<AppWrapper {...thisProps}></AppWrapper>
</Router>
);

expect(getByTestId('custom-create-user-spinner')).toBeInTheDocument();

await waitFor(() => {
expect(getByText(/User Type/)).toBeInTheDocument();
});

expect(fetch.mock.calls.map((req) => req[0])).toEqual(['http://test-keycloak.server.org/groups']);

// simulate first Name change
const firstNameInput = document.querySelector('input#firstName');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
userEvent.type(firstNameInput!, 'flotus');

const lastNameInput = document.querySelector('input#lastName');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
userEvent.type(lastNameInput!, 'plotus');

const emailInput = document.querySelector('input#email');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
userEvent.type(emailInput!, '[email protected]');

const usernameInput = document.querySelector('input#username');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
userEvent.type(usernameInput!, 'flopo');

const markSupervisor = document.querySelectorAll('input[name="userType"]')[1];
userEvent.click(markSupervisor);

const submitButton = document.querySelector('button[type="submit"]');

// find antd Select with id 'fhirCoreAppId' in the 'Form' component
const appIdSection = document.querySelector('[data-testid="fhirCoreAppId"]') as Element;

// click on input. - should see the first 5 records by default
const appIdInput = appIdSection.querySelector('.ant-select-selector') as Element;

// simulate click on select - to show dropdown items
fireEvent.mouseDown(appIdInput);

// await waitForElementToBeRemoved(appIdSection.querySelector('.anticon-spin'));
await waitFor(() => {
const spin = appIdSection.querySelector('.anticon-spin');
expect(spin).toBeNull();
});

fireEvent.click(queryByTitle('Device configurations(cha)') as Element);

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
fireEvent.click(submitButton!);

// need not concern ourselves with groups, should be tested in user-management package
await waitFor(() => {
expect(errorStub).toHaveBeenCalledTimes(0);
// TODO - Includes caught mock calls from previous test
expect(successStub.mock.calls).toEqual([
['User created successfully'],
['Practitioner created successfully'],
['User Group edited successfully'],
['Group resource created successfully'],
['PractitionerRole created successfully'],
]);
});

expect(fetch.mock.calls.map((req) => req[0])).toEqual([
'http://test-keycloak.server.org/groups',
'http://test-keycloak.server.org/users',
]);

expect(
fetch.mock.calls.map((call) => ({
endpoint: call[0],
method: call[1]?.method,
}))
).toEqual([
{ endpoint: 'http://test-keycloak.server.org/groups', method: 'GET' },
{
endpoint: 'http://test-keycloak.server.org/users',
method: 'POST',
},
]);

expect(history.location.pathname).toEqual(
'/admin/users/credentials/cab07278-c77b-4bc7-b154-bcbf01b7d35b/flopo'
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const TableActions = (props: Props): JSX.Element => {
<Button
type="link"
data-testid="credentials"
onClick={() => history.push(`${URL_USER_CREDENTIALS}/${record.id}`)}
onClick={() => history.push(`${URL_USER_CREDENTIALS}/${record.id}/${record.username}`)}
>
{t('Credentials')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@ describe('forms/utils/submitForm', () => {
['Practitioner created successfully'],
['User Group edited successfully'],
]);
expect(historyPushMock).toHaveBeenCalledWith(`/admin/users/credentials/${keycloakUserId}`);
expect(historyPushMock).toHaveBeenCalledWith(
`/admin/users/credentials/${keycloakUserId}/janedoe`
);
});

it('ensures error notification is not thrown when creating new user', async () => {
Expand Down Expand Up @@ -211,7 +213,9 @@ describe('forms/utils/submitForm', () => {
});
// ensure that redirect only happens once
expect(historyPushMock).toHaveBeenCalledTimes(1);
expect(historyPushMock).toHaveBeenCalledWith(`/admin/users/credentials/${keycloakUserId}`);
expect(historyPushMock).toHaveBeenCalledWith(
`/admin/users/credentials/${keycloakUserId}/janedoe`
);
});

it('submits user edit correctly', async () => {
Expand Down
Loading

0 comments on commit e5d206a

Please sign in to comment.