merge: integrate Emmanuel changes into main
This commit is contained in:
41
frontend/src/test/fonctionnel/Accueil.test.jsx
Normal file
41
frontend/src/test/fonctionnel/Accueil.test.jsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import Accueil from '../../pages/Accueil'
|
||||
import { getGameWindowApi } from '../../services/game'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
|
||||
vi.mock('../../services/game', () => ({
|
||||
getGameWindowApi: vi.fn(),
|
||||
}))
|
||||
|
||||
describe('Accueil - dates du jeu-concours', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
|
||||
it("affiche les dates fixées dans le tableau de bord admin", async () => {
|
||||
getGameWindowApi.mockResolvedValue({
|
||||
configured: true,
|
||||
phase: 'SCHEDULED',
|
||||
startDate: '2026-11-14T23:00:00.000Z',
|
||||
participationDeadline: '2026-12-14T23:00:00.000Z',
|
||||
claimDeadline: '2027-01-13T23:00:00.000Z',
|
||||
})
|
||||
|
||||
renderWithProviders(<Accueil />, { route: '/accueil' })
|
||||
|
||||
expect(await screen.findByText('Du 15 novembre au 14 décembre 2026')).toBeInTheDocument()
|
||||
expect(screen.getByText(/ouverte du 15 novembre au 14 décembre 2026 inclus/)).toBeInTheDocument()
|
||||
expect(screen.getByText(/retirer jusqu'au 13 janvier 2027/)).toBeInTheDocument()
|
||||
expect(document.title).toBe('Jeu-concours 100 % Gagnant du 15 novembre au 14 décembre | Thé Tip Top')
|
||||
})
|
||||
|
||||
it("affiche les dates par défaut (2 → 31 octobre 2026) si l'API ne répond pas", async () => {
|
||||
getGameWindowApi.mockRejectedValue(new Error('réseau'))
|
||||
|
||||
renderWithProviders(<Accueil />, { route: '/accueil' })
|
||||
|
||||
expect(screen.getByText('Du 02 au 31 octobre 2026')).toBeInTheDocument()
|
||||
expect(screen.getByText(/retirer jusqu'au 30 novembre 2026/)).toBeInTheDocument()
|
||||
await vi.waitFor(() => expect(getGameWindowApi).toHaveBeenCalled())
|
||||
expect(screen.getByText('Du 02 au 31 octobre 2026')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -42,7 +42,8 @@ describe('Connexion', () => {
|
||||
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' })
|
||||
// captchaToken vide : aucun widget Turnstile en test (voir vite.config.js).
|
||||
expect(loginApi).toHaveBeenCalledWith({ email: 'test@example.com', password: 'mauvais-mdp', captchaToken: '' })
|
||||
})
|
||||
|
||||
it('connecte un client et redirige vers /mes-gains', async () => {
|
||||
|
||||
56
frontend/src/test/fonctionnel/DefinirMotDePasse.test.jsx
Normal file
56
frontend/src/test/fonctionnel/DefinirMotDePasse.test.jsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import DefinirMotDePasse from '../../pages/DefinirMotDePasse'
|
||||
import { resetPasswordApi } from '../../services/auth'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
|
||||
vi.mock('../../services/auth', () => ({
|
||||
resetPasswordApi: vi.fn(),
|
||||
}))
|
||||
|
||||
async function remplir(password, confirmPassword = password) {
|
||||
await userEvent.type(screen.getByLabelText(/^nouveau mot de passe/i), password)
|
||||
await userEvent.type(screen.getByLabelText(/^confirmer/i), confirmPassword)
|
||||
await userEvent.click(screen.getByRole('button', { name: /enregistrer/i }))
|
||||
}
|
||||
|
||||
describe('DefinirMotDePasse', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
|
||||
it('affiche les règles du mot de passe', () => {
|
||||
const { container } = renderWithProviders(<DefinirMotDePasse />, { route: '/definir-mot-de-passe/abc' })
|
||||
|
||||
expect(container.querySelector('[data-rule="length"]')).toBeInTheDocument()
|
||||
expect(container.querySelector('[data-rule="special"]')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("refuse un mot de passe sans caractère spécial sans appeler l'API", async () => {
|
||||
renderWithProviders(<DefinirMotDePasse />, { route: '/definir-mot-de-passe/abc' })
|
||||
|
||||
await remplir('MonMotDePasse1')
|
||||
|
||||
expect(screen.getByText(/dont un caractère spécial/i)).toBeInTheDocument()
|
||||
expect(resetPasswordApi).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('propose de demander un nouveau lien quand celui-ci a expiré', async () => {
|
||||
resetPasswordApi.mockRejectedValue(new Error('Lien de réinitialisation invalide ou expiré.'))
|
||||
renderWithProviders(<DefinirMotDePasse />, { route: '/definir-mot-de-passe/abc' })
|
||||
|
||||
await remplir('MonMotDePasse1!')
|
||||
|
||||
expect(await screen.findByRole('link', { name: /demander un nouveau lien/i })).toHaveAttribute('href', '/mot-de-passe-oublie')
|
||||
})
|
||||
|
||||
it('envoie un mot de passe conforme', async () => {
|
||||
resetPasswordApi.mockResolvedValue({ message: 'ok' })
|
||||
renderWithProviders(<DefinirMotDePasse />, { route: '/definir-mot-de-passe/abc' })
|
||||
|
||||
await remplir('MonMotDePasse1!')
|
||||
|
||||
expect(resetPasswordApi).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ password: 'MonMotDePasse1!', confirmPassword: 'MonMotDePasse1!' })
|
||||
)
|
||||
})
|
||||
})
|
||||
97
frontend/src/test/fonctionnel/EmployeeDeliveries.test.jsx
Normal file
97
frontend/src/test/fonctionnel/EmployeeDeliveries.test.jsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { render, screen, within } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import EmployeeDeliveries from '../../components/admin/EmployeeDeliveries'
|
||||
import { getEmployeesApi, getEmployeeDeliveriesApi, getDeliveryByTicketCodeApi } from '../../services/admin'
|
||||
|
||||
vi.mock('../../services/admin', () => ({
|
||||
getEmployeesApi: vi.fn(),
|
||||
getEmployeeDeliveriesApi: vi.fn(),
|
||||
getDeliveryByTicketCodeApi: vi.fn(),
|
||||
}))
|
||||
|
||||
const MARC = { id: 10, firstname: 'Marc', lastname: 'Durand', email: 'marc@example.com', createdAt: '2026-09-01T00:00:00Z', mustChangePassword: false, deliveredCount: 1 }
|
||||
const SOPHIE = { id: 11, firstname: 'Sophie', lastname: 'Bernard', email: 'sophie@example.com', createdAt: '2026-09-02T00:00:00Z', mustChangePassword: true, deliveredCount: 0 }
|
||||
|
||||
function renderComponent() {
|
||||
return render(<EmployeeDeliveries refreshKey={0} onAuthError={() => false} />)
|
||||
}
|
||||
|
||||
describe('EmployeeDeliveries', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
getEmployeesApi.mockResolvedValue({ employees: [MARC, SOPHIE] })
|
||||
})
|
||||
|
||||
it('liste les employés et filtre par nom', async () => {
|
||||
renderComponent()
|
||||
|
||||
expect(await screen.findByRole('button', { name: 'Marc Durand' })).toBeInTheDocument()
|
||||
expect(screen.getByText('Première connexion en attente')).toBeInTheDocument()
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/rechercher un employé/i), 'sophie')
|
||||
|
||||
expect(screen.queryByRole('button', { name: 'Marc Durand' })).not.toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'Sophie Bernard' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("affiche les lots remis quand on clique sur le nom d'un employé", async () => {
|
||||
getEmployeeDeliveriesApi.mockResolvedValue({
|
||||
employee: MARC,
|
||||
deliveries: [{
|
||||
claimId: 1,
|
||||
ticketCode: 'A1B2C3D4E5',
|
||||
lot: { name: 'Infuseur à thé', value: 39 },
|
||||
client: { id: 5, firstname: 'Chloé', lastname: 'Martin', email: 'chloe@example.com' },
|
||||
deliveredAt: '2026-09-10T14:30:00Z',
|
||||
}],
|
||||
})
|
||||
renderComponent()
|
||||
|
||||
await userEvent.click(await screen.findByRole('button', { name: 'Marc Durand' }))
|
||||
|
||||
expect(getEmployeeDeliveriesApi).toHaveBeenCalledWith(10)
|
||||
expect(await screen.findByText('A1B2C3D4E5')).toBeInTheDocument()
|
||||
expect(screen.getByText(/lots remis par marc durand/i)).toBeInTheDocument()
|
||||
expect(screen.getByText('Infuseur à thé')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("retrouve l'employé et la date de remise à partir du numéro de ticket", async () => {
|
||||
getDeliveryByTicketCodeApi.mockResolvedValue({
|
||||
ticketCode: 'A1B2C3D4E5',
|
||||
lot: { name: 'Infuseur à thé', value: 39 },
|
||||
status: 'DELIVERED',
|
||||
playedAt: '2026-09-01T10:00:00Z',
|
||||
client: { id: 5, firstname: 'Chloé', lastname: 'Martin', email: 'chloe@example.com' },
|
||||
deliveredBy: { id: 10, firstname: 'Marc', lastname: 'Durand', email: 'marc@example.com' },
|
||||
deliveredAt: '2026-09-10T14:30:00Z',
|
||||
})
|
||||
getEmployeeDeliveriesApi.mockResolvedValue({ employee: MARC, deliveries: [] })
|
||||
renderComponent()
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/numéro du ticket/i), 'a1b2c3d4e5')
|
||||
await userEvent.click(screen.getByRole('button', { name: /^rechercher$/i }))
|
||||
|
||||
const resultat = await screen.findByTestId('ticket-result')
|
||||
expect(getDeliveryByTicketCodeApi).toHaveBeenCalledWith('a1b2c3d4e5')
|
||||
expect(within(resultat).getByText('Lot remis')).toBeInTheDocument()
|
||||
expect(within(resultat).getByText(/remis par/i)).toHaveTextContent(new Date('2026-09-10T14:30:00Z').toLocaleString('fr-FR', {
|
||||
day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit',
|
||||
}))
|
||||
|
||||
// Le nom de l'employé mène à la liste de ses remises.
|
||||
await userEvent.click(within(resultat).getByRole('button', { name: 'Marc Durand' }))
|
||||
expect(getEmployeeDeliveriesApi).toHaveBeenCalledWith(10)
|
||||
expect(await screen.findByText(/n'a encore remis aucun lot/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("affiche l'erreur quand le ticket n'existe pas", async () => {
|
||||
getDeliveryByTicketCodeApi.mockRejectedValue(new Error('Aucun ticket ne correspond à ce numéro.'))
|
||||
renderComponent()
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/numéro du ticket/i), 'INCONNU')
|
||||
await userEvent.click(screen.getByRole('button', { name: /^rechercher$/i }))
|
||||
|
||||
expect(await screen.findByText('Aucun ticket ne correspond à ce numéro.')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -10,13 +10,21 @@ vi.mock('../../services/auth', () => ({
|
||||
verifyCodeApi: vi.fn(),
|
||||
}))
|
||||
|
||||
// Remplit et soumet le formulaire d'inscription (étape 1).
|
||||
async function remplirEtSoumettre() {
|
||||
// Remplit les champs obligatoires (la date de naissance l'est depuis la règle
|
||||
// des 18 ans), sans soumettre.
|
||||
async function remplirChampsObligatoires({ password = 'MotDePasse123!', confirmPassword = password } = {}) {
|
||||
await userEvent.type(screen.getByLabelText(/adresse email/i), 'jean@example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^nom/i), 'Dupont')
|
||||
await userEvent.type(screen.getByLabelText(/prénom/i), 'Jean')
|
||||
await userEvent.type(screen.getByLabelText(/^mot de passe/i), 'MotDePasse123!')
|
||||
await userEvent.type(screen.getByLabelText(/date de naissance/i), '1990-05-14')
|
||||
await userEvent.type(screen.getByLabelText(/^mot de passe/i), password)
|
||||
await userEvent.type(screen.getByLabelText(/confirmer le mot de passe/i), confirmPassword)
|
||||
await userEvent.click(screen.getByRole('checkbox', { name: /conditions d'utilisation/i }))
|
||||
}
|
||||
|
||||
// Remplit et soumet le formulaire d'inscription (étape 1).
|
||||
async function remplirEtSoumettre(options) {
|
||||
await remplirChampsObligatoires(options)
|
||||
await userEvent.click(screen.getByRole('button', { name: /s'inscrire/i }))
|
||||
}
|
||||
|
||||
@@ -41,6 +49,50 @@ describe('Inscription', () => {
|
||||
expect(screen.getByLabelText(/^nom/i)).toBeInTheDocument()
|
||||
expect(screen.getByLabelText(/prénom/i)).toBeInTheDocument()
|
||||
expect(screen.getByLabelText(/^mot de passe/i)).toBeInTheDocument()
|
||||
expect(screen.getByLabelText(/confirmer le mot de passe/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('coche les règles du mot de passe au fil de la saisie', async () => {
|
||||
const { container } = renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
const regle = (id) => container.querySelector(`[data-rule="${id}"]`)
|
||||
|
||||
expect(regle('length')).toHaveAttribute('data-valid', 'false')
|
||||
expect(regle('special')).toHaveAttribute('data-valid', 'false')
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^mot de passe/i), 'abcdefgh')
|
||||
expect(regle('length')).toHaveAttribute('data-valid', 'true')
|
||||
expect(regle('special')).toHaveAttribute('data-valid', 'false')
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/^mot de passe/i), '!')
|
||||
expect(regle('special')).toHaveAttribute('data-valid', 'true')
|
||||
})
|
||||
|
||||
it("refuse un mot de passe sans caractère spécial sans appeler l'API", async () => {
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
await remplirEtSoumettre({ password: 'MotDePasse123' })
|
||||
|
||||
expect(screen.getByText(/au moins 8 caractères, dont un caractère spécial/i)).toBeInTheDocument()
|
||||
expect(registerApi).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("refuse un mot de passe trop court sans appeler l'API", async () => {
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
await remplirEtSoumettre({ password: 'Ab1!xyz' })
|
||||
|
||||
expect(screen.getByText(/au moins 8 caractères, dont un caractère spécial/i)).toBeInTheDocument()
|
||||
expect(registerApi).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("signale une confirmation différente et bloque l'inscription", async () => {
|
||||
renderWithProviders(<Inscription />, { route: '/inscription' })
|
||||
await remplirChampsObligatoires({ password: 'MotDePasse123!', confirmPassword: 'MotDePasse124!' })
|
||||
|
||||
expect(screen.getByLabelText(/confirmer le mot de passe/i)).toHaveAttribute('aria-invalid', 'true')
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /s'inscrire/i }))
|
||||
|
||||
expect(screen.getAllByText(/ne correspondent pas/i).length).toBeGreaterThan(0)
|
||||
expect(registerApi).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("désactive le bouton tant que les conditions ne sont pas acceptées", async () => {
|
||||
@@ -64,9 +116,11 @@ describe('Inscription', () => {
|
||||
firstname: 'Jean',
|
||||
lastname: 'Dupont',
|
||||
password: 'MotDePasse123!',
|
||||
birthdate: '',
|
||||
confirmPassword: 'MotDePasse123!',
|
||||
birthdate: '1990-05-14',
|
||||
gender: '',
|
||||
marketingOptIn: false,
|
||||
captchaToken: '',
|
||||
})
|
||||
expect(await screen.findByRole('heading', { name: /vérifiez votre email/i })).toBeInTheDocument()
|
||||
expect(screen.getByText('jean@example.com')).toBeInTheDocument()
|
||||
@@ -83,6 +137,7 @@ describe('Inscription', () => {
|
||||
await userEvent.type(screen.getByLabelText(/date de naissance/i), '1990-05-14')
|
||||
await userEvent.selectOptions(screen.getByLabelText(/genre/i), 'Femme')
|
||||
await userEvent.type(screen.getByLabelText(/^mot de passe/i), 'MotDePasse123!')
|
||||
await userEvent.type(screen.getByLabelText(/confirmer le mot de passe/i), 'MotDePasse123!')
|
||||
await userEvent.click(screen.getByRole('checkbox', { name: /conditions d'utilisation/i }))
|
||||
await userEvent.click(screen.getByRole('button', { name: /s'inscrire/i }))
|
||||
|
||||
@@ -99,13 +154,8 @@ describe('Inscription', () => {
|
||||
const marketing = screen.getByRole('checkbox', { name: /offres et actualités/i })
|
||||
expect(marketing).not.toBeChecked()
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/adresse email/i), 'jean@example.com')
|
||||
await userEvent.type(screen.getByLabelText(/^nom/i), 'Dupont')
|
||||
await userEvent.type(screen.getByLabelText(/prénom/i), 'Jean')
|
||||
await userEvent.type(screen.getByLabelText(/^mot de passe/i), 'MotDePasse123!')
|
||||
await userEvent.click(marketing)
|
||||
await userEvent.click(screen.getByRole('checkbox', { name: /conditions d'utilisation/i }))
|
||||
await userEvent.click(screen.getByRole('button', { name: /s'inscrire/i }))
|
||||
await remplirEtSoumettre()
|
||||
|
||||
expect(registerApi).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ marketingOptIn: true })
|
||||
|
||||
51
frontend/src/test/fonctionnel/MotDePasseOublie.test.jsx
Normal file
51
frontend/src/test/fonctionnel/MotDePasseOublie.test.jsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import MotDePasseOublie from '../../pages/MotDePasseOublie'
|
||||
import Connexion from '../../pages/Connexion'
|
||||
import { forgotPasswordApi } from '../../services/auth'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
|
||||
vi.mock('../../services/auth', () => ({
|
||||
forgotPasswordApi: vi.fn(),
|
||||
loginApi: vi.fn(),
|
||||
}))
|
||||
|
||||
describe('MotDePasseOublie', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
|
||||
it("envoie la demande et affiche la confirmation neutre", async () => {
|
||||
forgotPasswordApi.mockResolvedValue({ message: 'Si un compte existe avec cet email, un lien de réinitialisation vient de lui être envoyé.' })
|
||||
renderWithProviders(<MotDePasseOublie />, { route: '/mot-de-passe-oublie' })
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/adresse email/i), 'lea@example.com')
|
||||
await userEvent.click(screen.getByRole('button', { name: /recevoir le lien/i }))
|
||||
|
||||
expect(forgotPasswordApi).toHaveBeenCalledWith({ email: 'lea@example.com', captchaToken: '' })
|
||||
expect(await screen.findByRole('status')).toHaveTextContent(/si un compte existe/i)
|
||||
expect(screen.getByRole('link', { name: /retour à la connexion/i })).toHaveAttribute('href', '/connexion')
|
||||
})
|
||||
|
||||
it("affiche l'erreur renvoyée par l'API", async () => {
|
||||
forgotPasswordApi.mockRejectedValue(new Error('Trop de tentatives, réessayez dans quelques minutes.'))
|
||||
renderWithProviders(<MotDePasseOublie />, { route: '/mot-de-passe-oublie' })
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/adresse email/i), 'lea@example.com')
|
||||
await userEvent.click(screen.getByRole('button', { name: /recevoir le lien/i }))
|
||||
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent(/trop de tentatives/i)
|
||||
})
|
||||
|
||||
it("le lien de la page de connexion y mène en reprenant l'email saisi", async () => {
|
||||
renderWithProviders(<Connexion />, {
|
||||
route: '/connexion',
|
||||
routes: { '/mot-de-passe-oublie': <MotDePasseOublie /> },
|
||||
})
|
||||
|
||||
await userEvent.type(screen.getByLabelText(/adresse email/i), 'lea@example.com')
|
||||
await userEvent.click(screen.getByRole('link', { name: /mot de passe oublié/i }))
|
||||
|
||||
expect(await screen.findByRole('heading', { name: /mot de passe oublié/i })).toBeInTheDocument()
|
||||
expect(screen.getByLabelText(/adresse email/i)).toHaveValue('lea@example.com')
|
||||
})
|
||||
})
|
||||
74
frontend/src/test/fonctionnel/NouveauMotDePasse.test.jsx
Normal file
74
frontend/src/test/fonctionnel/NouveauMotDePasse.test.jsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import NouveauMotDePasse from '../../pages/NouveauMotDePasse'
|
||||
import { setInitialPasswordApi } from '../../services/auth'
|
||||
import { renderWithProviders } from '../renderWithProviders'
|
||||
|
||||
vi.mock('../../services/auth', () => ({
|
||||
setInitialPasswordApi: vi.fn(),
|
||||
}))
|
||||
|
||||
const EMPLOYE = { id: 3, firstname: 'Marc', email: 'marc@example.com', role: 'EMPLOYEE', mustChangePassword: true }
|
||||
|
||||
async function remplir(password, confirmPassword) {
|
||||
await userEvent.type(screen.getByLabelText(/^nouveau mot de passe/i), password)
|
||||
await userEvent.type(screen.getByLabelText(/^confirmer/i), confirmPassword)
|
||||
await userEvent.click(screen.getByRole('button', { name: /enregistrer/i }))
|
||||
}
|
||||
|
||||
describe('NouveauMotDePasse', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
|
||||
it("refuse deux mots de passe différents sans appeler l'API", async () => {
|
||||
renderWithProviders(<NouveauMotDePasse />, { route: '/nouveau-mot-de-passe', user: EMPLOYE })
|
||||
|
||||
await remplir('NouveauMdp123!', 'AutreMdp456!')
|
||||
|
||||
expect(screen.getByRole('alert')).toHaveTextContent(/ne correspondent pas/i)
|
||||
expect(setInitialPasswordApi).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("enregistre le mot de passe puis ouvre l'espace employé", async () => {
|
||||
setInitialPasswordApi.mockResolvedValue({ message: 'ok' })
|
||||
renderWithProviders(<NouveauMotDePasse />, {
|
||||
route: '/nouveau-mot-de-passe',
|
||||
user: EMPLOYE,
|
||||
routes: { '/employe': <p>Page Employé</p> },
|
||||
})
|
||||
|
||||
await remplir('NouveauMdp123!', 'NouveauMdp123!')
|
||||
|
||||
expect(await screen.findByText('Page Employé')).toBeInTheDocument()
|
||||
expect(setInitialPasswordApi).toHaveBeenCalledWith({ password: 'NouveauMdp123!', confirmPassword: 'NouveauMdp123!' })
|
||||
expect(JSON.parse(localStorage.getItem('user')).mustChangePassword).toBe(false)
|
||||
})
|
||||
|
||||
it("affiche l'erreur renvoyée par l'API", async () => {
|
||||
setInitialPasswordApi.mockRejectedValue(new Error('Choisissez un mot de passe différent du mot de passe provisoire.'))
|
||||
renderWithProviders(<NouveauMotDePasse />, { route: '/nouveau-mot-de-passe', user: EMPLOYE })
|
||||
|
||||
await remplir('Provisoire12!', 'Provisoire12!')
|
||||
|
||||
expect(await screen.findByText(/différent du mot de passe provisoire/i)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("refuse un mot de passe sans caractère spécial sans appeler l'API", async () => {
|
||||
renderWithProviders(<NouveauMotDePasse />, { route: '/nouveau-mot-de-passe', user: EMPLOYE })
|
||||
|
||||
await remplir('NouveauMdp123', 'NouveauMdp123')
|
||||
|
||||
expect(screen.getByRole('alert')).toHaveTextContent(/caractère spécial/i)
|
||||
expect(setInitialPasswordApi).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("renvoie vers son espace un utilisateur qui n'a pas de mot de passe provisoire", () => {
|
||||
renderWithProviders(<NouveauMotDePasse />, {
|
||||
route: '/nouveau-mot-de-passe',
|
||||
user: { ...EMPLOYE, mustChangePassword: false },
|
||||
routes: { '/employe': <p>Page Employé</p> },
|
||||
})
|
||||
|
||||
expect(screen.getByText('Page Employé')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -77,4 +77,20 @@ describe('ProtectedRoute', () => {
|
||||
|
||||
expect(screen.getByText('Page Employé')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('impose le choix du mot de passe tant que le provisoire n\'est pas remplacé', () => {
|
||||
renderWithProviders(
|
||||
<ProtectedRoute roles={['EMPLOYEE']}>
|
||||
<p>Espace employé</p>
|
||||
</ProtectedRoute>,
|
||||
{
|
||||
route: '/employe',
|
||||
user: { id: 3, email: 'employe@example.com', role: 'EMPLOYEE', mustChangePassword: true },
|
||||
routes: { '/nouveau-mot-de-passe': <p>Page Nouveau mot de passe</p> },
|
||||
}
|
||||
)
|
||||
|
||||
expect(screen.getByText('Page Nouveau mot de passe')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Espace employé')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user