Production Caddy/FPM setup (build/Dockerfile, docker-compose.yml) is untouched -- this only swaps the local dev stack. - .ddev/config.yaml: PHP 8.4, Node 20, sqlite (db container omitted), libreoffice/ghostscript/poppler/sqlite3 packages, Vite port 5173 via Traefik, post-start hooks bootstrap the app on every `ddev start`. - .ddev/commands/web/dev: custom `ddev dev` runs queue + pail + vite (mirror of old `composer dev`). - start_dev.sh / stop_dev.sh: rewritten as DDEV wrappers so devs can onboard without DDEV knowledge; --keep-ddev keeps containers up. - vite.config.js: HMR over WSS to https://pp-planer.ddev.site:5173. - playwright + auth.setup.ts: baseURL switched to https://pp-planer.ddev.site. - .env.example: APP_URL and CHURCHTOOLS_REDIRECT_URI use ddev.site. - composer: drop laravel/sail (replaced by DDEV). - package.json: add explicit "name" so host/container lockfiles match (container WORKDIR is /var/www/html, npm would otherwise pick "html" as project name). - tests/fixtures/propresenter/Test.pro: inline reference fixture; tests no longer depend on a sibling host directory. - AGENTS.md: docs rewritten for DDEV workflow.
120 lines
3.7 KiB
PHP
120 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Song;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Tests\TestCase;
|
|
|
|
final class ProFileImportTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function test_pro_file(): UploadedFile
|
|
{
|
|
$sourcePath = base_path('tests/fixtures/propresenter/Test.pro');
|
|
|
|
return new UploadedFile($sourcePath, 'Test.pro', 'application/octet-stream', null, true);
|
|
}
|
|
|
|
public function test_import_pro_datei_erstellt_song_mit_gruppen_und_slides(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$response = $this->actingAs($user)->postJson(route('api.songs.import-pro'), [
|
|
'file' => $this->test_pro_file(),
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$response->assertJsonPath('songs.0.title', 'Test');
|
|
|
|
$song = Song::where('title', 'Test')->first();
|
|
$this->assertNotNull($song);
|
|
$this->assertSame(4, $song->groups()->count());
|
|
$this->assertSame(5, $song->groups()->withCount('slides')->get()->sum('slides_count'));
|
|
$this->assertSame(2, $song->arrangements()->count());
|
|
$this->assertTrue($song->has_translation);
|
|
}
|
|
|
|
public function test_import_pro_mit_ccli_upserted_bei_doppeltem_import(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$this->actingAs($user)->postJson(route('api.songs.import-pro'), [
|
|
'file' => $this->test_pro_file(),
|
|
]);
|
|
|
|
$this->assertSame(1, Song::count());
|
|
|
|
// Second import of same file with same CCLI should upsert, not duplicate
|
|
$this->actingAs($user)->postJson(route('api.songs.import-pro'), [
|
|
'file' => $this->test_pro_file(),
|
|
]);
|
|
|
|
$this->assertSame(1, Song::count());
|
|
}
|
|
|
|
public function test_import_pro_upsert_mit_ccli_dupliziert_nicht(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$existingSong = Song::create([
|
|
'title' => 'Old Title',
|
|
'ccli_id' => '999',
|
|
]);
|
|
$existingSong->groups()->create(['name' => 'Old Group', 'color' => '#FF0000', 'order' => 0]);
|
|
|
|
$this->assertSame(1, $existingSong->groups()->count());
|
|
|
|
$existingSong->update(['ccli_id' => '999']);
|
|
$this->assertSame(1, Song::count());
|
|
|
|
$response = $this->actingAs($user)->postJson(route('api.songs.import-pro'), [
|
|
'file' => $this->test_pro_file(),
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$this->assertSame(2, Song::count());
|
|
}
|
|
|
|
public function test_import_pro_lehnt_ungueltige_datei_ab(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$invalidFile = UploadedFile::fake()->create('test.txt', 100);
|
|
|
|
$response = $this->actingAs($user)->postJson(route('api.songs.import-pro'), [
|
|
'file' => $invalidFile,
|
|
]);
|
|
|
|
$response->assertStatus(422);
|
|
}
|
|
|
|
public function test_import_pro_erfordert_authentifizierung(): void
|
|
{
|
|
$response = $this->postJson(route('api.songs.import-pro'), [
|
|
'file' => $this->test_pro_file(),
|
|
]);
|
|
|
|
$response->assertUnauthorized();
|
|
}
|
|
|
|
public function test_import_pro_erstellt_arrangement_gruppen(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$this->actingAs($user)->postJson(route('api.songs.import-pro'), [
|
|
'file' => $this->test_pro_file(),
|
|
]);
|
|
|
|
$song = Song::where('title', 'Test')->first();
|
|
$normalArrangement = $song->arrangements()->where('name', 'normal')->first();
|
|
|
|
$this->assertNotNull($normalArrangement);
|
|
$this->assertTrue($normalArrangement->is_default);
|
|
$this->assertSame(5, $normalArrangement->arrangementGroups()->count());
|
|
}
|
|
}
|