(string) Str::uuid(), 'name' => 'Test', 'email' => 'test+'.uniqid().'@example.com', ]); } public function test_redirect_records_device_browser_os_and_country(): void { config(['link.geoip_database' => base_path('tests/fixtures/GeoLite2-Country-Test.mmdb')]); $user = $this->user(); ShortLink::create([ 'user_id' => $user->id, 'slug' => 'tracked', 'source_app' => 'link', 'source_kind' => 'redirect', 'is_managed_here' => true, 'destination_url' => 'https://example.com/target', 'is_active' => true, ]); $this->withHeaders([ 'User-Agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1', 'CF-IPCountry' => 'GH', ])->get('https://ladl.link/tracked') ->assertRedirect('https://example.com/target'); $click = LinkClick::first(); $this->assertNotNull($click); $this->assertSame('mobile', $click->device_type); $this->assertSame('Safari', $click->browser); $this->assertSame('iOS', $click->os); $this->assertSame('GH', $click->country); } public function test_redirect_records_country_from_ip_when_proxy_header_missing(): void { config(['link.geoip_database' => base_path('tests/fixtures/GeoLite2-Country-Test.mmdb')]); $user = $this->user(); ShortLink::create([ 'user_id' => $user->id, 'slug' => 'geo-ip', 'source_app' => 'link', 'source_kind' => 'redirect', 'is_managed_here' => true, 'destination_url' => 'https://example.com/target', 'is_active' => true, ]); $this->withServerVariables(['REMOTE_ADDR' => '81.2.69.142']) ->withHeaders([ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', ])->get('https://ladl.link/geo-ip') ->assertRedirect('https://example.com/target'); $this->assertSame('GB', LinkClick::first()?->country); } public function test_breakdown_for_link_groups_clicks_by_device(): void { $user = $this->user(); $link = ShortLink::create([ 'user_id' => $user->id, 'slug' => 'breakdown', 'source_app' => 'link', 'source_kind' => 'redirect', 'is_managed_here' => true, 'destination_url' => 'https://example.com', 'is_active' => true, 'clicks_total' => 2, 'unique_clicks_total' => 2, ]); LinkClick::create([ 'short_link_id' => $link->id, 'ip_hash' => 'a', 'device_type' => 'mobile', 'browser' => 'Chrome', 'os' => 'Android', 'country' => 'GH', 'is_unique' => true, 'clicked_at' => now(), ]); LinkClick::create([ 'short_link_id' => $link->id, 'ip_hash' => 'b', 'device_type' => 'desktop', 'browser' => 'Chrome', 'os' => 'Windows', 'country' => 'US', 'is_unique' => true, 'clicked_at' => now(), ]); $devices = app(LinkAnalyticsService::class)->breakdownForLink($link, 'device_type'); $this->assertCount(2, $devices); $labels = array_column($devices, 'label'); $this->assertContains('Mobile', $labels); $this->assertContains('Desktop', $labels); } }