presseportale/tests/Feature/Web/TransparencyPagesTest.php
Kevin Adametz 375138679d web: Erstquelle-Absatz in der Veröffentlichungsmail, vierte Transparenzseite „kostenlos veröffentlichen" (Anhang 1: 1d, 2.4, E7)
Meldungen, die über die API eingegangen sind, bekommen in der
Veröffentlichungsmail einen Absatz zum Unterschied Erstquelle/Kopie —
technische Tatsache, ohne Preis und Angebot; direkt eingereichte nicht.

/pressemitteilung-kostenlos-veroeffentlichen beantwortet die Suche nach
„kostenlos" ehrlich: kein kostenloser Weg (E7), was kostenlose Portale
leisten, warum Links aus Presseportalen kaum tragen (auch bei uns
sponsored nofollow), warum Annahme ohne Gegenwert und Prüfung sich
ausschließen, wer am Ende zahlt. Die Liste kostenloser Portale ist in
config/transparency.php vorbereitet und bleibt leer, bis geprüfte
Einträge mit Prüfdatum vorliegen.

Unter-Navigation, Hilfe, Sitemaps, llms.txt und die Modelltabelle der
Kostenseite verlinken die neue Seite. Anhang 1 und Protokoll Teil 6.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 14:22:05 +00:00

128 lines
6.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Models\Plan;
use App\Services\Web\PricingTransparencyData;
use Tests\TestCase;
/**
* Transparenzseiten (Roadmap 2.4): Zahlen aus der Konfiguration, kein
* Anbietername, Rechenbeispiel mit gemischtem Ausgang.
*/
beforeEach(function (): void {
config()->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('<strong>19 € netto</strong> (22,61 € inkl. 19 % USt.)', false)
->assertSee('Woran man Folgekosten erkennt')
->assertSee('Rechenbeispiel')
->assertSee('228&nbsp;€', false)
->assertSee('10 € netto')
->assertSee('35 € netto')
->assertSee('/de/pressemitteilung-loeschen-oder-aendern-lassen', false)
->assertSee('<title>Was kostet eine Pressemitteilung? Preis, Modelle, Rechenbeispiel – presseecho</title>', 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('<code>rel="sponsored nofollow"</code>', false)
->assertSee('Warum kostenfreie Annahme und Prüfung sich ausschließen')
->assertSee('Wer bei kostenlosen Angeboten am Ende zahlt')
->assertDontSee('Kostenlose Presseportale</h2>', false)
->assertSee('aria-current="page">Kostenlos veröffentlichen?</span>', 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</h2>', false)
->assertSee('am 17.09.2026 kostenlos Einreichungen angenommen haben')
->assertSee('<a href="https://portal.example" rel="nofollow noopener" target="_blank">Beispielportal</a>', 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</span>', 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 &amp; Preise</span>', 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('<loc>https://presseecho.test/de/was-kostet-eine-pressemitteilung</loc>', false)
->assertSee('<loc>https://presseecho.test/de/pressemitteilung-kostenlos-veroeffentlichen</loc>', false);
$this->get('https://presseecho.test/llms.txt')->assertSuccessful()
->assertSee('/de/pressemitteilung-kostenlos-veroeffentlichen', false);
$this->get('https://pressekonto.test/sitemap.xml')->assertSuccessful()
->assertSee('<loc>https://pressekonto.test/de/pressemitteilung-loeschen-oder-aendern-lassen</loc>', false);
});