364 lines
11 KiB
TypeScript
Executable File
364 lines
11 KiB
TypeScript
Executable File
import { renderHook, waitFor } from '@testing-library/react'
|
|
import { useDashboard } from '../useDashboard'
|
|
import { clientService, chantierService, devisService, factureService } from '../../services/api'
|
|
|
|
// Mock des services
|
|
jest.mock('../../services/api')
|
|
|
|
const mockClientService = clientService as jest.Mocked<typeof clientService>
|
|
const mockChantierService = chantierService as jest.Mocked<typeof chantierService>
|
|
const mockDevisService = devisService as jest.Mocked<typeof devisService>
|
|
const mockFactureService = factureService as jest.Mocked<typeof factureService>
|
|
|
|
const mockClients = [
|
|
{ id: '1', nom: 'Client', prenom: 'Un', email: 'client1@test.com' },
|
|
{ id: '2', nom: 'Client', prenom: 'Deux', email: 'client2@test.com' },
|
|
]
|
|
|
|
const mockChantiers = [
|
|
{
|
|
id: '1',
|
|
nom: 'Chantier 1',
|
|
client: mockClients[0],
|
|
statut: 'EN_COURS',
|
|
dateDebut: '2024-01-01',
|
|
montantPrevu: 10000,
|
|
},
|
|
{
|
|
id: '2',
|
|
nom: 'Chantier 2',
|
|
client: mockClients[1],
|
|
statut: 'PLANIFIE',
|
|
dateDebut: '2024-01-15',
|
|
montantPrevu: 15000,
|
|
},
|
|
{
|
|
id: '3',
|
|
nom: 'Chantier 3',
|
|
client: mockClients[0],
|
|
statut: 'TERMINE',
|
|
dateDebut: '2024-01-10',
|
|
montantPrevu: 8000,
|
|
},
|
|
]
|
|
|
|
const mockDevis = [
|
|
{
|
|
id: '1',
|
|
numero: 'D2024-001',
|
|
client: mockClients[0],
|
|
statut: 'ENVOYE',
|
|
dateEmission: '2024-01-01',
|
|
dateValidite: '2024-12-31',
|
|
montantTTC: 5000,
|
|
},
|
|
{
|
|
id: '2',
|
|
numero: 'D2024-002',
|
|
client: mockClients[1],
|
|
statut: 'ACCEPTE',
|
|
dateEmission: '2024-01-05',
|
|
dateValidite: '2024-12-31',
|
|
montantTTC: 7000,
|
|
},
|
|
]
|
|
|
|
const mockFactures = [
|
|
{
|
|
id: '1',
|
|
numero: 'F2024-001',
|
|
client: mockClients[0],
|
|
statut: 'PAYEE',
|
|
dateEmission: '2024-01-01',
|
|
dateEcheance: '2024-01-31',
|
|
montantTTC: 10000,
|
|
},
|
|
{
|
|
id: '2',
|
|
numero: 'F2024-002',
|
|
client: mockClients[1],
|
|
statut: 'ENVOYEE',
|
|
dateEmission: '2024-01-10',
|
|
dateEcheance: '2024-01-01', // En retard
|
|
montantTTC: 5000,
|
|
},
|
|
]
|
|
|
|
describe('Hook useDashboard', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
jest.spyOn(console, 'log').mockImplementation(() => {})
|
|
jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
})
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks()
|
|
})
|
|
|
|
it('devrait initialiser avec les valeurs par défaut', () => {
|
|
mockClientService.getAll.mockImplementation(() => new Promise(() => {}))
|
|
mockChantierService.getAll.mockImplementation(() => new Promise(() => {}))
|
|
mockDevisService.getAll.mockImplementation(() => new Promise(() => {}))
|
|
mockFactureService.getAll.mockImplementation(() => new Promise(() => {}))
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
expect(result.current.stats).toBeNull()
|
|
expect(result.current.chantiersRecents).toEqual([])
|
|
expect(result.current.facturesEnRetard).toEqual([])
|
|
expect(result.current.devisEnAttente).toEqual([])
|
|
expect(result.current.loading).toBe(true)
|
|
expect(result.current.error).toBeNull()
|
|
})
|
|
|
|
it('devrait charger les données avec succès', async () => {
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue(mockChantiers)
|
|
mockDevisService.getAll.mockResolvedValue(mockDevis)
|
|
mockFactureService.getAll.mockResolvedValue(mockFactures)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.stats).toEqual({
|
|
totalClients: 2,
|
|
totalChantiers: 3,
|
|
chantiersEnCours: 1,
|
|
chantiersPlanifies: 1,
|
|
chantiersTermines: 1,
|
|
totalDevis: 2,
|
|
devisAcceptes: 1,
|
|
devisEnAttente: 1,
|
|
totalFactures: 2,
|
|
facturesPayees: 1,
|
|
facturesEnRetard: 1,
|
|
chiffreAffaires: 10000,
|
|
chiffreAffairesMois: expect.any(Number),
|
|
chiffreAffairesAnnee: expect.any(Number),
|
|
})
|
|
})
|
|
|
|
it('devrait calculer les chantiers récents', async () => {
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue(mockChantiers)
|
|
mockDevisService.getAll.mockResolvedValue(mockDevis)
|
|
mockFactureService.getAll.mockResolvedValue(mockFactures)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.chantiersRecents).toHaveLength(3)
|
|
expect(result.current.chantiersRecents[0]).toEqual({
|
|
id: '2',
|
|
nom: 'Chantier 2',
|
|
client: 'Client Deux',
|
|
statut: 'PLANIFIE',
|
|
dateDebut: '2024-01-15',
|
|
montantPrevu: 15000,
|
|
})
|
|
})
|
|
|
|
it('devrait calculer les factures en retard', async () => {
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue(mockChantiers)
|
|
mockDevisService.getAll.mockResolvedValue(mockDevis)
|
|
mockFactureService.getAll.mockResolvedValue(mockFactures)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.facturesEnRetard).toHaveLength(1)
|
|
expect(result.current.facturesEnRetard[0]).toEqual({
|
|
id: '2',
|
|
numero: 'F2024-002',
|
|
client: 'Client Deux',
|
|
montantTTC: 5000,
|
|
dateEcheance: '2024-01-01',
|
|
joursRetard: expect.any(Number),
|
|
})
|
|
})
|
|
|
|
it('devrait calculer les devis en attente', async () => {
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue(mockChantiers)
|
|
mockDevisService.getAll.mockResolvedValue(mockDevis)
|
|
mockFactureService.getAll.mockResolvedValue(mockFactures)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.devisEnAttente).toHaveLength(1)
|
|
expect(result.current.devisEnAttente[0]).toEqual({
|
|
id: '1',
|
|
numero: 'D2024-001',
|
|
client: 'Client Un',
|
|
montantTTC: 5000,
|
|
dateEmission: '2024-01-01',
|
|
dateValidite: '2024-12-31',
|
|
joursRestants: expect.any(Number),
|
|
})
|
|
})
|
|
|
|
it('devrait gérer les erreurs partielles', async () => {
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockRejectedValue(new Error('Erreur chantiers'))
|
|
mockDevisService.getAll.mockResolvedValue(mockDevis)
|
|
mockFactureService.getAll.mockResolvedValue(mockFactures)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.error).toBeNull()
|
|
expect(result.current.stats?.totalClients).toBe(2)
|
|
expect(result.current.stats?.totalChantiers).toBe(0)
|
|
expect(result.current.chantiersRecents).toEqual([])
|
|
})
|
|
|
|
it('devrait gérer les erreurs complètes', async () => {
|
|
mockClientService.getAll.mockRejectedValue(new Error('Erreur clients'))
|
|
mockChantierService.getAll.mockRejectedValue(new Error('Erreur chantiers'))
|
|
mockDevisService.getAll.mockRejectedValue(new Error('Erreur devis'))
|
|
mockFactureService.getAll.mockRejectedValue(new Error('Erreur factures'))
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.error).toBeNull()
|
|
expect(result.current.stats?.totalClients).toBe(0)
|
|
expect(result.current.stats?.totalChantiers).toBe(0)
|
|
expect(result.current.chantiersRecents).toEqual([])
|
|
})
|
|
|
|
it('devrait permettre de rafraîchir les données', async () => {
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue(mockChantiers)
|
|
mockDevisService.getAll.mockResolvedValue(mockDevis)
|
|
mockFactureService.getAll.mockResolvedValue(mockFactures)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(mockClientService.getAll).toHaveBeenCalledTimes(1)
|
|
|
|
// Rafraîchir
|
|
result.current.refresh()
|
|
|
|
await waitFor(() => {
|
|
expect(mockClientService.getAll).toHaveBeenCalledTimes(2)
|
|
})
|
|
})
|
|
|
|
it('devrait gérer les données non-array', async () => {
|
|
mockClientService.getAll.mockResolvedValue(null as any)
|
|
mockChantierService.getAll.mockResolvedValue(undefined as any)
|
|
mockDevisService.getAll.mockResolvedValue({} as any)
|
|
mockFactureService.getAll.mockResolvedValue('invalid' as any)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.stats?.totalClients).toBe(0)
|
|
expect(result.current.stats?.totalChantiers).toBe(0)
|
|
expect(result.current.stats?.totalDevis).toBe(0)
|
|
expect(result.current.stats?.totalFactures).toBe(0)
|
|
})
|
|
|
|
it('devrait calculer correctement le chiffre d\'affaires mensuel', async () => {
|
|
const today = new Date()
|
|
const thisMonth = today.getMonth()
|
|
const thisYear = today.getFullYear()
|
|
|
|
const facturesThisMonth = [
|
|
{
|
|
id: '1',
|
|
numero: 'F2024-001',
|
|
client: mockClients[0],
|
|
statut: 'PAYEE',
|
|
dateEmission: new Date(thisYear, thisMonth, 1).toISOString(),
|
|
dateEcheance: new Date(thisYear, thisMonth, 31).toISOString(),
|
|
montantTTC: 10000,
|
|
},
|
|
{
|
|
id: '2',
|
|
numero: 'F2024-002',
|
|
client: mockClients[1],
|
|
statut: 'PAYEE',
|
|
dateEmission: new Date(thisYear, thisMonth - 1, 1).toISOString(), // Mois précédent
|
|
dateEcheance: new Date(thisYear, thisMonth - 1, 31).toISOString(),
|
|
montantTTC: 5000,
|
|
},
|
|
]
|
|
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue([])
|
|
mockDevisService.getAll.mockResolvedValue([])
|
|
mockFactureService.getAll.mockResolvedValue(facturesThisMonth)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.stats?.chiffreAffairesMois).toBe(10000)
|
|
})
|
|
|
|
it('devrait limiter les chantiers récents à 5', async () => {
|
|
const manyChantiers = Array.from({ length: 10 }, (_, i) => ({
|
|
id: `${i + 1}`,
|
|
nom: `Chantier ${i + 1}`,
|
|
client: mockClients[0],
|
|
statut: 'EN_COURS',
|
|
dateDebut: new Date(2024, 0, i + 1).toISOString(),
|
|
montantPrevu: 10000,
|
|
}))
|
|
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue(manyChantiers)
|
|
mockDevisService.getAll.mockResolvedValue([])
|
|
mockFactureService.getAll.mockResolvedValue([])
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.loading).toBe(false)
|
|
})
|
|
|
|
expect(result.current.chantiersRecents).toHaveLength(5)
|
|
})
|
|
|
|
it('devrait fournir un alias isLoading', async () => {
|
|
mockClientService.getAll.mockResolvedValue(mockClients)
|
|
mockChantierService.getAll.mockResolvedValue(mockChantiers)
|
|
mockDevisService.getAll.mockResolvedValue(mockDevis)
|
|
mockFactureService.getAll.mockResolvedValue(mockFactures)
|
|
|
|
const { result } = renderHook(() => useDashboard())
|
|
|
|
expect(result.current.isLoading).toBe(result.current.loading)
|
|
})
|
|
}) |