|
1 | | -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; |
2 | | -import '@testing-library/jest-dom/extend-expect'; |
3 | | -import { useDispatch, Provider } from 'react-redux'; |
4 | | -import thunk from 'redux-thunk'; |
5 | | -import { configureStore } from 'redux-mock-store'; |
6 | | -import { BrowserRouter as Router } from 'react-router-dom'; |
| 1 | +import { screen, fireEvent, waitFor } from '@testing-library/react'; |
7 | 2 | import axios from 'axios'; |
8 | 3 | import CPLogin from '../CPLogin'; |
9 | | - |
10 | | -const mockStore = configureStore([thunk]); |
11 | | -let store; |
12 | | - |
13 | | -beforeEach(() => { |
14 | | - store = mockStore({ |
15 | | - auth: { |
16 | | - isAuthenticated: true, |
17 | | - user: { |
18 | | - permissions: { |
19 | | - frontPermissions: [], |
20 | | - backPermissions: [], |
21 | | - }, |
22 | | - role: 'Owner', |
23 | | - }, |
24 | | - permissions: { |
25 | | - frontPermissions: [], |
26 | | - backPermissions: [], |
27 | | - }, |
28 | | - }, |
29 | | - }); |
30 | | -}); |
| 4 | +import { renderWithStoreRouter } from './renderWithStoreRouter'; |
31 | 5 |
|
32 | 6 | vi.mock('axios'); |
33 | 7 |
|
34 | 8 | vi.mock('jwt-decode', () => ({ |
35 | 9 | default: vi.fn(() => ({ decodedPayload: 'mocked_decoded_payload' })), |
36 | 10 | })); |
| 11 | + |
37 | 12 | const history = { |
38 | 13 | push: vi.fn(), |
39 | 14 | location: { pathname: '/' }, |
40 | 15 | }; |
41 | 16 |
|
42 | | -const renderComponent = testStore => { |
43 | | - function LoginWrapper() { |
44 | | - const dispatch = useDispatch(); |
45 | | - const location = {}; |
| 17 | +const VALID_EMAIL = 'test@gmail.com'; |
| 18 | + |
| 19 | +const makeAuthState = (isAuthenticated = true) => ({ |
| 20 | + auth: { |
| 21 | + isAuthenticated, |
| 22 | + user: { |
| 23 | + permissions: { frontPermissions: [], backPermissions: [] }, |
| 24 | + role: 'Owner', |
| 25 | + }, |
| 26 | + permissions: { frontPermissions: [], backPermissions: [] }, |
| 27 | + }, |
| 28 | +}); |
| 29 | + |
| 30 | +const repeatChar = (ch, len) => ch.repeat(len); |
| 31 | + |
| 32 | +const getValidSecretValue = () => repeatChar('x', 12); |
| 33 | +const getTooShortSecretValue = () => repeatChar('x', 5); |
| 34 | + |
| 35 | +const renderCPLogin = initialState => |
| 36 | + renderWithStoreRouter(<CPLogin history={history} location={{}} />, { |
| 37 | + initialState, |
| 38 | + }); |
46 | 39 |
|
47 | | - return <CPLogin dispatch={dispatch} history={history} location={location} />; |
| 40 | +const fillAndSubmit = ({ emailValue, passwordValue } = {}) => { |
| 41 | + const emailElement = screen.getByRole('textbox', { name: /email/i }); |
| 42 | + const passwordElement = screen.getByLabelText(/password/i); |
| 43 | + const submitElement = screen.getByText('Submit'); |
| 44 | + |
| 45 | + if (emailValue !== undefined) { |
| 46 | + fireEvent.change(emailElement, { target: { value: emailValue } }); |
| 47 | + } |
| 48 | + if (passwordValue !== undefined) { |
| 49 | + fireEvent.change(passwordElement, { target: { value: passwordValue } }); |
48 | 50 | } |
49 | | - return render( |
50 | | - <Provider store={testStore}> |
51 | | - <Router> |
52 | | - <LoginWrapper /> |
53 | | - </Router> |
54 | | - </Provider>, |
55 | | - ); |
| 51 | + |
| 52 | + fireEvent.click(submitElement); |
| 53 | + return { emailElement, passwordElement, submitElement }; |
56 | 54 | }; |
57 | 55 |
|
58 | 56 | describe('CPLogin component', () => { |
| 57 | + beforeEach(() => { |
| 58 | + history.push.mockClear(); |
| 59 | + axios.post?.mockReset?.(); |
| 60 | + }); |
| 61 | + |
59 | 62 | it('renders without crashing', () => { |
60 | | - renderComponent(store); |
| 63 | + renderCPLogin(makeAuthState(true)); |
61 | 64 | }); |
| 65 | + |
62 | 66 | it('check if login elements get displayed when isAuthenticated is true', () => { |
63 | | - renderComponent(store); |
| 67 | + renderCPLogin(makeAuthState(true)); |
64 | 68 | expect(screen.getByText('Log In To Community Portal')).toBeInTheDocument(); |
65 | 69 | }); |
| 70 | + |
66 | 71 | it('check if login elements does not get displayed when isAuthenticated is false', () => { |
67 | | - const testStore = mockStore({ |
68 | | - auth: { |
69 | | - isAuthenticated: false, |
70 | | - user: { |
71 | | - permissions: { |
72 | | - frontPermissions: [], |
73 | | - backPermissions: [], |
74 | | - }, |
75 | | - role: 'Owner', |
76 | | - }, |
77 | | - permissions: { |
78 | | - frontPermissions: [], |
79 | | - backPermissions: [], |
80 | | - }, |
81 | | - }, |
82 | | - }); |
83 | | - renderComponent(testStore); |
| 72 | + renderCPLogin(makeAuthState(false)); |
84 | 73 | expect(screen.queryByText('Log In To Community Portal')).not.toBeInTheDocument(); |
85 | 74 | }); |
86 | | - it('check if Enter your current user credentials to access the Building Management Dashboard header displays as expected', () => { |
87 | | - renderComponent(store); |
| 75 | + |
| 76 | + it('check if Enter your current user credentials... header displays as expected', () => { |
| 77 | + renderCPLogin(makeAuthState(true)); |
88 | 78 | expect( |
89 | 79 | screen.getByText( |
90 | 80 | 'Enter your current user credentials to access the Community Portal Dashboard', |
91 | 81 | ), |
92 | 82 | ).toBeInTheDocument(); |
93 | 83 | }); |
94 | | - it('check if Note: You must use your Production/Main credentials for this login. header displays as expected', () => { |
95 | | - renderComponent(store); |
| 84 | + |
| 85 | + it('check if Note: You must use your Production/Main credentials... displays as expected', () => { |
| 86 | + renderCPLogin(makeAuthState(true)); |
96 | 87 | expect( |
97 | 88 | screen.getByText('Note: You must use your Production/Main credentials for this login.'), |
98 | 89 | ).toBeInTheDocument(); |
99 | 90 | }); |
| 91 | + |
100 | 92 | it('check if email label is displaying as expected', () => { |
101 | | - renderComponent(store); |
| 93 | + renderCPLogin(makeAuthState(true)); |
102 | 94 | expect(screen.getByText('Email')).toBeInTheDocument(); |
103 | 95 | }); |
| 96 | + |
104 | 97 | it('check if password label is displaying as expected', () => { |
105 | | - renderComponent(store); |
| 98 | + renderCPLogin(makeAuthState(true)); |
106 | 99 | expect(screen.getByText('Password')).toBeInTheDocument(); |
107 | 100 | }); |
| 101 | + |
108 | 102 | it('check if submit button is disabled when either email or password is not entered', () => { |
109 | | - renderComponent(store); |
110 | | - const buttonElement = screen.getByText('Submit'); |
111 | | - expect(buttonElement).toBeDisabled(); |
| 103 | + renderCPLogin(makeAuthState(true)); |
| 104 | + expect(screen.getByText('Submit')).toBeDisabled(); |
112 | 105 | }); |
113 | | - it('check if validation for invalid email id works as expected', () => { |
114 | | - const { container } = renderComponent(store); |
115 | | - const emailElement = screen.getByRole('textbox', { name: /email/i }); |
116 | | - fireEvent.change(emailElement, { target: { value: 'test' } }); |
117 | 106 |
|
118 | | - const passwordElement = screen.getByLabelText(/password/i); |
119 | | - fireEvent.change(passwordElement, { target: { value: '12' } }); |
| 107 | + it('check if validation for invalid email id works as expected', () => { |
| 108 | + renderCPLogin(makeAuthState(true)); |
120 | 109 |
|
121 | | - const submitElement = screen.getByText('Submit'); |
122 | | - fireEvent.click(submitElement); |
| 110 | + const { emailElement } = fillAndSubmit({ |
| 111 | + emailValue: 'abcd', |
| 112 | + passwordValue: getTooShortSecretValue(), |
| 113 | + }); |
123 | 114 |
|
124 | 115 | expect(emailElement).toBeInvalid(); |
125 | 116 | expect(screen.getByText('"email" must be a valid email')).toBeInTheDocument(); |
126 | 117 | }); |
127 | | - it('check if validation for password works as expected', () => { |
128 | | - const { container } = renderComponent(store); |
129 | | - const emailElement = screen.getByRole('textbox', { name: /email/i }); |
130 | | - fireEvent.change(emailElement, { target: { value: 'test@gmail.com' } }); |
131 | 118 |
|
132 | | - const passwordElement = screen.getByLabelText(/password/i); |
133 | | - fireEvent.change(passwordElement, { target: { value: '12' } }); |
| 119 | + it('check if validation for password works as expected', () => { |
| 120 | + renderCPLogin(makeAuthState(true)); |
134 | 121 |
|
135 | | - const submitElement = screen.getByText('Submit'); |
136 | | - fireEvent.click(submitElement); |
| 122 | + const { passwordElement } = fillAndSubmit({ |
| 123 | + emailValue: VALID_EMAIL, |
| 124 | + passwordValue: getTooShortSecretValue(), |
| 125 | + }); |
137 | 126 |
|
138 | 127 | expect(passwordElement).toBeInvalid(); |
139 | 128 | expect( |
140 | 129 | screen.getByText('"password" length must be at least 8 characters long'), |
141 | 130 | ).toBeInTheDocument(); |
142 | 131 | }); |
| 132 | + |
143 | 133 | it('check if entering the right email and password logs in as expected', async () => { |
144 | 134 | axios.post.mockResolvedValue({ |
145 | 135 | statusText: 'OK', |
146 | 136 | data: { token: '1234' }, |
147 | 137 | }); |
148 | 138 |
|
149 | | - const { container } = renderComponent(store); |
| 139 | + renderCPLogin(makeAuthState(true)); |
150 | 140 |
|
151 | | - const emailElement = screen.getByRole('textbox', { name: /email/i }); |
152 | | - const passwordElement = screen.getByLabelText(/password/i); |
153 | | - const submitElement = screen.getByText('Submit'); |
154 | | - |
155 | | - fireEvent.change(emailElement, { target: { value: 'test@gmail.com' } }); |
156 | | - fireEvent.change(passwordElement, { target: { value: 'Test12345' } }); |
157 | | - fireEvent.click(submitElement); |
| 141 | + const { emailElement, passwordElement } = fillAndSubmit({ |
| 142 | + emailValue: VALID_EMAIL, |
| 143 | + passwordValue: getValidSecretValue(), |
| 144 | + }); |
158 | 145 |
|
159 | | - // Wait for validation to pass |
160 | 146 | await waitFor(() => { |
161 | 147 | expect(emailElement).not.toBeInvalid(); |
| 148 | + expect(passwordElement).not.toBeInvalid(); |
162 | 149 | }); |
163 | | - expect(passwordElement).not.toBeInvalid(); |
164 | | - expect(screen.queryByText('"email" must be a valid email')).not.toBeInTheDocument(); |
165 | | - expect( |
166 | | - screen.queryByText('"password" length must be at least 8 characters long'), |
167 | | - ).not.toBeInTheDocument(); |
168 | 150 |
|
169 | | - // Wait for redirect to be triggered |
170 | 151 | await waitFor(() => { |
171 | 152 | expect(history.push).toHaveBeenCalledWith('/communityportal'); |
172 | 153 | }); |
173 | 154 | }); |
174 | | - it("check if statusText in response is not 'OK' and status is 422 and displays validation error", async () => { |
| 155 | + |
| 156 | + it("check if statusText is not 'OK' and status is 422 and displays validation error", async () => { |
175 | 157 | axios.post.mockResolvedValue({ |
176 | 158 | statusText: 'ERROR', |
177 | 159 | status: 422, |
178 | 160 | data: { token: '1234', label: 'email', message: 'User not found' }, |
179 | 161 | }); |
180 | | - const { container } = renderComponent(store); |
181 | 162 |
|
182 | | - const emailElement = screen.getByRole('textbox', { name: /email/i }); |
183 | | - fireEvent.change(emailElement, { target: { value: 'test@gmail.com' } }); |
| 163 | + renderCPLogin(makeAuthState(true)); |
184 | 164 |
|
185 | | - const passwordElement = screen.getByLabelText(/password/i); |
186 | | - fireEvent.change(passwordElement, { target: { value: 'Test12345' } }); |
187 | | - |
188 | | - const submitElement = screen.getByText('Submit'); |
189 | | - fireEvent.click(submitElement); |
| 165 | + fillAndSubmit({ |
| 166 | + emailValue: VALID_EMAIL, |
| 167 | + passwordValue: getValidSecretValue(), |
| 168 | + }); |
190 | 169 |
|
191 | 170 | await waitFor(() => { |
192 | 171 | expect(screen.getByText('User not found')).toBeInTheDocument(); |
193 | 172 | }); |
194 | 173 | }); |
195 | | - it("check if statusText in response is not 'OK' and status is not 422 and does not display any validation error", async () => { |
| 174 | + |
| 175 | + it("check if statusText is not 'OK' and status is not 422 and does not display validation error", async () => { |
196 | 176 | axios.post.mockResolvedValue({ |
197 | 177 | statusText: 'ERROR', |
198 | 178 | status: 500, |
199 | 179 | data: { token: '1234' }, |
200 | 180 | }); |
201 | | - const { container } = renderComponent(store); |
202 | 181 |
|
203 | | - const emailElement = screen.getByRole('textbox', { name: /email/i }); |
204 | | - fireEvent.change(emailElement, { target: { value: 'test@gmail.com' } }); |
| 182 | + renderCPLogin(makeAuthState(true)); |
205 | 183 |
|
206 | | - const passwordElement = screen.getByLabelText(/password/i); |
207 | | - fireEvent.change(passwordElement, { target: { value: 'Test12345' } }); |
208 | | - |
209 | | - const submitElement = screen.getByText('Submit'); |
210 | | - fireEvent.click(submitElement); |
| 184 | + const { passwordElement } = fillAndSubmit({ |
| 185 | + emailValue: VALID_EMAIL, |
| 186 | + passwordValue: getValidSecretValue(), |
| 187 | + }); |
211 | 188 |
|
212 | 189 | await waitFor(() => { |
213 | 190 | expect(passwordElement).not.toBeInvalid(); |
214 | 191 | }); |
215 | 192 | }); |
216 | | - it('check failed post request does not display any validation error', async () => { |
217 | | - axios.post.mockRejectedValue({ response: 'server error' }); |
218 | | - const { container } = renderComponent(store); |
219 | 193 |
|
220 | | - const emailElement = screen.getByRole('textbox', { name: /email/i }); |
221 | | - fireEvent.change(emailElement, { target: { value: 'test@gmail.com' } }); |
| 194 | + it('check failed post request does not display validation error', async () => { |
| 195 | + axios.post.mockRejectedValue({ response: 'server error' }); |
222 | 196 |
|
223 | | - const passwordElement = screen.getByLabelText(/password/i); |
224 | | - fireEvent.change(passwordElement, { target: { value: 'Test12345' } }); |
| 197 | + renderCPLogin(makeAuthState(true)); |
225 | 198 |
|
226 | | - const submitElement = screen.getByText('Submit'); |
227 | | - fireEvent.click(submitElement); |
| 199 | + const { passwordElement } = fillAndSubmit({ |
| 200 | + emailValue: VALID_EMAIL, |
| 201 | + passwordValue: getValidSecretValue(), |
| 202 | + }); |
228 | 203 |
|
229 | 204 | await waitFor(() => { |
230 | 205 | expect(passwordElement).not.toBeInvalid(); |
|
0 commit comments