11import type { DevframeDockEntry } from '@devframes/hub'
22import type { DevframeRpcClient } from '@devframes/hub/client'
3+ import type { } from '@devframes/json-render/hub'
34import type { SharedState } from 'devframe/utils/shared-state'
5+ import { DEVFRAME_EVENTS } from 'devframe/constants'
46import { createEventEmitter } from 'devframe/utils/events'
57import { createSharedState } from 'devframe/utils/shared-state'
68import { afterEach , describe , expect , it , vi } from 'vitest'
@@ -52,6 +54,7 @@ afterEach(() => {
5254
5355describe ( 'dock client scripts' , ( ) => {
5456 it ( 'retries setup on a later activation after it fails' , async ( ) => {
57+ expect . assertions ( 3 )
5558 vi . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } )
5659 let attempts = 0
5760 globalThis . __DEVFRAME_CLIENT_SCRIPT_ATTEMPT__ = ( ) => {
@@ -63,11 +66,10 @@ describe('dock client scripts', () => {
6366 const context = await createDocksContext ( 'embedded' , rpc )
6467 const entry = {
6568 id : 'retry-client-script' ,
66- type : 'iframe ' ,
69+ type : 'custom-render ' ,
6770 title : 'Retry client script' ,
6871 icon : 'ph:play' ,
69- url : '/retry' ,
70- clientScript : {
72+ renderer : {
7173 importFrom : 'data:text/javascript,export default () => globalThis.__DEVFRAME_CLIENT_SCRIPT_ATTEMPT__()' ,
7274 } ,
7375 } satisfies DevframeDockEntry
@@ -81,3 +83,75 @@ describe('dock client scripts', () => {
8183 expect ( attempts ) . toBe ( 2 )
8284 } )
8385} )
86+
87+ it . each ( [ 'iframe' , 'json-render' ] as const ) ( 'starts a %s page script before dock activation, once per RPC client' , async ( type ) => {
88+ expect . assertions ( 3 )
89+ let attempts = 0
90+ globalThis . __DEVFRAME_CLIENT_SCRIPT_ATTEMPT__ = ( ) => {
91+ attempts ++
92+ }
93+ const { rpc, sharedStates } = createStubRpc ( )
94+ const context = await createDocksContext ( 'embedded' , rpc )
95+ const clientScript = { importFrom : 'data:text/javascript,export default () => globalThis.__DEVFRAME_CLIENT_SCRIPT_ATTEMPT__()' }
96+ const entry = { id : `background-${ type } ` , type, title : 'Background page script' , icon : 'ph:browser' , url : '/fixture' , view : { stateKey : 'fixture:view' } , clientScript } satisfies DevframeDockEntry
97+ sharedStates . get ( 'devframe:docks' ) ! . push ( [ entry ] )
98+ await expect . poll ( ( ) => attempts ) . toBe ( 1 )
99+ expect ( context . docks . selectedId ) . toBeNull ( )
100+ await context . docks . switchEntry ( entry . id )
101+ expect ( attempts ) . toBe ( 1 )
102+ } )
103+
104+ it ( 'waits for trust and keeps the same dock script bound separately to each RPC client' , async ( ) => {
105+ expect . assertions ( 4 )
106+ let attempts = 0
107+ globalThis . __DEVFRAME_CLIENT_SCRIPT_ATTEMPT__ = ( ) => {
108+ attempts ++
109+ }
110+ const first = createStubRpc ( )
111+ const second = createStubRpc ( )
112+ Object . assign ( first . rpc , { isTrusted : false } )
113+ await createDocksContext ( 'embedded' , first . rpc )
114+ await createDocksContext ( 'embedded' , second . rpc )
115+ const entry = {
116+ id : 'per-rpc-page-script' ,
117+ type : 'iframe' ,
118+ title : 'Page commands' ,
119+ icon : 'ph:browser' ,
120+ url : '/fixture' ,
121+ clientScript : { importFrom : 'data:text/javascript,export default () => globalThis.__DEVFRAME_CLIENT_SCRIPT_ATTEMPT__()' } ,
122+ } satisfies DevframeDockEntry
123+ first . sharedStates . get ( 'devframe:docks' ) ! . push ( [ entry ] )
124+ await nextTick ( )
125+ expect ( attempts ) . toBe ( 0 )
126+ second . sharedStates . get ( 'devframe:docks' ) ! . push ( [ entry ] )
127+ await expect . poll ( ( ) => attempts ) . toBe ( 1 )
128+ Object . assign ( first . rpc , { isTrusted : true } )
129+ first . rpc . events . emit ( DEVFRAME_EVENTS . client . isTrustedUpdated , true )
130+ await expect . poll ( ( ) => attempts ) . toBe ( 2 )
131+ first . sharedStates . get ( 'devframe:docks' ) ! . push ( [ { ...entry } ] )
132+ second . sharedStates . get ( 'devframe:docks' ) ! . push ( [ { ...entry } ] )
133+ await nextTick ( )
134+ expect ( attempts ) . toBe ( 2 )
135+ } )
136+
137+ it ( 'does not invoke action docks while initializing page scripts' , async ( ) => {
138+ expect . assertions ( 2 )
139+ let attempts = 0
140+ globalThis . __DEVFRAME_CLIENT_SCRIPT_ATTEMPT__ = ( ) => {
141+ attempts ++
142+ }
143+ const { rpc, sharedStates } = createStubRpc ( )
144+ const context = await createDocksContext ( 'embedded' , rpc )
145+ const entry = {
146+ id : 'explicit-action-script' ,
147+ type : 'action' ,
148+ title : 'Explicit action' ,
149+ icon : 'ph:play' ,
150+ action : { importFrom : 'data:text/javascript,export default () => globalThis.__DEVFRAME_CLIENT_SCRIPT_ATTEMPT__()' } ,
151+ } satisfies DevframeDockEntry
152+ sharedStates . get ( 'devframe:docks' ) ! . push ( [ entry ] )
153+ await nextTick ( )
154+ expect ( attempts ) . toBe ( 0 )
155+ await context . docks . switchEntry ( entry . id )
156+ expect ( attempts ) . toBe ( 1 )
157+ } )
0 commit comments