seed(\Database\Seeders\RolesSeeder::class); $tenant = Tenant::firstOrCreate(['name' => 'Test Schule'], ['type' => 'school', 'active' => true]); $this->user = User::withoutGlobalScopes()->create([ 'name' => 'Runner Tester', 'email' => 'runner@test.example', 'tenant_id' => $tenant->id, 'password' => bcrypt('password'), ]); $role = Role::where('name', 'child')->first(); DB::table('role_user')->insert(['user_id' => $this->user->id, 'role_id' => $role->id, 'created_at' => now(), 'updated_at' => now()]); $license = License::withoutGlobalScopes()->create([ 'tenant_id' => $tenant->id, 'type' => 'school_flat', 'expires_at' => now()->addYear(), 'active' => true, ]); DB::table('license_assignments')->insert(['license_id' => $license->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now()]); $this->task = ['key' => 't1', 'title' => 'Multiplikation bis 100', 'meta' => 'Mathe ยท 4 Aufgaben', 'icon' => 'โˆ‘', 'points' => 120]; $this->actingAs($this->user); }); it('Runner modal class extends ModalComponent', function () { expect(is_subclass_of(Runner::class, ModalComponent::class))->toBeTrue(); }); it('Runner alias resolves to App\\Livewire\\Tasks\\Modals\\Runner', function () { $cls = app('livewire.finder')->resolveClassComponentClassName('tasks.modals.runner'); expect($cls)->toBe(Runner::class); }); it('Runner renders question + 4 options for step 1', function () { Livewire::test(Runner::class, ['task' => $this->task]) ->assertSet('currentStep', 1) ->assertSet('totalSteps', 4) ->assertSet('finished', false) ->assertSee('Multiplikation bis 100') ->assertSeeHtml('data-testid="runner-question"') ->assertSeeHtml('data-testid="runner-option-0"') ->assertSeeHtml('data-testid="runner-option-3"'); }); it('submitAnswer with correct option increments correctAnswers + advances step', function () { Livewire::test(Runner::class, ['task' => $this->task]) ->call('submitAnswer', 2) // step 1 correct = index 2 ->assertSet('correctAnswers', 1) ->assertSet('currentStep', 2); }); it('submitAnswer with wrong option still advances step but no point', function () { Livewire::test(Runner::class, ['task' => $this->task]) ->call('submitAnswer', 0) // step 1 wrong ->assertSet('correctAnswers', 0) ->assertSet('currentStep', 2); }); it('finishing all steps sets finished=true', function () { Livewire::test(Runner::class, ['task' => $this->task]) ->call('submitAnswer', 2) // step 1 ->call('submitAnswer', 1) // step 2 ->call('submitAnswer', 1) // step 3 ->call('submitAnswer', 2) // step 4 โ€” final ->assertSet('finished', true) ->assertSet('correctAnswers', 4) ->assertSeeHtml('data-testid="runner-finished"'); }); it('restart resets state', function () { Livewire::test(Runner::class, ['task' => $this->task]) ->call('submitAnswer', 2) ->call('submitAnswer', 1) ->call('restart') ->assertSet('currentStep', 1) ->assertSet('correctAnswers', 0) ->assertSet('finished', false); }); it('Runner does NOT close on click-away (must finish or cancel explicitly)', function () { expect(Runner::closeModalOnClickAway())->toBeFalse(); }); it('Runner displays progress bar with step indicator', function () { $html = Livewire::test(Runner::class, ['task' => $this->task])->html(); expect($html)->toContain('Frage 1 / 4'); }); it('Runner shows trophy on success, arrow-path on partial', function () { // 4/4 correct โ†’ trophy (passed) $html = Livewire::test(Runner::class, ['task' => $this->task]) ->call('submitAnswer', 2) ->call('submitAnswer', 1) ->call('submitAnswer', 1) ->call('submitAnswer', 2) ->html(); expect($html)->toContain('Super gemacht!'); });