Skip to content

Commit f21a83e

Browse files
committed
1695-login/register tests
1 parent 2e7bbb8 commit f21a83e

File tree

7 files changed

+532
-0
lines changed

7 files changed

+532
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
import {useAuthenticationStore} from '@/shared/stores/useAuthenticationStore';
2+
import {render, screen, userEvent, waitFor} from '@/shared/util/test-utils';
3+
import {MemoryRouter, Route, Routes} from 'react-router-dom';
4+
import {afterEach, beforeEach, expect, it, vi} from 'vitest';
5+
6+
import AccountErrorPage from '../AccountErrorPage';
7+
import Login from '../Login';
8+
import PasswordResetInit from '../PasswordResetInit';
9+
import Register from '../Register';
10+
import {mockApplicationInfoStore} from '../tests/mocks/mockApplicationInfoStore';
11+
import {mockAuthenticationStore} from '../tests/mocks/mockAuthenticationStore';
12+
import {resetAll, windowResizeObserver} from './utils/testUtils';
13+
14+
screen.debug();
15+
16+
const renderLoginPage = () => {
17+
render(
18+
<MemoryRouter initialEntries={['/login']}>
19+
<Routes>
20+
<Route element={<Login />} path="/login" />
21+
</Routes>
22+
</MemoryRouter>
23+
);
24+
};
25+
26+
vi.mock('@/shared/stores/useAuthenticationStore', () => ({
27+
useAuthenticationStore: vi.fn(),
28+
}));
29+
30+
vi.mock('@/shared/stores/useApplicationInfoStore', () => ({
31+
useApplicationInfoStore: vi.fn(),
32+
}));
33+
34+
beforeEach(() => {
35+
mockApplicationInfoStore();
36+
});
37+
38+
beforeEach(() => {
39+
mockAuthenticationStore();
40+
});
41+
42+
beforeEach(() => {
43+
windowResizeObserver();
44+
});
45+
46+
afterEach(() => {
47+
resetAll();
48+
});
49+
50+
it('should render the login page on "/login" path', () => {
51+
renderLoginPage();
52+
53+
expect(screen.getByText('Welcome back')).toBeInTheDocument();
54+
});
55+
56+
it('should hide password input on render and toggle "show password" when "show password" icon is clicked', async () => {
57+
renderLoginPage();
58+
59+
const passwordInputField = screen.getByLabelText('Password');
60+
expect(passwordInputField).toHaveAttribute('type', 'password');
61+
62+
const button = screen.getByRole('button', {name: /Show Passwor/i});
63+
await userEvent.click(button);
64+
expect(passwordInputField).toHaveAttribute('type', 'text');
65+
66+
await userEvent.click(button);
67+
expect(passwordInputField).toHaveAttribute('type', 'password');
68+
});
69+
70+
it('should not submit form when only "show password" button is clicked', async () => {
71+
renderLoginPage();
72+
73+
const emailInputField = screen.getByLabelText('Email');
74+
const passwordInputField = screen.getByLabelText('Password');
75+
const stayLoggedInCheckbox = screen.getByRole('checkbox', {name: /stay logged in/i});
76+
77+
await userEvent.type(emailInputField, 'test@example.com');
78+
await userEvent.type(passwordInputField, 'password');
79+
await userEvent.click(stayLoggedInCheckbox);
80+
81+
const showPasswordButton = screen.getByRole('button', {name: /show password/i});
82+
83+
await userEvent.click(showPasswordButton);
84+
85+
await waitFor(() => {
86+
expect(useAuthenticationStore().login).not.toHaveBeenCalled();
87+
});
88+
});
89+
90+
it('should render "PasswordResetInit" page if "Forgot your password" is clicked', async () => {
91+
render(
92+
<MemoryRouter initialEntries={['/login']}>
93+
<Routes>
94+
<Route element={<Login />} path="/login" />
95+
96+
<Route element={<PasswordResetInit />} path="/password-reset/init" />
97+
</Routes>
98+
</MemoryRouter>
99+
);
100+
101+
expect(screen.getByText('Welcome back')).toBeInTheDocument();
102+
103+
const forgotPasswordButton = screen.getByText('Forgot your password');
104+
await userEvent.click(forgotPasswordButton);
105+
106+
await waitFor(() => {
107+
expect(screen.getByText('Forgot your password?')).toBeInTheDocument();
108+
});
109+
});
110+
111+
it('should render "Register" page if "Create account" is clicked', async () => {
112+
render(
113+
<MemoryRouter initialEntries={['/login']}>
114+
<Routes>
115+
<Route element={<Login />} path="/login" />
116+
117+
<Route element={<Register />} path="/register" />
118+
</Routes>
119+
</MemoryRouter>
120+
);
121+
122+
expect(screen.getByText('Welcome back')).toBeInTheDocument();
123+
124+
const createAccountButton = screen.getByText('Create account');
125+
await userEvent.click(createAccountButton);
126+
127+
await waitFor(() => {
128+
expect(screen.getByText('Create your account')).toBeInTheDocument();
129+
});
130+
});
131+
132+
it('should render "AccountErrorPage" if loginError is true', async () => {
133+
mockAuthenticationStore({
134+
loginError: true,
135+
reset: vi.fn(),
136+
});
137+
138+
render(
139+
<MemoryRouter initialEntries={['/login']}>
140+
<Routes>
141+
<Route element={<Login />} path="/login" />
142+
143+
<Route element={<AccountErrorPage />} path="/account-error" />
144+
</Routes>
145+
</MemoryRouter>
146+
);
147+
148+
await waitFor(() => {
149+
expect(screen.getByText('Failed to sign in, please check your credentials and try again.')).toBeInTheDocument();
150+
});
151+
});
152+
153+
it('should submit form with correct login details when "Log in" is clicked', async () => {
154+
renderLoginPage();
155+
156+
const emailInputField = screen.getByLabelText('Email');
157+
const passwordInputField = screen.getByLabelText('Password');
158+
const stayLoggedInCheckbox = screen.getByRole('checkbox', {name: /stay logged in/i});
159+
160+
const logInButton = screen.getByRole('button', {name: /log in/i});
161+
162+
await userEvent.type(emailInputField, 'test@example.com');
163+
await userEvent.type(passwordInputField, 'password');
164+
await userEvent.click(stayLoggedInCheckbox);
165+
166+
await userEvent.click(logInButton);
167+
168+
await waitFor(() => {
169+
expect(useAuthenticationStore().login).toHaveBeenCalledWith('test@example.com', 'password', true);
170+
});
171+
});
172+
173+
it('should show validation errors after clicking "Log in" button, if input fields are empty strings', async () => {
174+
renderLoginPage();
175+
176+
const emailInputField = screen.getByLabelText('Email');
177+
const passwordInputField = screen.getByLabelText('Password');
178+
179+
const logInButton = screen.getByRole('button', {name: /log in/i});
180+
181+
await userEvent.type(emailInputField, ' ');
182+
await userEvent.type(passwordInputField, ' ');
183+
184+
await userEvent.click(logInButton);
185+
186+
expect(screen.getByText('Email is required')).toBeInTheDocument();
187+
expect(screen.getByText('Password is required')).toBeInTheDocument();
188+
});
189+
190+
it('should toggle "Stay logged in" checkbox on click', async () => {
191+
renderLoginPage();
192+
193+
const checkbox = screen.getByLabelText('Stay logged in');
194+
195+
expect(checkbox).not.toBeChecked();
196+
197+
await userEvent.click(checkbox);
198+
expect(checkbox).toBeChecked();
199+
200+
await userEvent.click(checkbox);
201+
expect(checkbox).not.toBeChecked();
202+
});
203+
204+
it('should disable submit button and show loading icon while log in credentials are being authenticated', async () => {
205+
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
206+
207+
mockAuthenticationStore({
208+
login: async () => {
209+
await delay(1000);
210+
},
211+
});
212+
213+
renderLoginPage();
214+
215+
const logInButton = screen.getByLabelText('log in button');
216+
217+
expect(logInButton).not.toBeDisabled();
218+
expect(screen.queryByLabelText('loading icon')).not.toBeInTheDocument();
219+
220+
await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
221+
await userEvent.type(screen.getByLabelText('Password'), 'password');
222+
await userEvent.click(screen.getByRole('button', {name: /log in/i}));
223+
224+
expect(logInButton).toBeDisabled();
225+
expect(screen.getByLabelText('loading icon')).toBeInTheDocument();
226+
});
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import {render, screen, userEvent, waitFor} from '@/shared/util/test-utils';
2+
import {MemoryRouter, Route, Routes} from 'react-router-dom';
3+
import {afterEach, beforeEach, expect, it, vi} from 'vitest';
4+
5+
import AccountErrorPage from '../AccountErrorPage';
6+
import Login from '../Login';
7+
import PasswordResetEmailSent from '../PasswordResetEmailSent';
8+
import PasswordResetInit from '../PasswordResetInit';
9+
import {mockPasswordResetStore} from '../tests/mocks/mockPasswordResetStore';
10+
import {resetAll, windowResizeObserver} from './utils/testUtils';
11+
12+
screen.debug();
13+
14+
const renderPasswordResetInitPage = () => {
15+
render(
16+
<MemoryRouter initialEntries={['/password-reset/init']}>
17+
<Routes>
18+
<Route element={<PasswordResetInit />} path="/password-reset/init" />
19+
</Routes>
20+
</MemoryRouter>
21+
);
22+
};
23+
24+
vi.mock('@/pages/account/public/stores/usePasswordResetStore', () => ({
25+
usePasswordResetStore: vi.fn(),
26+
}));
27+
28+
beforeEach(() => {
29+
mockPasswordResetStore();
30+
});
31+
32+
beforeEach(() => {
33+
windowResizeObserver();
34+
});
35+
36+
afterEach(() => {
37+
resetAll();
38+
});
39+
40+
it('should render the password reset init page', () => {
41+
renderPasswordResetInitPage();
42+
43+
expect(screen.getByText('Forgot your password?')).toBeInTheDocument();
44+
expect(screen.getByText('Send link to email')).toBeInTheDocument();
45+
});
46+
47+
it('should render "AccountError" page when "resetPasswordFailure" is true', async () => {
48+
mockPasswordResetStore({
49+
resetPasswordFailure: true,
50+
});
51+
52+
render(
53+
<MemoryRouter initialEntries={['/password-reset/init']}>
54+
<Routes>
55+
<Route element={<PasswordResetInit />} path="/password-reset/init" />
56+
57+
<Route element={<AccountErrorPage />} path="/account-error" />
58+
</Routes>
59+
</MemoryRouter>
60+
);
61+
62+
await waitFor(() => {
63+
expect(screen.getByText('Something went wrong. Try again.')).toBeInTheDocument();
64+
});
65+
});
66+
67+
it('should render "PasswordResetEmailSent" page when "resetPasswordSuccess" is true', async () => {
68+
mockPasswordResetStore({
69+
resetPasswordSuccess: true,
70+
});
71+
72+
render(
73+
<MemoryRouter initialEntries={['/password-reset/init']}>
74+
<Routes>
75+
<Route element={<PasswordResetInit />} path="/password-reset/init" />
76+
77+
<Route element={<PasswordResetEmailSent />} path="/password-reset/email" />
78+
</Routes>
79+
</MemoryRouter>
80+
);
81+
82+
await waitFor(() => {
83+
expect(screen.getByText('Please check your email')).toBeInTheDocument();
84+
});
85+
});
86+
87+
it('should show validation errors after clicking "Send link to email" button, if input field is empty', async () => {
88+
renderPasswordResetInitPage();
89+
90+
const sendLinkButton = screen.getByText('Send link to email');
91+
await userEvent.click(sendLinkButton);
92+
93+
await waitFor(() => {
94+
expect(screen.getByText('Email is required')).toBeInTheDocument();
95+
});
96+
});
97+
98+
it('should render "Login" page when "Log in" link is clicked', async () => {
99+
render(
100+
<MemoryRouter initialEntries={['/password-reset/init']}>
101+
<Routes>
102+
<Route element={<PasswordResetInit />} path="/password-reset/init" />
103+
104+
<Route element={<Login />} path="/login" />
105+
</Routes>
106+
</MemoryRouter>
107+
);
108+
109+
const loginLink = screen.getByText('Log in');
110+
await userEvent.click(loginLink);
111+
112+
await waitFor(() => {
113+
expect(screen.getByText('Welcome back')).toBeInTheDocument();
114+
});
115+
});

0 commit comments

Comments
 (0)