Skip to content

Commit 04084a6

Browse files
committed
test front authentication
1 parent 3ea743e commit 04084a6

File tree

12 files changed

+1157
-7
lines changed

12 files changed

+1157
-7
lines changed

frontend/package-lock.json

Lines changed: 946 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
"@graphql-codegen/typescript-operations": "^4.6.0",
3232
"@graphql-codegen/typescript-react-apollo": "^4.3.2",
3333
"@tailwindcss/postcss": "^4.1.13",
34+
"@testing-library/jest-dom": "^6.9.1",
35+
"@testing-library/react": "^16.3.2",
36+
"@testing-library/user-event": "^14.6.1",
3437
"@types/react": "^19.1.8",
3538
"@types/react-dom": "^19.1.6",
3639
"@vitejs/plugin-react": "^4.6.0",
@@ -39,6 +42,7 @@
3942
"eslint-plugin-react-hooks": "^5.2.0",
4043
"eslint-plugin-react-refresh": "^0.4.20",
4144
"globals": "^16.3.0",
45+
"jsdom": "^25.0.0",
4246
"postcss": "^8.5.6",
4347
"typescript": "~5.8.3",
4448
"typescript-eslint": "^8.35.1",

frontend/src/components/forms/auth/LoginForm.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const LoginForm = () => {
5959
>
6060
{messageError.length > 0 ? <p className="error-message">{messageError}</p> : null}
6161
<Input
62+
dataTestId="emailLogin"
6263
theme="dark"
6364
type="text"
6465
name="email"
@@ -67,6 +68,7 @@ const LoginForm = () => {
6768
onChange={(e) => setForm({ ...form, email: e.target.value })}
6869
/>
6970
<Input
71+
dataTestId="passwordLogin"
7072
theme="dark"
7173
type="password"
7274
name="password"
@@ -75,7 +77,13 @@ const LoginForm = () => {
7577
onChange={(e) => setForm({ ...form, password: e.target.value })}
7678
/>
7779

78-
<Button rounded colour="dark" className="text-xl px-[25px] py-[10px] mt-5" type="submit">
80+
<Button
81+
rounded
82+
colour="dark"
83+
className="text-xl px-[25px] py-[10px] mt-5"
84+
type="submit"
85+
dataTestId="buttonLogin"
86+
>
7987
Connexion
8088
</Button>
8189
</AuthFormTemplate>

frontend/src/components/forms/auth/RegisterForm.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ const RegisterForm = () => {
117117
{messageError && <p className="text-orange font-bold text-lg">{messageError}</p>}
118118

119119
<Input
120+
dataTestId="lastNameRegister"
120121
theme="dark"
121122
type="text"
122123
placeholder="Nom"
@@ -125,6 +126,7 @@ const RegisterForm = () => {
125126
onChange={(e) => setForm({ ...form, lastName: e.target.value })}
126127
></Input>
127128
<Input
129+
dataTestId="firstNameRegister"
128130
theme="dark"
129131
type="text"
130132
placeholder="Prénom"
@@ -133,6 +135,7 @@ const RegisterForm = () => {
133135
onChange={(e) => setForm({ ...form, firstName: e.target.value })}
134136
></Input>
135137
<Input
138+
dataTestId="emailRegister"
136139
theme="dark"
137140
type="text"
138141
placeholder="Adresse email"
@@ -141,6 +144,7 @@ const RegisterForm = () => {
141144
onChange={(e) => setForm({ ...form, email: e.target.value })}
142145
></Input>
143146
<Input
147+
dataTestId="birthdayRegister"
144148
theme="dark"
145149
type="date"
146150
placeholder="Date de naissance"
@@ -149,6 +153,7 @@ const RegisterForm = () => {
149153
onChange={(e) => setForm({ ...form, date_of_birth: e.target.value })}
150154
></Input>
151155
<Input
156+
dataTestId="passwordRegister"
152157
theme="dark"
153158
type="password"
154159
placeholder="Mot de passe"
@@ -157,6 +162,7 @@ const RegisterForm = () => {
157162
onChange={(e) => setForm({ ...form, password: e.target.value })}
158163
></Input>
159164
<Input
165+
dataTestId="passwordConfirmRegister"
160166
theme="dark"
161167
type="password"
162168
placeholder="Confirmation du mot de passe"
@@ -176,7 +182,13 @@ const RegisterForm = () => {
176182
</div>
177183

178184
{/* Bouton de connexion */}
179-
<Button type="submit" colour="dark" rounded className="text-xl px-[25px] py-[10px] mt-5">
185+
<Button
186+
type="submit"
187+
colour="dark"
188+
rounded
189+
className="text-xl px-[25px] py-[10px] mt-5"
190+
dataTestId="buttonRegister"
191+
>
180192
Inscription
181193
</Button>
182194
</AuthFormTemplate>

frontend/src/components/utils/Button.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type ButtonProps = {
1616
big?: boolean;
1717
small?: boolean;
1818
disabled?: boolean;
19+
dataTestId?: string;
1920
};
2021

2122
export default function Button({
@@ -29,6 +30,7 @@ export default function Button({
2930
type = "button",
3031
small = false,
3132
disabled = false,
33+
dataTestId,
3234
}: ButtonProps) {
3335
const backgroundColours = {
3436
blue: "bg-blue",
@@ -47,6 +49,7 @@ export default function Button({
4749
<button
4850
type={type}
4951
disabled={disabled}
52+
data-testid={dataTestId}
5053
className={`${backgroundColour} text-white font-inter-extra-bold
5154
${rounded ? "rounded-full p-2" : small ? "rounded-lg py-1.5 px-3 text-sm" : "rounded-lg py-2 px-4"}
5255
flex items-center gap-2 font-medium shadow-md

frontend/src/components/utils/Input.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
1313
label?: string;
1414
icon?: IconTypes;
1515
disabled?: boolean;
16+
dataTestId?: string;
1617
}
1718

1819
export default function Input({
@@ -27,6 +28,7 @@ export default function Input({
2728
placeholder,
2829
icon,
2930
disabled = false,
31+
dataTestId,
3032
...props
3133
}: InputProps) {
3234
const baseStyles =
@@ -64,6 +66,7 @@ export default function Input({
6466
className={`${baseStyles} ${themeStyles} ${disabledStyles} ${errorStyles} ${className}`}
6567
name={name}
6668
placeholder={placeholder}
69+
data-testid={dataTestId}
6770
{...props}
6871
/>
6972
{icon && (

frontend/tests/App.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ function sum(a: number, b: number): number {
66
test("1 + 1 = 2", () => {
77
expect(sum(1, 1)).toBe(2);
88
});
9+
10+
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/// <reference types="@testing-library/jest-dom" />
2+
import { describe, test, expect, vi, beforeEach } from 'vitest'
3+
import { render, screen, waitFor } from '@testing-library/react'
4+
import userEvent from '@testing-library/user-event'
5+
import { MemoryRouter } from 'react-router'
6+
import LoginForm from '../src/components/forms/auth/LoginForm'
7+
import RegisterForm from '../src/components/forms/auth/RegisterForm'
8+
9+
const { mockNavigate, mockLogin, mockSetUserProfile, mockRegister } = vi.hoisted(() => ({
10+
mockNavigate: vi.fn(),
11+
mockLogin: vi.fn(),
12+
mockRegister: vi.fn(),
13+
mockSetUserProfile: vi.fn(),
14+
}))
15+
16+
vi.mock('react-router', async (importOriginal) => {
17+
const actual = await importOriginal<typeof import('react-router')>()
18+
return { ...actual, useNavigate: () => mockNavigate }
19+
})
20+
21+
vi.mock('../src/graphql/generated/graphql-types', () => ({
22+
useLoginMutation: () => [mockLogin],
23+
useSignupMutation: () => [mockRegister],
24+
}))
25+
26+
vi.mock('../src/zustand/myProfileStore', () => ({
27+
useMyProfileStore: () => ({ setUserProfile: mockSetUserProfile }),
28+
}))
29+
30+
vi.mock('../src/hooks/erreurMod', () => ({ default: vi.fn() }))
31+
32+
const renderLoginForm = () => render(<LoginForm />, { wrapper: MemoryRouter })
33+
const renderRegisterForm = () => render(<RegisterForm />, { wrapper: MemoryRouter })
34+
35+
describe('LoginForm', () => {
36+
beforeEach(() => {
37+
vi.clearAllMocks()
38+
})
39+
40+
test('affiche les champs email, mot de passe et le bouton connexion', () => {
41+
renderLoginForm()
42+
expect(screen.getByTestId('emailLogin')).toBeInTheDocument()
43+
expect(screen.getByTestId('passwordLogin')).toBeInTheDocument()
44+
expect(screen.getByTestId('buttonLogin')).toBeInTheDocument()
45+
})
46+
47+
test("l'utilisateur peut remplir le formulaire et se connecter", async () => {
48+
mockLogin.mockResolvedValue({ data: { login: { id: '1', email: 'chloe@gmail.com' } } })
49+
const user = userEvent.setup()
50+
renderLoginForm()
51+
52+
await user.type(screen.getByTestId('emailLogin'), 'chloe@gmail.com')
53+
await user.type(screen.getByTestId('passwordLogin'), '123456')
54+
await user.click(screen.getByTestId('buttonLogin'))
55+
56+
await waitFor(() => {
57+
expect(mockNavigate).toHaveBeenCalledWith('/dashboard')
58+
})
59+
})
60+
61+
test("affiche un message d'erreur si les identifiants sont incorrects", async () => {
62+
mockLogin.mockRejectedValue({
63+
graphQLErrors: [{ message: 'Utilisateur introuvable' }],
64+
})
65+
const user = userEvent.setup()
66+
renderLoginForm()
67+
68+
await user.type(screen.getByTestId('emailLogin'), 'mauvais@email.com')
69+
await user.type(screen.getByTestId('passwordLogin'), 'mauvaismdp')
70+
await user.click(screen.getByTestId('buttonLogin'))
71+
72+
await waitFor(() => {
73+
expect(screen.getByText('Utilisateur introuvable')).toBeInTheDocument()
74+
})
75+
})
76+
})
77+
78+
79+
describe('RegisterForm', () => {
80+
beforeEach(() => {
81+
vi.clearAllMocks()
82+
})
83+
84+
test('affiche les champs du formulaire', () => {
85+
renderRegisterForm()
86+
expect(screen.getByTestId('lastNameRegister')).toBeInTheDocument()
87+
expect(screen.getByTestId('firstNameRegister')).toBeInTheDocument()
88+
expect(screen.getByTestId('emailRegister')).toBeInTheDocument()
89+
expect(screen.getByTestId('birthdayRegister')).toBeInTheDocument()
90+
expect(screen.getByTestId('passwordRegister')).toBeInTheDocument()
91+
expect(screen.getByTestId('passwordConfirmRegister')).toBeInTheDocument()
92+
})
93+
94+
test("l'utilisateur peut remplir le formulaire et s'inscrire'", async () => {
95+
mockRegister.mockResolvedValue({ data: { signup: { id: '1', email: 'chloe@gmail.com' } } })
96+
const user = userEvent.setup()
97+
renderRegisterForm()
98+
99+
await user.type(screen.getByTestId('lastNameRegister'), 'Chloe')
100+
await user.type(screen.getByTestId('firstNameRegister'), 'Bretnacher')
101+
await user.type(screen.getByTestId('emailRegister'), 'chloe@gmail.com')
102+
await user.type(screen.getByTestId('birthdayRegister'), '1997-06-26')
103+
await user.type(screen.getByTestId('passwordRegister'), '123456')
104+
await user.type(screen.getByTestId('passwordConfirmRegister'), '123456')
105+
await user.click(screen.getByTestId('buttonRegister'))
106+
107+
await waitFor(() => {
108+
expect(mockNavigate).toHaveBeenCalledWith('/dashboard')
109+
})
110+
})
111+
112+
test("affiche un message d'erreur si les inputs ne sont pas remplis correctement", async () => {
113+
const user = userEvent.setup()
114+
renderRegisterForm()
115+
116+
// Champs obligatoires vides
117+
await user.click(screen.getByTestId('buttonRegister'))
118+
await waitFor(() => {
119+
expect(screen.getByText('Tous les champs obligatoires doivent être remplis')).toBeInTheDocument()
120+
})
121+
122+
// Email invalide
123+
await user.type(screen.getByTestId('lastNameRegister'), 'Chloe')
124+
await user.type(screen.getByTestId('firstNameRegister'), 'Bretnacher')
125+
await user.type(screen.getByTestId('birthdayRegister'), '1997-06-26')
126+
await user.type(screen.getByTestId('emailRegister'), 'emailinvalide')
127+
await user.click(screen.getByTestId('buttonRegister'))
128+
await waitFor(() => {
129+
expect(screen.getByText('Adresse email invalide')).toBeInTheDocument()
130+
})
131+
132+
// Mot de passe trop court
133+
await user.clear(screen.getByTestId('emailRegister'))
134+
await user.type(screen.getByTestId('emailRegister'), 'chloe@gmail.com')
135+
await user.type(screen.getByTestId('passwordRegister'), '123')
136+
await user.click(screen.getByTestId('buttonRegister'))
137+
await waitFor(() => {
138+
expect(screen.getByText('Mot de passe trop court')).toBeInTheDocument()
139+
})
140+
141+
// Mots de passe ne correspondent pas
142+
await user.clear(screen.getByTestId('passwordRegister'))
143+
await user.type(screen.getByTestId('passwordRegister'), '123456')
144+
await user.type(screen.getByTestId('passwordConfirmRegister'), 'different')
145+
await user.click(screen.getByTestId('buttonRegister'))
146+
await waitFor(() => {
147+
expect(screen.getByText('Les mots de passe ne correspondent pas')).toBeInTheDocument()
148+
})
149+
})
150+
151+
test('tous les champs doivent être remplis', async () => {
152+
const user = userEvent.setup()
153+
renderRegisterForm()
154+
155+
await user.click(screen.getByTestId('buttonRegister'))
156+
157+
await waitFor(() => {
158+
expect(screen.getByText('Tous les champs obligatoires doivent être remplis')).toBeInTheDocument()
159+
})
160+
161+
expect(screen.getByTestId('lastNameRegister')).toHaveValue('')
162+
expect(screen.getByTestId('firstNameRegister')).toHaveValue('')
163+
expect(screen.getByTestId('emailRegister')).toHaveValue('')
164+
expect(screen.getByTestId('birthdayRegister')).toHaveValue('')
165+
expect(screen.getByTestId('passwordRegister')).toHaveValue('')
166+
expect(screen.getByTestId('passwordConfirmRegister')).toHaveValue('')
167+
})
168+
})
169+
170+

frontend/tests/Groupe.test.tsx

Whitespace-only changes.

frontend/tests/Wishlist.test.tsx

Whitespace-only changes.

0 commit comments

Comments
 (0)