set('billing.single_pm_price_cents', 1900); config()->set('billing.change_price_cents', 1000); config()->set('billing.depublication_price_cents', 3500); config()->set('billing.vat_rate', 0.19); config()->set('credits.extra_pm.starter', 15); Plan::factory()->create(['slug' => 'starter', 'name' => 'Starter', 'monthly_price_cents' => 2900, 'yearly_price_cents' => 29000, 'press_release_quota' => 3, 'is_active' => true]); }); test('the worked example lets pay-per-release win in some rows and the plan in others', function () { $data = app(PricingTransparencyData::class)->build(); expect($data['singleNet'])->toBe('19') ->and($data['singleGross'])->toBe('22,61') ->and($data['starterMonthlyNet'])->toBe('29') ->and(collect($data['examples'])->pluck('cheaper')->unique()->sort()->values()->all())->toBe(['single', 'starter']); }); test('the cost page shows the short answer with the configured price and no competitor names', function () { /** @var TestCase $this */ $response = $this->get('https://presseecho.test/de/was-kostet-eine-pressemitteilung')->assertSuccessful(); $response ->assertSee('Was kostet eine Pressemitteilung?') ->assertSee('19 € netto (22,61 € inkl. 19 % USt.)', false) ->assertSee('Woran man Folgekosten erkennt') ->assertSee('Rechenbeispiel') ->assertSee('228 €', false) ->assertSee('10 € netto') ->assertSee('35 € netto') ->assertSee('/de/pressemitteilung-loeschen-oder-aendern-lassen', false) ->assertSee('Was kostet eine Pressemitteilung? Preis, Modelle, Rechenbeispiel – presseecho', false); // Kein Anbietername, keine fremden Preise (Briefing 17.09.2026). $this->assertStringNotContainsStringIgnoringCase('presseportal.de', (string) $response->getContent()); $this->assertStringNotContainsStringIgnoringCase('openpr', (string) $response->getContent()); }); test('the no-subscription page and the change page render on every host in both editions', function (string $url) { /** @var TestCase $this */ $this->get($url)->assertSuccessful(); })->with([ 'https://businessportal24.test/de/pressemitteilung-veroeffentlichen-ohne-abo', 'https://businessportal24.test/en/pressemitteilung-veroeffentlichen-ohne-abo', 'https://pressekonto.test/de/pressemitteilung-loeschen-oder-aendern-lassen', 'https://presseecho.test/en/pressemitteilung-loeschen-oder-aendern-lassen', 'https://pressekonto.test/en/was-kostet-eine-pressemitteilung', 'https://presseecho.test/en/pressemitteilung-kostenlos-veroeffentlichen', ]); test('the free page answers honestly, names our own link policy and shows the portal list only when configured', function () { /** @var TestCase $this */ config()->set('transparency.free_portals', []); $response = $this->get('https://businessportal24.test/de/pressemitteilung-kostenlos-veroeffentlichen')->assertSuccessful(); $response ->assertSee('Pressemitteilung kostenlos veröffentlichen') ->assertSee('Einen kostenlosen Weg gibt es nicht') ->assertSee('rel="sponsored nofollow"', false) ->assertSee('Warum kostenfreie Annahme und Prüfung sich ausschließen') ->assertSee('Wer bei kostenlosen Angeboten am Ende zahlt') ->assertDontSee('Kostenlose Presseportale', false) ->assertSee('aria-current="page">Kostenlos veröffentlichen?', false) ->assertSee('/de/pressemitteilung-veroeffentlichen-ohne-abo', false); config()->set('transparency.free_portals', [['name' => 'Beispielportal', 'url' => 'https://portal.example', 'note' => 'nur Text, keine Links']]); config()->set('transparency.free_portals_checked_at', '2026-09-17'); $this->get('https://businessportal24.test/de/pressemitteilung-kostenlos-veroeffentlichen')->assertSuccessful() ->assertSee('Kostenlose Presseportale', false) ->assertSee('am 17.09.2026 kostenlos Einreichungen angenommen haben') ->assertSee('Beispielportal', false) ->assertSee('nur Text, keine Links') ->assertSee('Kein Eintrag ist eine Empfehlung.'); }); test('the change page names the five ways with their prices and points to the self-service entry', function () { /** @var TestCase $this */ $this->get('https://businessportal24.test/de/pressemitteilung-loeschen-oder-aendern-lassen') ->assertSuccessful() ->assertSee('Die fünf Wege') ->assertSee('kostenlos') ->assertSee('10 € netto') ->assertSee('35 € netto') ->assertSee('/de/melden/pm', false) ->assertSee('Die Meldung steht auf einem anderen Portal?') // Unter-Navigation: aktuelle Seite markiert, Preisseite verlinkt. ->assertSee('aria-current="page">Meldung löschen oder ändern', false) ->assertSee('/de/preise" class=', false); }); test('the pages are linked from the pricing page, the help centre and the sitemap', function () { /** @var TestCase $this */ $this->get('https://presseecho.test/de/preise')->assertSuccessful() ->assertSee('aria-label="Transparenz"', false) ->assertSee('aria-current="page">Tarife & Preise', false) ->assertSee('/de/was-kostet-eine-pressemitteilung', false) ->assertSee('/de/pressemitteilung-veroeffentlichen-ohne-abo', false) ->assertSee('/de/pressemitteilung-loeschen-oder-aendern-lassen', false) ->assertSee('/de/pressemitteilung-kostenlos-veroeffentlichen', false); $this->get('https://presseecho.test/de/hilfe')->assertSuccessful() ->assertSee('/de/pressemitteilung-loeschen-oder-aendern-lassen', false) ->assertSee('/de/pressemitteilung-veroeffentlichen-ohne-abo', false) ->assertSee('/de/pressemitteilung-kostenlos-veroeffentlichen', false); $this->get('https://presseecho.test/sitemap.xml')->assertSuccessful() ->assertSee('https://presseecho.test/de/was-kostet-eine-pressemitteilung', false) ->assertSee('https://presseecho.test/de/pressemitteilung-kostenlos-veroeffentlichen', false); $this->get('https://presseecho.test/llms.txt')->assertSuccessful() ->assertSee('/de/pressemitteilung-kostenlos-veroeffentlichen', false); // Die Seiten liegen auf allen drei Hosts; in der Sitemap steht nur die // führende Adresse (Anhang 2, E10) — beim Hub bleibt die API-Doku. $this->get('https://pressekonto.test/sitemap.xml')->assertSuccessful() ->assertDontSee('/de/pressemitteilung-loeschen-oder-aendern-lassen', false) ->assertSee('https://pressekonto.test/de/api', false); });