99} from '../utils/internal/requestUtils'
1010import { executeHandlers } from '../utils/executeHandlers'
1111import { 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