seed(LegalTextSeeder::class); $this->seed(LegalTextSeeder::class); expect(LegalText::query()->count())->toBe(3); $v2 = LegalText::findByKey('img-confirm-v2'); expect($v2?->body_sha256)->toBe(hash('sha256', (string) $v2?->body)) ->and($v2?->bound_agb_version)->toBe('0.6') ->and(LegalText::findByKey('img-confirm-v3')?->effective_from)->toBeNull(); }); test('currentFor picks the text bound to the active agb version and ignores fassungen without a date', function () { /** @var TestCase $this */ $this->seed(LegalTextSeeder::class); expect(LegalText::currentFor(LegalText::TYPE_IMAGE_RIGHTS_CONFIRMATION, '0.6')?->key)->toBe('img-confirm-v2') ->and(LegalText::currentFor(LegalText::TYPE_IMAGE_RIGHTS_CONFIRMATION, '0.7'))->toBeNull() ->and(LegalText::findByKey('img-confirm-v2')?->isCurrentFor('0.6'))->toBeTrue() ->and(LegalText::findByKey('img-confirm-v1')?->isCurrentFor('0.6'))->toBeFalse(); }); test('legal texts are immutable', function () { /** @var TestCase $this */ $this->seed(LegalTextSeeder::class); $text = LegalText::findByKey('img-confirm-v2'); expect(fn () => $text->update(['body' => 'geändert']))->toThrow(LogicException::class) ->and(fn () => $text->delete())->toThrow(LogicException::class); }); test('the renderer resolves agb version, date and url into the long and short wording', function () { /** @var TestCase $this */ $this->seed(LegalDocumentSeeder::class); $this->seed(LegalTextSeeder::class); $renderer = app(ImageRightsTextRenderer::class); $text = $renderer->current(); expect($text?->key)->toBe('img-confirm-v2'); $long = $renderer->renderLong($text, 'https://presseecho.test/de/agb'); $short = $renderer->renderShort($text, 'https://presseecho.test/de/agb'); expect($long)->toContain('Fassung vom 3. Juli 2026 (Version 0.6, https://presseecho.test/de/agb)') ->toContain('presseecho.de und businessportal24.com') ->toContain('§ 8 und § 9') ->not->toContain('{agb_version}') ->and($short)->toContain('Fassung vom 3. Juli 2026') ->and(LegalDocument::currentAgbVersion())->toBe('0.6'); }); test('the backfill command gives every old confirmation a protocol row pointing at img-confirm-v1', function () { /** @var TestCase $this */ $this->seed(LegalTextSeeder::class); $pressRelease = PressRelease::factory()->create(); $confirmed = PressReleaseImage::factory()->for($pressRelease)->create(['rights_confirmed_at' => now()->subMonth()]); PressReleaseImage::factory()->for($pressRelease)->legacy()->create(); $this->artisan('image-rights:backfill-confirmations', ['--dry-run' => true]) ->expectsOutputToContain('Bilder mit alter Bestätigung ohne Protokoll: 1') ->assertSuccessful(); expect(ImageRightsConfirmation::query()->count())->toBe(0); $this->artisan('image-rights:backfill-confirmations')->assertSuccessful(); $this->artisan('image-rights:backfill-confirmations')->assertSuccessful(); $confirmation = $confirmed->rightsConfirmations()->sole(); expect(ImageRightsConfirmation::query()->count())->toBe(1) ->and($confirmation->legal_text_key)->toBe('img-confirm-v1') ->and($confirmation->agb_version)->toBe('0.6') ->and($confirmation->user_id)->toBe($pressRelease->user_id) ->and($confirmation->company_id)->toBe($pressRelease->company_id) ->and($confirmation->confirmed_at->toDateTimeString())->toBe($confirmed->rights_confirmed_at->toDateTimeString()) ->and($confirmation->declaration_snapshot['backfilled'])->toBeTrue() ->and($confirmation->text_snapshot)->toBe(LegalText::findByKey('img-confirm-v1')?->body); });