Replaces the disabled "Coming soon" buttons on the pricing page with a waitlist band so visitors can be notified when alerts launch — separate from registered users. - waitlist_subscribers table (name, email unique, source, referrer) - WaitlistService::subscribe — normalises email, idempotent - Public POST /api/waitlist (throttle:10,1), thin controller + form request - Read-only Filament resource with streamed CSV export - Vue: useWaitlist composable + WaitlistForm, rendered below the grid while any tier is still "coming soon"; sends source + document.referrer Announcement send mechanism deferred to a later task. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
1.7 KiB
PHP
48 lines
1.7 KiB
PHP
<?php
|
|
|
|
use App\Models\WaitlistSubscriber;
|
|
use App\Services\WaitlistService;
|
|
|
|
it('normalises the email to trimmed lowercase before storing', function () {
|
|
$subscriber = app(WaitlistService::class)->subscribe('Ada Lovelace', ' Ada@Example.COM ');
|
|
|
|
expect($subscriber->email)->toBe('ada@example.com')
|
|
->and($subscriber->name)->toBe('Ada Lovelace');
|
|
|
|
$this->assertDatabaseHas('waitlist_subscribers', ['email' => 'ada@example.com']);
|
|
});
|
|
|
|
it('is idempotent — re-subscribing the same email keeps a single row and returns the original', function () {
|
|
$service = app(WaitlistService::class);
|
|
|
|
$first = $service->subscribe('Ada', 'ada@example.com');
|
|
$second = $service->subscribe('Different Name', 'ADA@example.com');
|
|
|
|
expect($second->id)->toBe($first->id)
|
|
->and($second->name)->toBe('Ada');
|
|
|
|
expect(WaitlistSubscriber::where('email', 'ada@example.com')->count())->toBe(1);
|
|
});
|
|
|
|
it('stores the source and referrer on a new subscriber', function () {
|
|
$subscriber = app(WaitlistService::class)->subscribe(
|
|
'Ada',
|
|
'ada@example.com',
|
|
source: 'pricing',
|
|
referrer: 'https://duckduckgo.com/',
|
|
);
|
|
|
|
expect($subscriber->source)->toBe('pricing')
|
|
->and($subscriber->referrer)->toBe('https://duckduckgo.com/');
|
|
});
|
|
|
|
it('preserves the original meta when an existing email re-subscribes', function () {
|
|
$service = app(WaitlistService::class);
|
|
|
|
$service->subscribe('Ada', 'ada@example.com', source: 'pricing', referrer: 'https://a.test');
|
|
$second = $service->subscribe('Ada', 'ada@example.com', source: 'home', referrer: 'https://b.test');
|
|
|
|
expect($second->source)->toBe('pricing')
|
|
->and($second->referrer)->toBe('https://a.test');
|
|
});
|