Initial commit

This commit is contained in:
dahoud
2025-10-01 01:39:07 +00:00
commit b430bf3b96
826 changed files with 255287 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
import React from 'react'
import { render, screen } from '../../../test-utils'
import userEvent from '@testing-library/user-event'
import ChantiersList from '../ChantiersList'
import { ChantierRecent, StatutChantier } from '../../../types/btp'
const mockChantiers: ChantierRecent[] = [
{
id: '1',
nom: 'Rénovation Bureau',
client: 'Entreprise ABC',
statut: StatutChantier.EN_COURS,
dateDebut: '2024-01-15',
montantPrevu: 45000,
},
{
id: '2',
nom: 'Construction Garage',
client: 'Client XYZ',
statut: StatutChantier.PLANIFIE,
dateDebut: '2024-02-01',
montantPrevu: 25000,
},
{
id: '3',
nom: 'Réparation Toiture',
client: 'Mairie',
statut: StatutChantier.TERMINE,
dateDebut: '2024-01-01',
montantPrevu: 15000,
},
]
describe('Composant ChantiersList', () => {
const mockOnViewAll = jest.fn()
beforeEach(() => {
jest.clearAllMocks()
})
it('devrait afficher la liste des chantiers', () => {
render(<ChantiersList chantiers={mockChantiers} onViewAll={mockOnViewAll} />)
expect(screen.getByText('Chantiers récents')).toBeInTheDocument()
expect(screen.getByText('Rénovation Bureau')).toBeInTheDocument()
expect(screen.getByText('Construction Garage')).toBeInTheDocument()
expect(screen.getByText('Réparation Toiture')).toBeInTheDocument()
})
it('devrait afficher les informations détaillées de chaque chantier', () => {
render(<ChantiersList chantiers={mockChantiers} onViewAll={mockOnViewAll} />)
// Vérifier les noms des clients
expect(screen.getByText('Entreprise ABC')).toBeInTheDocument()
expect(screen.getByText('Client XYZ')).toBeInTheDocument()
expect(screen.getByText('Mairie')).toBeInTheDocument()
// Vérifier les montants formatés
expect(screen.getByText('45 000 €')).toBeInTheDocument()
expect(screen.getByText('25 000 €')).toBeInTheDocument()
expect(screen.getByText('15 000 €')).toBeInTheDocument()
})
it('devrait afficher les statuts corrects avec les bonnes couleurs', () => {
render(<ChantiersList chantiers={mockChantiers} onViewAll={mockOnViewAll} />)
expect(screen.getByText('En cours')).toBeInTheDocument()
expect(screen.getByText('Planifié')).toBeInTheDocument()
expect(screen.getByText('Terminé')).toBeInTheDocument()
})
it('devrait formater les dates correctement', () => {
render(<ChantiersList chantiers={mockChantiers} onViewAll={mockOnViewAll} />)
// Vérifier que les dates sont au format français
expect(screen.getByText('15/01/2024')).toBeInTheDocument()
expect(screen.getByText('01/02/2024')).toBeInTheDocument()
expect(screen.getByText('01/01/2024')).toBeInTheDocument()
})
it('devrait afficher le bouton "Voir tout" et le rendre cliquable', async () => {
const user = userEvent.setup()
render(<ChantiersList chantiers={mockChantiers} onViewAll={mockOnViewAll} />)
const viewAllButton = screen.getByText('Voir tout')
expect(viewAllButton).toBeInTheDocument()
await user.click(viewAllButton)
expect(mockOnViewAll).toHaveBeenCalledTimes(1)
})
it('ne devrait pas afficher le bouton "Voir tout" si onViewAll n\'est pas fourni', () => {
render(<ChantiersList chantiers={mockChantiers} />)
expect(screen.queryByText('Voir tout')).not.toBeInTheDocument()
})
it('devrait afficher un message quand il n\'y a pas de chantiers', () => {
render(<ChantiersList chantiers={[]} onViewAll={mockOnViewAll} />)
expect(screen.getByText('Aucun chantier récent')).toBeInTheDocument()
})
it('devrait afficher l\'état de chargement', () => {
render(<ChantiersList chantiers={[]} loading={true} />)
// Vérifier que le titre n'est pas affiché en mode chargement
expect(screen.queryByText('Chantiers récents')).not.toBeInTheDocument()
// Vérifier la présence des skeletons
const skeletons = document.querySelectorAll('[data-pc-name="skeleton"]')
expect(skeletons.length).toBeGreaterThan(0)
})
it('devrait gérer tous les statuts de chantier', () => {
const chantiersAvecTousStatuts: ChantierRecent[] = [
{
id: '1',
nom: 'Chantier 1',
client: 'Client 1',
statut: StatutChantier.EN_COURS,
dateDebut: '2024-01-01',
montantPrevu: 1000,
},
{
id: '2',
nom: 'Chantier 2',
client: 'Client 2',
statut: StatutChantier.PLANIFIE,
dateDebut: '2024-01-01',
montantPrevu: 2000,
},
{
id: '3',
nom: 'Chantier 3',
client: 'Client 3',
statut: StatutChantier.TERMINE,
dateDebut: '2024-01-01',
montantPrevu: 3000,
},
{
id: '4',
nom: 'Chantier 4',
client: 'Client 4',
statut: StatutChantier.ANNULE,
dateDebut: '2024-01-01',
montantPrevu: 4000,
},
{
id: '5',
nom: 'Chantier 5',
client: 'Client 5',
statut: StatutChantier.SUSPENDU,
dateDebut: '2024-01-01',
montantPrevu: 5000,
},
]
render(<ChantiersList chantiers={chantiersAvecTousStatuts} />)
expect(screen.getByText('En cours')).toBeInTheDocument()
expect(screen.getByText('Planifié')).toBeInTheDocument()
expect(screen.getByText('Terminé')).toBeInTheDocument()
expect(screen.getByText('Annulé')).toBeInTheDocument()
expect(screen.getByText('Suspendu')).toBeInTheDocument()
})
it('devrait gérer les montants manquants', () => {
const chantiersAvecMontantManquant: ChantierRecent[] = [
{
id: '1',
nom: 'Chantier sans montant',
client: 'Client Test',
statut: StatutChantier.EN_COURS,
dateDebut: '2024-01-01',
montantPrevu: undefined,
},
]
render(<ChantiersList chantiers={chantiersAvecMontantManquant} />)
expect(screen.getByText('-')).toBeInTheDocument()
})
it('devrait avoir une structure de table responsive', () => {
const { container } = render(<ChantiersList chantiers={mockChantiers} />)
const dataTable = container.querySelector('[data-pc-name="datatable"]')
expect(dataTable).toBeInTheDocument()
// Vérifier que les en-têtes sont cachés
expect(dataTable).toHaveAttribute('data-pc-section', 'wrapper')
})
it('devrait formater correctement les gros montants', () => {
const chantiersAvecGrosMontants: ChantierRecent[] = [
{
id: '1',
nom: 'Gros Chantier',
client: 'Client VIP',
statut: StatutChantier.EN_COURS,
dateDebut: '2024-01-01',
montantPrevu: 1234567,
},
]
render(<ChantiersList chantiers={chantiersAvecGrosMontants} />)
// Vérifier que le montant est formaté avec des séparateurs
expect(screen.getByText(/1[,\s]?234[,\s]?567 €/)).toBeInTheDocument()
})
})

