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('#]*\bsrc=)[^>]*>(.*?)#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([]); });