@@ -20,6 +20,8 @@ const SERVER_HANDLER_NAME = '___netlify-server-handler'
2020 * @property {string } [url] TThe relative path that should be requested. Defaults to '/'
2121 * @property {Record<string, string> } [headers] The headers used for the invocation
2222 * @property {Record<string, unknown> } [flags] Feature flags that should be set during the invocation
23+ *
24+ * @typedef {Pick<FunctionInvocationOptions, 'env'> } LoadFunctionOptions
2325 */
2426
2527/**
@@ -109,73 +111,84 @@ const DEFAULT_FLAGS = {}
109111
110112/**
111113 * @param {FixtureTestContext } ctx
112- * @param {FunctionInvocationOptions } options
114+ * @param {LoadFunctionOptions } options
113115 */
114- export async function loadAndInvokeFunctionImpl (
115- ctx ,
116- { headers, httpMethod, flags, url, env } = { } ,
117- ) {
116+ export async function loadFunction ( ctx , { env } = { } ) {
118117 const restoreEnvironment = temporarilySetEnv ( ctx , env )
119118
120119 const { handler } = await import (
121120 'file:///' + join ( ctx . functionDist , SERVER_HANDLER_NAME , '___netlify-entry-point.mjs' )
122121 )
123122
124- let resolveInvocation , rejectInvocation
125- const invocationPromise = new Promise ( ( resolve , reject ) => {
126- resolveInvocation = resolve
127- rejectInvocation = reject
128- } )
123+ /**
124+ * @param {FunctionInvocationOptions } options
125+ */
126+ async function invokeFunction ( { headers, httpMethod, flags, url, env : invokeEnv } = { } ) {
127+ const restoreEnvironment = temporarilySetEnv ( ctx , {
128+ ...env ,
129+ ...invokeEnv ,
130+ } )
129131
130- const response = await execute ( {
131- event : {
132- headers : headers || { } ,
133- httpMethod : httpMethod || 'GET' ,
134- rawUrl : new URL ( url || '/' , 'https://example.netlify' ) . href ,
135- flags : flags ?? DEFAULT_FLAGS ,
136- } ,
137- lambdaFunc : { handler } ,
138- timeoutMs : 4_000 ,
139- onInvocationEnd : ( error ) => {
140- // lambda-local resolve promise return from execute when response is closed
141- // but we should wait for tracked background work to finish
142- // before resolving the promise to allow background work to finish
143- if ( error ) {
144- rejectInvocation ( error )
145- } else {
146- resolveInvocation ( )
147- }
148- } ,
149- } )
132+ let resolveInvocation , rejectInvocation
133+ const invocationPromise = new Promise ( ( resolve , reject ) => {
134+ resolveInvocation = resolve
135+ rejectInvocation = reject
136+ } )
137+
138+ const response = await execute ( {
139+ event : {
140+ headers : headers || { } ,
141+ httpMethod : httpMethod || 'GET' ,
142+ rawUrl : new URL ( url || '/' , 'https://example.netlify' ) . href ,
143+ flags : flags ?? DEFAULT_FLAGS ,
144+ } ,
145+ lambdaFunc : { handler } ,
146+ timeoutMs : 4_000 ,
147+ onInvocationEnd : ( error ) => {
148+ // lambda-local resolve promise return from execute when response is closed
149+ // but we should wait for tracked background work to finish
150+ // before resolving the promise to allow background work to finish
151+ if ( error ) {
152+ rejectInvocation ( error )
153+ } else {
154+ resolveInvocation ( )
155+ }
156+ } ,
157+ } )
150158
151- await invocationPromise
159+ await invocationPromise
152160
153- if ( ! response ) {
154- throw new Error ( 'No response from lambda-local' )
155- }
161+ if ( ! response ) {
162+ throw new Error ( 'No response from lambda-local' )
163+ }
156164
157- const responseHeaders = Object . entries ( response . multiValueHeaders || { } ) . reduce (
158- ( prev , [ key , value ] ) => ( {
159- ...prev ,
160- [ key ] : value . length === 1 ? `${ value } ` : value . join ( ', ' ) ,
161- } ) ,
162- response . headers || { } ,
163- )
165+ const responseHeaders = Object . entries ( response . multiValueHeaders || { } ) . reduce (
166+ ( prev , [ key , value ] ) => ( {
167+ ...prev ,
168+ [ key ] : value . length === 1 ? `${ value } ` : value . join ( ', ' ) ,
169+ } ) ,
170+ response . headers || { } ,
171+ )
164172
165- const bodyBuffer = await streamToBuffer ( response . body )
173+ const bodyBuffer = await streamToBuffer ( response . body )
166174
167- restoreEnvironment ( )
175+ restoreEnvironment ( )
168176
169- return {
170- statusCode : response . statusCode ,
171- bodyBuffer,
172- body : bodyBuffer . toString ( 'utf-8' ) ,
173- headers : responseHeaders ,
174- isBase64Encoded : response . isBase64Encoded ,
177+ return {
178+ statusCode : response . statusCode ,
179+ bodyBuffer,
180+ body : bodyBuffer . toString ( 'utf-8' ) ,
181+ headers : responseHeaders ,
182+ isBase64Encoded : response . isBase64Encoded ,
183+ }
175184 }
185+
186+ restoreEnvironment ( )
187+
188+ return invokeFunction
176189}
177190
178191/**
179- * @typedef {typeof loadAndInvokeFunctionImpl } InvokeFunction
192+ * @typedef {Awaited<ReturnType< typeof loadFunction>> } InvokeFunction
180193 * @typedef {Promise<Awaited<ReturnType<InvokeFunction>>> } InvokeFunctionResult
181194 */
0 commit comments