View File

@@ -0,0 +1,132 @@
import React from 'react'
import { render, screen } from '../../../test-utils'
import StatsCard from '../StatsCard'
describe('Composant StatsCard', () => {
const defaultProps = {
title: 'Projets actifs',
value: 42,
icon: 'pi pi-building',
color: 'primary' as const,
}
it('devrait afficher les informations de base', () => {
render(<StatsCard {...defaultProps} />)
expect(screen.getByText('Projets actifs')).toBeInTheDocument()
expect(screen.getByText('42')).toBeInTheDocument()
expect(document.querySelector('.pi-building')).toBeInTheDocument()
})
it('devrait formater les nombres avec des séparateurs', () => {
render(<StatsCard {...defaultProps} value={1234567} />)
// Le format peut varier selon la locale
expect(screen.getByText(/1[,\s]?234[,\s]?567/)).toBeInTheDocument()
})
it('devrait afficher les valeurs string directement', () => {
render(<StatsCard {...defaultProps} value="50 000 €" />)
expect(screen.getByText('50 000 €')).toBeInTheDocument()
})
it('devrait afficher le sous-titre si fourni', () => {
render(<StatsCard {...defaultProps} subtitle="En cours ce mois" />)
expect(screen.getByText('En cours ce mois')).toBeInTheDocument()
})
it('devrait afficher la tendance positive', () => {
render(
<StatsCard
{...defaultProps}
trend={{ value: 15, isPositive: true }}
/>
)
expect(screen.getByText('+15%')).toBeInTheDocument()
expect(screen.getByText('Augmentation ce mois')).toBeInTheDocument()
})
it('devrait afficher la tendance négative', () => {
render(
<StatsCard
{...defaultProps}
trend={{ value: 5, isPositive: false }}
/>
)
expect(screen.getByText('-5%')).toBeInTheDocument()
expect(screen.getByText('Diminution ce mois')).toBeInTheDocument()
})
it('devrait appliquer la bonne couleur', () => {
const colors = [
{ color: 'primary' as const, textClass: 'text-blue-500', bgClass: 'bg-blue-100' },
{ color: 'success' as const, textClass: 'text-green-500', bgClass: 'bg-green-100' },
{ color: 'info' as const, textClass: 'text-cyan-500', bgClass: 'bg-cyan-100' },
{ color: 'warning' as const, textClass: 'text-yellow-500', bgClass: 'bg-yellow-100' },
{ color: 'danger' as const, textClass: 'text-red-500', bgClass: 'bg-red-100' },
]
colors.forEach(({ color, textClass, bgClass }) => {
const { container } = render(<StatsCard {...defaultProps} color={color} />)
const icon = container.querySelector(`.${defaultProps.icon.replace(' ', '.')}`)
const iconContainer = icon?.parentElement
expect(icon).toHaveClass(textClass)
expect(iconContainer).toHaveClass(bgClass)
})
})
it('devrait afficher l\'état de chargement', () => {
render(<StatsCard {...defaultProps} loading={true} />)
// Vérifier la présence des skeletons
expect(screen.queryByText('Projets actifs')).not.toBeInTheDocument()
expect(screen.queryByText('42')).not.toBeInTheDocument()
// PrimeReact Skeleton crée des éléments avec data-pc-name="skeleton"
const skeletons = document.querySelectorAll('[data-pc-name="skeleton"]')
expect(skeletons.length).toBeGreaterThan(0)
})
it('devrait avoir une hauteur complète', () => {
const { container } = render(<StatsCard {...defaultProps} />)
const card = container.querySelector('[data-pc-name="card"]')
expect(card).toHaveClass('h-full')
})
it('devrait gérer tous les types d\'icônes PrimeIcons', () => {
const icons = ['pi pi-users', 'pi pi-euro', 'pi pi-exclamation-triangle']
icons.forEach(icon => {
const { container } = render(<StatsCard {...defaultProps} icon={icon} />)
const iconElement = container.querySelector(`.${icon.split(' ').join('.')}`)
expect(iconElement).toBeInTheDocument()
})
})
it('devrait afficher correctement avec toutes les props', () => {
render(
<StatsCard
title="Chiffre d'affaires"
value="125 450 €"
icon="pi pi-euro"
color="success"
subtitle="Total ce mois"
trend={{ value: 8, isPositive: true }}
/>
)
expect(screen.getByText("Chiffre d'affaires")).toBeInTheDocument()
expect(screen.getByText("125 450 €")).toBeInTheDocument()
expect(screen.getByText("Total ce mois")).toBeInTheDocument()
expect(screen.getByText("+8%")).toBeInTheDocument()
expect(screen.getByText("Augmentation ce mois")).toBeInTheDocument()
expect(document.querySelector('.pi-euro')).toBeInTheDocument()
})
})