Files
preregister/tests/Feature/DestroySubscriberTest.php
bert.hausmans 1e7ee14540 fix: clear Mailwizz checkboxlist tag when deleting subscriber
Encode empty checkboxlist arrays as an empty scalar so multipart requests
include the field. On delete, PUT only coupon and tag fields to Mailwizz
after merging the tag CSV from getSubscriber.

Made-with: Cursor
2026-04-05 13:33:56 +02:00

334 lines
13 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature;
use App\Models\MailwizzConfig;
use App\Models\PreregistrationPage;
use App\Models\Subscriber;
use App\Models\User;
use App\Models\WeeztixConfig;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use Tests\TestCase;
class DestroySubscriberTest extends TestCase
{
use RefreshDatabase;
public function test_page_owner_can_delete_subscriber_on_that_page(): void
{
$user = User::factory()->create(['role' => 'user']);
$page = PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $user->id,
'title' => 'Fest',
'heading' => 'Fest',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subDay(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'background_image' => null,
'logo_image' => null,
'is_active' => true,
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'Ada',
'last_name' => 'Lovelace',
'email' => 'ada@example.com',
]);
$response = $this->actingAs($user)->delete(route('admin.pages.subscribers.destroy', [$page, $subscriber]));
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
$response->assertSessionHas('status');
$this->assertDatabaseMissing('subscribers', ['id' => $subscriber->id]);
}
public function test_other_user_cannot_delete_subscriber(): void
{
$owner = User::factory()->create(['role' => 'user']);
$intruder = User::factory()->create(['role' => 'user']);
$page = PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $owner->id,
'title' => 'Fest',
'heading' => 'Fest',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subDay(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'background_image' => null,
'logo_image' => null,
'is_active' => true,
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'A',
'last_name' => 'B',
'email' => 'x@example.com',
]);
$response = $this->actingAs($intruder)->delete(route('admin.pages.subscribers.destroy', [$page, $subscriber]));
$response->assertForbidden();
$this->assertDatabaseHas('subscribers', ['id' => $subscriber->id]);
}
public function test_cannot_delete_subscriber_using_wrong_page_in_url(): void
{
$user = User::factory()->create(['role' => 'user']);
$pageA = PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $user->id,
'title' => 'A',
'heading' => 'A',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subDay(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'background_image' => null,
'logo_image' => null,
'is_active' => true,
]);
$pageB = PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $user->id,
'title' => 'B',
'heading' => 'B',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subDay(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'background_image' => null,
'logo_image' => null,
'is_active' => true,
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $pageB->id,
'first_name' => 'A',
'last_name' => 'B',
'email' => 'y@example.com',
]);
$response = $this->actingAs($user)->delete(route('admin.pages.subscribers.destroy', [$pageA, $subscriber]));
$response->assertForbidden();
$this->assertDatabaseHas('subscribers', ['id' => $subscriber->id]);
}
public function test_delete_strips_mailwizz_source_tag_and_clears_coupon_field(): void
{
Http::fake(function (Request $request) {
$url = $request->url();
if (str_contains($url, 'search-by-email')) {
return Http::response(['status' => 'success', 'data' => ['subscriber_uid' => 'sub-to-clean']]);
}
if ($request->method() === 'GET' && str_contains($url, '/subscribers/sub-to-clean') && ! str_contains($url, 'search-by-email')) {
return Http::response([
'status' => 'success',
'data' => [
'record' => [
'TAGS' => 'preregister-source,other-tag',
'COUPON' => 'PREREG-OLD',
],
],
]);
}
if ($request->method() === 'PUT' && str_contains($url, '/subscribers/sub-to-clean')) {
$body = $request->body();
$this->assertStringContainsString('other-tag', $body);
$this->assertStringNotContainsString('preregister-source', $body);
$this->assertStringContainsString('COUPON', $body);
return Http::response(['status' => 'success']);
}
return Http::response(['status' => 'error'], 500);
});
$user = User::factory()->create(['role' => 'user']);
$page = $this->makePageForDestroyTest($user);
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,
'field_coupon_code' => 'COUPON',
'tag_field' => 'TAGS',
'tag_value' => 'preregister-source',
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'Clean',
'last_name' => 'Up',
'email' => 'cleanup@example.com',
'coupon_code' => 'PREREG-LOCAL',
]);
$response = $this->actingAs($user)->delete(route('admin.pages.subscribers.destroy', [$page, $subscriber]));
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
$this->assertDatabaseMissing('subscribers', ['id' => $subscriber->id]);
Http::assertSentCount(3);
}
public function test_delete_clears_mailwizz_checkboxlist_when_only_configured_tag_is_present(): void
{
Http::fake(function (Request $request) {
$url = $request->url();
if (str_contains($url, 'search-by-email')) {
return Http::response(['status' => 'success', 'data' => ['subscriber_uid' => 'sub-single-tag']]);
}
if ($request->method() === 'GET' && str_contains($url, '/subscribers/sub-single-tag') && ! str_contains($url, 'search-by-email')) {
return Http::response([
'status' => 'success',
'data' => [
'record' => [
'TAGS' => 'preregister-source',
'COUPON' => 'PREREG-OLD',
],
],
]);
}
if ($request->method() === 'PUT' && str_contains($url, '/subscribers/sub-single-tag')) {
$body = $request->body();
$this->assertStringContainsString('TAGS', $body);
$this->assertStringNotContainsString('preregister-source', $body);
$this->assertStringNotContainsString('TAGS[]', $body);
$this->assertStringContainsString('COUPON', $body);
return Http::response(['status' => 'success']);
}
return Http::response(['status' => 'error'], 500);
});
$user = User::factory()->create(['role' => 'user']);
$page = $this->makePageForDestroyTest($user);
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,
'field_coupon_code' => 'COUPON',
'tag_field' => 'TAGS',
'tag_value' => 'preregister-source',
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'Solo',
'last_name' => 'Tag',
'email' => 'solo-tag@example.com',
'coupon_code' => 'PREREG-LOCAL',
]);
$response = $this->actingAs($user)->delete(route('admin.pages.subscribers.destroy', [$page, $subscriber]));
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
$this->assertDatabaseMissing('subscribers', ['id' => $subscriber->id]);
Http::assertSentCount(3);
}
public function test_delete_removes_coupon_code_in_weeztix_when_configured(): void
{
Http::fake(function (Request $request) {
$url = $request->url();
if ($request->method() === 'GET' && preg_match('#/coupon/coupon-guid-test/codes$#', $url) === 1) {
return Http::response([
'data' => [
['guid' => 'wzx-code-guid', 'code' => 'PREREG-DEL99'],
],
], 200);
}
if ($request->method() === 'DELETE' && str_contains($url, '/coupon/coupon-guid-test/codes/wzx-code-guid')) {
return Http::response(null, 204);
}
return Http::response(['status' => 'error'], 500);
});
$user = User::factory()->create(['role' => 'user']);
$page = $this->makePageForDestroyTest($user);
WeeztixConfig::query()->create([
'preregistration_page_id' => $page->id,
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'redirect_uri' => 'https://app.test/callback',
'access_token' => 'access-token',
'refresh_token' => 'refresh-token',
'token_expires_at' => now()->addHour(),
'refresh_token_expires_at' => now()->addMonth(),
'company_guid' => 'company-guid-test',
'company_name' => 'Test Co',
'coupon_guid' => 'coupon-guid-test',
'coupon_name' => 'PreReg',
'is_connected' => true,
]);
$subscriber = Subscriber::query()->create([
'preregistration_page_id' => $page->id,
'first_name' => 'Weez',
'last_name' => 'Tix',
'email' => 'weez@example.com',
'coupon_code' => 'PREREG-DEL99',
]);
$response = $this->actingAs($user)->delete(route('admin.pages.subscribers.destroy', [$page, $subscriber]));
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
$this->assertDatabaseMissing('subscribers', ['id' => $subscriber->id]);
Http::assertSent(function (Request $request): bool {
return $request->method() === 'DELETE'
&& str_contains($request->url(), '/coupon/coupon-guid-test/codes/wzx-code-guid');
});
}
private function makePageForDestroyTest(User $user): PreregistrationPage
{
return PreregistrationPage::query()->create([
'slug' => (string) Str::uuid(),
'user_id' => $user->id,
'title' => 'Fest',
'heading' => 'Fest',
'intro_text' => null,
'thank_you_message' => null,
'expired_message' => null,
'ticketshop_url' => null,
'start_date' => now()->subDay(),
'end_date' => now()->addMonth(),
'phone_enabled' => false,
'background_image' => null,
'logo_image' => null,
'is_active' => true,
]);
}
}