Skip to content

Commit

Permalink
Enable password reset for practitioners (#1248)
Browse files Browse the repository at this point in the history
* Add credentials opton to update user's password

* Fix lint errors

* Add tests for credentials view
  • Loading branch information
mutuajames authored Aug 31, 2023
1 parent 39a20c1 commit 8beec0d
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ export const UserList = (props: OrganizationListProps) => {
extraData,
queryClient,
t,
onViewDetails
onViewDetails,
history
);

const searchFormProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import type { MenuProps } from 'antd';
import { MoreOutlined } from '@ant-design/icons';
import { deleteUser } from './utils';
import { Link } from 'react-router-dom';
import { KeycloakUser, URL_USER_EDIT, KEYCLOAK_URL_USERS } from '@opensrp/user-management';
import {
KeycloakUser,
URL_USER_EDIT,
KEYCLOAK_URL_USERS,
URL_USER_CREDENTIALS,
} from '@opensrp/user-management';
import { Dictionary } from '@onaio/utils';
import { Column } from '@opensrp/react-utils';
import { sendErrorNotification } from '@opensrp/notifications';
import { QueryClient } from 'react-query';
import type { TFunction } from '@opensrp/i18n';
import { History } from 'history';

/**
* Get table columns for user list
Expand All @@ -20,14 +26,16 @@ import type { TFunction } from '@opensrp/i18n';
* @param queryClient - react query client
* @param t - translator function
* @param onViewDetails - callback when view details is clicked.
* @param history - history object for managing navigation
*/
export const getTableColumns = (
keycloakBaseUrl: string,
baseUrl: string,
extraData: Dictionary,
queryClient: QueryClient,
t: TFunction,
onViewDetails: (recordId: string) => void
onViewDetails: (recordId: string) => void,
history: History
): Column<KeycloakUser>[] => {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { user_id } = extraData;
Expand Down Expand Up @@ -85,6 +93,18 @@ export const getTableColumns = (
</Popconfirm>
),
},
{
key: '3',
label: (
<Button
type="link"
data-testid="credentials"
onClick={() => history.push(`${URL_USER_CREDENTIALS}/${record.id}`)}
>
{t('Credentials')}
</Button>
),
},
];

dataElements.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import nock from 'nock';
import { waitFor, waitForElementToBeRemoved } from '@testing-library/dom';
import { act, cleanup, fireEvent, render, screen } from '@testing-library/react';
import userEvents from '@testing-library/user-event';
import { URL_USER } from '@opensrp/user-management';
import { URL_USER, URL_USER_CREDENTIALS, UserCredentials } from '@opensrp/user-management';
import { careTeams, practitioner, userFixtures, group } from './fixtures';
import fetch from 'jest-fetch-mock';
import {
Expand Down Expand Up @@ -75,6 +75,9 @@ const AppWrapper = (props: any) => {
<Route exact path={`${URL_USER}/:id`}>
{(routeProps) => <UserList {...{ ...props, ...routeProps }} />}
</Route>
<Route exact path={`${URL_USER_CREDENTIALS}/:id`}>
{(routeProps) => <UserCredentials {...{ ...props, ...routeProps }} />}
</Route>
</Switch>
</QueryClientProvider>
</Provider>
Expand Down Expand Up @@ -269,6 +272,69 @@ test('renders correctly when listing resources', async () => {
expect(nock.isDone()).toBeTruthy();
});

test('credentials view renders correctly', async () => {
const history = createMemoryHistory();
history.push(URL_USER);

fetch
.once(JSON.stringify(15))
.once(JSON.stringify(userFixtures))
.once(JSON.stringify(userFixtures[0]));
fetch.mockResponse(JSON.stringify([]));

render(
<Router history={history}>
<AppWrapper {...props}></AppWrapper>
</Router>
);

await waitFor(async () => {
const spin = document.querySelector('.ant-spin');
expect(spin).toBeNull();
});

const practitionerObj = practitioner.entry?.[0].resource;

nock(props.fhirBaseURL)
.get(`/${practitionerResourceType}/_search`)
.query({ identifier: userFixtures[14].id })
.reply(200, practitioner)
.get(`/Group/_search`)
.query({ identifier: userFixtures[14].id })
.reply(200, group)
.get(`/${careTeamResourceType}/_search`)
.query({ 'participant:Practitioner': practitionerObj?.id, _summary: 'count' })
.reply(200, { total: 2 })
.get(`/${careTeamResourceType}/_search`)
.query({ 'participant:Practitioner': practitionerObj?.id, _count: '2' })
.reply(200, careTeams)
.get(`/${practitionerRoleResourceType}/_search`)
.query({ identifier: userFixtures[14].id })
.reply(200, practitionerRoleBundle)
.persist();

// target the initial row view details
const dropdown = document.querySelector(
'tbody tr:nth-child(1) [data-testid="action-dropdown"]'
) as Element;
fireEvent.click(dropdown);

// Clicking credentials takes you to the credentials view
const updateLink = screen.getByText(/Credentials/i);
fireEvent.click(updateLink);
expect(history.location.pathname).toEqual(
`${URL_USER_CREDENTIALS}/081724e8-5fc1-47dd-8d0c-fa0c6ae6ddf0`
);

// Confirm we are in the credentials view
expect(screen.getByText(/User Credentials/i)).toBeInTheDocument();

// Clicking cancel returns us to users
fireEvent.click(screen.getByRole('button', { name: 'Cancel' }));

expect(history.location.pathname).toEqual(URL_USER);
});

test('responds as expected to errors', async () => {
const history = createMemoryHistory();
history.push(URL_USER);
Expand Down

0 comments on commit 8beec0d

Please sign in to comment.