@hubspot/ui-extensions-dev-server 1.1.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/DevServerState.d.ts +1 -1
- package/dist/lib/ExtensionsWebSocket.js +26 -2
- package/dist/lib/__tests__/ExtensionsWebSocket.spec.js +42 -8
- package/dist/lib/__tests__/app-functions/context.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/context.spec.js +101 -0
- package/dist/lib/__tests__/app-functions/errorReporter.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/errorReporter.spec.js +102 -0
- package/dist/lib/__tests__/app-functions/executor_v20231.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/executor_v20231.spec.js +168 -0
- package/dist/lib/__tests__/app-functions/executor_v20232.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/executor_v20232.spec.js +190 -0
- package/dist/lib/__tests__/app-functions/fixtures/constants.d.ts +18 -0
- package/dist/lib/__tests__/app-functions/fixtures/constants.js +139 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-async-fails.cjs +8 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-async-fails.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-async-succeeds.cjs +8 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-async-succeeds.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-callback-on-promise-rejected.cjs +8 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-callback-on-promise-rejected.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-callback-on-promise-resolved.cjs +8 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-callback-on-promise-resolved.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-does-not-export-main.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-does-not-export-main.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-echos-input.cjs +8 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-echos-input.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-logs.cjs +10 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-logs.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-function.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-function.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-promise-rejected.cjs +7 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-promise-rejected.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-promise-resolved.cjs +7 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-promise-resolved.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-text.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-text.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-undefined.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-returns-undefined.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-throws-error.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-throws-error.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-times-out.cjs +10 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-times-out.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-undeclared.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-undeclared.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-uses-secret.cjs +14 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.1/app.functions/func-uses-secret.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-async-fails.cjs +5 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-async-fails.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-async-succeeds.cjs +5 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-async-succeeds.d.cts +3 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-calls-callback.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-calls-callback.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-does-not-export-main.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-does-not-export-main.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-echos-input.cjs +8 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-echos-input.d.cts +5 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-logs.cjs +10 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-logs.d.cts +3 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-function.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-function.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-implicitly.cjs +7 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-implicitly.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-promise-rejected.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-promise-rejected.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-promise-resolved.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-promise-resolved.d.cts +3 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-text.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-text.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-undefined.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-returns-undefined.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-throws-error.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-throws-error.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-times-out.cjs +12 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-times-out.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-undeclared.cjs +4 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-undeclared.d.cts +1 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-uses-secret.cjs +14 -0
- package/dist/lib/__tests__/app-functions/fixtures/v2023.2/app.functions/func-uses-secret.d.cts +4 -0
- package/dist/lib/__tests__/app-functions/secrets.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/secrets.spec.js +278 -0
- package/dist/lib/__tests__/app-functions/services/AppProxyService.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/services/AppProxyService.spec.js +667 -0
- package/dist/lib/__tests__/app-functions/services/PrivateAppUserTokenManager.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/services/PrivateAppUserTokenManager.spec.js +243 -0
- package/dist/lib/__tests__/app-functions/services/services_v20231.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/services/services_v20231.spec.js +319 -0
- package/dist/lib/__tests__/app-functions/services/services_v20232.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/services/services_v20232.spec.js +302 -0
- package/dist/lib/__tests__/app-functions/setup.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/setup.js +7 -0
- package/dist/lib/__tests__/app-functions/signing.spec.d.ts +1 -0
- package/dist/lib/__tests__/app-functions/signing.spec.js +460 -0
- package/dist/lib/__tests__/ast.spec.js +1 -1
- package/dist/lib/__tests__/server.spec.js +24 -2
- package/dist/lib/app-functions/api/privateAppUserToken.d.ts +16 -0
- package/dist/lib/app-functions/api/privateAppUserToken.js +28 -0
- package/dist/lib/app-functions/config.d.ts +4 -0
- package/dist/lib/app-functions/config.js +48 -0
- package/dist/lib/app-functions/constants.d.ts +26 -0
- package/dist/lib/app-functions/constants.js +63 -0
- package/dist/lib/app-functions/context.d.ts +3 -0
- package/dist/lib/app-functions/context.js +65 -0
- package/dist/lib/app-functions/errorReporter.d.ts +22 -0
- package/dist/lib/app-functions/errorReporter.js +42 -0
- package/dist/lib/app-functions/errors.d.ts +44 -0
- package/dist/lib/app-functions/errors.js +82 -0
- package/dist/lib/app-functions/executor.d.ts +3 -0
- package/dist/lib/app-functions/executor.js +131 -0
- package/dist/lib/app-functions/index.d.ts +4 -0
- package/dist/lib/app-functions/index.js +4 -0
- package/dist/lib/app-functions/secrets.d.ts +5 -0
- package/dist/lib/app-functions/secrets.js +55 -0
- package/dist/lib/app-functions/services/AppFunctionExecutionService.d.ts +2 -0
- package/dist/lib/app-functions/services/AppFunctionExecutionService.js +55 -0
- package/dist/lib/app-functions/services/AppProxyService.d.ts +5 -0
- package/dist/lib/app-functions/services/AppProxyService.js +196 -0
- package/dist/lib/app-functions/services/PrivateAppUserTokenManager.d.ts +22 -0
- package/dist/lib/app-functions/services/PrivateAppUserTokenManager.js +185 -0
- package/dist/lib/app-functions/services/constants.d.ts +4 -0
- package/dist/lib/app-functions/services/constants.js +4 -0
- package/dist/lib/app-functions/services/index.d.ts +3 -0
- package/dist/lib/app-functions/services/index.js +3 -0
- package/dist/lib/app-functions/services/messages.d.ts +14 -0
- package/dist/lib/app-functions/services/messages.js +36 -0
- package/dist/lib/app-functions/signing.d.ts +29 -0
- package/dist/lib/app-functions/signing.js +51 -0
- package/dist/lib/app-functions/types.d.ts +172 -0
- package/dist/lib/app-functions/types.js +6 -0
- package/dist/lib/app-functions/utils.d.ts +15 -0
- package/dist/lib/app-functions/utils.js +28 -0
- package/dist/lib/ast.js +2 -1
- package/dist/lib/server.js +15 -4
- package/dist/lib/types.d.ts +2 -2
- package/package.json +9 -6
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach, beforeEach, } from 'vitest';
|
|
2
|
+
import httpMocks from 'node-mocks-http';
|
|
3
|
+
import { EventEmitter } from 'node:events';
|
|
4
|
+
import { AppFunctionExecutionService } from "../../../app-functions/services/index.js";
|
|
5
|
+
import { TEST_CONFIG_V20232 as TEST_CONFIG } from "../fixtures/constants.js";
|
|
6
|
+
import * as executor from "../../../app-functions/executor.js";
|
|
7
|
+
import { scopesOnAccessToken as __scopesOnAccessToken } from '@hubspot/local-dev-lib/personalAccessKey';
|
|
8
|
+
import { USER_TOKEN_READ, USER_TOKEN_WRITE, } from "../../../app-functions/services/constants.js";
|
|
9
|
+
import { PrivateAppUserTokenManager } from "../../../app-functions/services/PrivateAppUserTokenManager.js";
|
|
10
|
+
vi.mock('../../../app-functions/services/PrivateAppUserTokenManager.ts');
|
|
11
|
+
vi.mock('@hubspot/local-dev-lib/personalAccessKey');
|
|
12
|
+
const scopesOnAccessToken = __scopesOnAccessToken;
|
|
13
|
+
const callAppFunction = async (functionName, parameters) => {
|
|
14
|
+
const request = httpMocks.createRequest({
|
|
15
|
+
method: 'POST',
|
|
16
|
+
url: '/action/function/100',
|
|
17
|
+
params: {
|
|
18
|
+
id: 100,
|
|
19
|
+
},
|
|
20
|
+
body: {
|
|
21
|
+
serverlessFunction: functionName,
|
|
22
|
+
parameters,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
const response = httpMocks.createResponse({
|
|
26
|
+
req: request,
|
|
27
|
+
eventEmitter: EventEmitter,
|
|
28
|
+
});
|
|
29
|
+
const handler = AppFunctionExecutionService(TEST_CONFIG);
|
|
30
|
+
// Hold response until the handler finishes writing to it. THis must
|
|
31
|
+
// be set up before calling the handler or it may miss the `end` event.
|
|
32
|
+
const responsePromised = new Promise((resolve) => {
|
|
33
|
+
response.on('end', () => {
|
|
34
|
+
resolve(response);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
await handler(request, response);
|
|
38
|
+
return await responsePromised;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Validate the service for executing app functions
|
|
42
|
+
*/
|
|
43
|
+
describe('app function dev server', () => {
|
|
44
|
+
const initialEnvJson = JSON.stringify(process.env);
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
scopesOnAccessToken.mockResolvedValue([USER_TOKEN_READ, USER_TOKEN_WRITE]);
|
|
47
|
+
});
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
// restore process.env
|
|
50
|
+
process.env = JSON.parse(initialEnvJson);
|
|
51
|
+
vi.resetAllMocks();
|
|
52
|
+
vi.restoreAllMocks();
|
|
53
|
+
});
|
|
54
|
+
it('returns "200 OK" response if function execution succeeded', async () => {
|
|
55
|
+
const getTokenspy = vi.spyOn(PrivateAppUserTokenManager.prototype, 'getPrivateAppUserToken');
|
|
56
|
+
const response = await callAppFunction('returns-text');
|
|
57
|
+
// Validate response status and body
|
|
58
|
+
expect(response.statusCode).toEqual(200);
|
|
59
|
+
expect(response._getJSONData()).toEqual({
|
|
60
|
+
logId: 'n/a',
|
|
61
|
+
response: 'result',
|
|
62
|
+
});
|
|
63
|
+
// Validate log output
|
|
64
|
+
expect(TEST_CONFIG.logger.debug).toHaveBeenCalledWith(expect.stringContaining('App function "returns-text" execution succeeded'));
|
|
65
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledTimes(0);
|
|
66
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledTimes(0);
|
|
67
|
+
// Validate process.env is put back to what it was before the call
|
|
68
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
69
|
+
// get the token
|
|
70
|
+
expect(getTokenspy).toHaveBeenCalledTimes(1);
|
|
71
|
+
});
|
|
72
|
+
it('returns "400 Bad Request" response if function execution failed', async () => {
|
|
73
|
+
const response = await callAppFunction('throws-error');
|
|
74
|
+
// Validate response status and body
|
|
75
|
+
expect(response.statusCode).toEqual(400);
|
|
76
|
+
const body = response._getJSONData();
|
|
77
|
+
expect(body).toHaveProperty('status', 'error');
|
|
78
|
+
expect(body).toHaveProperty('category', 'VALIDATION_ERROR');
|
|
79
|
+
const exception = body.errors?.[0]?.context?.exception?.[0];
|
|
80
|
+
expect(exception).toEqual('Error: Oops');
|
|
81
|
+
// Validate log output
|
|
82
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "throws-error" execution failed'));
|
|
83
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith('App function encountered an uncaught error.', expect.anything());
|
|
84
|
+
// Validate process.env is put back to what it was before the call
|
|
85
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
86
|
+
});
|
|
87
|
+
describe('handles asynchronous functions (promise chaining)', () => {
|
|
88
|
+
it('returns "200 OK" response if function returns a promise that resolves', async () => {
|
|
89
|
+
const response = await callAppFunction('returns-promise-resolved');
|
|
90
|
+
// Validate response status and body
|
|
91
|
+
expect(response.statusCode).toEqual(200);
|
|
92
|
+
expect(response._getJSONData()).toEqual({
|
|
93
|
+
logId: 'n/a',
|
|
94
|
+
response: { result: 'simulated' },
|
|
95
|
+
});
|
|
96
|
+
// Validate log output
|
|
97
|
+
expect(TEST_CONFIG.logger.debug).toHaveBeenCalledWith(expect.stringContaining('App function "returns-promise-resolved" execution succeeded'));
|
|
98
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledTimes(0);
|
|
99
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledTimes(0);
|
|
100
|
+
// Validate process.env is put back to what it was before the call
|
|
101
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
102
|
+
});
|
|
103
|
+
it('returns "400 Bad Request" response if function returns a promise that rejects', async () => {
|
|
104
|
+
const response = await callAppFunction('returns-promise-rejected');
|
|
105
|
+
// Validate response status and body
|
|
106
|
+
expect(response.statusCode).toEqual(400);
|
|
107
|
+
const body = response._getJSONData();
|
|
108
|
+
expect(body).toHaveProperty('status', 'error');
|
|
109
|
+
expect(body).toHaveProperty('category', 'VALIDATION_ERROR');
|
|
110
|
+
const exception = body.errors?.[0]?.context?.exception?.[0];
|
|
111
|
+
expect(exception).toEqual('Error: fail');
|
|
112
|
+
// Validate log output
|
|
113
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "returns-promise-rejected" execution failed'));
|
|
114
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith('App function encountered an uncaught error.', expect.anything());
|
|
115
|
+
// Validate process.env is put back to what it was before the call
|
|
116
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('handles asynchronous functions (async/await)', () => {
|
|
120
|
+
it('returns "200 OK" response if an async function execution succeeded', async () => {
|
|
121
|
+
const response = await callAppFunction('async-succeeds');
|
|
122
|
+
// Validate response status and body
|
|
123
|
+
expect(response.statusCode).toEqual(200);
|
|
124
|
+
expect(response._getJSONData()).toEqual({
|
|
125
|
+
logId: 'n/a',
|
|
126
|
+
response: { result: 'simulated' },
|
|
127
|
+
});
|
|
128
|
+
// Validate log output
|
|
129
|
+
expect(TEST_CONFIG.logger.debug).toHaveBeenCalledWith(expect.stringContaining('App function "async-succeeds" execution succeeded'));
|
|
130
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledTimes(0);
|
|
131
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledTimes(0);
|
|
132
|
+
// Validate process.env is put back to what it was before the call
|
|
133
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
134
|
+
});
|
|
135
|
+
it('returns "400 Bad Request" response if an async function execution failed', async () => {
|
|
136
|
+
const response = await callAppFunction('async-fails');
|
|
137
|
+
// Validate response status and body
|
|
138
|
+
expect(response.statusCode).toEqual(400);
|
|
139
|
+
const body = response._getJSONData();
|
|
140
|
+
expect(body).toHaveProperty('status', 'error');
|
|
141
|
+
expect(body).toHaveProperty('category', 'VALIDATION_ERROR');
|
|
142
|
+
const exception = body.errors?.[0]?.context?.exception?.[0];
|
|
143
|
+
expect(exception).toEqual('Error: fail');
|
|
144
|
+
// Validate log output
|
|
145
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "async-fails" execution failed'));
|
|
146
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith('App function encountered an uncaught error.', expect.anything());
|
|
147
|
+
// Validate process.env is put back to what it was before the call
|
|
148
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
it('returns "200 OK" response if function returns implicitly (only 2023.2)', async () => {
|
|
152
|
+
const response = await callAppFunction('returns-implicitly');
|
|
153
|
+
// Validate response status and body
|
|
154
|
+
expect(response.statusCode).toEqual(200);
|
|
155
|
+
expect(response._getJSONData()).toEqual({
|
|
156
|
+
logId: 'n/a',
|
|
157
|
+
response: null,
|
|
158
|
+
});
|
|
159
|
+
// Validate log output
|
|
160
|
+
expect(TEST_CONFIG.logger.debug).toHaveBeenCalledWith(expect.stringContaining('App function "returns-implicitly" execution succeeded'));
|
|
161
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledTimes(0);
|
|
162
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledTimes(0);
|
|
163
|
+
// Validate process.env is put back to what it was before the call
|
|
164
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
165
|
+
});
|
|
166
|
+
it('returns "400 Bad Request" response if function not found', async () => {
|
|
167
|
+
const response = await callAppFunction('does-not-exist');
|
|
168
|
+
// Validate response status and body
|
|
169
|
+
expect(response.statusCode).toEqual(400);
|
|
170
|
+
const body = response._getJSONData();
|
|
171
|
+
expect(body).toHaveProperty('status', 'error');
|
|
172
|
+
expect(body).toHaveProperty('category', 'VALIDATION_ERROR');
|
|
173
|
+
const exception = body.errors?.[0]?.context?.exception?.[0];
|
|
174
|
+
expect(exception).toMatch(/doesn't exist in this project/);
|
|
175
|
+
// Validate log output
|
|
176
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "does-not-exist" execution failed'));
|
|
177
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith(expect.stringContaining('Could not find file'));
|
|
178
|
+
// Validate process.env is put back to what it was before the call
|
|
179
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
180
|
+
});
|
|
181
|
+
it('returns "400 Bad Request" response if function does not export main', async () => {
|
|
182
|
+
// TEST_CONFIG.functionTimeoutMs = 250
|
|
183
|
+
const response = await callAppFunction('does-not-export-main');
|
|
184
|
+
// Validate response status and body
|
|
185
|
+
expect(response.statusCode).toEqual(400);
|
|
186
|
+
const body = response._getJSONData();
|
|
187
|
+
expect(body).toHaveProperty('status', 'error');
|
|
188
|
+
expect(body).toHaveProperty('category', 'VALIDATION_ERROR');
|
|
189
|
+
const exception = body.errors?.[0]?.context?.exception?.[0];
|
|
190
|
+
expect(exception).toMatch(/customerPayload\.main is not a function/);
|
|
191
|
+
// Validate log output
|
|
192
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "does-not-export-main" execution failed'));
|
|
193
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith(expect.stringContaining('Could not find "main" export in'));
|
|
194
|
+
// Validate process.env is put back to what it was before the call
|
|
195
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
196
|
+
});
|
|
197
|
+
it('returns "400 Bad Request" response if function returns invalid json', async () => {
|
|
198
|
+
// TEST_CONFIG.functionTimeoutMs = 250
|
|
199
|
+
const response = await callAppFunction('returns-function');
|
|
200
|
+
// Validate response status and body
|
|
201
|
+
expect(response.statusCode).toEqual(400);
|
|
202
|
+
const body = response._getJSONData();
|
|
203
|
+
expect(body).toHaveProperty('status', 'error');
|
|
204
|
+
expect(body).toHaveProperty('category', 'VALIDATION_ERROR');
|
|
205
|
+
const exception = body.errors?.[0]?.context?.exception?.[0];
|
|
206
|
+
expect(exception).toMatch(/Wrong arguments/);
|
|
207
|
+
// Validate log output
|
|
208
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "returns-function" execution failed'));
|
|
209
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith('App function reponse is not valid JSON.');
|
|
210
|
+
// Validate process.env is put back to what it was before the call
|
|
211
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
212
|
+
});
|
|
213
|
+
it('returns "200 OK" response if function returns before timeout', async () => {
|
|
214
|
+
// TEST_CONFIG.functionTimeoutMs = 250
|
|
215
|
+
const response = await callAppFunction('times-out', { delayMs: 200 });
|
|
216
|
+
const variance = 10; // milliseconds
|
|
217
|
+
// Validate response status and body
|
|
218
|
+
expect(response.statusCode).toEqual(200);
|
|
219
|
+
const body = response._getJSONData();
|
|
220
|
+
expect(body).toEqual({
|
|
221
|
+
logId: 'n/a',
|
|
222
|
+
response: { status: 'success', elapsedMs: expect.anything() },
|
|
223
|
+
});
|
|
224
|
+
expect(body.response.elapsedMs).toBeGreaterThanOrEqual(200 - variance);
|
|
225
|
+
expect(body.response.elapsedMs).toBeLessThanOrEqual(200 + variance);
|
|
226
|
+
// Validate log output
|
|
227
|
+
expect(TEST_CONFIG.logger.debug).toHaveBeenCalledWith(expect.stringContaining('App function "times-out" execution succeeded'));
|
|
228
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledTimes(0);
|
|
229
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledTimes(0);
|
|
230
|
+
// Validate process.env is put back to what it was before the call
|
|
231
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
232
|
+
});
|
|
233
|
+
it('returns "400 Bad Request" response if function returns after timeout', async () => {
|
|
234
|
+
// TEST_CONFIG.functionTimeoutMs = 250
|
|
235
|
+
const response = await callAppFunction('times-out', { delayMs: 300 });
|
|
236
|
+
// Validate response status and body
|
|
237
|
+
expect(response.statusCode).toEqual(400);
|
|
238
|
+
const body = response._getJSONData();
|
|
239
|
+
expect(body).toHaveProperty('status', 'error');
|
|
240
|
+
expect(body).toHaveProperty('category', 'VALIDATION_ERROR');
|
|
241
|
+
const exception = body.errors?.[0]?.context?.exception?.[0];
|
|
242
|
+
expect(exception).toMatch(/Task timed out after/);
|
|
243
|
+
// Validate log output
|
|
244
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "times-out" execution failed'));
|
|
245
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith('App function failed to callback within 0.25 second.');
|
|
246
|
+
// Validate process.env is put back to what it was before the call
|
|
247
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
248
|
+
});
|
|
249
|
+
it('returns "500 Internal Server Error" response if something went wrong', async () => {
|
|
250
|
+
const error = new Error('Something went terribly wrong!');
|
|
251
|
+
vi.spyOn(executor, 'executeFunction').mockImplementation(() => {
|
|
252
|
+
throw error;
|
|
253
|
+
});
|
|
254
|
+
// Act
|
|
255
|
+
const response = await callAppFunction('returns-text');
|
|
256
|
+
// Validate response status and body
|
|
257
|
+
expect(response.statusCode).toEqual(500);
|
|
258
|
+
const body = response._getJSONData();
|
|
259
|
+
expect(body).toHaveProperty('status', 'error');
|
|
260
|
+
expect(body).not.toHaveProperty('category', 'INTERNAL_ERROR');
|
|
261
|
+
expect(body).toHaveProperty('message', 'internal error');
|
|
262
|
+
// Validate log output
|
|
263
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledWith(expect.stringContaining('App function "returns-text" execution failed due to server internal error'));
|
|
264
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledWith(error);
|
|
265
|
+
// Validate process.env is put back to what it was before the call
|
|
266
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
267
|
+
});
|
|
268
|
+
it('logs to console from inside the function', async () => {
|
|
269
|
+
const log = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
270
|
+
const debug = vi.spyOn(console, 'debug').mockImplementation(() => { });
|
|
271
|
+
const info = vi.spyOn(console, 'info').mockImplementation(() => { });
|
|
272
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
273
|
+
const error = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
274
|
+
// Act
|
|
275
|
+
const response = await callAppFunction('logs');
|
|
276
|
+
// Validate response status and body
|
|
277
|
+
expect(response.statusCode).toEqual(200);
|
|
278
|
+
expect(response._getJSONData()).toEqual({
|
|
279
|
+
logId: 'n/a',
|
|
280
|
+
response: { status: 'success' },
|
|
281
|
+
});
|
|
282
|
+
// Validate function logging
|
|
283
|
+
expect(log).toHaveBeenCalledTimes(1);
|
|
284
|
+
expect(log).toHaveBeenCalledWith('log line');
|
|
285
|
+
expect(debug).toHaveBeenCalledTimes(1);
|
|
286
|
+
expect(debug).toHaveBeenCalledWith('debug line');
|
|
287
|
+
expect(info).toHaveBeenCalledTimes(2);
|
|
288
|
+
expect(info).toHaveBeenNthCalledWith(1, 'info line');
|
|
289
|
+
expect(info).toHaveBeenNthCalledWith(2, 'print data:', [1, 2]);
|
|
290
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
291
|
+
expect(warn).toHaveBeenCalledWith('warn line');
|
|
292
|
+
expect(error).toHaveBeenCalledTimes(1);
|
|
293
|
+
expect(error).toHaveBeenCalledWith('error line');
|
|
294
|
+
// Validate service logging, which is separate from function logging
|
|
295
|
+
expect(TEST_CONFIG.logger.debug).toHaveBeenCalledTimes(1);
|
|
296
|
+
expect(TEST_CONFIG.logger.debug).toHaveBeenNthCalledWith(1, expect.stringContaining('App function "logs" execution succeeded'));
|
|
297
|
+
expect(TEST_CONFIG.logger.warn).toHaveBeenCalledTimes(0);
|
|
298
|
+
expect(TEST_CONFIG.logger.error).toHaveBeenCalledTimes(0);
|
|
299
|
+
// Validate process.env is put back to what it was before the call
|
|
300
|
+
expect(process.env).toEqual(JSON.parse(initialEnvJson));
|
|
301
|
+
});
|
|
302
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|