mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 16:15:42 -06:00
Chore: Add tests for ChangePasswordPage and SendResetMailPage (#36313)
* added tests for changePassword and forgotPassword component * added tests for ChangePassword screen in user profile section * addressed review changes
This commit is contained in:
parent
3cce67c044
commit
36592e0927
@ -23,14 +23,16 @@ export const ChangePassword: FC<Props> = ({ onSubmit, onSkip }) => {
|
||||
<Field label="New password" invalid={!!errors.newPassword} error={errors?.newPassword?.message}>
|
||||
<Input
|
||||
autoFocus
|
||||
id="new-password"
|
||||
type="password"
|
||||
{...register('newPassword', {
|
||||
required: 'New password required',
|
||||
required: 'New password is required',
|
||||
})}
|
||||
/>
|
||||
</Field>
|
||||
<Field label="Confirm new password" invalid={!!errors.confirmNew} error={errors?.confirmNew?.message}>
|
||||
<Input
|
||||
id="confirm-new-password"
|
||||
type="password"
|
||||
{...register('confirmNew', {
|
||||
required: 'Confirmed password is required',
|
||||
|
@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
|
||||
|
||||
import { ChangePasswordPage, Props } from './ChangePasswordPage';
|
||||
|
||||
const postMock = jest.fn();
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
getBackendSrv: () => ({
|
||||
post: postMock,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('app/core/config', () => {
|
||||
return {
|
||||
loginError: false,
|
||||
buildInfo: {
|
||||
version: 'v1.0',
|
||||
commit: '1',
|
||||
env: 'production',
|
||||
edition: 'Open Source',
|
||||
isEnterprise: false,
|
||||
},
|
||||
licenseInfo: {
|
||||
stateInfo: '',
|
||||
licenseUrl: '',
|
||||
},
|
||||
appSubUrl: '',
|
||||
};
|
||||
});
|
||||
const props: Props = {
|
||||
...getRouteComponentProps({
|
||||
queryParams: { code: 'some code' },
|
||||
}),
|
||||
};
|
||||
|
||||
describe('ChangePassword Page', () => {
|
||||
it('renders correctly', () => {
|
||||
render(<ChangePasswordPage {...props} />);
|
||||
|
||||
expect(screen.getByLabelText('New password')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Confirm new password')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
|
||||
});
|
||||
it('should pass validation checks for password and confirm password field', async () => {
|
||||
render(<ChangePasswordPage {...props} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Submit' }));
|
||||
expect(await screen.findByText('New password is required')).toBeInTheDocument();
|
||||
expect(screen.getByText('Confirmed password is required')).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
await userEvent.type(screen.getByLabelText('New password'), 'admin');
|
||||
await userEvent.type(screen.getByLabelText('Confirm new password'), 'a');
|
||||
expect(screen.getByText('Passwords must match!')).toBeInTheDocument();
|
||||
|
||||
await userEvent.type(screen.getByLabelText('Confirm new password'), 'dmin');
|
||||
expect(screen.queryByText('Passwords must match!')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('should navigate to default url if change password is successful', async () => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
assign: jest.fn(),
|
||||
},
|
||||
});
|
||||
postMock.mockResolvedValueOnce({ message: 'Logged in' });
|
||||
render(<ChangePasswordPage {...props} />);
|
||||
|
||||
await userEvent.type(screen.getByLabelText('New password'), 'test');
|
||||
await userEvent.type(screen.getByLabelText('Confirm new password'), 'test');
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Submit' }));
|
||||
await waitFor(() =>
|
||||
expect(postMock).toHaveBeenCalledWith('/api/user/password/reset', {
|
||||
code: 'some code',
|
||||
confirmPassword: 'test',
|
||||
newPassword: 'test',
|
||||
})
|
||||
);
|
||||
expect(window.location.assign).toHaveBeenCalledWith('/');
|
||||
});
|
||||
});
|
@ -4,7 +4,7 @@ import { ChangePassword } from './ChangePassword';
|
||||
import LoginCtrl from '../Login/LoginCtrl';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
|
||||
interface Props extends GrafanaRouteComponentProps<{}, { code: string }> {}
|
||||
export interface Props extends GrafanaRouteComponentProps<{}, { code: string }> {}
|
||||
|
||||
export const ChangePasswordPage: FC<Props> = (props) => {
|
||||
return (
|
||||
|
@ -51,7 +51,11 @@ export const ForgottenPassword: FC = () => {
|
||||
invalid={!!errors.userOrEmail}
|
||||
error={errors?.userOrEmail?.message}
|
||||
>
|
||||
<Input placeholder="Email or username" {...register('userOrEmail', { required: true })} />
|
||||
<Input
|
||||
id="user-input"
|
||||
placeholder="Email or username"
|
||||
{...register('userOrEmail', { required: 'Email or username is required' })}
|
||||
/>
|
||||
</Field>
|
||||
<HorizontalGroup>
|
||||
<Button>Send reset email</Button>
|
||||
|
@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { SendResetMailPage } from './SendResetMailPage';
|
||||
|
||||
const postMock = jest.fn();
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
getBackendSrv: () => ({
|
||||
post: postMock,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('app/core/config', () => {
|
||||
return {
|
||||
buildInfo: {
|
||||
version: 'v1.0',
|
||||
commit: '1',
|
||||
env: 'production',
|
||||
edition: 'Open Source',
|
||||
isEnterprise: false,
|
||||
},
|
||||
licenseInfo: {
|
||||
stateInfo: '',
|
||||
licenseUrl: '',
|
||||
},
|
||||
appSubUrl: '',
|
||||
};
|
||||
});
|
||||
|
||||
describe('VerifyEmail Page', () => {
|
||||
it('renders correctly', () => {
|
||||
render(<SendResetMailPage />);
|
||||
expect(screen.getByText('Reset password')).toBeInTheDocument();
|
||||
expect(screen.getByRole('textbox', { name: /User Enter your information/i })).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByRole('button', { name: 'Send reset email' })).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByRole('link', { name: 'Back to login' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: 'Back to login' })).toHaveAttribute('href', '/login');
|
||||
});
|
||||
it('should pass validation checks for email field', async () => {
|
||||
render(<SendResetMailPage />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Send reset email' }));
|
||||
expect(await screen.findByText('Email or username is required')).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
await userEvent.type(screen.getByRole('textbox', { name: /User Enter your information/i }), 'test@gmail.com');
|
||||
expect(screen.queryByText('Email is invalid')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('should show success meessage if reset-password is successful', async () => {
|
||||
postMock.mockResolvedValueOnce({ message: 'Email sent' });
|
||||
render(<SendResetMailPage />);
|
||||
|
||||
await userEvent.type(screen.getByRole('textbox', { name: /User Enter your information/i }), 'test@gmail.com');
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Send reset email' }));
|
||||
await waitFor(() =>
|
||||
expect(postMock).toHaveBeenCalledWith('/api/user/password/send-reset-email', {
|
||||
userOrEmail: 'test@gmail.com',
|
||||
})
|
||||
);
|
||||
expect(screen.getByText(/An email with a reset link/i)).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: 'Back to login' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: 'Back to login' })).toHaveAttribute('href', '/login');
|
||||
});
|
||||
});
|
@ -34,11 +34,16 @@ export const ChangePasswordForm: FC<Props> = ({ user, onChangePassword, isSaving
|
||||
return (
|
||||
<>
|
||||
<Field label="Old password" invalid={!!errors.oldPassword} error={errors?.oldPassword?.message}>
|
||||
<Input type="password" {...register('oldPassword', { required: 'Old password is required' })} />
|
||||
<Input
|
||||
id="old-password"
|
||||
type="password"
|
||||
{...register('oldPassword', { required: 'Old password is required' })}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field label="New password" invalid={!!errors.newPassword} error={errors?.newPassword?.message}>
|
||||
<Input
|
||||
id="new-password"
|
||||
type="password"
|
||||
{...register('newPassword', {
|
||||
required: 'New password is required',
|
||||
@ -52,6 +57,7 @@ export const ChangePasswordForm: FC<Props> = ({ user, onChangePassword, isSaving
|
||||
|
||||
<Field label="Confirm password" invalid={!!errors.confirmNew} error={errors?.confirmNew?.message}>
|
||||
<Input
|
||||
id="confirm-new-password"
|
||||
type="password"
|
||||
{...register('confirmNew', {
|
||||
required: 'New password confirmation is required',
|
||||
|
122
public/app/features/profile/ChangePasswordPage.test.tsx
Normal file
122
public/app/features/profile/ChangePasswordPage.test.tsx
Normal file
@ -0,0 +1,122 @@
|
||||
import React from 'react';
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import config from 'app/core/config';
|
||||
import { Props, ChangePasswordPage } from './ChangePasswordPage';
|
||||
import { initialUserState } from './state/reducers';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
import { backendSrv } from '../../core/services/backend_srv';
|
||||
|
||||
const defaultProps: Props = {
|
||||
...initialUserState,
|
||||
user: {
|
||||
id: 1,
|
||||
name: 'Test User',
|
||||
email: 'test@test.com',
|
||||
login: 'test',
|
||||
isDisabled: false,
|
||||
isGrafanaAdmin: false,
|
||||
orgId: 0,
|
||||
authLabels: ['github'],
|
||||
},
|
||||
navModel: getNavModel(
|
||||
{
|
||||
'profile-settings': {
|
||||
icon: 'sliders-v-alt',
|
||||
id: 'profile-settings',
|
||||
parentItem: {
|
||||
id: 'profile',
|
||||
text: 'Test User',
|
||||
img: '/avatar/46d229b033af06a191ff2267bca9ae56',
|
||||
url: '/profile',
|
||||
},
|
||||
text: 'Preferences',
|
||||
url: '/profile',
|
||||
},
|
||||
},
|
||||
'profile-settings'
|
||||
),
|
||||
loadUser: jest.fn(),
|
||||
changePassword: jest.fn(),
|
||||
};
|
||||
|
||||
async function getTestContext(overrides: Partial<Props> = {}) {
|
||||
jest.clearAllMocks();
|
||||
jest.spyOn(backendSrv, 'get').mockResolvedValue({
|
||||
id: 1,
|
||||
name: 'Test User',
|
||||
email: 'test@test.com',
|
||||
login: 'test',
|
||||
isDisabled: false,
|
||||
isGrafanaAdmin: false,
|
||||
orgId: 0,
|
||||
});
|
||||
|
||||
const props = { ...defaultProps, ...overrides };
|
||||
const { rerender } = render(<ChangePasswordPage {...props} />);
|
||||
|
||||
await waitFor(() => expect(props.loadUser).toHaveBeenCalledTimes(1));
|
||||
|
||||
return { rerender, props };
|
||||
}
|
||||
|
||||
describe('ChangePasswordPage', () => {
|
||||
it('should show loading placeholder', async () => {
|
||||
await getTestContext({ user: null });
|
||||
|
||||
expect(screen.getByText(/loading \.\.\./i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show change password form when user has loaded', async () => {
|
||||
await getTestContext();
|
||||
expect(screen.getByText('Change Your Password')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByLabelText('Old password')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('New password')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Confirm password')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByRole('button', { name: 'Change Password' })).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByRole('link', { name: 'Cancel' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: 'Cancel' })).toHaveAttribute('href', '/profile');
|
||||
});
|
||||
it('should call changePassword if change password is valid', async () => {
|
||||
const { props } = await getTestContext();
|
||||
|
||||
await userEvent.type(screen.getByLabelText('Old password'), 'test');
|
||||
await userEvent.type(screen.getByLabelText('New password'), 'admin');
|
||||
await userEvent.type(screen.getByLabelText('Confirm password'), 'admin');
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Change Password' }));
|
||||
await waitFor(() => {
|
||||
expect(props.changePassword).toHaveBeenCalledTimes(1);
|
||||
expect(props.changePassword).toHaveBeenCalledWith(
|
||||
{
|
||||
confirmNew: 'admin',
|
||||
newPassword: 'admin',
|
||||
oldPassword: 'test',
|
||||
},
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
});
|
||||
it('should cannot change password form if ldap or authProxy enabled', async () => {
|
||||
config.ldapEnabled = true;
|
||||
const { rerender } = await getTestContext();
|
||||
expect(
|
||||
screen.getByText('You cannot change password when LDAP or auth proxy authentication is enabled.')
|
||||
).toBeInTheDocument();
|
||||
config.ldapEnabled = false;
|
||||
config.authProxyEnabled = true;
|
||||
rerender(<ChangePasswordPage {...defaultProps} />);
|
||||
expect(
|
||||
screen.getByText('You cannot change password when LDAP or auth proxy authentication is enabled.')
|
||||
).toBeInTheDocument();
|
||||
config.authProxyEnabled = false;
|
||||
});
|
||||
it('should show cannot change password if disableLoginForm is true and auth', async () => {
|
||||
config.disableLoginForm = true;
|
||||
await getTestContext();
|
||||
expect(screen.getByText('Password cannot be changed here.')).toBeInTheDocument();
|
||||
config.disableLoginForm = false;
|
||||
});
|
||||
});
|
@ -31,7 +31,7 @@ const mapDispatchToProps = {
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
export type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
|
||||
export function ChangePasswordPage({ navModel, loadUser, isUpdating, user, changePassword }: Props) {
|
||||
useMount(() => loadUser());
|
||||
|
Loading…
Reference in New Issue
Block a user