mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
test(packages/tuono): messageChannel - use vi.fn (#241)
This commit is contained in:
committed by
GitHub
parent
498601c21a
commit
de74647c43
@@ -1,48 +1,43 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
|
||||
import { MessageChannelPolyfill, MessagePortPolyfill } from './messageChannel'
|
||||
|
||||
describe('MessagePortPolyfill', () => {
|
||||
it('should invoke onmessage when a message is posted', () => {
|
||||
const port = new MessagePortPolyfill()
|
||||
let messageReceived: string | null = null
|
||||
|
||||
port.onmessage = (event: MessageEvent<string>): void => {
|
||||
messageReceived = event.data
|
||||
}
|
||||
const onmessageMock = vi.fn<EventListener>()
|
||||
|
||||
port.onmessage = onmessageMock
|
||||
|
||||
port.dispatchEvent({ data: 'Hello, world!' } as MessageEvent)
|
||||
expect(messageReceived).toBe('Hello, world!')
|
||||
|
||||
expect(onmessageMock).toHaveBeenCalledOnce()
|
||||
expect(onmessageMock).toHaveBeenCalledWith({ data: 'Hello, world!' })
|
||||
})
|
||||
|
||||
it('should handle multiple event listeners', () => {
|
||||
const port = new MessagePortPolyfill()
|
||||
const messages: Array<string> = []
|
||||
|
||||
const listener1 = ((event: MessageEvent): void => {
|
||||
messages.push('Listener1: ' + event.data)
|
||||
}) as EventListener
|
||||
const listener2 = ((event: MessageEvent): void => {
|
||||
messages.push('Listener2: ' + event.data)
|
||||
}) as EventListener
|
||||
const listener1 = vi.fn<EventListener>()
|
||||
const listener2 = vi.fn<EventListener>()
|
||||
|
||||
port.addEventListener('message', listener1)
|
||||
port.addEventListener('message', listener2)
|
||||
|
||||
port.dispatchEvent({ data: 'Test message' } as MessageEvent)
|
||||
expect(messages).toEqual([
|
||||
'Listener1: Test message',
|
||||
'Listener2: Test message',
|
||||
])
|
||||
|
||||
expect(listener1).toHaveBeenCalledOnce()
|
||||
expect(listener1).toHaveBeenCalledWith({ data: 'Test message' })
|
||||
|
||||
expect(listener2).toHaveBeenCalledOnce()
|
||||
expect(listener2).toHaveBeenCalledWith({ data: 'Test message' })
|
||||
})
|
||||
|
||||
it('should not invoke removed event listeners', () => {
|
||||
const port = new MessagePortPolyfill()
|
||||
const messages: Array<string> = []
|
||||
|
||||
const listener = ((event: MessageEvent<string>): void => {
|
||||
messages.push(event.data)
|
||||
}) as EventListener
|
||||
const listener = vi.fn<EventListener>()
|
||||
|
||||
port.addEventListener('message', listener)
|
||||
port.dispatchEvent({ data: 'First message' } as MessageEvent)
|
||||
@@ -50,73 +45,85 @@ describe('MessagePortPolyfill', () => {
|
||||
port.removeEventListener('message', listener)
|
||||
port.dispatchEvent({ data: 'Second message' } as MessageEvent)
|
||||
|
||||
expect(messages).toEqual(['First message'])
|
||||
expect(listener).toHaveBeenCalledOnce()
|
||||
expect(listener).toHaveBeenCalledWith({ data: 'First message' })
|
||||
})
|
||||
|
||||
it('should not post messages if otherPort is null', () => {
|
||||
const port = new MessagePortPolyfill()
|
||||
let messageReceived: string | null = null
|
||||
|
||||
port.onmessage = (event: MessageEvent<string>): void => {
|
||||
messageReceived = event.data
|
||||
}
|
||||
const listener = vi.fn<EventListener>()
|
||||
|
||||
port.onmessage = listener
|
||||
|
||||
port.postMessage('Hello!')
|
||||
expect(messageReceived).toBeNull()
|
||||
|
||||
expect(listener).not.toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
|
||||
describe('MessageChannelPolyfill', () => {
|
||||
it('should send and receive messages between ports', () => {
|
||||
const channel = new MessageChannelPolyfill()
|
||||
const messages: Array<string> = []
|
||||
|
||||
channel.port1.onmessage = (event: MessageEvent<string>): void => {
|
||||
messages.push(event.data)
|
||||
}
|
||||
const listener = vi.fn<EventListener>()
|
||||
|
||||
channel.port1.onmessage = listener
|
||||
|
||||
channel.port2.postMessage('Hello, port1!')
|
||||
channel.port2.postMessage('How are you?')
|
||||
|
||||
expect(messages).toEqual(['Hello, port1!', 'How are you?'])
|
||||
expect(listener).toHaveBeenCalledTimes(2)
|
||||
expect(listener).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ data: 'Hello, port1!' }),
|
||||
)
|
||||
expect(listener).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({ data: 'How are you?' }),
|
||||
)
|
||||
})
|
||||
|
||||
it('should support addEventListener and removeEventListener', () => {
|
||||
const channel = new MessageChannelPolyfill()
|
||||
const messages: Array<string> = []
|
||||
|
||||
const listener = ((event: MessageEvent<string>): void => {
|
||||
messages.push(event.data)
|
||||
}) as EventListener
|
||||
const listener = vi.fn<EventListener>()
|
||||
|
||||
channel.port1.addEventListener('message', listener)
|
||||
channel.port2.postMessage('Hello, port1!')
|
||||
expect(messages).toEqual(['Hello, port1!'])
|
||||
|
||||
expect(listener).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ data: 'Hello, port1!' }),
|
||||
)
|
||||
|
||||
channel.port1.removeEventListener('message', listener)
|
||||
channel.port2.postMessage('Message after removing listener')
|
||||
|
||||
expect(messages).toEqual(['Hello, port1!'])
|
||||
expect(listener).not.toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('should handle bidirectional communication between ports', () => {
|
||||
const channel = new MessageChannelPolyfill()
|
||||
const messagesPort1: Array<string> = []
|
||||
const messagesPort2: Array<string> = []
|
||||
|
||||
channel.port1.onmessage = (event: MessageEvent<string>): void => {
|
||||
messagesPort1.push(event.data)
|
||||
}
|
||||
const listener1 = vi.fn<EventListener>()
|
||||
const listener2 = vi.fn<EventListener>()
|
||||
|
||||
channel.port2.onmessage = (event: MessageEvent<string>): void => {
|
||||
messagesPort2.push(event.data)
|
||||
}
|
||||
channel.port1.onmessage = listener1
|
||||
channel.port2.onmessage = listener2
|
||||
|
||||
channel.port1.postMessage('Hello, port2!')
|
||||
channel.port2.postMessage('Hello, port1!')
|
||||
|
||||
expect(messagesPort1).toEqual(['Hello, port1!'])
|
||||
expect(messagesPort2).toEqual(['Hello, port2!'])
|
||||
expect(listener1).toHaveBeenCalledOnce()
|
||||
expect(listener1).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ data: 'Hello, port1!' }),
|
||||
)
|
||||
|
||||
expect(listener2).toHaveBeenCalledOnce()
|
||||
expect(listener2).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ data: 'Hello, port2!' }),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -124,17 +131,20 @@ describe('MessagePort', () => {
|
||||
it('should not send a message on close', () => {
|
||||
const { port1, port2 } = new MessageChannelPolyfill()
|
||||
|
||||
const messages: Array<string> = []
|
||||
port1.onmessage = (event: MessageEvent<string>): void => {
|
||||
messages.push(event.data)
|
||||
}
|
||||
const listener = vi.fn<EventListener>()
|
||||
|
||||
port1.onmessage = listener
|
||||
|
||||
port2.postMessage('Test message')
|
||||
expect(messages).toEqual(['Test message'])
|
||||
|
||||
expect(listener).toHaveBeenCalledOnce()
|
||||
expect(listener).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ data: 'Test message' }),
|
||||
)
|
||||
|
||||
port1.close()
|
||||
port2.postMessage('Another message')
|
||||
|
||||
expect(messages).toEqual(['Test message'])
|
||||
expect(listener).not.toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,10 +24,12 @@
|
||||
|
||||
export class MessagePortPolyfill implements MessagePort {
|
||||
onmessage: ((this: MessagePort, ev: MessageEvent) => unknown) | null = null
|
||||
/** @warning this is declared to satisfy {@link MessagePort} interface requirements but is never called */
|
||||
onmessageerror: ((this: MessagePort, ev: MessageEvent) => unknown) | null =
|
||||
null
|
||||
|
||||
otherPort: MessagePortPolyfill | null = null
|
||||
|
||||
private onmessageListeners: Array<(ev: MessageEvent) => void> = []
|
||||
private isClosed = false
|
||||
|
||||
@@ -42,6 +44,7 @@ export class MessagePortPolyfill implements MessagePort {
|
||||
|
||||
postMessage(message: unknown): void {
|
||||
if (this.isClosed || !this.otherPort) return
|
||||
|
||||
const event = new MessageEvent('message', { data: message })
|
||||
this.otherPort.dispatchEvent(event)
|
||||
}
|
||||
@@ -51,11 +54,12 @@ export class MessagePortPolyfill implements MessagePort {
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
): void {
|
||||
if (this.isClosed || type !== 'message') return
|
||||
|
||||
if (
|
||||
typeof listener === 'function' &&
|
||||
!this.onmessageListeners.includes(listener)
|
||||
) {
|
||||
this.onmessageListeners.push(listener as (ev: MessageEvent) => void)
|
||||
this.onmessageListeners.push(listener)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +68,9 @@ export class MessagePortPolyfill implements MessagePort {
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
): void {
|
||||
if (this.isClosed || type !== 'message') return
|
||||
|
||||
if (typeof listener === 'function') {
|
||||
const index = this.onmessageListeners.indexOf(
|
||||
listener as (ev: MessageEvent) => void,
|
||||
)
|
||||
const index = this.onmessageListeners.indexOf(listener)
|
||||
if (index !== -1) {
|
||||
this.onmessageListeners.splice(index, 1)
|
||||
}
|
||||
@@ -90,6 +93,7 @@ export class MessageChannelPolyfill implements MessageChannel {
|
||||
constructor() {
|
||||
this.port1 = new MessagePortPolyfill()
|
||||
this.port2 = new MessagePortPolyfill()
|
||||
|
||||
this.port1.otherPort = this.port2
|
||||
this.port2.otherPort = this.port1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user