getJson(route('scraper.search', ['query' => 'mario'])) ->assertRedirect(); } public function test_search_validates_query(): void { $user = User::factory()->create(); $this->actingAs($user) ->getJson(route('scraper.search', ['query' => ''])) ->assertSessionHasErrors('query'); } public function test_search_validates_min_query_length(): void { $user = User::factory()->create(); $this->actingAs($user) ->getJson(route('scraper.search', ['query' => 'a'])) ->assertSessionHasErrors('query'); } public function test_search_returns_results(): void { $user = User::factory()->create(); Http::fake([ 'https://id.twitch.tv/oauth2/token' => Http::response(['access_token' => 'fake-token']), 'https://api.igdb.com/v4/games' => Http::response([ [ 'id' => 1, 'name' => 'Super Mario Bros', 'cover' => null, 'release_dates' => [], ], ]), ]); config([ 'services.igdb.client_id' => 'test-id', 'services.igdb.client_secret' => 'test-secret', ]); $this->actingAs($user) ->getJson(route('scraper.search', ['query' => 'mario'])) ->assertOk() ->assertJsonCount(1, 'results'); } public function test_apply_requires_authentication(): void { $this->post(route('scraper.apply', 'some-game')) ->assertRedirect(route('login')); } public function test_apply_validates_cover_url(): void { $user = User::factory()->create(); $game = Game::factory()->create(); $this->actingAs($user) ->post(route('scraper.apply', $game->slug), []) ->assertSessionHasErrors('cover_url'); } public function test_apply_downloads_and_updates_cover(): void { Storage::fake('local'); $user = User::factory()->create(); $game = Game::factory()->create(); $game->load('console'); Http::fake([ 'https://example.com/cover.jpg' => Http::response('image-data'), ]); $this->actingAs($user) ->post(route('scraper.apply', $game->slug), [ 'cover_url' => 'https://example.com/cover.jpg', ]) ->assertRedirect(); $game->refresh(); $this->assertNotNull($game->cover_path); } }