create(['portal' => Portal::Businessportal24]); $company = Company::factory()->create(['portal' => Portal::Businessportal24, 'is_active' => true]); return PressRelease::factory() ->published() ->forPortal(Portal::Businessportal24) ->for($category) ->for($company) ->create(array_merge(['slug' => 'tracking-pm', 'published_at' => now()->subDay()], $attributes)); } test('release detail logs a view event alongside the hit counter', function () { /** @var TestCase $this */ $release = trackingRelease(['hits' => 4]); $this->get('https://businessportal24.test/de/press-release/'.$release->slug)->assertSuccessful(); expect(PressRelease::withoutGlobalScopes()->find($release->id)->hits)->toBe(5); $event = PressReleaseEvent::query()->sole(); expect($event->press_release_id)->toBe($release->id) ->and($event->type)->toBe(PressReleaseEventType::View) ->and($event->channel)->toBeNull(); }); test('release detail shows the public view count', function () { /** @var TestCase $this */ $release = trackingRelease(['hits' => 1233]); // Anzeige inkl. des aktuellen Aufrufs (1234). $this->get('https://businessportal24.test/de/press-release/'.$release->slug) ->assertSuccessful() ->assertSeeText('1.234 Aufrufe'); }); test('share endpoint logs a share event with its channel', function () { /** @var TestCase $this */ $release = trackingRelease(); $this->postJson('https://businessportal24.test/de/press-release/'.$release->slug.'/share', [ 'channel' => 'linkedin', ])->assertNoContent(); $event = PressReleaseEvent::query()->sole(); expect($event->press_release_id)->toBe($release->id) ->and($event->type)->toBe(PressReleaseEventType::Share) ->and($event->channel)->toBe(PressReleaseShareChannel::LinkedIn); }); test('share endpoint rejects unknown channels', function () { /** @var TestCase $this */ $release = trackingRelease(); $this->postJson('https://businessportal24.test/de/press-release/'.$release->slug.'/share', [ 'channel' => 'myspace', ])->assertUnprocessable(); expect(PressReleaseEvent::query()->count())->toBe(0); }); test('share endpoint returns 404 for drafts and unknown slugs', function () { /** @var TestCase $this */ $category = Category::factory()->create(['portal' => Portal::Businessportal24]); $company = Company::factory()->create(['portal' => Portal::Businessportal24, 'is_active' => true]); $draft = PressRelease::factory() ->forPortal(Portal::Businessportal24) ->for($category) ->for($company) ->create(['status' => PressReleaseStatus::Draft, 'slug' => 'entwurf-pm']); $this->postJson('https://businessportal24.test/de/press-release/'.$draft->slug.'/share', [ 'channel' => 'x', ])->assertNotFound(); $this->postJson('https://businessportal24.test/de/press-release/gibt-es-nicht/share', [ 'channel' => 'x', ])->assertNotFound(); expect(PressReleaseEvent::query()->count())->toBe(0); }); test('customer panel shows view and share stats for the owner', function () { /** @var TestCase $this */ $this->seed(RolesAndPermissionsSeeder::class); $customer = User::factory()->create(['is_active' => true]); $customer->assignRole('customer'); $company = Company::factory()->presseecho()->create(); $customer->companies()->attach($company->id, ['role' => 'owner']); $release = PressRelease::factory()->published()->create([ 'user_id' => $customer->id, 'company_id' => $company->id, 'category_id' => Category::factory()->create()->id, 'portal' => $company->portal->value, 'hits' => 42, ]); PressReleaseEvent::factory()->share(PressReleaseShareChannel::LinkedIn)->for($release)->count(2)->create(); PressReleaseEvent::factory()->share(PressReleaseShareChannel::CopyLink)->for($release)->create(); $this->actingAs($customer); LivewireVolt::test('customer.press-releases.show', ['id' => $release->id]) ->assertSee('Aufrufe') ->assertSee('42') ->assertSee('Geteilt') ->assertSee('LinkedIn 2') ->assertSee('Link kopiert 1'); }); test('deleting a press release removes its tracked events', function () { $release = trackingRelease(); PressReleaseEvent::factory()->for($release)->create(); PressReleaseEvent::factory()->share(PressReleaseShareChannel::X)->for($release)->create(); PressRelease::withoutGlobalScopes()->find($release->id)->forceDelete(); expect(PressReleaseEvent::query()->count())->toBe(0); });