Skip to content

Commit d427536

Browse files
committed
chore: split network frame handling
1 parent 4de76dc commit d427536

File tree

2 files changed

+127
-114
lines changed

2 files changed

+127
-114
lines changed

src/core/new/define-network.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ export interface NetworkApi<Handler extends AnyHandler>
4242
/**
4343
* Enables the network interception.
4444
*/
45-
enable: () => Promise<void>
45+
enable(): Promise<void>
4646

4747
/**
4848
* Disables the network interception.
4949
*/
50-
disable: () => Promise<void>
50+
disable(): Promise<void>
5151

5252
/**
5353
* @fixme Infer the EventMap type from the sources passed to this network.
@@ -56,10 +56,10 @@ export interface NetworkApi<Handler extends AnyHandler>
5656
}
5757

5858
export interface NetworkHandlersApi<Handler extends AnyHandler> {
59-
use: (...handlers: Array<Handler>) => void
60-
resetHandlers: (...nextHandlers: Array<Handler>) => void
61-
restoreHandlers: () => void
62-
listHandlers: () => ReadonlyArray<Handler>
59+
use(...handlers: Array<Handler>): void
60+
resetHandlers(...nextHandlers: Array<Handler>): void
61+
restoreHandlers(): void
62+
listHandlers(): ReadonlyArray<Handler>
6363
}
6464

6565
export function defineNetwork<Handler extends AnyHandler>(

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

Lines changed: 121 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
} from '../utils/internal/requestUtils'
1010
import { executeHandlers } from '../utils/executeHandlers'
1111
import { storeResponseCookies } from '../utils/request/storeResponseCookies'
12+
import { HttpNetworkFrame } from './frames/http-frame'
13+
import { WebSocketNetworkFrame } from './frames/websocket-frame'
1214

1315
/**
1416
* Resolve a network frame against the given list of handlers.
@@ -21,121 +23,15 @@ export async function resolveNetworkFrame(
2123
handlers: Array<AnyHandler>,
2224
): Promise<boolean> {
2325
switch (frame.protocol) {
24-
/**
25-
* HTTP.
26-
*/
2726
case 'http': {
28-
const { request } = frame.data
29-
const requestId = createRequestId()
30-
const requestCloneForLogs = request.clone()
31-
32-
frame.events.emit('request:start', { request, requestId })
33-
34-
// Perform requests wrapped in "bypass()" as-is.
35-
if (shouldBypassRequest(request)) {
36-
frame.passthrough()
37-
return true
38-
}
39-
40-
const requestHandlers = handlers.filter(isHandlerKind('RequestHandler'))
41-
42-
const [lookupError, lookupResult] = await until(() => {
43-
return executeHandlers({
44-
request,
45-
requestId,
46-
handlers: requestHandlers,
47-
resolutionContext: {},
48-
})
49-
})
50-
51-
if (lookupError) {
52-
// Allow developers to react to unhandled exceptions in request handlers.
53-
frame.events.emit('unhandledException', {
54-
error: lookupError,
55-
request,
56-
requestId,
57-
})
58-
frame.errorWith(lookupError)
59-
return false
60-
}
61-
62-
// If the handler lookup returned nothing, no request handler was found
63-
// matching this request. Report the request as unhandled.
64-
if (!lookupResult) {
65-
frame.events.emit('request:unhandled', { request, requestId })
66-
frame.events.emit('request:end', { request, requestId })
67-
frame.passthrough()
68-
return false
69-
}
70-
71-
const { response, handler, parsedResult } = lookupResult
72-
73-
// When the handled request returned no mocked response, warn the developer,
74-
// as it may be an oversight on their part. Perform the request as-is.
75-
if (!response) {
76-
frame.events.emit('request:end', { request, requestId })
77-
frame.passthrough()
78-
return true
79-
}
80-
81-
// Perform the request as-is when the developer explicitly returned `passthrough()`.
82-
// This produces no warning as the request was handled.
83-
if (isPassthroughResponse(response)) {
84-
frame.events.emit('request:end', { request, requestId })
85-
frame.passthrough()
86-
return true
87-
}
88-
89-
// Store all the received response cookies in the cookie jar.
90-
await storeResponseCookies(request, response)
91-
92-
frame.events.emit('request:match', { request, requestId })
93-
94-
frame.respondWith(response.clone())
95-
96-
frame.events.emit('request:end', { request, requestId })
97-
98-
// Log mocked responses. Use the Network tab to observe the original network.
99-
handler.log({
100-
request: requestCloneForLogs,
101-
response,
102-
parsedResult,
103-
})
104-
105-
return true
27+
return resolveHttpNetworkFrame(frame, handlers)
10628
}
10729

