test
This commit is contained in:
84
frontend/src/test/fonctionnel/Connexion.test.jsx
Normal file
84
frontend/src/test/fonctionnel/Connexion.test.jsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import Connexion from '../../pages/Connexion'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
import { loginApi } from '../../services/auth'
|
||||
|
||||
// On mocke le service d'API : les tests de composant ne font pas de vraies requêtes HTTP.
|
||||
vi.mock('../../services/auth', () => ({
|
||||
loginApi: vi.fn(),
|
||||
}))
|
||||
|
||||
describe('Connexion', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('affiche le formulaire de connexion', () => {
|
||||
renderWithProviders(<Connexion />, { route: '/connexion' })
|
||||
|
||||
expect(screen.getByRole('heading', { name: /se connecter/i })).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText(/votre email/i)).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText(/votre mot de passe/i)).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: /se connecter/i })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('affiche le message de succès après une inscription', () => {
|
||||
renderWithProviders(<Connexion />, {
|
||||
route: { pathname: '/connexion', state: { registered: true } },
|
||||
})
|
||||
|
||||
expect(screen.getByText(/compte créé avec succès/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("affiche l'erreur renvoyée par l'API en cas d'échec", async () => {
|
||||
loginApi.mockRejectedValue(new Error('Email ou mot de passe incorrect.'))
|
||||
|
||||
renderWithProviders(<Connexion />, { route: '/connexion' })
|
||||
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre email/i), 'test@example.com')
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre mot de passe/i), 'mauvais-mdp')
|
||||
await userEvent.click(screen.getByRole('button', { name: /se connecter/i }))
|
||||
|
||||
expect(await screen.findByText('Email ou mot de passe incorrect.')).toBeInTheDocument()
|
||||
expect(loginApi).toHaveBeenCalledWith({ email: 'test@example.com', password: 'mauvais-mdp' })
|
||||
})
|
||||
|
||||
it('connecte un client et redirige vers /mes-gains', async () => {
|
||||
loginApi.mockResolvedValue({
|
||||
token: 'jwt-token',
|
||||
user: { id: 1, email: 'client@example.com', role: 'CLIENT' },
|
||||
})
|
||||
|
||||
renderWithProviders(<Connexion />, {
|
||||
route: '/connexion',
|
||||
routes: { '/mes-gains': <p>Page Mes Gains</p> },
|
||||
})
|
||||
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre email/i), 'client@example.com')
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre mot de passe/i), 'MotDePasse123!')
|
||||
await userEvent.click(screen.getByRole('button', { name: /se connecter/i }))
|
||||
|
||||
expect(await screen.findByText('Page Mes Gains')).toBeInTheDocument()
|
||||
expect(localStorage.getItem('token')).toBe('jwt-token')
|
||||
})
|
||||
|
||||
it("connecte un admin et redirige vers /admin", async () => {
|
||||
loginApi.mockResolvedValue({
|
||||
token: 'jwt-token',
|
||||
user: { id: 2, email: 'admin@example.com', role: 'ADMIN' },
|
||||
})
|
||||
|
||||
renderWithProviders(<Connexion />, {
|
||||
route: '/connexion',
|
||||
routes: { '/admin': <p>Page Admin</p> },
|
||||
})
|
||||
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre email/i), 'admin@example.com')
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre mot de passe/i), 'MotDePasse123!')
|
||||
await userEvent.click(screen.getByRole('button', { name: /se connecter/i }))
|
||||
|
||||
expect(await screen.findByText('Page Admin')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
39
frontend/src/test/fonctionnel/CookieBanner.test.jsx
Normal file
39
frontend/src/test/fonctionnel/CookieBanner.test.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import CookieBanner from '../../components/CookieBanner'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
|
||||
describe('CookieBanner', () => {
|
||||
it("s'affiche quand aucun choix n'a été fait", () => {
|
||||
renderWithProviders(<CookieBanner />)
|
||||
|
||||
expect(screen.getByText(/ce site utilise des cookies/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('enregistre le consentement et disparaît quand on accepte', async () => {
|
||||
renderWithProviders(<CookieBanner />)
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /accepter/i }))
|
||||
|
||||
expect(screen.queryByText(/ce site utilise des cookies/i)).not.toBeInTheDocument()
|
||||
expect(localStorage.getItem('cookieConsent')).toBe('accepted')
|
||||
})
|
||||
|
||||
it('enregistre le refus et disparaît quand on refuse', async () => {
|
||||
renderWithProviders(<CookieBanner />)
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /refuser/i }))
|
||||
|
||||
expect(screen.queryByText(/ce site utilise des cookies/i)).not.toBeInTheDocument()
|
||||
expect(localStorage.getItem('cookieConsent')).toBe('refused')
|
||||
})
|
||||
|
||||
it("ne s'affiche pas si un choix a déjà été fait", () => {
|
||||
localStorage.setItem('cookieConsent', 'accepted')
|
||||
|
||||
renderWithProviders(<CookieBanner />)
|
||||
|
||||
expect(screen.queryByText(/ce site utilise des cookies/i)).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
120
frontend/src/test/fonctionnel/Inscription.test.jsx
Normal file
120
frontend/src/test/fonctionnel/Inscription.test.jsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import Inscription from '../../pages/Inscription'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
import { registerApi, verifyCodeApi } from '../../services/auth'
|
||||
|
||||
vi.mock('../../services/auth', () => ({
|
||||
registerApi: vi.fn(),
|
||||
verifyCodeApi: vi.fn(),
|
||||
}))
|
||||
|
||||
// Remplit et soumet le formulaire d'inscription (étape 1).
|
||||
async function remplirEtSoumettre() {
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre email/i), 'jean@example.com')
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre nom/i), 'Dupont')
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre prénom/i), 'Jean')
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre mot de passe/i), 'MotDePasse123!')
|
||||
await userEvent.click(screen.getByRole('checkbox'))
|
||||
await userEvent.click(screen.getByRole('button', { name: /s'inscrire/i }))
|
||||
}
|
||||
|
||||
// Saisit le code à 4 chiffres de l'étape de vérification.
|
||||
async function saisirCode(code) {
|
||||
const inputs = screen.getAllByRole('textbox')
|
||||
for (let i = 0; i < 4; i++) {
|
||||
await userEvent.type(inputs[i], code[i])
|
||||
}
|
||||
}
|
||||
|
||||
describe('Inscription', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it("affiche le formulaire d'inscription", () => {
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
|
||||
expect(screen.getByRole('heading', { name: /s'inscrire/i })).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText(/votre email/i)).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText(/votre nom/i)).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText(/votre prénom/i)).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText(/votre mot de passe/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("désactive le bouton tant que les conditions ne sont pas acceptées", async () => {
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
|
||||
const bouton = screen.getByRole('button', { name: /s'inscrire/i })
|
||||
expect(bouton).toBeDisabled()
|
||||
|
||||
await userEvent.click(screen.getByRole('checkbox'))
|
||||
expect(bouton).toBeEnabled()
|
||||
})
|
||||
|
||||
it("passe à l'étape de vérification après une inscription réussie", async () => {
|
||||
registerApi.mockResolvedValue({ message: 'ok' })
|
||||
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
await remplirEtSoumettre()
|
||||
|
||||
expect(registerApi).toHaveBeenCalledWith({
|
||||
email: 'jean@example.com',
|
||||
firstname: 'Jean',
|
||||
lastname: 'Dupont',
|
||||
password: 'MotDePasse123!',
|
||||
})
|
||||
expect(await screen.findByRole('heading', { name: /vérifiez votre email/i })).toBeInTheDocument()
|
||||
expect(screen.getByText('jean@example.com')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("affiche l'erreur de l'API si l'inscription échoue", async () => {
|
||||
registerApi.mockRejectedValue(new Error('Cet email est déjà utilisé.'))
|
||||
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
await remplirEtSoumettre()
|
||||
|
||||
expect(await screen.findByText('Cet email est déjà utilisé.')).toBeInTheDocument()
|
||||
expect(screen.queryByRole('heading', { name: /vérifiez votre email/i })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('connecte et redirige vers /saisir-code-unique quand le code est valide', async () => {
|
||||
registerApi.mockResolvedValue({ message: 'ok' })
|
||||
verifyCodeApi.mockResolvedValue({
|
||||
token: 'jwt-token',
|
||||
user: { id: 1, email: 'jean@example.com', role: 'CLIENT' },
|
||||
})
|
||||
|
||||
renderWithProviders(<Inscription />, {
|
||||
route: '/inscription',
|
||||
routes: { '/saisir-code-unique': <p>Page Saisir Code</p> },
|
||||
})
|
||||
await remplirEtSoumettre()
|
||||
await screen.findByRole('heading', { name: /vérifiez votre email/i })
|
||||
|
||||
await saisirCode('1234')
|
||||
await userEvent.click(screen.getByRole('button', { name: /valider le code/i }))
|
||||
|
||||
expect(verifyCodeApi).toHaveBeenCalledWith({ email: 'jean@example.com', code: '1234' })
|
||||
expect(await screen.findByText('Page Saisir Code')).toBeInTheDocument()
|
||||
expect(localStorage.getItem('token')).toBe('jwt-token')
|
||||
})
|
||||
|
||||
it("affiche l'erreur et vide les champs quand le code est invalide", async () => {
|
||||
registerApi.mockResolvedValue({ message: 'ok' })
|
||||
verifyCodeApi.mockRejectedValue(new Error('Code invalide.'))
|
||||
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
await remplirEtSoumettre()
|
||||
await screen.findByRole('heading', { name: /vérifiez votre email/i })
|
||||
|
||||
await saisirCode('0000')
|
||||
await userEvent.click(screen.getByRole('button', { name: /valider le code/i }))
|
||||
|
||||
expect(await screen.findByText('Code invalide.')).toBeInTheDocument()
|
||||
for (const input of screen.getAllByRole('textbox')) {
|
||||
expect(input).toHaveValue('')
|
||||
}
|
||||
})
|
||||
})
|
||||
80
frontend/src/test/fonctionnel/ProtectedRoute.test.jsx
Normal file
80
frontend/src/test/fonctionnel/ProtectedRoute.test.jsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import ProtectedRoute from '../../components/ProtectedRoute'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
|
||||
describe('ProtectedRoute', () => {
|
||||
it("redirige vers /connexion si l'utilisateur n'est pas connecté", () => {
|
||||
renderWithProviders(
|
||||
<ProtectedRoute>
|
||||
<p>Contenu protégé</p>
|
||||
</ProtectedRoute>,
|
||||
{
|
||||
route: '/mes-gains',
|
||||
routes: { '/connexion': <p>Page Connexion</p> },
|
||||
}
|
||||
)
|
||||
|
||||
expect(screen.getByText('Page Connexion')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Contenu protégé')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("affiche le contenu si l'utilisateur est connecté", () => {
|
||||
renderWithProviders(
|
||||
<ProtectedRoute>
|
||||
<p>Contenu protégé</p>
|
||||
</ProtectedRoute>,
|
||||
{
|
||||
route: '/mes-gains',
|
||||
user: { id: 1, email: 'client@example.com', role: 'CLIENT' },
|
||||
}
|
||||
)
|
||||
|
||||
expect(screen.getByText('Contenu protégé')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('affiche le contenu si le rôle est autorisé', () => {
|
||||
renderWithProviders(
|
||||
<ProtectedRoute roles={['ADMIN']}>
|
||||
<p>Espace admin</p>
|
||||
</ProtectedRoute>,
|
||||
{
|
||||
route: '/admin',
|
||||
user: { id: 2, email: 'admin@example.com', role: 'ADMIN' },
|
||||
}
|
||||
)
|
||||
|
||||
expect(screen.getByText('Espace admin')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("redirige un client vers son espace s'il tente d'accéder à l'admin", () => {
|
||||
renderWithProviders(
|
||||
<ProtectedRoute roles={['ADMIN']}>
|
||||
<p>Espace admin</p>
|
||||
</ProtectedRoute>,
|
||||
{
|
||||
route: '/admin',
|
||||
user: { id: 1, email: 'client@example.com', role: 'CLIENT' },
|
||||
routes: { '/mes-gains': <p>Page Mes Gains</p> },
|
||||
}
|
||||
)
|
||||
|
||||
expect(screen.getByText('Page Mes Gains')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Espace admin')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("redirige un employé vers son espace s'il tente d'accéder à l'admin", () => {
|
||||
renderWithProviders(
|
||||
<ProtectedRoute roles={['ADMIN']}>
|
||||
<p>Espace admin</p>
|
||||
</ProtectedRoute>,
|
||||
{
|
||||
route: '/admin',
|
||||
user: { id: 3, email: 'employe@example.com', role: 'EMPLOYEE' },
|
||||
routes: { '/employe': <p>Page Employé</p> },
|
||||
}
|
||||
)
|
||||
|
||||
expect(screen.getByText('Page Employé')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
93
frontend/src/test/fonctionnel/SaisirCodeUnique.test.jsx
Normal file
93
frontend/src/test/fonctionnel/SaisirCodeUnique.test.jsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import SaisirCodeUnique from '../../pages/SaisirCodeUnique'
|
||||
import Perdu from '../../pages/Perdu'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
import { participateApi } from '../../services/game'
|
||||
|
||||
vi.mock('../../services/game', () => ({
|
||||
participateApi: vi.fn(),
|
||||
}))
|
||||
|
||||
const client = { id: 1, email: 'client@example.com', role: 'CLIENT' }
|
||||
|
||||
async function saisirEtValider(code) {
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre code/i), code)
|
||||
await userEvent.click(screen.getByRole('button', { name: /valider/i }))
|
||||
}
|
||||
|
||||
describe('SaisirCodeUnique', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('désactive le bouton tant que le code ne fait pas 10 caractères', async () => {
|
||||
renderWithProviders(<SaisirCodeUnique />, { route: '/saisir-code-unique', user: client })
|
||||
|
||||
const bouton = screen.getByRole('button', { name: /valider/i })
|
||||
expect(bouton).toBeDisabled()
|
||||
|
||||
await userEvent.type(screen.getByPlaceholderText(/votre code/i), 'ABCDE12345')
|
||||
expect(bouton).toBeEnabled()
|
||||
})
|
||||
|
||||
it('met le code en majuscules et l\'envoie à l\'API', async () => {
|
||||
participateApi.mockResolvedValue({ gain: { name: 'Thé détox' }, claim: { id: 1 } })
|
||||
|
||||
renderWithProviders(<SaisirCodeUnique />, { route: '/saisir-code-unique', user: client })
|
||||
await saisirEtValider('abcde12345')
|
||||
|
||||
expect(participateApi).toHaveBeenCalledWith('ABCDE12345')
|
||||
})
|
||||
|
||||
it("affiche l'écran Félicitation puis le détail du lot quand le code est gagnant", async () => {
|
||||
participateApi.mockResolvedValue({
|
||||
gain: { name: 'Thé signature', description: 'Un thé d\'exception', value: 39 },
|
||||
claim: { id: 1 },
|
||||
})
|
||||
|
||||
renderWithProviders(<SaisirCodeUnique />, { route: '/saisir-code-unique', user: client })
|
||||
await saisirEtValider('ABCDE12345')
|
||||
|
||||
// Overlay de félicitation
|
||||
expect(await screen.findByText(/félicitation/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('Thé signature')).toBeInTheDocument()
|
||||
|
||||
// Détail du lot
|
||||
await userEvent.click(screen.getByRole('button', { name: /découvrir mon lot/i }))
|
||||
expect(screen.getByText(/valeur estimée/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('39 €')).toBeInTheDocument()
|
||||
expect(screen.getByText(/en attente de remise/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("redirige vers /perdu avec le message de l'API quand le code est invalide", async () => {
|
||||
participateApi.mockRejectedValue(new Error('Ce code a déjà été utilisé.'))
|
||||
|
||||
renderWithProviders(<SaisirCodeUnique />, {
|
||||
route: '/saisir-code-unique',
|
||||
user: client,
|
||||
routes: { '/perdu': <Perdu /> },
|
||||
})
|
||||
await saisirEtValider('ABCDE12345')
|
||||
|
||||
expect(await screen.findByText(/réessayer la prochaine fois/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('Ce code a déjà été utilisé.')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('déconnecte et redirige vers /connexion si la session a expiré (401)', async () => {
|
||||
participateApi.mockRejectedValue(
|
||||
Object.assign(new Error('Session expirée'), { status: 401 })
|
||||
)
|
||||
|
||||
renderWithProviders(<SaisirCodeUnique />, {
|
||||
route: '/saisir-code-unique',
|
||||
user: client,
|
||||
routes: { '/connexion': <p>Page Connexion</p> },
|
||||
})
|
||||
await saisirEtValider('ABCDE12345')
|
||||
|
||||
expect(await screen.findByText('Page Connexion')).toBeInTheDocument()
|
||||
expect(localStorage.getItem('token')).toBeNull()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user