diff --git a/packages/preview-process/src/parts/WaitForServerToBeReady/WaitForServerToBeReady.ts b/packages/preview-process/src/parts/WaitForServerToBeReady/WaitForServerToBeReady.ts index 1fba3888..be719bf4 100644 --- a/packages/preview-process/src/parts/WaitForServerToBeReady/WaitForServerToBeReady.ts +++ b/packages/preview-process/src/parts/WaitForServerToBeReady/WaitForServerToBeReady.ts @@ -1,7 +1,14 @@ import type { WebViewServer } from '../WebViewServerTypes/WebViewServerTypes.ts' +import * as GetFirstEvent from '../GetFirstEvent/GetFirstEvent.ts' export const waitForServerToBeReady = async (server: WebViewServer, port: string): Promise => { - const { resolve, promise } = Promise.withResolvers() - server.listen(port, resolve) - await promise + const responsePromise = GetFirstEvent.getFirstEvent(server as any, { + error: 1, + listening: 2, + }) + server.listen(port, () => {}) + const { type, event } = await responsePromise + if (type === 1) { + throw new Error(`Server error: ${event}`) + } } diff --git a/packages/preview-process/test/WaitForServerToBeReady.test.ts b/packages/preview-process/test/WaitForServerToBeReady.test.ts index 41bf6ed4..3f659ae8 100644 --- a/packages/preview-process/test/WaitForServerToBeReady.test.ts +++ b/packages/preview-process/test/WaitForServerToBeReady.test.ts @@ -1,16 +1,49 @@ -import { expect, jest, test } from '@jest/globals' +import { expect, test } from '@jest/globals' +import { EventEmitter } from 'node:events' +import type { WebViewServer } from '../src/parts/WebViewServerTypes/WebViewServerTypes.ts' import * as WaitForServerToBeReady from '../src/parts/WaitForServerToBeReady/WaitForServerToBeReady.ts' -test('waitForServerToBeReady', async () => { - const mockServer = { - listen: jest.fn((port, callback) => { - // @ts-ignore +class MockServer extends EventEmitter implements WebViewServer { + handler = undefined + listening = false + + setHandler(handler: any): void { + this.handler = handler + } + + listen(port: string, callback: () => void): void { + process.nextTick(() => { + this.listening = true + this.emit('listening') callback() - }), + }) } + isListening(): boolean { + return this.listening + } +} + +test('waitForServerToBeReady - success', async () => { + const server = new MockServer() + const port = '3000' + await WaitForServerToBeReady.waitForServerToBeReady(server, port) + expect(server.listening).toBe(true) +}) + +test('waitForServerToBeReady - handles EADDRINUSE error', async () => { + const server = new MockServer() + const port = '3000' + process.nextTick(() => { + server.emit('error', new Error('EADDRINUSE')) + }) + await expect(WaitForServerToBeReady.waitForServerToBeReady(server, port)).rejects.toThrow('EADDRINUSE') +}) + +test('waitForServerToBeReady - handles other errors', async () => { + const server = new MockServer() const port = '3000' - // @ts-ignore - await WaitForServerToBeReady.waitForServerToBeReady(mockServer, port) - expect(mockServer.listen).toHaveBeenCalledTimes(1) - expect(mockServer.listen).toHaveBeenCalledWith(port, expect.any(Function)) + process.nextTick(() => { + server.emit('error', new Error('Some other error')) + }) + await expect(WaitForServerToBeReady.waitForServerToBeReady(server, port)).rejects.toThrow('Some other error') }) diff --git a/packages/test-integration/test/PreviewProcessPortConflict.test.ts b/packages/test-integration/test/PreviewProcessPortConflict.test.ts index be6a7117..2c19dc2d 100644 --- a/packages/test-integration/test/PreviewProcessPortConflict.test.ts +++ b/packages/test-integration/test/PreviewProcessPortConflict.test.ts @@ -2,7 +2,7 @@ import { expect, test } from '@jest/globals' import getPort from 'get-port' import { createPreviewProcess } from '../src/parts/CreatePreviewProcess/CreatePreviewProcess.js' -test.skip('preview process - handles port already in use', async () => { +test('preview process - handles port already in use', async () => { const previewProcess1 = createPreviewProcess() const previewProcess2 = createPreviewProcess() const id1 = 1 @@ -13,9 +13,8 @@ test.skip('preview process - handles port already in use', async () => { await previewProcess1.invoke('WebViewServer.start', id1, port) await previewProcess2.invoke('WebViewServer.create', id2) - // TODO improve error message await expect(previewProcess2.invoke('WebViewServer.start', id2, port)).rejects.toThrow( - "Failed to start webview server: TypeError: Cannot read properties of undefined (reading 'server')", + `Failed to start webview server: Server error: Error: listen EADDRINUSE: address already in use :::${port}`, ) previewProcess1[Symbol.dispose]()