Skip to content

Commit 04e8e2f

Browse files
committed
fix(wip): figuring out websocket .errorWith()
1 parent 1ac66f0 commit 04e8e2f

File tree

7 files changed

+43
-31
lines changed

7 files changed

+43
-31
lines changed

src/core/new/define-network.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,7 @@ export function defineNetwork(options: DefineNetworkOptions): NetworkApi {
8383
frame,
8484
options.onUnhandledFrame || 'bypass',
8585
).catch((error) => {
86-
/**
87-
* @fixme `.errorWith()` should exist on WebSocket frames too
88-
* since you can error the connection by dispatching the "error" event.
89-
*/
90-
if (frame.protocol === 'http') {
91-
frame.errorWith(error)
92-
}
86+
frame.errorWith(error)
9387
})
9488
},
9589
})

src/core/new/frames/base-frame.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export abstract class BaseNetworkFrame<
1414
this.events = new Emitter<Events>()
1515
}
1616

17+
public abstract errorWith(reason?: unknown): unknown
18+
1719
/**
1820
* Returns a message to be used when this frame goes unhandled.
1921
*/

src/core/new/resolve-network-frame.ts

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -154,32 +154,26 @@ async function resolveWebSocketNetworkFrame(
154154
})
155155

156156
if (eventHandlers.length > 0) {
157-
const matches = await Promise.all<boolean>(
157+
await Promise.all(
158158
eventHandlers.map(async (handler) => {
159159
// Foward the connection data to every WebSocket handler.
160160
// This is equivalent to dispatching the connection event
161161
// onto multiple listeners.
162-
return handler.run(connection).then((matches) => {
163-
if (matches) {
164-
flow?.handled?.({ frame, handler })
162+
const matches = await handler.run(connection)
165163

166-
if (!flow?.quiet) {
167-
handler.log(connection)
168-
}
169-
}
164+
if (matches) {
165+
flow?.handled?.({ frame, handler })
170166

171-
return matches
172-
})
167+
if (!flow?.quiet) {
168+
handler.log(connection)
169+
}
170+
}
173171
}),
174172
)
175173

176-
if (matches.every((match) => !match)) {
177-
flow?.unhandled?.()
178-
}
179-
180174
return
181175
}
182176

177+
flow?.unhandled?.()
183178
frame.passthrough()
184-
flow.unhandled?.()
185179
}

src/core/new/sources/interceptor-source.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ export class InterceptorSource extends NetworkSource {
4545
* @fixme Incorrect disciminated union when merging multiple
4646
* events map in `BatchInterceptor` (results in `Listener<unknown>`).
4747
*/
48-
this.#interceptor.on('request', this.#onRequest.bind(this) as any)
49-
this.#interceptor.on('response', this.#onResponse.bind(this) as any)
48+
this.#interceptor
49+
.on('request', this.#onRequest.bind(this) as any)
50+
.on('response', this.#onResponse.bind(this) as any)
5051

5152
this.#interceptor.on(
5253
'connection',
@@ -163,6 +164,30 @@ class InterceptorWebSocketNetworkFrame extends WebSocketNetworkFrame {
163164
})
164165
}
165166

167+
public errorWith(reason?: unknown): void {
168+
if (reason instanceof Error) {
169+
const { client } = this.data.connection
170+
171+
/**
172+
* Use `client.errorWith(reason)` in the future.
173+
* @see https://github.com/mswjs/interceptors/issues/747
174+
*/
175+
const errorEvent = new Event('error')
176+
Object.defineProperty(errorEvent, 'cause', {
177+
enumerable: true,
178+
configurable: false,
179+
value: reason,
180+
})
181+
182+
/**
183+
* @fixme So this all is fine but it doesn't fire at the right time.
184+
* WS interceptor does NOT await listeners.
185+
*/
186+
client.socket.dispatchEvent(errorEvent)
187+
client.close(1011, reason.message)
188+
}
189+
}
190+
166191
public passthrough() {
167192
this.data.connection.server.connect()
168193
}

src/node/setup-remote-server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export interface SetupRemoteServerListenOptions extends SharedOptions {
1212
port: number
1313
}
1414

15-
interface SetupRemoteServer extends NetworkHandlersApi<AnyHandler> {
15+
interface SetupRemoteServer extends NetworkHandlersApi {
1616
listen(options: SetupRemoteServerListenOptions): Promise<void>
1717
close(): Promise<void>
1818
boundary<Args extends Array<any>, R>(

src/node/setup-server.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class SetupServerApi implements SetupServer {
4040
public restoreHandlers: SetupServerCommon['restoreHandlers']
4141
public listHandlers: SetupServerCommon['listHandlers']
4242

43-
#network: NetworkApi<AnyHandler>
43+
#network: NetworkApi
4444
#handlersController: AsyncHandlersController
4545
#currentHandlersProxy?: ReversibleProxy<HandlersController['currentHandlers']>
4646
#listenOptions?: Partial<ListenOptions>
@@ -65,10 +65,6 @@ export class SetupServerApi implements SetupServer {
6565
}),
6666
})
6767

68-
this.#network.events.on('log', (event) => {
69-
event.preventDefault()
70-
})
71-
7268
/**
7369
* @fixme This expects a readonly emitter (subset of methods).
7470
*/

test/node/ws-api/on-unhandled-request/error.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ afterAll(() => {
2020
vi.restoreAllMocks()
2121
})
2222

23-
it(
23+
it.only(
2424
'errors on unhandled WebSocket connection',
2525
server.boundary(async () => {
2626
const socket = new WebSocket('wss://localhost:4321')
@@ -32,6 +32,7 @@ it(
3232
socket.addEventListener('error', errorListener)
3333
socket.addEventListener('error', resolve)
3434
socket.onopen = () => {
35+
console.log('[test] onopen', new Error().stack)
3536
reject(new Error('WebSocket connection opened unexpectedly'))
3637
}
3738
})

0 commit comments

Comments
 (0)