import { describe, test, it, expect, beforeEach, afterEach, vi } from 'vitest' import { EventSourcePolyfill } from 'event-source-polyfill' import SseSource from '~/services/sse/sseSource' class TestableSseSource extends SseSource { public getUrl() { return this.url } public getOnOpen() { return this.onOpen } public getOnMessage() { return this.onMessage } public getOnClose() { return this.onClose } public getWithCredentials() { return this.withCredentials } public createEventSource( url: string, withCredentials: boolean, ): EventSourcePolyfill { return super.createEventSource(url, withCredentials) } public setEventSource(eventSource: EventSourcePolyfill) { this.eventSource = eventSource } } let mercureUrl: string let topic: string let onOpen: () => any let onMessage: (data: Array) => any let onClose: () => any let sseSource: TestableSseSource const initConsoleLog = console.log beforeEach(() => { mercureUrl = 'https://my.mercure.com' topic = 'mytopic' onOpen = () => 'opened' onMessage = (data: Array) => 'message' onClose = () => 'closed' sseSource = new TestableSseSource( mercureUrl, topic, onOpen, onMessage, onClose, false, ) }) afterEach(() => { console.log = initConsoleLog vi.restoreAllMocks() }) describe('test constructor', () => { test('with all params', () => { expect(sseSource.getUrl().toString()).toEqual( 'https://my.mercure.com/?topic=mytopic', ) expect(sseSource.getOnOpen()).toEqual(onOpen) expect(sseSource.getOnMessage()).toEqual(onMessage) expect(sseSource.getOnClose()).toEqual(onClose) expect(sseSource.getWithCredentials()).toEqual(false) }) }) describe('createEventSource', () => { test('simple call', () => { const eventSource = sseSource.createEventSource(mercureUrl, false) expect(eventSource.readyState).toEqual(0) expect(eventSource.url).toEqual(mercureUrl) expect(eventSource.withCredentials).toEqual(false) }) }) describe('isConnected', () => { test('no event source', () => { expect(sseSource.isConnected()).toEqual(false) }) test('got an event source, but it is not open', () => { const eventSource = sseSource.createEventSource(mercureUrl, true) sseSource.setEventSource(eventSource) expect(sseSource.isConnected()).toEqual(false) }) test('got an open event source', () => { // @ts-ignore const eventSource = vi.fn() as EventSourcePolyfill // @ts-ignore // noinspection JSConstantReassignment eventSource.readyState = EventSourcePolyfill.OPEN sseSource.setEventSource(eventSource) expect(sseSource.isConnected()).toEqual(true) }) }) describe('subscribe', () => { test('already connected', () => { sseSource.isConnected = vi.fn(() => true) expect(() => sseSource.subscribe()).toThrowError( 'SSE - Already subscribed to this event source', ) }) test('is server side', () => { import.meta.server = true expect(() => sseSource.subscribe()).toThrowError( 'SSE - Cannot subscribe on server side', ) import.meta.server = false }) test('successful subscription', () => { onOpen = vi.fn(() => null) onMessage = vi.fn((data: Array) => null) sseSource = new TestableSseSource( mercureUrl, topic, onOpen, onMessage, onClose, ) const dummyEventSource = new EventSourcePolyfill('https://my.mercure.com', { withCredentials: true, }) sseSource.createEventSource = vi.fn( (url: string, withCredentials: boolean) => { return dummyEventSource }, ) console.log = vi.fn() console.error = vi.fn() sseSource.subscribe() expect(sseSource.createEventSource).toHaveBeenCalled() // @ts-ignore dummyEventSource.onopen() expect(onOpen).toHaveBeenCalled() expect(console.log).toHaveBeenCalledWith('SSE - Listening for events...') // @ts-ignore dummyEventSource.onmessage({ data: '1' }) expect(onMessage).toHaveBeenCalledWith(1) // @ts-ignore const event = { target: { readyState: EventSourcePolyfill.CLOSED } } dummyEventSource.close = vi.fn() // @ts-ignore dummyEventSource.onerror(event) expect(console.log).toHaveBeenCalledWith('SSE closed') expect(dummyEventSource.close).toHaveBeenCalled() }) }) describe('unsubscribe', () => { test('if no event source, does nothing', () => { onClose = vi.fn(() => null) sseSource = new TestableSseSource( mercureUrl, topic, onOpen, onMessage, onClose, ) sseSource.unsubscribe() expect(onClose).toHaveBeenCalledTimes(0) }) test('if event source is not opened, does nothing', () => { onClose = vi.fn(() => null) sseSource = new TestableSseSource( mercureUrl, topic, onOpen, onMessage, onClose, ) // @ts-ignore const eventSource = vi.fn() as EventSourcePolyfill // @ts-ignore // noinspection JSConstantReassignment eventSource.readyState = EventSourcePolyfill.CLOSED sseSource.setEventSource(eventSource) sseSource.unsubscribe() expect(onClose).toHaveBeenCalledTimes(0) }) test('has an open subscription', () => { onClose = vi.fn(() => null) sseSource = new TestableSseSource( mercureUrl, topic, onOpen, onMessage, onClose, ) // @ts-ignore const eventSource = vi.fn() as EventSourcePolyfill // @ts-ignore // noinspection JSConstantReassignment eventSource.readyState = EventSourcePolyfill.OPEN eventSource.close = vi.fn(() => null) sseSource.setEventSource(eventSource) console.log = vi.fn() sseSource.unsubscribe() expect(eventSource.close).toHaveBeenCalled() expect(onClose).toHaveBeenCalled() expect(console.log).toHaveBeenCalledWith('SSE - Subscription closed') }) })