Commit a8056e2c by Hugo Häggmark Committed by GitHub

Admin: Fixes so form values are filled in from backend (#30544)

* Admin: Fixes so form values are filled in from backend

* Chore: tidy up the imports
parent 16f5d60d
import React from 'react';
import * as redux from 'react-redux';
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import SignupInvitedPage from './SignupInvited';
import { backendSrv } from '../../core/services/backend_srv';
jest.mock('app/core/core', () => ({
contextSrv: {
user: { orgName: 'Invited to Org Name' },
},
}));
jest.mock('@grafana/runtime', () => ({
...((jest.requireActual('@grafana/runtime') as unknown) as object),
getBackendSrv: () => backendSrv,
}));
const defaultGet = {
email: 'some.user@localhost',
name: 'Some User',
invitedBy: 'Invited By User',
username: 'someuser',
};
async function setupTestContext({ get = defaultGet }: { get?: typeof defaultGet | null } = {}) {
jest.clearAllMocks();
const reduxSpy = jest.spyOn(redux, 'useSelector');
reduxSpy.mockReturnValue('some code');
const getSpy = jest.spyOn(backendSrv, 'get');
getSpy.mockResolvedValue(get);
const postSpy = jest.spyOn(backendSrv, 'post');
postSpy.mockResolvedValue([]);
render(<SignupInvitedPage />);
await waitFor(() => expect(getSpy).toHaveBeenCalled());
expect(getSpy).toHaveBeenCalledTimes(1);
return { getSpy, postSpy };
}
describe('SignupInvitedPage', () => {
describe('when initialized but invite data has not been retrieved yet', () => {
it('then it should not render', async () => {
await setupTestContext({ get: null });
expect(screen.queryByText(/email/i)).not.toBeInTheDocument();
});
});
describe('when initialized and invite data has been retrieved', () => {
it('then the greeting should be correct', async () => {
await setupTestContext();
expect(
screen.getByRole('heading', {
name: /hello some user\./i,
})
).toBeInTheDocument();
});
it('then the invited by should be correct', async () => {
await setupTestContext();
const view = screen.getByText(
/has invited you to join grafana and the organization please complete the following and choose a password to accept your invitation and continue:/i
);
expect(within(view).getByText(/invited by user/i)).toBeInTheDocument();
});
it('then the organization invited to should be correct', async () => {
await setupTestContext();
const view = screen.getByText(
/has invited you to join grafana and the organization please complete the following and choose a password to accept your invitation and continue:/i
);
expect(within(view).getByText(/invited to org name/i)).toBeInTheDocument();
});
it('then the form should include form data', async () => {
await setupTestContext();
expect(screen.getByPlaceholderText(/email@example\.com/i)).toHaveValue('some.user@localhost');
expect(screen.getByPlaceholderText(/name \(optional\)/i)).toHaveValue('Some User');
expect(screen.getByPlaceholderText(/username/i)).toHaveValue('some.user@localhost');
expect(screen.getByPlaceholderText(/password/i)).toHaveValue('');
});
});
describe('when user submits the form and the required fields are not filled in', () => {
it('then required fields should show error messages and nothing should be posted', async () => {
const { postSpy } = await setupTestContext({ get: { email: '', invitedBy: '', name: '', username: '' } });
userEvent.click(screen.getByRole('button', { name: /sign up/i }));
await waitFor(() => expect(screen.getByText(/email is required/i)).toBeInTheDocument());
expect(screen.getByText(/username is required/i)).toBeInTheDocument();
expect(screen.getByText(/password is required/i)).toBeInTheDocument();
expect(postSpy).toHaveBeenCalledTimes(0);
});
});
describe('when user submits the form and the required fields are filled in', () => {
it('then correct form data should be posted', async () => {
const { postSpy } = await setupTestContext();
await userEvent.type(screen.getByPlaceholderText(/password/i), 'pass@word1');
userEvent.click(screen.getByRole('button', { name: /sign up/i }));
await waitFor(() => expect(postSpy).toHaveBeenCalledTimes(1));
expect(postSpy).toHaveBeenCalledWith('/api/user/invite/complete', {
email: 'some.user@localhost',
name: 'Some User',
username: 'some.user@localhost',
password: 'pass@word1',
inviteCode: 'some code',
});
});
});
});
import React, { FC, useState } from 'react'; import React, { FC, useState } from 'react';
import { hot } from 'react-hot-loader'; import { useSelector } from 'react-redux';
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
import { StoreState } from 'app/types';
import { updateLocation } from 'app/core/actions';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { Button, Field, Form, Input } from '@grafana/ui'; import { Button, Field, Form, Input } from '@grafana/ui';
import { useAsync } from 'react-use'; import { useAsync } from 'react-use';
import { StoreState } from 'app/types';
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
import { getConfig } from 'app/core/config'; import { getConfig } from 'app/core/config';
import { UrlQueryValue } from '@grafana/data';
interface ConnectedProps {
code?: UrlQueryValue;
}
interface DispatchProps {
updateLocation: typeof updateLocation;
}
interface FormModel { interface FormModel {
email: string; email: string;
...@@ -38,12 +28,13 @@ const navModel = { ...@@ -38,12 +28,13 @@ const navModel = {
}, },
}; };
const SingupInvitedPageUnconnected: FC<DispatchProps & ConnectedProps> = ({ code }) => { export const SignupInvitedPage: FC = () => {
const code = useSelector((state: StoreState) => state.location.routeParams.code);
const [initFormModel, setInitFormModel] = useState<FormModel>(); const [initFormModel, setInitFormModel] = useState<FormModel>();
const [greeting, setGreeting] = useState<string>(); const [greeting, setGreeting] = useState<string>();
const [invitedBy, setInvitedBy] = useState<string>(); const [invitedBy, setInvitedBy] = useState<string>();
useAsync(async () => { useAsync(async () => {
const invite = await getBackendSrv().get('/api/user/invite/' + code); const invite = await getBackendSrv().get(`/api/user/invite/${code}`);
setInitFormModel({ setInitFormModel({
email: invite.email, email: invite.email,
name: invite.name, name: invite.name,
...@@ -52,13 +43,17 @@ const SingupInvitedPageUnconnected: FC<DispatchProps & ConnectedProps> = ({ code ...@@ -52,13 +43,17 @@ const SingupInvitedPageUnconnected: FC<DispatchProps & ConnectedProps> = ({ code
setGreeting(invite.name || invite.email || invite.username); setGreeting(invite.name || invite.email || invite.username);
setInvitedBy(invite.invitedBy); setInvitedBy(invite.invitedBy);
}, []); }, [code]);
const onSubmit = async (formData: FormModel) => { const onSubmit = async (formData: FormModel) => {
await getBackendSrv().post('/api/user/invite/complete', { ...formData, inviteCode: code }); await getBackendSrv().post('/api/user/invite/complete', { ...formData, inviteCode: code });
window.location.href = getConfig().appSubUrl + '/'; window.location.href = getConfig().appSubUrl + '/';
}; };
if (!initFormModel) {
return null;
}
return ( return (
<Page navModel={navModel}> <Page navModel={navModel}>
<Page.Contents> <Page.Contents>
...@@ -110,12 +105,4 @@ const SingupInvitedPageUnconnected: FC<DispatchProps & ConnectedProps> = ({ code ...@@ -110,12 +105,4 @@ const SingupInvitedPageUnconnected: FC<DispatchProps & ConnectedProps> = ({ code
); );
}; };
const mapStateToProps: MapStateToProps<ConnectedProps, {}, StoreState> = (state: StoreState) => ({ export default SignupInvitedPage;
code: state.location.routeParams.code,
});
const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = {
updateLocation,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(SingupInvitedPageUnconnected));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment