Skip to content

Commit dc949b1

Browse files
committed
test: split loading and invoking function
1 parent 8d42a49 commit dc949b1

File tree

3 files changed

+72
-56
lines changed

3 files changed

+72
-56
lines changed

tests/utils/fixture.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { env } from 'node:process'
1414
import { fileURLToPath } from 'node:url'
1515
import { v4 } from 'uuid'
1616
import { LocalServer } from './local-server.js'
17-
import { loadAndInvokeFunctionImpl, type FunctionInvocationOptions } from './lambda-helpers.mjs'
17+
import { loadFunction, type FunctionInvocationOptions } from './lambda-helpers.mjs'
1818

1919
import { glob } from 'fast-glob'
2020
import {
@@ -345,7 +345,8 @@ export async function invokeFunction(
345345
.spyOn(process, 'cwd')
346346
.mockReturnValue(join(ctx.functionDist, SERVER_HANDLER_NAME))
347347
try {
348-
return await loadAndInvokeFunctionImpl(ctx, options)
348+
const invokeFunctionImpl = await loadFunction(ctx, options)
349+
return await invokeFunctionImpl(options)
349350
} finally {
350351
cwdMock.mockRestore()
351352
}

tests/utils/lambda-helpers.mjs

+65-52
Original file line numberDiff line numberDiff line change
@@ -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,76 +111,87 @@ 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: {
133-
// 'x-nf-debug-logging': 1,
134-
...(headers || {}),
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: {
141+
// 'x-nf-debug-logging': 1,
142+
...(headers || {}),
143+
},
144+
httpMethod: httpMethod || 'GET',
145+
rawUrl: new URL(url || '/', 'https://example.netlify').href,
146+
flags: flags ?? DEFAULT_FLAGS,
135147
},
136-
httpMethod: httpMethod || 'GET',
137-
rawUrl: new URL(url || '/', 'https://example.netlify').href,
138-
flags: flags ?? DEFAULT_FLAGS,
139-
},
140-
lambdaFunc: { handler },
141-
timeoutMs: 4_000,
142-
onInvocationEnd: (error) => {
143-
// lambda-local resolve promise return from execute when response is closed
144-
// but we should wait for tracked background work to finish
145-
// before resolving the promise to allow background work to finish
146-
if (error) {
147-
rejectInvocation(error)
148-
} else {
149-
resolveInvocation()
150-
}
151-
},
152-
})
148+
lambdaFunc: { handler },
149+
timeoutMs: 4_000,
150+
onInvocationEnd: (error) => {
151+
// lambda-local resolve promise return from execute when response is closed
152+
// but we should wait for tracked background work to finish
153+
// before resolving the promise to allow background work to finish
154+
if (error) {
155+
rejectInvocation(error)
156+
} else {
157+
resolveInvocation()
158+
}
159+
},
160+
})
153161

154-
await invocationPromise
162+
await invocationPromise
155163

156-
if (!response) {
157-
throw new Error('No response from lambda-local')
158-
}
164+
if (!response) {
165+
throw new Error('No response from lambda-local')
166+
}
159167

160-
const responseHeaders = Object.entries(response.multiValueHeaders || {}).reduce(
161-
(prev, [key, value]) => ({
162-
...prev,
163-
[key]: value.length === 1 ? `${value}` : value.join(', '),
164-
}),
165-
response.headers || {},
166-
)
168+
const responseHeaders = Object.entries(response.multiValueHeaders || {}).reduce(
169+
(prev, [key, value]) => ({
170+
...prev,
171+
[key]: value.length === 1 ? `${value}` : value.join(', '),
172+
}),
173+
response.headers || {},
174+
)
167175

168-
const bodyBuffer = await streamToBuffer(response.body)
176+
const bodyBuffer = await streamToBuffer(response.body)
169177

170-
restoreEnvironment()
178+
restoreEnvironment()
171179

172-
return {
173-
statusCode: response.statusCode,
174-
bodyBuffer,
175-
body: bodyBuffer.toString('utf-8'),
176-
headers: responseHeaders,
177-
isBase64Encoded: response.isBase64Encoded,
180+
return {
181+
statusCode: response.statusCode,
182+
bodyBuffer,
183+
body: bodyBuffer.toString('utf-8'),
184+
headers: responseHeaders,
185+
isBase64Encoded: response.isBase64Encoded,
186+
}
178187
}
188+
189+
restoreEnvironment()
190+
191+
return invokeFunction
179192
}
180193

181194
/**
182-
* @typedef {typeof loadAndInvokeFunctionImpl} InvokeFunction
195+
* @typedef {Awaited<ReturnType<typeof loadFunction>>} InvokeFunction
183196
* @typedef {Promise<Awaited<ReturnType<InvokeFunction>>>} InvokeFunctionResult
184197
*/

tests/utils/sandbox-child.mjs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @ts-check
22

33
import { getLogger } from 'lambda-local'
4-
import { loadAndInvokeFunctionImpl } from './lambda-helpers.mjs'
4+
import { loadFunction } from './lambda-helpers.mjs'
55

66
getLogger().level = 'alert'
77

@@ -17,7 +17,9 @@ process.on(
1717
try {
1818
const [ctx, options] = msg.args
1919

20-
const result = await loadAndInvokeFunctionImpl(ctx, options)
20+
const invokeFunctionImpl = await loadFunction(ctx, options)
21+
const result = await invokeFunctionImpl(options)
22+
2123
if (process.send) {
2224
process.send({
2325
action: 'invokeFunctionResult',

0 commit comments

Comments
 (0)