10830
/**
10931
* WebSocket.
11032
*/
11133
case 'ws': {
112-
const { connection } = frame.data
113-
const eventHandlers = handlers.filter(isHandlerKind('EventHandler'))
114-
115-
frame.events.emit('websocket:connection', {
116-
url: connection.client.url,
117-
protocols: connection.info.protocols,
118-
})
119-
120-
if (eventHandlers.length > 0) {
121-
await Promise.all(
122-
eventHandlers.map((handler) => {
123-
// Foward the connection data to every WebSocket handler.
124-
// This is equivalent to dispatching the connection event
125-
// onto multiple listeners.
126-
return handler.run(connection)
127-
}),
128-
)
129-
130-
return true
131-
}
132-
133-
/**
134-
* @todo Support WebSocket logging, somehow.
135-
*/
136-
137-
frame.passthrough()
138-
return false
34+
return resolveWebSocketNetworkFrame(frame, handlers)
13935
}
14036

14137
default: {
@@ -146,3 +42,120 @@ export async function resolveNetworkFrame(
14642
}
14743
}
14844
}
45+
46+
async function resolveHttpNetworkFrame(
47+
frame: HttpNetworkFrame,
48+
handlers: Array<AnyHandler>,
49+
): Promise<boolean> {
50+
const { request } = frame.data
51+
const requestId = createRequestId()
52+
const requestCloneForLogs = request.clone()
53+
54+
frame.events.emit('request:start', { request, requestId })
55+
56+
// Perform requests wrapped in "bypass()" as-is.
57+
if (shouldBypassRequest(request)) {
58+
frame.passthrough()
59+
return true
60+
}
61+
62+
const requestHandlers = handlers.filter(isHandlerKind('RequestHandler'))
63+
64+
const [lookupError, lookupResult] = await until(() => {
65+
return executeHandlers({
66+
request,
67+
requestId,
68+
handlers: requestHandlers,
69+
resolutionContext: {},
70+
})
71+
})
72+
73+
if (lookupError) {
74+
// Allow developers to react to unhandled exceptions in request handlers.
75+
frame.events.emit('unhandledException', {
76+
error: lookupError,
77+
request,
78+
requestId,
79+
})
80+
frame.errorWith(lookupError)
81+
return false
82+
}
83+
84+
// If the handler lookup returned nothing, no request handler was found
85+
// matching this request. Report the request as unhandled.
86+
if (!lookupResult) {
87+
frame.events.emit('request:unhandled', { request, requestId })
88+
frame.events.emit('request:end', { request, requestId })
89+
frame.passthrough()
90+
return false
91+
}
92+
93+
const { response, handler, parsedResult } = lookupResult
94+
95+
// When the handled request returned no mocked response, warn the developer,
96+
// as it may be an oversight on their part. Perform the request as-is.
97+
if (!response) {
98+
frame.events.emit('request:end', { request, requestId })
99+
frame.passthrough()
100+
return true
101+
}
102+
103+
// Perform the request as-is when the developer explicitly returned `passthrough()`.
104+
// This produces no warning as the request was handled.
105+
if (isPassthroughResponse(response)) {
106+
frame.events.emit('request:end', { request, requestId })
107+
frame.passthrough()
108+
return true
109+
}
110+
111+
// Store all the received response cookies in the cookie jar.
112+
await storeResponseCookies(request, response)
113+
114+
frame.events.emit('request:match', { request, requestId })
115+
116+
frame.respondWith(response.clone())
117+
118+
frame.events.emit('request:end', { request, requestId })
119+
120+
// Log mocked responses. Use the Network tab to observe the original network.
121+
handler.log({
122+
request: requestCloneForLogs,
123+
response,
124+
parsedResult,
125+
})
126+
127+
return true
128+
}
129+
130+
async function resolveWebSocketNetworkFrame(
131+
frame: WebSocketNetworkFrame,
132+
handlers: Array<AnyHandler>,
133+
): Promise<boolean> {
134+
const { connection } = frame.data
135+
const eventHandlers = handlers.filter(isHandlerKind('EventHandler'))
136+
137+
frame.events.emit('websocket:connection', {
138+
url: connection.client.url,
139+
protocols: connection.info.protocols,
140+
})
141+
142+
if (eventHandlers.length > 0) {
143+
await Promise.all(
144+
eventHandlers.map((handler) => {
145+
// Foward the connection data to every WebSocket handler.
146+
// This is equivalent to dispatching the connection event
147+
// onto multiple listeners.
148+
return handler.run(connection)
149+
}),
150+
)
151+
152+
return true
153+
}
154+
155+
/**
156+
* @todo Support WebSocket logging, somehow.
157+
*/
158+
159+
frame.passthrough()
160+
return false
161+
}

0 commit comments

Comments
 (0)