Files
preregister/tests/Feature/QueueUnsyncedMailwizzSubscribersTest.php
bert.hausmans 845665c8be feat: per-subscriber Mailwizz sync button on admin list
Add POST route and form request to queue SyncSubscriberToMailwizz for one
subscriber when the page has Mailwizz configured. Include Dutch strings
and feature tests for auth and edge cases.

Made-with: Cursor
2026-04-05 13:45:30 +02:00

254 lines
8.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature;
use App\Jobs\SyncSubscriberToMailwizz;
use App\Models\MailwizzConfig;
use App\Models\PreregistrationPage;
use App\Models\Subscriber;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Str;
use Tests\TestCase;
class QueueUnsyncedMailwizzSubscribersTest extends TestCase
{
use RefreshDatabase;
public function test_artisan_dry_run_counts_unsynced_subscribers_with_mailwizz(): void
{
$page = $this->makePageWithMailwizz();
Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'A',
'last_name' => 'B',
'email' => 'a@example.com',
'synced_to_mailwizz' => false,
]);
$exit = Artisan::call('mailwizz:queue-unsynced', ['--dry-run' => true]);
$this->assertSame(0, $exit);
$this->assertStringContainsString('1', Artisan::output());
}
public function test_owner_can_queue_mailwizz_sync_from_subscribers_index(): void
{
Http::fake(function (Request $request) {
$url = $request->url();
if (str_contains($url, 'search-by-email')) {
return Http::response(['status' => 'error']);
}
if ($request->method() === 'POST' && preg_match('#/lists/[^/]+/subscribers$#', $url) === 1) {
return Http::response(['status' => 'success']);
}
return Http::response(['status' => 'error'], 500);
});
$user = User::factory()->create(['role' => 'user']);
$page = $this->makePageWithMailwizzForUser($user);
Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'A',
'last_name' => 'B',
'email' => 'syncme@example.com',
'synced_to_mailwizz' => false,
]);
$response = $this->actingAs($user)->post(route('admin.pages.subscribers.queue-mailwizz-sync', $page));
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
$response->assertSessionHas('status');
$this->assertDatabaseHas('subscribers', [
'email' => 'syncme@example.com',
'synced_to_mailwizz' => true,
]);
}
public function test_other_user_cannot_queue_mailwizz_sync(): void
{
$owner = User::factory()->create(['role' => 'user']);
$intruder = User::factory()->create(['role' => 'user']);
$page = $this->makePageWithMailwizzForUser($owner);
$response = $this->actingAs($intruder)->post(route('admin.pages.subscribers.queue-mailwizz-sync', $page));
$response->assertForbidden();
}
public function test_owner_can_queue_single_subscriber_mailwizz_sync(): void
{
Queue::fake();
$user = User::factory()->create(['role' => 'user']);
$page = $this->makePageWithMailwizzForUser($user);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'One',
'last_name' => 'Off',
'email' => 'oneoff@example.com',
'synced_to_mailwizz' => true,
]);
$response = $this->actingAs($user)->post(
route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber])
);
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
$response->assertSessionHas('status');
Queue::assertPushed(SyncSubscriberToMailwizz::class, function (SyncSubscriberToMailwizz $job) use ($subscriber): bool {
return $job->subscriberId === $subscriber->id;
});
}
public function test_other_user_cannot_queue_single_subscriber_mailwizz_sync(): void
{
Queue::fake();
$owner = User::factory()->create(['role' => 'user']);
$intruder = User::factory()->create(['role' => 'user']);
$page = $this->makePageWithMailwizzForUser($owner);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'A',
'last_name' => 'B',
'email' => 'ab@example.com',
]);
$response = $this->actingAs($intruder)->post(
route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber])
);
$response->assertForbidden();
Queue::assertNothingPushed();
}
public function test_single_subscriber_mailwizz_sync_redirects_with_error_when_page_has_no_mailwizz(): void
{
Queue::fake();
$user = User::factory()->create(['role' => 'user']);
$page = PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $user->id,
'title' => 'Fest',
'heading' => 'Join',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subHour(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'is_active' => true,
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'A',
'last_name' => 'B',
'email' => 'nomw@example.com',
]);
$response = $this->actingAs($user)->post(
route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber])
);
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
$response->assertSessionHas('error');
Queue::assertNothingPushed();
}
public function test_cannot_queue_single_subscriber_mailwizz_sync_with_mismatched_page(): void
{
Queue::fake();
$user = User::factory()->create(['role' => 'user']);
$pageA = $this->makePageWithMailwizzForUser($user);
$pageB = PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $user->id,
'title' => 'Other',
'heading' => 'Other',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subHour(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'is_active' => true,
]);
MailwizzConfig::query()->create([
'preregistration_page_id' => $pageB->id,
'api_key' => 'fake-api-key',
'list_uid' => 'list-uid-2',
'list_name' => 'List B',
'field_email' => 'EMAIL',
'field_first_name' => 'FNAME',
'field_last_name' => 'LNAME',
'field_phone' => null,
'tag_field' => 'TAGS',
'tag_value' => 'b-source',
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $pageB->id,
'first_name' => 'A',
'last_name' => 'B',
'email' => 'on-b@example.com',
]);
$response = $this->actingAs($user)->post(
route('admin.pages.subscribers.sync-mailwizz', [$pageA, $subscriber])
);
$response->assertForbidden();
Queue::assertNothingPushed();
}
private function makePageWithMailwizz(): PreregistrationPage
{
$user = User::factory()->create(['role' => 'user']);
return $this->makePageWithMailwizzForUser($user);
}
private function makePageWithMailwizzForUser(User $user): PreregistrationPage
{
$page = PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $user->id,
'title' => 'Fest',
'heading' => 'Join',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subHour(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'is_active' => true,
]);
MailwizzConfig::query()->create([
'preregistration_page_id' => $page->id,
'api_key' => 'fake-api-key',
'list_uid' => 'list-uid-1',
'list_name' => 'Main list',
'field_email' => 'EMAIL',
'field_first_name' => 'FNAME',
'field_last_name' => 'LNAME',
'field_phone' => null,
'tag_field' => 'TAGS',
'tag_value' => 'preregister-source',
]);
return $page;
}
}