test(frontend): ajout tests unitaires Jest composants frais [#NEWTS-9]

This commit is contained in:
Luc SORIGNET
2026-03-15 12:09:18 +01:00
parent e30a41a58b
commit 7576b5a68c
2 changed files with 294 additions and 0 deletions

View File

@ -0,0 +1,149 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import FeeTypeSection from '@/components/Structure/Tarification/FeeTypeSection';
// Mock du contexte établissement
jest.mock('@/context/EstablishmentContext', () => ({
useEstablishment: () => ({ selectedEstablishmentId: 1 }),
}));
// Mock des sous-composants pour isoler FeeTypeSection
jest.mock(
'@/components/Structure/Tarification/FeesSection',
() =>
function MockFeesSection({ type }) {
return (
<div data-testid={`fees-section-type-${type}`}>
FeesSection type={type}
</div>
);
}
);
jest.mock(
'@/components/Structure/Tarification/DiscountsSection',
() =>
function MockDiscountsSection({ type }) {
return (
<div data-testid={`discounts-section-type-${type}`}>
DiscountsSection type={type}
</div>
);
}
);
jest.mock(
'@/components/PaymentPlanSelector',
() =>
function MockPaymentPlanSelector({ type }) {
return (
<div data-testid={`payment-plan-type-${type}`}>
PaymentPlanSelector type={type}
</div>
);
}
);
jest.mock(
'@/components/PaymentModeSelector',
() =>
function MockPaymentModeSelector({ type }) {
return (
<div data-testid={`payment-mode-type-${type}`}>
PaymentModeSelector type={type}
</div>
);
}
);
jest.mock('@/utils/Url', () => ({
BE_SCHOOL_FEES_URL: '/api/fees',
BE_SCHOOL_DISCOUNTS_URL: '/api/discounts',
BE_SCHOOL_PAYMENT_PLANS_URL: '/api/payment-plans',
BE_SCHOOL_PAYMENT_MODES_URL: '/api/payment-modes',
}));
const defaultProps = {
title: "Frais d'inscription",
fees: [],
setFees: jest.fn(),
discounts: [],
setDiscounts: jest.fn(),
paymentPlans: [],
setPaymentPlans: jest.fn(),
paymentModes: [],
setPaymentModes: jest.fn(),
type: 0,
handleCreate: jest.fn(),
handleEdit: jest.fn(),
handleDelete: jest.fn(),
onDiscountDelete: jest.fn(),
};
describe('FeeTypeSection - type inscription (type=0)', () => {
it('affiche le titre passé en props', () => {
render(<FeeTypeSection {...defaultProps} />);
expect(screen.getByText("Frais d'inscription")).toBeInTheDocument();
});
it('rend le composant FeesSection avec le bon type', () => {
render(<FeeTypeSection {...defaultProps} />);
expect(screen.getByTestId('fees-section-type-0')).toBeInTheDocument();
});
it('rend le composant DiscountsSection avec le bon type', () => {
render(<FeeTypeSection {...defaultProps} />);
expect(screen.getByTestId('discounts-section-type-0')).toBeInTheDocument();
});
it('rend le composant PaymentPlanSelector avec le bon type', () => {
render(<FeeTypeSection {...defaultProps} />);
expect(screen.getByTestId('payment-plan-type-0')).toBeInTheDocument();
});
it('rend le composant PaymentModeSelector avec le bon type', () => {
render(<FeeTypeSection {...defaultProps} />);
expect(screen.getByTestId('payment-mode-type-0')).toBeInTheDocument();
});
});
describe('FeeTypeSection - type scolarité (type=1)', () => {
const tuitionProps = {
...defaultProps,
title: 'Frais de scolarité',
type: 1,
};
it('affiche le titre "Frais de scolarité"', () => {
render(<FeeTypeSection {...tuitionProps} />);
expect(screen.getByText('Frais de scolarité')).toBeInTheDocument();
});
it('rend tous les sous-composants avec type=1', () => {
render(<FeeTypeSection {...tuitionProps} />);
expect(screen.getByTestId('fees-section-type-1')).toBeInTheDocument();
expect(screen.getByTestId('discounts-section-type-1')).toBeInTheDocument();
expect(screen.getByTestId('payment-plan-type-1')).toBeInTheDocument();
expect(screen.getByTestId('payment-mode-type-1')).toBeInTheDocument();
});
});
describe('FeeTypeSection - transmission des handlers', () => {
it('passe les fonctions handleCreate, handleEdit, handleDelete aux sous-composants', () => {
const handleCreate = jest.fn();
const handleEdit = jest.fn();
const handleDelete = jest.fn();
// On vérifie que le composant se rend sans erreur avec les handlers
expect(() =>
render(
<FeeTypeSection
{...defaultProps}
handleCreate={handleCreate}
handleEdit={handleEdit}
handleDelete={handleDelete}
/>
)
).not.toThrow();
});
});

View File

@ -0,0 +1,145 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import FeesManagement from '@/components/Structure/Tarification/FeesManagement';
jest.mock('@/context/EstablishmentContext', () => ({
useEstablishment: () => ({ selectedEstablishmentId: 1 }),
}));
jest.mock('@/utils/Url', () => ({
BE_SCHOOL_FEES_URL: '/api/fees',
BE_SCHOOL_DISCOUNTS_URL: '/api/discounts',
BE_SCHOOL_PAYMENT_PLANS_URL: '/api/payment-plans',
BE_SCHOOL_PAYMENT_MODES_URL: '/api/payment-modes',
}));
jest.mock('@/utils/logger', () => ({ error: jest.fn() }));
jest.mock(
'@/components/Structure/Tarification/FeesSection',
() =>
function MockFeesSection({ fees, unified }) {
return (
<div
data-testid="fees-section"
data-unified={unified ? 'true' : 'false'}
>
{fees.map((f) => (
<span key={f.id}>{f.name}</span>
))}
</div>
);
}
);
jest.mock(
'@/components/Structure/Tarification/DiscountsSection',
() =>
function MockDiscountsSection({ discounts, unified }) {
return (
<div
data-testid="discounts-section"
data-unified={unified ? 'true' : 'false'}
>
{discounts.map((d) => (
<span key={d.id}>{d.name}</span>
))}
</div>
);
}
);
jest.mock(
'@/components/PaymentPlanSelector',
() =>
function MockPaymentPlanSelector({ allPaymentPlans }) {
return (
<div data-testid="payment-plan-selector">
{(allPaymentPlans ?? []).length} plans
</div>
);
}
);
jest.mock(
'@/components/PaymentModeSelector',
() =>
function MockPaymentModeSelector({ allPaymentModes }) {
return (
<div data-testid="payment-mode-selector">
{(allPaymentModes ?? []).length} modes
</div>
);
}
);
const defaultProps = {
registrationFees: [],
setRegistrationFees: jest.fn(),
tuitionFees: [],
setTuitionFees: jest.fn(),
registrationDiscounts: [],
setRegistrationDiscounts: jest.fn(),
tuitionDiscounts: [],
setTuitionDiscounts: jest.fn(),
registrationPaymentPlans: [],
setRegistrationPaymentPlans: jest.fn(),
tuitionPaymentPlans: [],
setTuitionPaymentPlans: jest.fn(),
registrationPaymentModes: [],
setRegistrationPaymentModes: jest.fn(),
tuitionPaymentModes: [],
setTuitionPaymentModes: jest.fn(),
handleCreate: jest.fn(),
handleEdit: jest.fn(),
handleDelete: jest.fn(),
};
describe('FeesManagement - vue unifiée', () => {
it('affiche la section des frais en mode unifié', () => {
render(<FeesManagement {...defaultProps} />);
const section = screen.getByTestId('fees-section');
expect(section).toBeInTheDocument();
expect(section).toHaveAttribute('data-unified', 'true');
});
it('affiche la section des réductions en mode unifié', () => {
render(<FeesManagement {...defaultProps} />);
const section = screen.getByTestId('discounts-section');
expect(section).toBeInTheDocument();
expect(section).toHaveAttribute('data-unified', 'true');
});
it('affiche le sélecteur de plans de paiement', () => {
render(<FeesManagement {...defaultProps} />);
expect(screen.getByTestId('payment-plan-selector')).toBeInTheDocument();
});
it('affiche le sélecteur de modes de paiement', () => {
render(<FeesManagement {...defaultProps} />);
expect(screen.getByTestId('payment-mode-selector')).toBeInTheDocument();
});
it('fusionne les frais inscription et scolarité en une seule liste', () => {
render(
<FeesManagement
{...defaultProps}
registrationFees={[{ id: 1, name: 'Inscription A', type: 0 }]}
tuitionFees={[{ id: 2, name: 'Scolarité B', type: 1 }]}
/>
);
expect(screen.getByText('Inscription A')).toBeInTheDocument();
expect(screen.getByText('Scolarité B')).toBeInTheDocument();
});
it('fusionne les plans de paiement inscription et scolarité', () => {
render(
<FeesManagement
{...defaultProps}
registrationPaymentPlans={[{ id: 10, plan_type: 1, type: 0 }]}
tuitionPaymentPlans={[{ id: 11, plan_type: 1, type: 1 }]}
/>
);
expect(screen.getByText('2 plans')).toBeInTheDocument();
});
});