@@ -325,6 +325,77 @@ describe('in-page channel over bring-your-own ports', () => {
325325} )
326326
327327describe ( 'in-page channel shared state' , ( ) => {
328+ it . each ( [ 'patch' , 'full state' ] as const ) ( 'round-trips %s updates through both endpoint codecs' , async ( mode ) => {
329+ function codec ( sender : string , receiver : string ) {
330+ return {
331+ serialize : vi . fn ( value => ( { encodedBy : sender , value } ) ) ,
332+ deserialize : vi . fn ( ( wire : unknown ) => {
333+ expect ( wire ) . toHaveProperty ( 'encodedBy' , receiver )
334+ return ( wire as { value : unknown } ) . value
335+ } ) ,
336+ }
337+ }
338+ const pageCodec = codec ( 'page-script' , 'panel' )
339+ const panelCodec = codec ( 'panel' , 'page-script' )
340+ const { pageScript, panel, dispose } = createLinkedPair ( { pageScript : pageCodec , panel : panelCodec } )
341+ try {
342+ const authority = await pageScript . sharedState . get ( 'doc' , { initialValue : { count : 1 } } )
343+ const mirror = await panel . sharedState . get ( 'doc' )
344+ expect ( mirror . value ( ) ) . toEqual ( { count : 1 } )
345+ expect ( pageCodec . serialize ) . toHaveBeenCalledWith ( { count : 1 } )
346+ expect ( panelCodec . serialize . mock . calls [ 0 ] ?. [ 0 ] ) . toBe ( 'doc' )
347+
348+ function update ( state : typeof authority , count : number ) {
349+ if ( mode === 'patch' ) {
350+ state . mutate ( ( draft ) => {
351+ draft . count = count
352+ } )
353+ }
354+ else {
355+ state . patch ( [ { op : 'replace' , path : [ 'count' ] , value : count } ] )
356+ }
357+ }
358+
359+ update ( authority , 2 )
360+ await until ( ( ) => mirror . value ( ) . count === 2 )
361+ update ( mirror , 3 )
362+ await until ( ( ) => authority . value ( ) . count === 3 )
363+ await panel . call ( 'echo' , 'flushed' )
364+ expect ( authority . value ( ) ) . toEqual ( { count : 3 } )
365+ expect ( mirror . value ( ) ) . toEqual ( { count : 3 } )
366+ }
367+ finally {
368+ dispose ( )
369+ }
370+ } )
371+
372+ it ( 'deserializes both subscription snapshots and subsequent notifications' , async ( ) => {
373+ function restore ( value : unknown ) : unknown {
374+ if ( Array . isArray ( value ) )
375+ return value . map ( restore )
376+ if ( value && typeof value === 'object' ) {
377+ const restored = Object . fromEntries ( Object . entries ( value ) . map ( ( [ key , item ] ) => [ key , restore ( item ) ] ) )
378+ return 'count' in restored ? { ...restored , label : 'restored' } : restored
379+ }
380+ return value
381+ }
382+ const { pageScript, panel, dispose } = createLinkedPair ( {
383+ panel : { deserialize : restore } ,
384+ } )
385+ try {
386+ const authority = await pageScript . sharedState . get ( 'doc' , { initialValue : { count : 1 } } )
387+ const mirror = await panel . sharedState . get ( 'doc' )
388+ expect ( mirror . value ( ) ) . toEqual ( { count : 1 , label : 'restored' } )
389+
390+ authority . mutate ( ( ) => ( { count : 2 } ) )
391+ await until ( ( ) => mirror . value ( ) . count === 2 )
392+ expect ( mirror . value ( ) ) . toEqual ( { count : 2 , label : 'restored' } )
393+ }
394+ finally {
395+ dispose ( )
396+ }
397+ } )
398+
328399 it ( 'seeds an equal snapshot and skips unchanged writes on both endpoints' , async ( ) => {
329400 const { pageScript, panel, dispose } = createLinkedPair ( )
330401 try {
0 commit comments