>
- let mockBroadcast: HintsClientFunctions
-
- beforeEach(() => {
- hooks = createHooks()
- mockBroadcast = {
- onHydrationMismatch: vi.fn(),
- onHydrationCleared: vi.fn(),
- onLazyLoadReport: vi.fn(),
- onLazyLoadCleared: vi.fn(),
- onHtmlValidateReport: vi.fn(),
- onHtmlValidateDeleted: vi.fn(),
- }
- globalThis.__nuxtHintsRpcBroadcast = mockBroadcast
-
- rpcBridge({ hooks } as unknown as NitroApp)
- })
-
- afterEach(() => {
- globalThis.__nuxtHintsRpcBroadcast = undefined
- })
-
- it('should broadcast hydration mismatch via RPC', async () => {
- const mismatch = { id: '1', componentName: 'Test', fileLocation: '/test.vue', htmlPreHydration: '', htmlPostHydration: '' }
- await hooks.callHook('hints:hydration:mismatch', mismatch)
- expect(mockBroadcast.onHydrationMismatch).toHaveBeenCalledWith(mismatch)
- })
-
- it('should broadcast hydration cleared via RPC', async () => {
- await hooks.callHook('hints:hydration:cleared', { id: ['1', '2'] })
- expect(mockBroadcast.onHydrationCleared).toHaveBeenCalledWith(['1', '2'])
- })
-
- it('should broadcast lazy-load report via RPC', async () => {
- const data = { id: '1', route: '/', state: { pageLoaded: true, hasReported: true, directImports: [] } }
- await hooks.callHook('hints:lazy-load:report', data)
- expect(mockBroadcast.onLazyLoadReport).toHaveBeenCalledWith(data)
- })
-
- it('should broadcast lazy-load cleared via RPC', async () => {
- await hooks.callHook('hints:lazy-load:cleared', { id: 'test-id' })
- expect(mockBroadcast.onLazyLoadCleared).toHaveBeenCalledWith('test-id')
- })
-
- it('should broadcast html-validate report via RPC', async () => {
- const report = { id: '1', path: '/test', html: '', results: [] }
- await hooks.callHook('hints:html-validate:report', report)
- expect(mockBroadcast.onHtmlValidateReport).toHaveBeenCalledWith(report)
- })
-
- it('should broadcast html-validate deleted via RPC', async () => {
- await hooks.callHook('hints:html-validate:deleted', 'test-id')
- expect(mockBroadcast.onHtmlValidateDeleted).toHaveBeenCalledWith('test-id')
- })
-
- it('should not throw when RPC broadcast is not available', async () => {
- globalThis.__nuxtHintsRpcBroadcast = undefined
- expect(() =>
- hooks.callHook('hints:hydration:mismatch', { id: '1', componentName: 'Test', fileLocation: '/test.vue', htmlPreHydration: '', htmlPostHydration: '' }),
- ).not.toThrow()
- })
-})
diff --git a/test/unit/core/sse.test.ts b/test/unit/core/sse.test.ts
new file mode 100644
index 0000000..71b79c9
--- /dev/null
+++ b/test/unit/core/sse.test.ts
@@ -0,0 +1,53 @@
+import { describe, expect, it, vi, beforeEach, afterAll, beforeAll } from 'vitest'
+import { createApp, toWebHandler, toNodeListener } from 'h3'
+import sseEndpoint from '../../../src/runtime/core/server/sse'
+import type { Hookable } from 'hookable'
+import { createHooks } from 'hookable'
+import { useNitroApp } from 'nitropack/runtime'
+import type { NitroRuntimeHooks } from 'nitropack/types'
+import { createServer } from 'node:http'
+
+import {
+ getRandomPort,
+} from 'get-port-please'
+
+vi.mock('nitropack/runtime', async () => ({
+ useNitroApp: vi.fn(),
+}))
+
+const app = createApp()
+
+app.use('/', sseEndpoint)
+const handler = toWebHandler(app)
+const server = createServer(toNodeListener(app))
+
+describe('sseEndpoint', () => {
+ let hooks: Hookable
+ let port: number
+
+ beforeAll(async () => {
+ port = await getRandomPort()
+ server.listen(port, () => {
+ console.log(`Test server running on http://localhost:${port}`)
+ })
+ })
+
+ beforeEach(() => {
+ hooks = createHooks()
+ vi.mocked(useNitroApp).mockReturnValue({ hooks } as unknown as ReturnType)
+ })
+
+ afterAll(() => {
+ server.close()
+ })
+
+ it('should call registered SSE handlers on setup', async () => {
+ const mockHandler = vi.fn()
+
+ hooks.hook('hints:sse:setup', mockHandler)
+ const response = await handler(new Request(new URL('/', `http://localhost:${port}`)))
+ expect(mockHandler).toHaveBeenCalled()
+ expect(response.status).toBe(200)
+ expect(response.headers.get('Content-Type')).toBe('text/event-stream')
+ })
+})