get('/submit'); $response->assertStatus(200); $response->assertSeeLivewire('url-submission-form'); } // ------------------------------------------------------------------------- // Test 2 — valid submission creates a page row as Discovered // ------------------------------------------------------------------------- public function test_valid_url_submission_creates_page_as_discovered(): void { Livewire::test(UrlSubmissionForm::class) ->set('url', 'https://example.com/interesting-post') ->call('submit') ->assertHasNoErrors(); $this->assertDatabaseHas('pages', [ 'url' => 'https://example.com/interesting-post', 'status' => PageStatusEnum::Discovered, 'instance_id' => null, ]); } // ------------------------------------------------------------------------- // Test 3 — duplicate submission is idempotent (no second row created) // ------------------------------------------------------------------------- public function test_duplicate_url_submission_does_not_create_second_page(): void { $url = 'https://example.com/seen-before'; Page::factory()->create([ 'url' => $url, 'status' => PageStatusEnum::Discovered, ]); Livewire::test(UrlSubmissionForm::class) ->set('url', $url) ->call('submit') ->assertHasNoErrors(); $this->assertDatabaseCount('pages', 1); } // ------------------------------------------------------------------------- // Test 4 — confirmation state echoes submitted URL // ------------------------------------------------------------------------- public function test_confirmation_state_echoes_submitted_url(): void { $url = 'https://example.com/great-article'; Livewire::test(UrlSubmissionForm::class) ->set('url', $url) ->call('submit') ->assertHasNoErrors() ->assertSet('confirmedUrl', $url) ->assertSet('url', '') ->assertSee($url); } // ------------------------------------------------------------------------- // Test 5 — empty URL fails validation (regression lock) // ------------------------------------------------------------------------- public function test_missing_url_fails_validation(): void { Livewire::test(UrlSubmissionForm::class) ->set('url', '') ->call('submit') ->assertHasErrors(['url' => 'required']); } // ------------------------------------------------------------------------- // Test 6 — invalid URL formats fail validation // ------------------------------------------------------------------------- #[DataProvider('invalidUrls')] public function test_invalid_url_formats_fail_validation(string $url): void { Livewire::test(UrlSubmissionForm::class) ->set('url', $url) ->call('submit') ->assertHasErrors('url'); } public static function invalidUrls(): array { return [ 'no scheme' => ['not-a-url'], 'disallowed scheme' => ['ftp://example.com'], 'javascript scheme' => ['javascript:alert(1)'], ]; } // ------------------------------------------------------------------------- // Test 7 — rate limit blocks the 11th submission within a minute // ------------------------------------------------------------------------- public function test_rate_limit_blocks_eleventh_submission_within_a_minute(): void { // 10 submissions within the limit — each must succeed for ($i = 1; $i <= 10; $i++) { Livewire::test(UrlSubmissionForm::class) ->set('url', "https://example.com/post-{$i}") ->call('submit') ->assertHasNoErrors(); } // 11th submission from the same IP must be blocked, with the message visible Livewire::test(UrlSubmissionForm::class) ->set('url', 'https://example.com/post-11') ->call('submit') ->assertHasErrors('rate_limit') ->assertSee('Too many submissions'); // The 11th URL must NOT have been persisted $this->assertDatabaseCount('pages', 10); } }