pp-planer/tests/Feature/SongIndexTest.php
Thorsten Bus ff3484466b fix(songs): resolve seven song/service editing bugs
- CCLI import: group lyrics into 2-line slides (no blank line per line)
- Add-section: searchable label combobox with create-new option
- Service edit: show current global key-visual/background default live
- Assign dialog: prefill+open search, SongSelect link by CCLI nr/name
- "Auf SongSelect suchen" now also opens the CCLI import dialog
- SongDB: mark empty songs "Ohne Inhalt", default-on content filter
- Translation paste: strip section-mark lines so line mapping holds
2026-05-31 21:39:44 +02:00

140 lines
4.4 KiB
PHP

<?php
use App\Models\Song;
use App\Models\User;
/*
|--------------------------------------------------------------------------
| Song Index Page Tests (Inertia)
|--------------------------------------------------------------------------
*/
beforeEach(function () {
$this->user = User::factory()->create();
$this->withoutVite();
});
test('songs index page renders for authenticated users', function () {
$response = $this->actingAs($this->user)
->get('/songs');
$response->assertOk();
$response->assertInertia(fn ($page) => $page->component('Songs/Index'));
});
test('songs index page redirects unauthenticated users to login', function () {
$response = $this->get('/songs');
$response->assertRedirect('/login');
});
test('songs index route is named songs.index', function () {
$this->actingAs($this->user);
$url = route('songs.index');
expect($url)->toContain('/songs');
});
test('songs api returns data for songs page', function () {
Song::factory()->count(3)->create();
$response = $this->actingAs($this->user)
->getJson('/api/songs');
$response->assertOk()
->assertJsonStructure([
'data' => [['id', 'title', 'ccli_id', 'has_translation', 'has_content', 'created_at', 'updated_at']],
'meta' => ['current_page', 'last_page', 'per_page', 'total'],
]);
expect($response->json('meta.total'))->toBe(3);
});
test('songs api marks songs without slides as no content', function () {
$song = Song::factory()->create();
$response = $this->actingAs($this->user)
->getJson('/api/songs');
$response->assertOk();
expect($response->json('data.0.has_content'))->toBeFalse();
});
test('songs api with_content filter hides songs without content', function () {
$withContent = Song::factory()->create(['title' => 'Mit Inhalt']);
$section = $withContent->sections()->create([
'label_id' => \App\Models\Label::factory()->create()->id,
'order' => 1,
]);
$section->slides()->create(['order' => 1, 'text_content' => 'Zeile']);
Song::factory()->create(['title' => 'Ohne Inhalt']);
$response = $this->actingAs($this->user)
->getJson('/api/songs?with_content=1');
$response->assertOk();
expect($response->json('meta.total'))->toBe(1);
expect($response->json('data.0.title'))->toBe('Mit Inhalt');
expect($response->json('data.0.has_content'))->toBeTrue();
});
test('songs api search filters by title', function () {
Song::factory()->create(['title' => 'Großer Gott wir loben dich']);
Song::factory()->create(['title' => 'Amazing Grace']);
$response = $this->actingAs($this->user)
->getJson('/api/songs?search=Großer');
$response->assertOk();
expect($response->json('meta.total'))->toBe(1);
expect($response->json('data.0.title'))->toBe('Großer Gott wir loben dich');
});
test('songs api search filters by ccli id', function () {
Song::factory()->create(['ccli_id' => '7654321', 'title' => 'Song A']);
Song::factory()->create(['ccli_id' => '1234567', 'title' => 'Song B']);
$response = $this->actingAs($this->user)
->getJson('/api/songs?search=7654321');
$response->assertOk();
expect($response->json('meta.total'))->toBe(1);
expect($response->json('data.0.ccli_id'))->toBe('7654321');
});
test('songs api does not return soft-deleted songs', function () {
Song::factory()->count(2)->create();
Song::factory()->create(['deleted_at' => now()]);
$response = $this->actingAs($this->user)
->getJson('/api/songs');
$response->assertOk();
expect($response->json('meta.total'))->toBe(2);
});
test('songs api paginates results', function () {
Song::factory()->count(25)->create();
$response = $this->actingAs($this->user)
->getJson('/api/songs?per_page=10');
$response->assertOk();
expect($response->json('meta.total'))->toBe(25);
expect($response->json('meta.per_page'))->toBe(10);
expect($response->json('meta.last_page'))->toBe(3);
expect(count($response->json('data')))->toBe(10);
});
test('songs api delete soft-deletes a song', function () {
$song = Song::factory()->create(['title' => 'To Delete']);
$response = $this->actingAs($this->user)
->deleteJson("/api/songs/{$song->id}");
$response->assertOk();
expect(Song::find($song->id))->toBeNull();
expect(Song::withTrashed()->find($song->id))->not->toBeNull();
});