whisper-money/tests/Feature/UserLeadTest.php

259 lines
8.6 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\Mail\WaitlistOvertaken;
use App\Mail\WaitlistReferralNotification;
use App\Mail\WaitlistWelcome;
use App\Models\UserLead;
use Illuminate\Support\Facades\Mail;
beforeEach(function () {
Mail::fake();
});
test('user lead is created with position starting at 500', function () {
$response = $this->post(route('user-leads.store'), [
'email' => 'first@example.com',
]);
$lead = UserLead::where('email', 'first@example.com')->first();
expect($lead)->not->toBeNull();
expect($lead->position)->toBe(500);
});
test('each subsequent lead gets a higher position', function () {
UserLead::factory()->create(['position' => 500]);
$this->post(route('user-leads.store'), ['email' => 'second@example.com']);
$lead = UserLead::where('email', 'second@example.com')->first();
expect($lead->position)->toBe(501);
});
test('user lead gets a referral code on creation', function () {
$this->post(route('user-leads.store'), ['email' => 'test@example.com']);
$lead = UserLead::where('email', 'test@example.com')->first();
expect($lead->referral_code)->not->toBeEmpty();
expect(strlen($lead->referral_code))->toBe(8);
});
test('user lead referral url is correct', function () {
$lead = UserLead::factory()->create(['referral_code' => 'TESTCODE']);
expect($lead->referral_url)->toContain('?ref=TESTCODE');
});
test('user lead redirects to the thank you page', function () {
$response = $this->post(route('user-leads.store'), [
'email' => 'test@example.com',
]);
$lead = UserLead::where('email', 'test@example.com')->first();
$response->assertRedirect(route('waitlist.thank-you', $lead));
});
test('welcome email is sent when a user lead is created', function () {
$this->post(route('user-leads.store'), ['email' => 'test@example.com']);
Mail::assertQueued(WaitlistWelcome::class, function (WaitlistWelcome $mail) {
return $mail->hasTo('test@example.com');
});
});
test('referrer moves forward 10 positions when someone uses their link', function () {
$referrer = UserLead::factory()->create(['position' => 510]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
expect($referrer->fresh()->position)->toBe(500);
});
test('referrer position cannot go below 1', function () {
$referrer = UserLead::factory()->create(['position' => 5]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
expect($referrer->fresh()->position)->toBe(1);
});
test('referral notification email is sent to the referrer', function () {
$referrer = UserLead::factory()->create(['position' => 510]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
Mail::assertQueued(WaitlistReferralNotification::class, function (WaitlistReferralNotification $mail) use ($referrer) {
return $mail->hasTo($referrer->email);
});
});
test('new lead is linked to the referrer', function () {
$referrer = UserLead::factory()->create();
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
$newLead = UserLead::where('email', 'new@example.com')->first();
expect($newLead->referred_by_id)->toBe($referrer->id);
});
test('invalid referrer code is silently ignored', function () {
$response = $this->post(route('user-leads.store'), [
'email' => 'test@example.com',
'referrer_code' => 'BADCODE1',
]);
$lead = UserLead::where('email', 'test@example.com')->first();
expect($lead)->not->toBeNull();
expect($lead->referred_by_id)->toBeNull();
Mail::assertQueued(WaitlistWelcome::class);
Mail::assertNotQueued(WaitlistReferralNotification::class);
});
test('user lead cannot be created with duplicate email', function () {
UserLead::factory()->create(['email' => 'test@example.com']);
$response = $this->post(route('user-leads.store'), [
'email' => 'test@example.com',
]);
$response->assertSessionHasErrors('email');
});
test('user lead requires valid email', function () {
$response = $this->post(route('user-leads.store'), [
'email' => 'invalid-email',
]);
$response->assertSessionHasErrors('email');
});
test('thank you page shows position and referral url', function () {
$lead = UserLead::factory()->create([
'position' => 500,
'referral_code' => 'TESTCODE',
]);
$response = $this->withoutVite()->get(route('waitlist.thank-you', $lead));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('waitlist/thank-you')
->where('position', 500)
->where('referralUrl', fn ($url) => str_contains($url, '?ref=TESTCODE'))
);
});
test('user lead stores the locale submitted with the form', function () {
$this->post(route('user-leads.store'), [
'email' => 'test@example.com',
'locale' => 'es',
]);
$lead = UserLead::where('email', 'test@example.com')->first();
expect($lead->locale)->toBe('es');
});
test('user lead defaults to app locale when no locale is submitted', function () {
$this->post(route('user-leads.store'), [
'email' => 'test@example.com',
]);
$lead = UserLead::where('email', 'test@example.com')->first();
expect($lead->locale)->toBe(app()->getLocale());
});
test('overtaken email is sent using the overtaken lead locale', function () {
$referrer = UserLead::factory()->create(['position' => 520]);
$between = UserLead::factory()->create(['position' => 515, 'locale' => 'es']);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
Mail::assertQueued(WaitlistOvertaken::class, function (WaitlistOvertaken $mail) use ($between) {
return $mail->hasTo($between->email) && $mail->locale === 'es';
});
});
test('overtaken leads are pushed back one position when referrer jumps forward', function () {
$referrer = UserLead::factory()->create(['position' => 520]);
$between1 = UserLead::factory()->create(['position' => 511]);
$between2 = UserLead::factory()->create(['position' => 515]);
$outsideRange = UserLead::factory()->create(['position' => 525]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
expect($between1->fresh()->position)->toBe(512);
expect($between2->fresh()->position)->toBe(516);
expect($outsideRange->fresh()->position)->toBe(525);
});
test('overtaken leads receive the overtaken email', function () {
$referrer = UserLead::factory()->create(['position' => 520]);
$between = UserLead::factory()->create(['position' => 515]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
Mail::assertQueued(WaitlistOvertaken::class, function (WaitlistOvertaken $mail) use ($between) {
return $mail->hasTo($between->email);
});
});
test('referrer does not receive the overtaken email', function () {
$referrer = UserLead::factory()->create(['position' => 520]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
Mail::assertNotQueued(WaitlistOvertaken::class, function (WaitlistOvertaken $mail) use ($referrer) {
return $mail->hasTo($referrer->email);
});
});
test('no overtaken emails when referrer is alone in their range', function () {
$referrer = UserLead::factory()->create(['position' => 520]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
Mail::assertNotQueued(WaitlistOvertaken::class);
});
test('clamped referrer only pushes back leads within the actual range', function () {
$referrer = UserLead::factory()->create(['position' => 5]);
$withinRange = UserLead::factory()->create(['position' => 3]);
$atOne = UserLead::factory()->create(['position' => 1]);
$this->post(route('user-leads.store'), [
'email' => 'new@example.com',
'referrer_code' => $referrer->referral_code,
]);
// Referrer clamps to 1, overtaken range is positions 14
expect($referrer->fresh()->position)->toBe(1);
expect($withinRange->fresh()->position)->toBe(4);
expect($atOne->fresh()->position)->toBe(2);
});