$user->id, 'type' => $type->value, ]); } test('notification mails contain the reason hint and a signed unsubscribe link', function () { $pressRelease = PressRelease::factory()->published()->create(); $user = $pressRelease->user; $html = (new PressReleasePublished($user, $pressRelease))->render(); expect($html) ->toContain('Warum erhalten Sie diese E-Mail?') ->toContain('Sie wurden als Pressekontakt hinterlegt') ->toContain('hier mit einem Klick austragen') ->toContain('e-mail-benachrichtigungen/abmelden/'.$user->id.'/'.EmailNotificationType::PressReleasePublished->value) ->toContain('signature='); $rejectedHtml = (new PressReleaseRejected($user, $pressRelease, 'Bitte Quellen ergänzen.'))->render(); expect($rejectedHtml) ->toContain('Warum erhalten Sie diese E-Mail?') ->toContain('e-mail-benachrichtigungen/abmelden/'.$user->id.'/'.EmailNotificationType::PressReleaseRejected->value); }); test('notification mails carry rfc 8058 list-unsubscribe headers', function () { $pressRelease = PressRelease::factory()->published()->create(); $mailable = new PressReleasePublished($pressRelease->user, $pressRelease); $headers = $mailable->headers(); expect($headers->text['List-Unsubscribe']) ->toContain('e-mail-benachrichtigungen/abmelden/') ->and($headers->text['List-Unsubscribe-Post']) ->toBe('List-Unsubscribe=One-Click'); }); test('the signed unsubscribe link opts the user out without login and shows a confirmation', function () { /** @var TestCase $this */ $user = User::factory()->create(); $this->get(signedUnsubscribeUrl($user, EmailNotificationType::PressReleasePublished)) ->assertSuccessful() ->assertSee('Erfolgreich abgemeldet') ->assertSee('Pressemitteilung veröffentlicht') ->assertSee('Abmeldung rückgängig machen'); expect($user->fresh()->wantsEmailNotification(EmailNotificationType::PressReleasePublished))->toBeFalse() ->and($user->fresh()->wantsEmailNotification(EmailNotificationType::PressReleaseRejected))->toBeTrue(); }); test('an unsubscribe link with a tampered signature does not opt out', function () { /** @var TestCase $this */ $user = User::factory()->create(); $url = route('email-preferences.unsubscribe', [ 'user' => $user->id, 'type' => EmailNotificationType::PressReleasePublished->value, ]).'?signature=manipuliert'; $this->get($url) ->assertSuccessful() ->assertSee('Dieser Abmelde-Link ist ungültig.'); expect($user->fresh()->wantsEmailNotification(EmailNotificationType::PressReleasePublished))->toBeTrue(); }); test('mail clients can one-click unsubscribe via post without a csrf token', function () { /** @var TestCase $this */ $user = User::factory()->create(); $this->post(signedUnsubscribeUrl($user, EmailNotificationType::PressReleaseRejected)) ->assertSuccessful(); expect($user->fresh()->wantsEmailNotification(EmailNotificationType::PressReleaseRejected))->toBeFalse(); }); test('the confirmation page allows undoing the unsubscribe', function () { /** @var TestCase $this */ $user = User::factory()->create(); $user->optOutOfEmailNotification(EmailNotificationType::PressReleasePublished); $resubscribeUrl = URL::signedRoute('email-preferences.resubscribe', [ 'user' => $user->id, 'type' => EmailNotificationType::PressReleasePublished->value, ]); $this->post($resubscribeUrl) ->assertSuccessful() ->assertSee('Wieder angemeldet'); expect($user->fresh()->wantsEmailNotification(EmailNotificationType::PressReleasePublished))->toBeTrue(); }); test('an unknown notification type returns 404', function () { /** @var TestCase $this */ $user = User::factory()->create(); $this->get(URL::signedRoute('email-preferences.unsubscribe', [ 'user' => $user->id, 'type' => 'gibt_es_nicht', ]))->assertNotFound(); }); test('the published notification is not sent to an opted-out author', function () { /** @var TestCase $this */ Mail::fake(); $pressRelease = PressRelease::factory()->create(['status' => PressReleaseStatus::Review->value]); $pressRelease->user->optOutOfEmailNotification(EmailNotificationType::PressReleasePublished); app(PressReleaseService::class)->publish($pressRelease); expect($pressRelease->fresh()->status)->toBe(PressReleaseStatus::Published); Mail::assertNothingOutgoing(); Mail::assertNotQueued(PressReleasePublished::class); }); test('the published notification is still sent to an author without opt-out', function () { /** @var TestCase $this */ Mail::fake(); $pressRelease = PressRelease::factory()->create(['status' => PressReleaseStatus::Review->value]); app(PressReleaseService::class)->publish($pressRelease); Mail::assertQueued(PressReleasePublished::class, fn (PressReleasePublished $mail) => $mail->hasTo($pressRelease->user->email)); }); test('the rejected notification is not sent to an opted-out author', function () { /** @var TestCase $this */ Mail::fake(); $pressRelease = PressRelease::factory()->create(['status' => PressReleaseStatus::Review->value]); $pressRelease->user->optOutOfEmailNotification(EmailNotificationType::PressReleaseRejected); app(PressReleaseService::class)->reject($pressRelease, 'Bitte überarbeiten.'); expect($pressRelease->fresh()->status)->toBe(PressReleaseStatus::Rejected); Mail::assertNotQueued(PressReleaseRejected::class); }); test('customers can manage their email notification preferences in the profile', function () { /** @var TestCase $this */ $this->seed(RolesAndPermissionsSeeder::class); $customer = User::factory()->create(['is_active' => true]); $customer->assignRole('customer'); $this->actingAs($customer); LivewireVolt::test('customer.profile') ->set('emailNotifications.'.EmailNotificationType::PressReleasePublished->value, false) ->call('saveProfile') ->assertHasNoErrors(); expect($customer->fresh()->wantsEmailNotification(EmailNotificationType::PressReleasePublished))->toBeFalse(); LivewireVolt::test('customer.profile') ->set('emailNotifications.'.EmailNotificationType::PressReleasePublished->value, true) ->call('saveProfile') ->assertHasNoErrors(); expect($customer->fresh()->wantsEmailNotification(EmailNotificationType::PressReleasePublished))->toBeTrue(); }); test('opting out twice keeps a single opt-out row', function () { $user = User::factory()->create(); $user->optOutOfEmailNotification(EmailNotificationType::PressReleasePublished); $user->optOutOfEmailNotification(EmailNotificationType::PressReleasePublished); expect(EmailNotificationOptOut::query()->where('user_id', $user->id)->count())->toBe(1); });