@@ -247,12 +247,49 @@ test.describe('TabMesh — multi-tab harness', () => {
247247 await b . close ( ) ;
248248 } ) ;
249249
250- test . fixme ( 'worker-side observation of lifecycle messages (#6)' , async ( ) => {
251- // SharedWorker console output is not visible to Playwright's page-
252- // attached console listener. Either:
253- // (a) route worker logs over a `port.ping`-style introspection that
254- // returns the recorded visibility state, or
255- // (b) use chrome://inspect/#workers via CDP to attach to the SW.
250+ test ( 'worker records lifecycle messages and replies via pong (#6)' , async ( { context } ) => {
251+ // Open the playground, drive a visibilitychange so the tab posts a
252+ // `lifecycle` message to the worker, then probe the worker by opening
253+ // a fresh SharedWorker port (same name) and sending a `ping` with the
254+ // playground tab's id. The pong now carries `visibilityState`, which
255+ // proves the lifecycle message reached the worker registry.
256+ const a = await newPlaygroundTab ( context ) ;
257+ await waitForTransportConnected ( a ) ;
258+
259+ const playgroundTabId = await a . evaluate ( ( ) =>
260+ sessionStorage . getItem ( 'tabmesh:tabId:playground-todos' )
261+ ) ;
262+ expect ( playgroundTabId ) . toBeTruthy ( ) ;
263+
264+ await a . evaluate ( ( ) => {
265+ Object . defineProperty ( document , 'visibilityState' , {
266+ value : 'hidden' ,
267+ configurable : true ,
268+ } ) ;
269+ document . dispatchEvent ( new Event ( 'visibilitychange' ) ) ;
270+ } ) ;
271+
272+ // Give the lifecycle message a tick to land in the worker.
273+ await a . waitForTimeout ( 150 ) ;
274+
275+ const visibility = await a . evaluate ( ( targetTabId ) => {
276+ return new Promise < string | undefined > ( ( resolve ) => {
277+ const w = new SharedWorker ( '/tabmesh-worker.js' , {
278+ name : 'tabmesh:playground-todos' ,
279+ } ) ;
280+ w . port . onmessage = ( e ) => {
281+ const msg = e . data as { kind ?: string ; visibilityState ?: string } ;
282+ if ( msg ?. kind === 'pong' ) resolve ( msg . visibilityState ) ;
283+ } ;
284+ w . port . start ( ) ;
285+ w . port . postMessage ( { kind : 'ping' , tabId : targetTabId } ) ;
286+ setTimeout ( ( ) => resolve ( undefined ) , 1500 ) ;
287+ } ) ;
288+ } , playgroundTabId ) ;
289+
290+ expect ( visibility ) . toBe ( 'hidden' ) ;
291+
292+ await a . close ( ) ;
256293 } ) ;
257294
258295 test . fixme ( 'Service Worker Background Sync drains pending events (#26 / #27)' , async ( ) => {
0 commit comments