create(); $content = ccliPasteControllerFixture('english-only-multi-verse.txt'); $songCountBefore = Song::count(); $response = $this->actingAs($user) ->postJson(route('api.ccli.preview'), ['raw_text' => $content]); $response->assertStatus(200); $response->assertJsonStructure(['title', 'author', 'ccliId', 'year', 'copyrightText', 'sections']); expect($response->json('title'))->toBe('Test Song 1'); expect($response->json('ccliId'))->toBe('9999001'); expect(Song::count())->toBe($songCountBefore); }); test('importPaste create mode persists song and returns 201', function () { $user = User::factory()->create(); $content = ccliPasteControllerFixture('english-only-multi-verse.txt'); $response = $this->actingAs($user) ->postJson(route('api.ccli.import'), [ 'raw_text' => $content, 'mode' => 'create', ]); $response->assertStatus(201); $response->assertJsonStructure(['song_id', 'status', 'warnings']); expect($response->json('status'))->toBe('created'); expect(Song::find($response->json('song_id')))->not->toBeNull(); }); test('importPaste returns 409 on duplicate ccli_id with existing_song_id', function () { $user = User::factory()->create(); $content = ccliPasteControllerFixture('english-only-multi-verse.txt'); $first = $this->actingAs($user) ->postJson(route('api.ccli.import'), ['raw_text' => $content, 'mode' => 'create']); $existingId = $first->json('song_id'); $response = $this->actingAs($user) ->postJson(route('api.ccli.import'), ['raw_text' => $content, 'mode' => 'create']); $response->assertStatus(409); $response->assertJsonStructure(['message', 'existing_song_id', 'edit_url']); expect($response->json('existing_song_id'))->toBe($existingId); expect($response->json('message'))->toContain('existiert bereits'); }); test('importPaste returns 422 on malformed paste with German error', function () { $user = User::factory()->create(); $response = $this->actingAs($user) ->postJson(route('api.ccli.import'), [ 'raw_text' => 'This has no section labels at all', 'mode' => 'create', ]); $response->assertStatus(422); $response->assertJsonStructure(['message']); expect($response->json('message'))->not->toBeEmpty(); }); test('importPaste returns 422 on empty raw_text', function () { $user = User::factory()->create(); $response = $this->actingAs($user) ->postJson(route('api.ccli.import'), [ 'raw_text' => '', 'mode' => 'create', ]); $response->assertStatus(422); }); test('importPaste assign-to-service-song imports and assigns song to service song', function () { $user = User::factory()->create(); $content = ccliPasteControllerFixture('english-only-multi-verse.txt'); $service = Service::factory()->create(); $serviceSong = ServiceSong::factory()->create([ 'service_id' => $service->id, 'song_id' => null, 'song_arrangement_id' => null, 'matched_at' => null, ]); $response = $this->actingAs($user) ->postJson(route('api.ccli.import'), [ 'raw_text' => $content, 'mode' => 'assign-to-service-song', 'target_id' => $serviceSong->id, ]); $response->assertStatus(201); $response->assertJsonStructure(['song_id', 'service_song_id', 'status']); $serviceSong->refresh(); expect($serviceSong->song_id)->toBe($response->json('song_id')); expect($serviceSong->matched_at)->not->toBeNull(); }); test('importPaste rejects unauthenticated requests with 401', function () { $response = $this->postJson(route('api.ccli.import'), [ 'raw_text' => 'test', 'mode' => 'create', ]); $response->assertUnauthorized(); }); test('showImportPage renders Inertia page with prefilled data from valid base64', function () { $user = User::factory()->create(); $this->withoutVite(); $payload = json_encode([ 'title' => 'Amazing Grace', 'author' => 'John Newton', 'ccliId' => '4760', 'sourceUrl' => 'https://songselect.ccli.com/Songs/4760', 'rawText' => "Amazing Grace\nJohn Newton\n\nVerse 1\nAmazing grace how sweet the sound\n\n© 1779\nCCLI # 4760", ]); $encoded = base64_encode($payload); $response = $this->actingAs($user) ->get(route('songs.import-from-ccli-paste', ['prefill' => $encoded])); $response->assertStatus(200); $response->assertInertia( fn ($page) => $page->component('Songs/ImportFromCcliPaste', false) ->has('prefilledText') ->has('prefilledMetadata') ->where('prefilledMetadata.title', 'Amazing Grace') ->where('prefilledMetadata.ccliId', '4760') ); }); test('showImportPage renders with error for invalid base64', function () { $user = User::factory()->create(); $this->withoutVite(); $response = $this->actingAs($user) ->get(route('songs.import-from-ccli-paste', ['prefill' => 'NOT_VALID_BASE64!!!'])); $response->assertStatus(200); $response->assertInertia( fn ($page) => $page->component('Songs/ImportFromCcliPaste', false) ->where('prefillError', fn ($v) => $v !== null) ); }); test('showImportPage redirects unauthenticated to login', function () { $response = $this->get(route('songs.import-from-ccli-paste')); $response->assertRedirect(route('login')); });