presseportale/tests/Feature/PressReleaseReclassifyTest.php
Kevin Adametz f581e1eb3a mail: Kontakterreichbarkeit - Formpruefung, Domainpruefung, Einlieferer-Bericht
Vier Punkte aus kontakterreichbarkeit-mx-bounces-2026-09-15.md, ohne
Veroeffentlichungssperre:

- PlausibleEmailDomain: Domain ohne Endung oder mit Tippfehler-TLD ist
  ein 422 an der Legacy-API, deterministisch ohne DNS.
- email_domain_checks + MailDomainChecker ueber DnsResolver-Schnittstelle
  (RFC 5321 impliziter MX, RFC 7505 Null MX, Unresolved ist kein Befund),
  Observer an Company/Contact, Job nach Commit, taeglicher Refresh,
  mail:check-domains fuer den Bestand. Nie eine Adresssperre aus DNS.
- Admin > Reports > Einlieferer-Bericht: tote Adressen aus Sperrliste
  und Domainbefund, automatisch abgelehnte Meldungen mit Grund,
  Text zum Kopieren und CSV. Versendet nichts.
- EmailBounceKind::Policy: 5.7.x wird protokolliert, zaehlt aber nicht
  auf den Schwellwert. Statuscode entscheidet vor Diagnosetext.

Messung vorab: 6 von 877 API-Domains ohne Zustellweg, eine davon fuer
66 der 151 Ruecklaeufer verantwortlich.

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

123 lines
4.3 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\Enums\PressReleaseClassification;
use App\Enums\PressReleaseStatus;
use App\Jobs\ClassifyPressRelease;
use App\Jobs\ScorePressRelease;
use App\Models\Category;
use App\Models\Company;
use App\Models\PressRelease;
use App\Models\User;
use App\Services\PressRelease\PressReleaseService;
use Illuminate\Support\Facades\Queue;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;
test('reclassifyIfClassified dispatches a non-routing job for an already classified press release', function () {
Queue::fake();
$pressRelease = PressRelease::factory()->create([
'classification' => PressReleaseClassification::Green->value,
'status' => PressReleaseStatus::Published->value,
]);
app(PressReleaseService::class)->reclassifyIfClassified($pressRelease);
Queue::assertPushedOn('classification', ClassifyPressRelease::class, function (ClassifyPressRelease $job) use ($pressRelease) {
return $job->pressReleaseId === $pressRelease->id && $job->route === false;
});
});
test('reclassifyIfClassified does nothing for a never-classified press release', function () {
Queue::fake();
$pressRelease = PressRelease::factory()->create(['classification' => null]);
app(PressReleaseService::class)->reclassifyIfClassified($pressRelease);
Queue::assertNotPushed(ClassifyPressRelease::class);
});
test('reprocessAfterContentChange reclassifies and rescores on the fresh model state', function () {
Queue::fake();
$pressRelease = PressRelease::factory()->create([
'classification' => PressReleaseClassification::Green->value,
'content_score' => 80,
'status' => PressReleaseStatus::Published->value,
]);
app(PressReleaseService::class)->reprocessAfterContentChange($pressRelease);
Queue::assertPushedOn('classification', ClassifyPressRelease::class);
Queue::assertPushedOn('classification', ScorePressRelease::class);
});
test('reprocessAfterContentChange does nothing for an unclassified, unscored press release', function () {
Queue::fake();
$pressRelease = PressRelease::factory()->create([
'classification' => null,
'content_score' => null,
]);
app(PressReleaseService::class)->reprocessAfterContentChange($pressRelease);
Queue::assertNotPushed(ClassifyPressRelease::class);
});
test('api update of a classified press release re-classifies when the content changes', function () {
/** @var TestCase $this */
Queue::fake();
$user = User::factory()->create();
$company = Company::factory()->presseecho()->create();
$category = Category::factory()->withTranslations()->create();
$user->companies()->attach($company->id, ['role' => 'owner']);
$pressRelease = PressRelease::factory()->create([
'user_id' => $user->id,
'company_id' => $company->id,
'category_id' => $category->id,
'portal' => $company->portal->value,
'status' => PressReleaseStatus::Draft->value,
'classification' => PressReleaseClassification::Green->value,
]);
Sanctum::actingAs($user, ['press-releases:write']);
$this->patchJson("/api/v1/press-releases/{$pressRelease->id}", [
'text' => 'Komplett neuer Inhalt, der erneut geprüft werden muss.',
])->assertOk();
Queue::assertPushed(ClassifyPressRelease::class, fn (ClassifyPressRelease $job) => $job->route === false);
});
test('api update does not re-classify when content is unchanged', function () {
/** @var TestCase $this */
Queue::fake();
$user = User::factory()->create();
$company = Company::factory()->presseecho()->create();
$category = Category::factory()->withTranslations()->create();
$user->companies()->attach($company->id, ['role' => 'owner']);
$pressRelease = PressRelease::factory()->create([
'user_id' => $user->id,
'company_id' => $company->id,
'category_id' => $category->id,
'portal' => $company->portal->value,
'status' => PressReleaseStatus::Draft->value,
'classification' => PressReleaseClassification::Green->value,
'keywords' => 'alt',
]);
Sanctum::actingAs($user, ['press-releases:write']);
// Nur Keywords ändern – kein Titel/Text → keine Neuklassifikation.
$this->patchJson("/api/v1/press-releases/{$pressRelease->id}", [
'keywords' => 'neu',
])->assertOk();
Queue::assertNotPushed(ClassifyPressRelease::class);
});