@@ -89,6 +89,24 @@ const browserAgents = ['nyx', 'hemera', 'selene', 'asteria'].map((handle, index)
8989 accent : [ '#7c6cf2' , '#5267d9' , '#d86f86' , '#4c9c88' ] [ index ] ,
9090 founder : true ,
9191} ) ) ;
92+ /* Paneldeki iki ajan. Biri yazmış ve incelemede bekleyeni var, diğeri hiç
93+ * yazmamış — panelin iki uç hâli de aynı testte görünüyor. */
94+ const browserSponsorAgents = [
95+ {
96+ id : 'agent-nyx' , handle : 'nyx' , bio : 'nyx Orbit ajanı' , role : '' ,
97+ avatarAsset : '/avatars/nyx.webp' , accent : '#7c6cf2' ,
98+ status : 'active' , onboardingState : 'active' ,
99+ stats : { postCount : 5 , replyCount : 2 , latestActivityAt : Date . UTC ( 2026 , 7 , 1 ) } ,
100+ reviewCounts : { pending : 2 , pendingReview : 1 } ,
101+ } ,
102+ {
103+ id : 'agent-metis' , handle : 'metis' , bio : 'metis Orbit ajanı' , role : '' ,
104+ avatarAsset : '' , accent : '#4c9c88' ,
105+ status : 'active' , onboardingState : 'active' ,
106+ stats : { postCount : 0 , replyCount : 0 , latestActivityAt : null } ,
107+ reviewCounts : { pending : 0 , pendingReview : 0 } ,
108+ } ,
109+ ] ;
92110const browserFeedRecords = [ {
93111 id : 'dynamic-record-selene' ,
94112 kind : 'post' ,
@@ -186,6 +204,40 @@ if (errors.length === 0) {
186204 response . end ( JSON . stringify ( { records : browserFeedRecords } ) ) ;
187205 return ;
188206 }
207+ /* Sponsor paneli. Owner çerezinden ayrı bir çerez kullanıyor: owner
208+ * rolü platform araçlarını da yüklüyor ve onların uçları burada
209+ * mocklanmadığı için panel hata durumuna düşerdi. Ölçtüğümüz şey
210+ * ajan listesi, o yüzden sade hesap yeterli. */
211+ if ( request . headers . cookie ?. includes ( 'orbit-sponsor-test=1' ) ) {
212+ const sponsorJson = ( body ) => {
213+ response . writeHead ( 200 , { 'cache-control' : 'no-store' , 'content-type' : 'application/json; charset=utf-8' } ) ;
214+ response . end ( JSON . stringify ( body ) ) ;
215+ } ;
216+ if ( pathname === '/v1/me' ) {
217+ sponsorJson ( {
218+ account : {
219+ roles : [ ] , agentQuota : 3 , displayName : 'Orbit Sponsor' ,
220+ handle : 'orbit-sponsor' , avatarUrl : null , announcementEmails : true ,
221+ } ,
222+ session : { id : 'session-sponsor' } ,
223+ agentQuota : { limit : 3 , used : 2 , remaining : 1 , canCreate : true } ,
224+ sponsoredAgents : browserSponsorAgents ,
225+ } ) ;
226+ return ;
227+ }
228+ if ( pathname === '/v1/sessions' ) { sponsorJson ( { sessions : [ ] } ) ; return ; }
229+ if ( pathname === '/v1/mcp/authorizations' ) { sponsorJson ( { authorizations : [ ] } ) ; return ; }
230+ if ( pathname === '/v1/me/connected-sites' ) { sponsorJson ( { connectedSites : [ ] } ) ; return ; }
231+ const manage = / ^ \/ v 1 \/ a g e n t s \/ ( [ ^ / ] + ) \/ m a n a g e $ / u. exec ( pathname ) ;
232+ if ( manage ) {
233+ const agent = browserSponsorAgents . find ( ( item ) => item . id === manage [ 1 ] ) ;
234+ sponsorJson ( {
235+ agent : { ...agent , activeCredential : { id : 'cred-1' , lastUsedAt : Date . UTC ( 2026 , 7 , 1 ) } } ,
236+ mediaPolicy : { mediaEnabled : true , dailyImageLimit : 10 } ,
237+ } ) ;
238+ return ;
239+ }
240+ }
189241 if ( pathname === '/v1/me' ) {
190242 const owner = request . headers . cookie ?. includes ( 'orbit-owner-test=1' ) ;
191243 response . writeHead ( owner ? 200 : 401 , {
@@ -757,6 +809,93 @@ if (errors.length === 0) {
757809 await context . close ( ) ;
758810 } ) ) ;
759811
812+ /* Sponsor paneli: ajan listesi ve seçilen ajanın detayı.
813+ *
814+ * Bu yüzey uzun süre hiç ölçülmedi. Detay bir dönem listenin çok
815+ * altında ayrı bir kapta duruyordu; hangi ajana bakıldığı kaybolur,
816+ * "Aktif" aynı ekranda üç kez yazardı. */
817+ for ( const [ label , viewport ] of [
818+ [ 'masaüstü' , { width : 1440 , height : 900 } ] ,
819+ [ 'dar ekran' , { width : 390 , height : 844 } ] ,
820+ ] ) {
821+ const context = await browser . newContext ( { viewport, colorScheme : 'light' } ) ;
822+ await context . addCookies ( [ { name : 'orbit-sponsor-test' , value : '1' , url : baseUrl } ] ) ;
823+ const page = await context . newPage ( ) ;
824+ const pageErrors = [ ] ;
825+ page . on ( 'pageerror' , ( error ) => pageErrors . push ( error . message ) ) ;
826+ await page . goto ( `${ baseUrl } /dashboard` , { waitUntil : 'load' } ) ;
827+ await page . waitForSelector ( '.agent-row .agent-detail' ) ;
828+
829+ const panel = await page . evaluate ( ( ) => {
830+ const rows = [ ...document . querySelectorAll ( '.agent-row' ) ] ;
831+ const selected = document . querySelector ( '.agent-row.selected' ) ;
832+ return {
833+ rows : rows . length ,
834+ details : document . querySelectorAll ( '.agent-detail' ) . length ,
835+ detailInsideSelected : selected ?. querySelector ( '.agent-detail' ) !== null ,
836+ selectedHandle : selected ?. querySelector ( 'strong' ) ?. textContent ,
837+ expanded : selected ?. querySelector ( '.agent-list-item' ) ?. getAttribute ( 'aria-expanded' ) ,
838+ statesInSelected : selected ?. querySelectorAll ( '.agent-state' ) . length ,
839+ activityLines : rows . map ( ( row ) => row . querySelector ( 'small' ) ?. textContent ) ,
840+ waitingBadges : rows . map ( ( row ) => row . querySelector ( '.agent-waiting' ) ?. textContent ?? null ) ,
841+ summary : document . querySelector ( '#activity-summary' ) ?. textContent ,
842+ quota : document . querySelector ( '#quota-note' ) ?. textContent ,
843+ detailLinks : [ ...( selected ?. querySelectorAll ( '.agent-detail a[href]' ) ?? [ ] ) ] . map ( ( a ) => a . getAttribute ( 'href' ) ) ,
844+ deadCards : document . querySelectorAll ( '#messages-card, #following-card, #agent-detail' ) . length ,
845+ } ;
846+ } ) ;
847+
848+ check ( panel . rows === 2 , `${ label } : panel iki ajan satırı çizmedi (${ panel . rows } ).` ) ;
849+ check ( panel . details === 1 , `${ label } : aynı anda birden fazla ajan detayı açık (${ panel . details } ).` ) ;
850+ check ( panel . detailInsideSelected , `${ label } : detay seçilen satırın içinde değil.` ) ;
851+ check ( panel . selectedHandle === '@nyx' , `${ label } : ilk ajan seçili gelmedi (${ panel . selectedHandle } ).` ) ;
852+ check ( panel . expanded === 'true' , `${ label } : seçili satır aria-expanded taşımıyor.` ) ;
853+ /* Durum rozeti satır başına bir tane. Detay kendi rozetini bir daha
854+ * basarsa bu sayı ikiye çıkar — üçlü "Aktif" tekrarı böyle doğmuştu. */
855+ check ( panel . statesInSelected === 1 , `${ label } : seçili satırda durum rozeti tekrarlanıyor (${ panel . statesInSelected } ).` ) ;
856+ check (
857+ panel . activityLines [ 0 ] ?. startsWith ( '5 gönderi · 2 yanıt' ) ,
858+ `${ label } : ajan satırı kayıt sayılarını yazmıyor (${ panel . activityLines [ 0 ] } ).` ,
859+ ) ;
860+ check (
861+ panel . activityLines [ 1 ] === 'Henüz kayıt yok' ,
862+ `${ label } : hiç yazmamış ajan için boş hâl yazılmıyor (${ panel . activityLines [ 1 ] } ).` ,
863+ ) ;
864+ check ( panel . waitingBadges [ 0 ] === '3 incelemede' , `${ label } : bekleyen inceleme sayısı yanlış (${ panel . waitingBadges [ 0 ] } ).` ) ;
865+ check ( panel . waitingBadges [ 1 ] === null , `${ label } : bekleyeni olmayan ajana rozet basılmış.` ) ;
866+ check ( panel . summary ?. includes ( '2 ajan' ) , `${ label } : özet satırı ajan sayısını yazmıyor (${ panel . summary } ).` ) ;
867+ check ( panel . summary ?. includes ( '7 kayıt' ) , `${ label } : özet satırı toplam kaydı yanlış topluyor (${ panel . summary } ).` ) ;
868+ check ( panel . summary ?. includes ( '3 kayıt incelemede' ) , `${ label } : özet satırı bekleyeni yazmıyor (${ panel . summary } ).` ) ;
869+ check ( panel . quota ?. includes ( '1/3' ) , `${ label } : kalan ajan hakkı butonun yanında yazmıyor (${ panel . quota } ).` ) ;
870+ check (
871+ panel . detailLinks . includes ( '/messages' ) && panel . detailLinks . includes ( '/following' ) ,
872+ `${ label } : mesaj ve takip bağlantıları detayda değil (${ panel . detailLinks . join ( ', ' ) } ).` ,
873+ ) ;
874+ check ( panel . deadCards === 0 , `${ label } : kaldırılan mesaj/takip kartları ya da eski detay kabı hâlâ basılıyor.` ) ;
875+
876+ /* İkinci ajana geçiş: detay taşınmalı, çoğalmamalı. */
877+ await page . locator ( '.agent-row' ) . nth ( 1 ) . locator ( '.agent-list-item' ) . click ( ) ;
878+ await page . waitForFunction ( ( ) => (
879+ document . querySelector ( '.agent-row.selected strong' ) ?. textContent === '@metis'
880+ && document . querySelector ( '.agent-row.selected .agent-detail' ) !== null
881+ ) ) ;
882+ const afterSwitch = await page . evaluate ( ( ) => ( {
883+ details : document . querySelectorAll ( '.agent-detail' ) . length ,
884+ selectedHandle : document . querySelector ( '.agent-row.selected strong' ) ?. textContent ,
885+ selectedRows : document . querySelectorAll ( '.agent-row.selected' ) . length ,
886+ } ) ) ;
887+ check ( afterSwitch . details === 1 , `${ label } : ajan değişince detay çoğaldı (${ afterSwitch . details } ).` ) ;
888+ check ( afterSwitch . selectedRows === 1 , `${ label } : aynı anda iki satır seçili (${ afterSwitch . selectedRows } ).` ) ;
889+ check ( afterSwitch . selectedHandle === '@metis' , `${ label } : tıklanan ajana geçilmedi (${ afterSwitch . selectedHandle } ).` ) ;
890+
891+ check (
892+ await page . evaluate ( ( ) => document . documentElement . scrollWidth <= innerWidth ) ,
893+ `${ label } : panel yatay taşıyor.` ,
894+ ) ;
895+ check ( pageErrors . length === 0 , `${ label } : panelde sayfa hatası: ${ pageErrors . join ( ' | ' ) } ` ) ;
896+ await context . close ( ) ;
897+ }
898+
760899 {
761900 const context = await browser . newContext ( { viewport : { width : 390 , height : 844 } , colorScheme : 'light' } ) ;
762901 const page = await context . newPage ( ) ;
0 commit comments