feat: Permettre l'import d'élèves via fichier CSV ou XLSX
L'import manuel élève par élève est fastidieux pour les établissements qui gèrent des centaines d'élèves. Un wizard d'import en 4 étapes (upload → mapping → preview → confirmation) permet de traiter un fichier complet en une seule opération, avec détection automatique du format (Pronote, École Directe) et validation avant import. L'import est traité de manière asynchrone via Messenger pour ne pas bloquer l'interface, avec suivi de progression en temps réel et réutilisation des mappings entre imports successifs.
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Administration\Domain\Model\Import;
|
||||
|
||||
use App\Administration\Domain\Exception\MappingIncompletException;
|
||||
use App\Administration\Domain\Model\Import\ColumnMapping;
|
||||
use App\Administration\Domain\Model\Import\KnownImportFormat;
|
||||
use App\Administration\Domain\Model\Import\StudentImportField;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ColumnMappingTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function creerWithAllRequiredFieldsSucceeds(): void
|
||||
{
|
||||
$mapping = ColumnMapping::creer(
|
||||
[
|
||||
'Nom' => StudentImportField::LAST_NAME,
|
||||
'Prénom' => StudentImportField::FIRST_NAME,
|
||||
'Classe' => StudentImportField::CLASS_NAME,
|
||||
],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
|
||||
self::assertCount(3, $mapping->colonnesSources());
|
||||
self::assertSame(KnownImportFormat::CUSTOM, $mapping->format);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function creerWithOptionalFieldsSucceeds(): void
|
||||
{
|
||||
$mapping = ColumnMapping::creer(
|
||||
[
|
||||
'Nom' => StudentImportField::LAST_NAME,
|
||||
'Prénom' => StudentImportField::FIRST_NAME,
|
||||
'Classe' => StudentImportField::CLASS_NAME,
|
||||
'Email' => StudentImportField::EMAIL,
|
||||
'Naissance' => StudentImportField::BIRTH_DATE,
|
||||
],
|
||||
KnownImportFormat::PRONOTE,
|
||||
);
|
||||
|
||||
self::assertCount(5, $mapping->colonnesSources());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function creerSansNomLeveException(): void
|
||||
{
|
||||
$this->expectException(MappingIncompletException::class);
|
||||
|
||||
ColumnMapping::creer(
|
||||
[
|
||||
'Prénom' => StudentImportField::FIRST_NAME,
|
||||
'Classe' => StudentImportField::CLASS_NAME,
|
||||
],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function creerSansPrenomLeveException(): void
|
||||
{
|
||||
$this->expectException(MappingIncompletException::class);
|
||||
|
||||
ColumnMapping::creer(
|
||||
[
|
||||
'Nom' => StudentImportField::LAST_NAME,
|
||||
'Classe' => StudentImportField::CLASS_NAME,
|
||||
],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function creerSansClasseLeveException(): void
|
||||
{
|
||||
$this->expectException(MappingIncompletException::class);
|
||||
|
||||
ColumnMapping::creer(
|
||||
[
|
||||
'Nom' => StudentImportField::LAST_NAME,
|
||||
'Prénom' => StudentImportField::FIRST_NAME,
|
||||
],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function champPourReturnsMappedField(): void
|
||||
{
|
||||
$mapping = ColumnMapping::creer(
|
||||
[
|
||||
'Nom' => StudentImportField::LAST_NAME,
|
||||
'Prénom' => StudentImportField::FIRST_NAME,
|
||||
'Classe' => StudentImportField::CLASS_NAME,
|
||||
],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
|
||||
self::assertSame(StudentImportField::LAST_NAME, $mapping->champPour('Nom'));
|
||||
self::assertSame(StudentImportField::FIRST_NAME, $mapping->champPour('Prénom'));
|
||||
self::assertNull($mapping->champPour('Inconnu'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function equalsComparesCorrectly(): void
|
||||
{
|
||||
$mapping1 = ColumnMapping::creer(
|
||||
['Nom' => StudentImportField::LAST_NAME, 'Prénom' => StudentImportField::FIRST_NAME, 'Classe' => StudentImportField::CLASS_NAME],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
|
||||
$mapping2 = ColumnMapping::creer(
|
||||
['Nom' => StudentImportField::LAST_NAME, 'Prénom' => StudentImportField::FIRST_NAME, 'Classe' => StudentImportField::CLASS_NAME],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
|
||||
$mapping3 = ColumnMapping::creer(
|
||||
['Nom' => StudentImportField::LAST_NAME, 'Prénom' => StudentImportField::FIRST_NAME, 'Classe' => StudentImportField::CLASS_NAME],
|
||||
KnownImportFormat::PRONOTE,
|
||||
);
|
||||
|
||||
self::assertTrue($mapping1->equals($mapping2));
|
||||
self::assertFalse($mapping1->equals($mapping3));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Administration\Domain\Model\Import;
|
||||
|
||||
use App\Administration\Domain\Model\Import\ImportRow;
|
||||
use App\Administration\Domain\Model\Import\ImportRowError;
|
||||
use App\Administration\Domain\Model\Import\StudentImportField;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ImportRowTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function rowSansErreurEstValide(): void
|
||||
{
|
||||
$row = new ImportRow(
|
||||
lineNumber: 1,
|
||||
rawData: ['Nom' => 'Dupont', 'Prénom' => 'Jean'],
|
||||
mappedData: ['lastName' => 'Dupont', 'firstName' => 'Jean'],
|
||||
);
|
||||
|
||||
self::assertTrue($row->estValide());
|
||||
self::assertSame(1, $row->lineNumber);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function rowAvecErreursEstInvalide(): void
|
||||
{
|
||||
$row = new ImportRow(
|
||||
lineNumber: 3,
|
||||
rawData: ['Nom' => '', 'Prénom' => 'Jean'],
|
||||
mappedData: ['lastName' => '', 'firstName' => 'Jean'],
|
||||
errors: [new ImportRowError('lastName', 'Le nom est obligatoire')],
|
||||
);
|
||||
|
||||
self::assertFalse($row->estValide());
|
||||
self::assertCount(1, $row->errors);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function valeurChampReturnsMappedValue(): void
|
||||
{
|
||||
$row = new ImportRow(
|
||||
lineNumber: 1,
|
||||
rawData: [],
|
||||
mappedData: ['lastName' => 'Dupont', 'firstName' => 'Jean'],
|
||||
);
|
||||
|
||||
self::assertSame('Dupont', $row->valeurChamp(StudentImportField::LAST_NAME));
|
||||
self::assertSame('Jean', $row->valeurChamp(StudentImportField::FIRST_NAME));
|
||||
self::assertNull($row->valeurChamp(StudentImportField::EMAIL));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function avecErreursCreatesNewRowWithAdditionalErrors(): void
|
||||
{
|
||||
$row = new ImportRow(
|
||||
lineNumber: 1,
|
||||
rawData: [],
|
||||
mappedData: ['lastName' => ''],
|
||||
errors: [new ImportRowError('lastName', 'Le nom est obligatoire')],
|
||||
);
|
||||
|
||||
$newRow = $row->avecErreurs(
|
||||
new ImportRowError('email', 'Email invalide'),
|
||||
);
|
||||
|
||||
self::assertCount(1, $row->errors);
|
||||
self::assertCount(2, $newRow->errors);
|
||||
self::assertSame($row->lineNumber, $newRow->lineNumber);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Administration\Domain\Model\Import;
|
||||
|
||||
use App\Administration\Domain\Model\Import\ImportStatus;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ImportStatusTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function peutDemarrerOnlyForPending(): void
|
||||
{
|
||||
self::assertTrue(ImportStatus::PENDING->peutDemarrer());
|
||||
self::assertFalse(ImportStatus::PROCESSING->peutDemarrer());
|
||||
self::assertFalse(ImportStatus::COMPLETED->peutDemarrer());
|
||||
self::assertFalse(ImportStatus::FAILED->peutDemarrer());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function estTermineForCompletedAndFailed(): void
|
||||
{
|
||||
self::assertFalse(ImportStatus::PENDING->estTermine());
|
||||
self::assertFalse(ImportStatus::PROCESSING->estTermine());
|
||||
self::assertTrue(ImportStatus::COMPLETED->estTermine());
|
||||
self::assertTrue(ImportStatus::FAILED->estTermine());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function labelReturnsReadableText(): void
|
||||
{
|
||||
self::assertSame('En attente', ImportStatus::PENDING->label());
|
||||
self::assertSame('En cours', ImportStatus::PROCESSING->label());
|
||||
self::assertSame('Terminé', ImportStatus::COMPLETED->label());
|
||||
self::assertSame('Échoué', ImportStatus::FAILED->label());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Administration\Domain\Model\Import;
|
||||
|
||||
use App\Administration\Domain\Event\ImportElevesLance;
|
||||
use App\Administration\Domain\Event\ImportElevesTermine;
|
||||
use App\Administration\Domain\Exception\ImportNonDemarrableException;
|
||||
use App\Administration\Domain\Model\Import\ColumnMapping;
|
||||
use App\Administration\Domain\Model\Import\ImportRow;
|
||||
use App\Administration\Domain\Model\Import\ImportRowError;
|
||||
use App\Administration\Domain\Model\Import\ImportStatus;
|
||||
use App\Administration\Domain\Model\Import\KnownImportFormat;
|
||||
use App\Administration\Domain\Model\Import\StudentImportBatch;
|
||||
use App\Administration\Domain\Model\Import\StudentImportField;
|
||||
use App\Shared\Domain\Tenant\TenantId;
|
||||
use DateTimeImmutable;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class StudentImportBatchTest extends TestCase
|
||||
{
|
||||
private const string TENANT_ID = '550e8400-e29b-41d4-a716-446655440001';
|
||||
|
||||
#[Test]
|
||||
public function creerCreatesBatchWithPendingStatus(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
|
||||
self::assertSame(ImportStatus::PENDING, $batch->status);
|
||||
self::assertSame(0, $batch->importedCount);
|
||||
self::assertSame(0, $batch->errorCount);
|
||||
self::assertNull($batch->completedAt);
|
||||
self::assertNull($batch->mapping);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function creerSetsAllProperties(): void
|
||||
{
|
||||
$tenantId = TenantId::fromString(self::TENANT_ID);
|
||||
$createdAt = new DateTimeImmutable('2026-02-24 10:00:00');
|
||||
$columns = ['Nom', 'Prénom', 'Classe'];
|
||||
|
||||
$batch = StudentImportBatch::creer(
|
||||
tenantId: $tenantId,
|
||||
originalFilename: 'eleves.csv',
|
||||
totalRows: 50,
|
||||
detectedColumns: $columns,
|
||||
detectedFormat: KnownImportFormat::PRONOTE,
|
||||
createdAt: $createdAt,
|
||||
);
|
||||
|
||||
self::assertTrue($batch->tenantId->equals($tenantId));
|
||||
self::assertSame('eleves.csv', $batch->originalFilename);
|
||||
self::assertSame(50, $batch->totalRows);
|
||||
self::assertSame($columns, $batch->detectedColumns);
|
||||
self::assertSame(KnownImportFormat::PRONOTE, $batch->detectedFormat);
|
||||
self::assertEquals($createdAt, $batch->createdAt);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function creerDoesNotRecordAnyEvent(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
|
||||
self::assertEmpty($batch->pullDomainEvents());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function appliquerMappingSetsMapping(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$mapping = $this->createValidMapping();
|
||||
|
||||
$batch->appliquerMapping($mapping);
|
||||
|
||||
self::assertNotNull($batch->mapping);
|
||||
self::assertTrue($batch->mapping->equals($mapping));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function enregistrerLignesStoresRows(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$rows = [
|
||||
new ImportRow(1, ['Nom' => 'Dupont'], ['lastName' => 'Dupont']),
|
||||
new ImportRow(2, ['Nom' => 'Martin'], ['lastName' => 'Martin']),
|
||||
];
|
||||
|
||||
$batch->enregistrerLignes($rows);
|
||||
|
||||
self::assertCount(2, $batch->lignes());
|
||||
self::assertSame(50, $batch->totalRows);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function demarrerTransitionsToProcessingAndRecordsEvent(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$batch->appliquerMapping($this->createValidMapping());
|
||||
$at = new DateTimeImmutable('2026-02-24 11:00:00');
|
||||
|
||||
$batch->demarrer($at);
|
||||
|
||||
self::assertSame(ImportStatus::PROCESSING, $batch->status);
|
||||
|
||||
$events = $batch->pullDomainEvents();
|
||||
self::assertCount(1, $events);
|
||||
self::assertInstanceOf(ImportElevesLance::class, $events[0]);
|
||||
self::assertTrue($events[0]->batchId->equals($batch->id));
|
||||
self::assertTrue($events[0]->tenantId->equals($batch->tenantId));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function demarrerSansMappingLeveException(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
|
||||
$this->expectException(ImportNonDemarrableException::class);
|
||||
|
||||
$batch->demarrer(new DateTimeImmutable());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function demarrerDepuisStatutNonPendingLeveException(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$batch->appliquerMapping($this->createValidMapping());
|
||||
$batch->demarrer(new DateTimeImmutable());
|
||||
|
||||
$this->expectException(ImportNonDemarrableException::class);
|
||||
|
||||
$batch->demarrer(new DateTimeImmutable());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function terminerSetsCompletedStatusAndRecordsEvent(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$batch->appliquerMapping($this->createValidMapping());
|
||||
$batch->demarrer(new DateTimeImmutable());
|
||||
$batch->pullDomainEvents();
|
||||
|
||||
$at = new DateTimeImmutable('2026-02-24 12:00:00');
|
||||
$batch->terminer(45, 5, $at);
|
||||
|
||||
self::assertSame(ImportStatus::COMPLETED, $batch->status);
|
||||
self::assertSame(45, $batch->importedCount);
|
||||
self::assertSame(5, $batch->errorCount);
|
||||
self::assertEquals($at, $batch->completedAt);
|
||||
self::assertTrue($batch->estTermine());
|
||||
|
||||
$events = $batch->pullDomainEvents();
|
||||
self::assertCount(1, $events);
|
||||
self::assertInstanceOf(ImportElevesTermine::class, $events[0]);
|
||||
self::assertSame(45, $events[0]->importedCount);
|
||||
self::assertSame(5, $events[0]->errorCount);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function echouerSetsFailedStatus(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$batch->appliquerMapping($this->createValidMapping());
|
||||
$batch->demarrer(new DateTimeImmutable());
|
||||
$batch->pullDomainEvents();
|
||||
|
||||
$at = new DateTimeImmutable('2026-02-24 12:00:00');
|
||||
$batch->echouer(50, $at);
|
||||
|
||||
self::assertSame(ImportStatus::FAILED, $batch->status);
|
||||
self::assertSame(50, $batch->errorCount);
|
||||
self::assertEquals($at, $batch->completedAt);
|
||||
self::assertTrue($batch->estTermine());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function lignesValidesFiltersCorrectly(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$rows = [
|
||||
new ImportRow(1, [], ['lastName' => 'Dupont']),
|
||||
new ImportRow(2, [], ['lastName' => ''], [new ImportRowError('lastName', 'Nom vide')]),
|
||||
new ImportRow(3, [], ['lastName' => 'Martin']),
|
||||
];
|
||||
|
||||
$batch->enregistrerLignes($rows);
|
||||
|
||||
self::assertCount(2, $batch->lignesValides());
|
||||
self::assertCount(1, $batch->lignesEnErreur());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function progressionCalculatesCorrectly(): void
|
||||
{
|
||||
$batch = $this->createBatch();
|
||||
$batch->appliquerMapping($this->createValidMapping());
|
||||
$batch->demarrer(new DateTimeImmutable());
|
||||
|
||||
$batch->terminer(40, 10, new DateTimeImmutable());
|
||||
|
||||
self::assertEqualsWithDelta(100.0, $batch->progression(), 0.01);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function progressionReturnsZeroForEmptyBatch(): void
|
||||
{
|
||||
$batch = StudentImportBatch::creer(
|
||||
tenantId: TenantId::fromString(self::TENANT_ID),
|
||||
originalFilename: 'empty.csv',
|
||||
totalRows: 0,
|
||||
detectedColumns: [],
|
||||
detectedFormat: null,
|
||||
createdAt: new DateTimeImmutable(),
|
||||
);
|
||||
|
||||
self::assertEqualsWithDelta(0.0, $batch->progression(), 0.01);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function reconstituteRestoresAllProperties(): void
|
||||
{
|
||||
$id = \App\Administration\Domain\Model\Import\ImportBatchId::generate();
|
||||
$tenantId = TenantId::fromString(self::TENANT_ID);
|
||||
$mapping = $this->createValidMapping();
|
||||
$createdAt = new DateTimeImmutable('2026-02-24 10:00:00');
|
||||
$completedAt = new DateTimeImmutable('2026-02-24 12:00:00');
|
||||
|
||||
$batch = StudentImportBatch::reconstitute(
|
||||
id: $id,
|
||||
tenantId: $tenantId,
|
||||
originalFilename: 'eleves.csv',
|
||||
totalRows: 50,
|
||||
detectedColumns: ['Nom', 'Prénom', 'Classe'],
|
||||
detectedFormat: KnownImportFormat::PRONOTE,
|
||||
status: ImportStatus::COMPLETED,
|
||||
mapping: $mapping,
|
||||
importedCount: 45,
|
||||
errorCount: 5,
|
||||
createdAt: $createdAt,
|
||||
completedAt: $completedAt,
|
||||
);
|
||||
|
||||
self::assertTrue($batch->id->equals($id));
|
||||
self::assertTrue($batch->tenantId->equals($tenantId));
|
||||
self::assertSame('eleves.csv', $batch->originalFilename);
|
||||
self::assertSame(50, $batch->totalRows);
|
||||
self::assertSame(ImportStatus::COMPLETED, $batch->status);
|
||||
self::assertNotNull($batch->mapping);
|
||||
self::assertSame(45, $batch->importedCount);
|
||||
self::assertSame(5, $batch->errorCount);
|
||||
self::assertEquals($createdAt, $batch->createdAt);
|
||||
self::assertEquals($completedAt, $batch->completedAt);
|
||||
self::assertEmpty($batch->pullDomainEvents());
|
||||
}
|
||||
|
||||
private function createBatch(): StudentImportBatch
|
||||
{
|
||||
return StudentImportBatch::creer(
|
||||
tenantId: TenantId::fromString(self::TENANT_ID),
|
||||
originalFilename: 'eleves.csv',
|
||||
totalRows: 50,
|
||||
detectedColumns: ['Nom', 'Prénom', 'Classe', 'Email'],
|
||||
detectedFormat: KnownImportFormat::CUSTOM,
|
||||
createdAt: new DateTimeImmutable('2026-02-24 10:00:00'),
|
||||
);
|
||||
}
|
||||
|
||||
private function createValidMapping(): ColumnMapping
|
||||
{
|
||||
return ColumnMapping::creer(
|
||||
[
|
||||
'Nom' => StudentImportField::LAST_NAME,
|
||||
'Prénom' => StudentImportField::FIRST_NAME,
|
||||
'Classe' => StudentImportField::CLASS_NAME,
|
||||
],
|
||||
KnownImportFormat::CUSTOM,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Unit\Administration\Domain\Model\Import;
|
||||
|
||||
use App\Administration\Domain\Model\Import\StudentImportField;
|
||||
use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class StudentImportFieldTest extends TestCase
|
||||
{
|
||||
#[Test]
|
||||
public function champsObligatoiresReturnsRequiredFields(): void
|
||||
{
|
||||
$required = StudentImportField::champsObligatoires();
|
||||
|
||||
self::assertCount(3, $required);
|
||||
self::assertContains(StudentImportField::LAST_NAME, $required);
|
||||
self::assertContains(StudentImportField::FIRST_NAME, $required);
|
||||
self::assertContains(StudentImportField::CLASS_NAME, $required);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function estObligatoireForRequiredFields(): void
|
||||
{
|
||||
self::assertTrue(StudentImportField::LAST_NAME->estObligatoire());
|
||||
self::assertTrue(StudentImportField::FIRST_NAME->estObligatoire());
|
||||
self::assertTrue(StudentImportField::CLASS_NAME->estObligatoire());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function estObligatoireFalseForOptionalFields(): void
|
||||
{
|
||||
self::assertFalse(StudentImportField::EMAIL->estObligatoire());
|
||||
self::assertFalse(StudentImportField::BIRTH_DATE->estObligatoire());
|
||||
self::assertFalse(StudentImportField::GENDER->estObligatoire());
|
||||
self::assertFalse(StudentImportField::STUDENT_NUMBER->estObligatoire());
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function labelReturnsReadableText(): void
|
||||
{
|
||||
self::assertSame('Nom', StudentImportField::LAST_NAME->label());
|
||||
self::assertSame('Prénom', StudentImportField::FIRST_NAME->label());
|
||||
self::assertSame('Classe', StudentImportField::CLASS_NAME->label());
|
||||
self::assertSame('Email', StudentImportField::EMAIL->label());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user