ajoute les devoirs maison (chantier vrai cockpit, étape 3) : rendu en texte libre, suivi des rendus, notation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
bd74eaf20f
commit
33531de44d
17 changed files with 582 additions and 2 deletions
115
portail/tests/Feature/DevoirTest.php
Normal file
115
portail/tests/Feature/DevoirTest.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Classe;
|
||||
use App\Models\Devoir;
|
||||
use App\Models\Eleve;
|
||||
use App\Models\RenduDevoir;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
|
||||
test('un prof crée un devoir, un élève le rend, le prof le note', function () {
|
||||
$classe = Classe::factory()->create();
|
||||
$eleve = Eleve::factory()->create(['classe_id' => $classe->id]);
|
||||
|
||||
commeProf($this, $classe->prof)->post(route('mes-classes.devoirs.store', $classe), [
|
||||
'titre' => 'Plan d’adressage',
|
||||
'consigne' => 'Découpe 192.168.1.0/24 en 4 sous-réseaux.',
|
||||
'echeance' => now()->addDays(3)->format('Y-m-d\TH:i'),
|
||||
])->assertRedirect();
|
||||
|
||||
$devoir = Devoir::where('titre', 'Plan d’adressage')->first();
|
||||
expect($devoir)->not->toBeNull()->and($devoir->classe_id)->toBe($classe->id);
|
||||
|
||||
eleve($this, $eleve)->get(route('devoirs.eleve.show', $devoir))->assertOk()->assertSee('Découpe 192.168.1.0/24');
|
||||
|
||||
eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), ['reponse' => 'Voici mon découpage : /26 x4.'])
|
||||
->assertRedirect();
|
||||
|
||||
$rendu = RenduDevoir::where('devoir_id', $devoir->id)->where('eleve_id', $eleve->id)->first();
|
||||
expect($rendu)->not->toBeNull()->and($rendu->reponse)->toBe('Voici mon découpage : /26 x4.')->and($rendu->note)->toBeNull();
|
||||
|
||||
commeProf($this, $classe->prof)->get(route('mes-classes.devoirs.show', [$classe, $devoir]))
|
||||
->assertSee($eleve->nomAffiche())
|
||||
->assertSee('Voici mon découpage');
|
||||
|
||||
commeProf($this, $classe->prof)->post(route('mes-classes.devoirs.noter', [$classe, $devoir, $rendu]), ['note' => 15])
|
||||
->assertRedirect();
|
||||
expect($rendu->refresh()->note)->toBe(15);
|
||||
});
|
||||
|
||||
test('un élève peut modifier son rendu avant l’échéance, un seul rendu par devoir en base', function () {
|
||||
$classe = Classe::factory()->create();
|
||||
$eleve = Eleve::factory()->create(['classe_id' => $classe->id]);
|
||||
$devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]);
|
||||
|
||||
eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), ['reponse' => 'Premier essai'])->assertRedirect();
|
||||
eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), ['reponse' => 'Version corrigée'])->assertRedirect();
|
||||
|
||||
expect(RenduDevoir::where('devoir_id', $devoir->id)->count())->toBe(1);
|
||||
expect(RenduDevoir::first()->reponse)->toBe('Version corrigée');
|
||||
});
|
||||
|
||||
test('un élève ne peut plus rendre après l’échéance', function () {
|
||||
$classe = Classe::factory()->create();
|
||||
$eleve = Eleve::factory()->create(['classe_id' => $classe->id]);
|
||||
$devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->subHour()]);
|
||||
|
||||
eleve($this, $eleve)->post(route('devoirs.eleve.rendre', $devoir), ['reponse' => 'Trop tard'])->assertStatus(409);
|
||||
expect(RenduDevoir::count())->toBe(0);
|
||||
});
|
||||
|
||||
test('un élève d’une autre classe ne peut pas voir ni rendre ce devoir', function () {
|
||||
$classe = Classe::factory()->create();
|
||||
$devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]);
|
||||
$autreEleve = Eleve::factory()->create();
|
||||
|
||||
eleve($this, $autreEleve)->get(route('devoirs.eleve.show', $devoir))->assertForbidden();
|
||||
eleve($this, $autreEleve)->post(route('devoirs.eleve.rendre', $devoir), ['reponse' => 'Intrus'])->assertForbidden();
|
||||
});
|
||||
|
||||
test('un prof d’une autre classe ne peut pas voir ni noter les rendus', function () {
|
||||
$classe = Classe::factory()->create();
|
||||
$eleve = Eleve::factory()->create(['classe_id' => $classe->id]);
|
||||
$devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]);
|
||||
$rendu = RenduDevoir::create(['devoir_id' => $devoir->id, 'eleve_id' => $eleve->id, 'reponse' => 'x', 'rendu_a' => now()]);
|
||||
$autreClasse = Classe::factory()->create();
|
||||
|
||||
commeProf($this, $autreClasse->prof)->get(route('mes-classes.devoirs.show', [$classe, $devoir]))->assertForbidden();
|
||||
commeProf($this, $autreClasse->prof)->post(route('mes-classes.devoirs.noter', [$classe, $devoir, $rendu]), ['note' => 20])->assertForbidden();
|
||||
});
|
||||
|
||||
test('archiver puis purger une classe supprime aussi ses devoirs et rendus', function () {
|
||||
$classe = Classe::factory()->create();
|
||||
$eleve = Eleve::factory()->create(['classe_id' => $classe->id]);
|
||||
$devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]);
|
||||
RenduDevoir::create(['devoir_id' => $devoir->id, 'eleve_id' => $eleve->id, 'reponse' => 'x', 'rendu_a' => now()]);
|
||||
|
||||
$classe->forceFill(['archivee_a' => now()->subDays(91)])->save();
|
||||
$this->artisan('classes:purger-archivees');
|
||||
|
||||
expect(Devoir::count())->toBe(0)->and(RenduDevoir::count())->toBe(0);
|
||||
});
|
||||
|
||||
test('les scripts en ligne de la page de notation d’un devoir sont du JavaScript valide', function () {
|
||||
if (Process::run('node --version')->failed()) {
|
||||
$this->markTestSkipped('Node absent');
|
||||
}
|
||||
|
||||
$classe = Classe::factory()->create();
|
||||
$devoir = Devoir::create(['classe_id' => $classe->id, 'titre' => 'Test', 'consigne' => 'Test', 'echeance' => now()->addDay()]);
|
||||
|
||||
$html = commeProf($this, $classe->prof)->get(route('mes-classes.devoirs.show', [$classe, $devoir]))->getContent();
|
||||
preg_match_all('#<script(?![^>]*\bsrc=)[^>]*>(.*?)</script>#s', $html, $scripts);
|
||||
|
||||
$erreurs = [];
|
||||
foreach ($scripts[1] as $i => $code) {
|
||||
$fichier = tempnam(sys_get_temp_dir(), 'js').'.js';
|
||||
file_put_contents($fichier, $code);
|
||||
$resultat = Process::run(['node', '--check', $fichier]);
|
||||
unlink($fichier);
|
||||
if ($resultat->failed()) {
|
||||
$erreurs[] = "script {$i} : ".strtok($resultat->errorOutput(), "\n");
|
||||
}
|
||||
}
|
||||
|
||||
expect($erreurs)->toBe([]);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue