@@ -7,7 +7,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
77import type { AgentGroupItem } from '@/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/agent-group-view'
88import {
99 BrowserAgentIcon ,
10- getBrowserAgentHostname ,
10+ getBrowserAgentFaviconUrl ,
1111} from '@/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/browser-agent-icon'
1212import type { ToolCallData } from '@/app/workspace/[workspaceId]/home/types'
1313
@@ -25,53 +25,72 @@ function tool(overrides: Partial<ToolCallData> = {}): AgentGroupItem {
2525 }
2626}
2727
28- describe ( 'getBrowserAgentHostname' , ( ) => {
28+ describe ( 'getBrowserAgentFaviconUrl' , ( ) => {
29+ it ( 'keeps the observed origin and port without disclosing page details' , ( ) => {
30+ expect (
31+ getBrowserAgentFaviconUrl ( [
32+ tool ( {
33+ result : {
34+ success : true ,
35+ output : {
36+ url : 'https://username:password@example.com:8443/document?token=private#part' ,
37+ } ,
38+ } ,
39+ } ) ,
40+ ] )
41+ ) . toBe ( 'https://example.com:8443/favicon.ico' )
42+ } )
43+
2944 it ( 'uses the pending destination, then the observed redirect, and retains it during editing' , ( ) => {
3045 const navigating = tool ( {
3146 status : 'executing' ,
3247 params : { url : 'https://example.org/start' } ,
3348 result : undefined ,
3449 } )
35- expect ( getBrowserAgentHostname ( [ tool ( ) , navigating ] ) ) . toBe ( 'example.org' )
50+ expect ( getBrowserAgentFaviconUrl ( [ tool ( ) , navigating ] ) ) . toBe ( 'https:// example.org/favicon.ico ' )
3651 const redirected = tool ( { params : { url : 'https://example.org/start' } } )
37- expect ( getBrowserAgentHostname ( [ redirected ] ) ) . toBe ( 'example.com' )
52+ expect ( getBrowserAgentFaviconUrl ( [ redirected ] ) ) . toBe ( 'https:// example.com/favicon.ico ' )
3853 expect (
39- getBrowserAgentHostname ( [
54+ getBrowserAgentFaviconUrl ( [
4055 redirected ,
4156 tool ( { toolName : 'browser_type' , status : 'executing' , result : undefined } ) ,
4257 ] )
43- ) . toBe ( 'example.com' )
58+ ) . toBe ( 'https:// example.com/favicon.ico ' )
4459 } )
4560
4661 it . each ( [ 'error' , 'cancelled' , 'rejected' , 'awaiting_approval' ] as const ) (
4762 'does not adopt a destination from a %s tool' ,
4863 ( status ) => {
4964 expect (
50- getBrowserAgentHostname ( [
65+ getBrowserAgentFaviconUrl ( [
5166 tool ( ) ,
5267 tool ( { status, params : { url : 'https://example.org' } , result : undefined } ) ,
5368 ] )
54- ) . toBe ( 'example.com' )
69+ ) . toBe ( 'https:// example.com/favicon.ico ' )
5570 }
5671 )
5772
58- it . each ( [ '' , 'about:blank' , 'file:///document' , 'data:text/html,hello' , 'not a URL' ] ) (
59- 'clears the previous site for a page without an HTTP hostname: %s' ,
60- ( url ) => {
61- expect (
62- getBrowserAgentHostname ( [
63- tool ( ) ,
64- tool ( { toolName : 'browser_switch_tab' , result : { success : true , output : { url } } } ) ,
65- ] )
66- ) . toBeNull ( )
67- }
68- )
73+ it . each ( [
74+ '' ,
75+ 'about:blank' ,
76+ 'http://example.com' ,
77+ 'file:///document' ,
78+ 'data:text/html,hello' ,
79+ 'not a URL' ,
80+ ] ) ( 'clears the previous site when the page cannot supply an allowed favicon: %s' , ( url ) => {
81+ expect (
82+ getBrowserAgentFaviconUrl ( [
83+ tool ( ) ,
84+ tool ( { toolName : 'browser_switch_tab' , result : { success : true , output : { url } } } ) ,
85+ ] )
86+ ) . toBeNull ( )
87+ } )
6988
7089 it . each ( [ 'browser_open_tab' , 'browser_switch_tab' , 'browser_close_tab' , 'browser_go_back' ] ) (
7190 'clears an obsolete site while %s has no known destination' ,
7291 ( toolName ) => {
7392 expect (
74- getBrowserAgentHostname ( [
93+ getBrowserAgentFaviconUrl ( [
7594 tool ( ) ,
7695 tool ( { toolName, status : 'executing' , result : undefined } ) ,
7796 ] )
@@ -89,13 +108,13 @@ describe('getBrowserAgentHostname', () => {
89108 { tabs, activeTabId : 'agent' } ,
90109 ] ) {
91110 expect (
92- getBrowserAgentHostname ( [
111+ getBrowserAgentFaviconUrl ( [
93112 tool ( { toolName : 'browser_list_tabs' , result : { success : true , output } } ) ,
94113 ] )
95- ) . toBe ( 'example.com' )
114+ ) . toBe ( 'https:// example.com/favicon.ico ' )
96115 }
97116 expect (
98- getBrowserAgentHostname ( [
117+ getBrowserAgentFaviconUrl ( [
99118 tool ( ) ,
100119 tool ( {
101120 toolName : 'browser_list_tabs' ,
@@ -118,14 +137,14 @@ describe('getBrowserAgentHostname', () => {
118137 [ 'browser_extract' , { page : { url : 'https://example.org' } } ] ,
119138 ] as const ) {
120139 expect (
121- getBrowserAgentHostname ( [ tool ( ) , tool ( { toolName, result : { success : true , output } } ) ] )
122- ) . toBe ( 'example.org' )
140+ getBrowserAgentFaviconUrl ( [ tool ( ) , tool ( { toolName, result : { success : true , output } } ) ] )
141+ ) . toBe ( 'https:// example.org/favicon.ico ' )
123142 }
124143 } )
125144
126145 it ( 'clears a stale site when an action navigated without reporting its destination' , ( ) => {
127146 expect (
128- getBrowserAgentHostname ( [
147+ getBrowserAgentFaviconUrl ( [
129148 tool ( ) ,
130149 tool ( {
131150 toolName : 'browser_click' ,
@@ -137,7 +156,7 @@ describe('getBrowserAgentHostname', () => {
137156
138157 it ( 'ignores URLs from other tools and nested agent runs' , ( ) => {
139158 expect (
140- getBrowserAgentHostname ( [
159+ getBrowserAgentFaviconUrl ( [
141160 tool ( ) ,
142161 tool ( {
143162 toolName : 'browser_read_text' ,
@@ -160,7 +179,7 @@ describe('getBrowserAgentHostname', () => {
160179 } ,
161180 } ,
162181 ] )
163- ) . toBe ( 'example.com' )
182+ ) . toBe ( 'https:// example.com/favicon.ico ' )
164183 } )
165184} )
166185
@@ -184,10 +203,11 @@ describe('BrowserAgentIcon', () => {
184203 )
185204 }
186205
187- it ( 'keeps the globe until load and resets image state when the hostname changes' , ( ) => {
188- render ( 'https://example.com/document?token=private#section' )
206+ it ( 'keeps the globe until load and resets image state when the page origin changes' , ( ) => {
207+ render ( 'https://username:password@ example.com/document?token=private#section' )
189208 const firstImage = container . querySelector ( 'img' ) !
190- expect ( firstImage . src ) . toBe ( 'https://www.google.com/s2/favicons?domain=example.com&sz=32' )
209+ expect ( firstImage . src ) . toBe ( 'https://example.com/favicon.ico' )
210+ expect ( firstImage . getAttribute ( 'referrerpolicy' ) ) . toBe ( 'no-referrer' )
191211 expect ( container . querySelector ( 'svg' ) ) . not . toBeNull ( )
192212 act ( ( ) => firstImage . dispatchEvent ( new Event ( 'load' ) ) )
193213 expect ( container . querySelector ( 'svg' ) ) . toBeNull ( )
0 commit comments