Explorar el Código

fix(test): await Client Console subscription delivery

Tianyi Cui hace 4 días
padre
commit
64dfd7a425

+ 9 - 0
packages/experimental/inspector/tests/fixtures/client-source.client.ts

@@ -35,6 +35,8 @@ interface ClientFixtureRequest {
     | 'refresh-tree'
     | 'remove-fiber'
     | 'set-global'
+    | 'set-ingest-paused'
+  readonly paused?: boolean
   readonly name?: string
   readonly value?: InspectorJsonValue
   readonly marker?: string
@@ -106,6 +108,13 @@ async function dispatch(message: ClientFixtureRequest): Promise<unknown> {
       return undefined
     case 'get-tree':
       return await service.cordis.getTree()
+    case 'set-ingest-paused': {
+      const socket = Reflect.get(source, 'socket') as WebSocket | undefined
+      if (socket === undefined) throw new Error('Inspector Client ingest socket is unavailable')
+      if (message.paused) socket.pause()
+      else socket.resume()
+      return undefined
+    }
     case 'disconnect': {
       const socket = Reflect.get(source, 'socket') as WebSocket | undefined
       socket?.terminate()

+ 8 - 0
packages/experimental/inspector/tests/fixtures/client-source.host.ts

@@ -98,6 +98,14 @@ export class InspectorClientFixture {
     return await this.request({ op: 'get-tree' }) as CordisRuntimeTree
   }
 
+  /**
+   * Pause or resume ingest reads without blocking the fixture MessagePort.
+   * @param paused - Whether incoming WebSocket frames must wait.
+   */
+  async setIngestPaused(paused: boolean): Promise<void> {
+    await this.request({ op: 'set-ingest-paused', paused })
+  }
+
   /** Break the active ingest socket while preserving the Client source. */
   async disconnect(): Promise<void> {
     await this.request({ op: 'disconnect' })

+ 26 - 1
packages/experimental/inspector/tests/integration.host.spec.ts

@@ -367,12 +367,27 @@ describe('experimental Inspector real Worker', () => {
     client = await InspectorClientFixture.start(inspector.endpoint.client, { label: 'Console Client' })
     cdp = await TestCdpClient.connect(inspector.endpoint.webSocketDebuggerUrl)
     secondCdp = await TestCdpClient.connect(inspector.endpoint.webSocketDebuggerUrl)
+    await vi.waitFor(async () => {
+      const response = await cdp!.call('DSHInspector.getSources')
+      expect(recordArray(response.result?.sources).some(source => source.kind === 'client')).toBe(true)
+    })
+    // The MessagePort can deliver log requests before ingest receives Console subscriptions.
+    await client.setIngestPaused(true)
     await Promise.all([cdp.call('Runtime.enable'), secondCdp.call('Runtime.enable')])
     const firstContext = await clientContext(cdp)
     const secondContext = await clientContext(secondCdp)
     const value = { owner: 'client-console' }
     const marker = 'client-console-event'
-    await client.log(value, marker)
+    const logged = (async () => {
+      // Both subscriptions precede this request on the same ingest WebSocket.
+      // A Client response, unlike Runtime.enable, acknowledges their delivery.
+      expect((await cdp.call('Runtime.evaluate', {
+        contextId: firstContext,
+        expression: 'void 0',
+      })).error).toBeUndefined()
+      await client.log(value, marker)
+    })()
+    await Promise.all([logged, client.setIngestPaused(false)])
     let firstEvent: CdpMessage | undefined
     let secondEvent: CdpMessage | undefined
     await vi.waitFor(() => {
@@ -398,6 +413,16 @@ describe('experimental Inspector real Worker', () => {
     expect((await cdp.call('Runtime.discardConsoleEntries')).error).toBeUndefined()
     expect((await cdp.call('Runtime.getProperties', { objectId: firstObjectId })).error).toBeDefined()
     expect((await secondCdp.call('Runtime.getProperties', { objectId: secondObjectId })).error).toBeUndefined()
+
+    await client.setIngestPaused(true)
+    await client.close()
+    client = undefined
+    await vi.waitFor(() => {
+      for (const [connection, contextId] of [[cdp!, firstContext], [secondCdp!, secondContext]] as const) {
+        expect(connection.events.some(event => event.method === 'Runtime.executionContextDestroyed'
+          && event.params?.executionContextId === contextId)).toBe(true)
+      }
+    })
   })
 
   it('projects a chunked Client bundle as read-only Debugger source', async () => {