serverless-spy 0.0.0
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/.eslintrc.yml +97 -0
- package/.gitattributes +24 -0
- package/.husky/pre-commit +4 -0
- package/.jsii +3199 -0
- package/.prettierignore +1 -0
- package/.prettierrc.json +5 -0
- package/API.md +123 -0
- package/LICENSE +202 -0
- package/README.md +1 -0
- package/cli/cli.ts +97 -0
- package/cli/index.html +43 -0
- package/cli/package-lock.json +2356 -0
- package/cli/package.json +14 -0
- package/cli/serverlessSpy.js +73 -0
- package/cli/spy_log.json +0 -0
- package/cli/style.css +43 -0
- package/cli/ws.ts +79 -0
- package/common/getWebSocketUrl.ts +68 -0
- package/common/package.json +22 -0
- package/common/spyEvents/DynamoDBSpyEvent.ts +12 -0
- package/common/spyEvents/EventBridgeRuleSpyEvent.ts +13 -0
- package/common/spyEvents/EventBridgeSpyEvent.ts +13 -0
- package/common/spyEvents/FunctionConsoleSpyEvent.ts +11 -0
- package/common/spyEvents/FunctionContext.ts +8 -0
- package/common/spyEvents/FunctionErrorSpyEvent.ts +9 -0
- package/common/spyEvents/FunctionRequestSpyEvent.ts +8 -0
- package/common/spyEvents/FunctionResponseSpyEvent.ts +10 -0
- package/common/spyEvents/S3SpyEvent.ts +9 -0
- package/common/spyEvents/SnsSubscriptionSpyEvent.ts +12 -0
- package/common/spyEvents/SnsTopicSpyEvent.ts +12 -0
- package/common/spyEvents/SpyEvent.ts +3 -0
- package/common/spyEvents/SpyMessage.ts +7 -0
- package/common/spyEvents/SqsSpyEvent.ts +8 -0
- package/functions/onConnect.ts +29 -0
- package/functions/onDisconnect.ts +28 -0
- package/functions/sendMessage.ts +277 -0
- package/functions/tsconfig.dev.json +16 -0
- package/functions/tsconfig.json +16 -0
- package/index.ts +2 -0
- package/lambda-extension/aws/Common.ts +88 -0
- package/lambda-extension/aws/Errors.ts +140 -0
- package/lambda-extension/aws/UserFunction.ts +169 -0
- package/lambda-extension/interceptor.ts +146 -0
- package/lambda-extension/spy-wrapper +4 -0
- package/lambda-extension/tsconfig.json +16 -0
- package/lib/ServerlessSpy.d.ts +27 -0
- package/lib/ServerlessSpy.js +301 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +14 -0
- package/listener/PrettifyForDisplay.ts +5 -0
- package/listener/RecursivePartial.ts +9 -0
- package/listener/SpyHandlers.ts.ts +190 -0
- package/listener/SpyListener.ts +104 -0
- package/listener/createServerlessSpyListener.ts +258 -0
- package/listener/index.ts +1 -0
- package/listener/matchers.ts +53 -0
- package/listener/package.json +19 -0
- package/listener/setup.ts +21 -0
- package/listener/tsconfig.dev.json +16 -0
- package/listener/tsconfig.json +16 -0
- package/package.json +132 -0
- package/scripts/run-task +1836 -0
- package/sst-esbuild/esbuild.js +57 -0
- package/x_jest.config.ts +203 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { DynamoDBSpyEvent } from 'serverless-spy-common/spyEvents/DynamoDBSpyEvent';
|
|
2
|
+
import { EventBridgeRuleSpyEvent } from 'serverless-spy-common/spyEvents/EventBridgeRuleSpyEvent';
|
|
3
|
+
import { EventBridgeSpyEvent } from 'serverless-spy-common/spyEvents/EventBridgeSpyEvent';
|
|
4
|
+
import { FunctionConsoleSpyEvent } from 'serverless-spy-common/spyEvents/FunctionConsoleSpyEvent';
|
|
5
|
+
import { FunctionRequestSpyEvent } from 'serverless-spy-common/spyEvents/FunctionRequestSpyEvent';
|
|
6
|
+
import { FunctionResponseSpyEvent } from 'serverless-spy-common/spyEvents/FunctionResponseSpyEvent';
|
|
7
|
+
import { S3SpyEvent } from 'serverless-spy-common/spyEvents/S3SpyEvent';
|
|
8
|
+
import { SnsSubscriptionSpyEvent } from 'serverless-spy-common/spyEvents/SnsSubscriptionSpyEvent';
|
|
9
|
+
import { SnsTopicSpyEvent } from 'serverless-spy-common/spyEvents/SnsTopicSpyEvent';
|
|
10
|
+
import { SqsSpyEvent } from 'serverless-spy-common/spyEvents/SqsSpyEvent';
|
|
11
|
+
|
|
12
|
+
import { WaitForParams } from './createServerlessSpyListener';
|
|
13
|
+
import { PrettifyForDisplay } from './PrettifyForDisplay';
|
|
14
|
+
import {
|
|
15
|
+
DynamoDBSpyHandler,
|
|
16
|
+
EventBridgeSpyHandler,
|
|
17
|
+
EventBridgeRuleSpyHandler,
|
|
18
|
+
S3SpyHandler,
|
|
19
|
+
SnsSubscriptionSpyHandler,
|
|
20
|
+
SnsTopicSpyHandler,
|
|
21
|
+
SqsSpyHandler,
|
|
22
|
+
FunctionRequestSpyHandler,
|
|
23
|
+
FunctionConsoleSpyHandler,
|
|
24
|
+
FunctionResponseSpyHandler,
|
|
25
|
+
} from './SpyHandlers.ts';
|
|
26
|
+
|
|
27
|
+
export type SpyListener<TSpyEvents> = {
|
|
28
|
+
[P in keyof FilterConditionally<TSpyEvents, `DynamoDB#${any}`> &
|
|
29
|
+
string as `waitFor${P}`]: <T = any>(
|
|
30
|
+
param?: PrettifyForDisplay<
|
|
31
|
+
WaitForParams<PrettifyForDisplay<DynamoDBSpyEvent>>
|
|
32
|
+
>
|
|
33
|
+
) => DynamoDBSpyHandler<T>;
|
|
34
|
+
} & {
|
|
35
|
+
[P in keyof FilterConditionally<TSpyEvents, `EventBridge#${any}`> &
|
|
36
|
+
string as `waitFor${P}`]: <T = any>(
|
|
37
|
+
param?: PrettifyForDisplay<
|
|
38
|
+
WaitForParams<PrettifyForDisplay<EventBridgeSpyEvent<T>>>
|
|
39
|
+
>
|
|
40
|
+
) => EventBridgeSpyHandler<T>;
|
|
41
|
+
} & {
|
|
42
|
+
[P in keyof FilterConditionally<TSpyEvents, `EventBridgeRule#${any}`> &
|
|
43
|
+
string as `waitFor${P}`]: <T = any>(
|
|
44
|
+
param?: PrettifyForDisplay<
|
|
45
|
+
WaitForParams<PrettifyForDisplay<EventBridgeRuleSpyEvent<T>>>
|
|
46
|
+
>
|
|
47
|
+
) => EventBridgeRuleSpyHandler<T>;
|
|
48
|
+
} & {
|
|
49
|
+
[P in keyof FilterConditionally<TSpyEvents, `S3#${any}`> &
|
|
50
|
+
string as `waitFor${P}`]: (
|
|
51
|
+
param?: PrettifyForDisplay<WaitForParams<PrettifyForDisplay<S3SpyEvent>>>
|
|
52
|
+
) => S3SpyHandler;
|
|
53
|
+
} & {
|
|
54
|
+
[P in keyof FilterConditionally<TSpyEvents, `SnsSubscription#${any}`> &
|
|
55
|
+
string as `waitFor${P}`]: <T = any>(
|
|
56
|
+
param?: PrettifyForDisplay<
|
|
57
|
+
WaitForParams<PrettifyForDisplay<SnsSubscriptionSpyEvent<T>>>
|
|
58
|
+
>
|
|
59
|
+
) => SnsSubscriptionSpyHandler<T>;
|
|
60
|
+
} & {
|
|
61
|
+
[P in keyof FilterConditionally<TSpyEvents, `SnsTopic#${any}`> &
|
|
62
|
+
string as `waitFor${P}`]: <T = any>(
|
|
63
|
+
param?: PrettifyForDisplay<
|
|
64
|
+
WaitForParams<PrettifyForDisplay<SnsTopicSpyEvent<T>>>
|
|
65
|
+
>
|
|
66
|
+
) => SnsTopicSpyHandler<T>;
|
|
67
|
+
} & {
|
|
68
|
+
[P in keyof FilterConditionally<TSpyEvents, `Sqs#${any}`> &
|
|
69
|
+
string as `waitFor${P}`]: <T = any>(
|
|
70
|
+
param?: PrettifyForDisplay<
|
|
71
|
+
WaitForParams<PrettifyForDisplay<SqsSpyEvent<T>>>
|
|
72
|
+
>
|
|
73
|
+
) => SqsSpyHandler<T>;
|
|
74
|
+
} & {
|
|
75
|
+
[P in keyof FilterConditionally<TSpyEvents, `Function#${any}#Request`> &
|
|
76
|
+
string as `waitFor${P}`]: <T = any>(
|
|
77
|
+
param?: PrettifyForDisplay<
|
|
78
|
+
WaitForParams<PrettifyForDisplay<FunctionRequestSpyEvent<T>>>
|
|
79
|
+
>
|
|
80
|
+
) => FunctionRequestSpyHandler<T>;
|
|
81
|
+
} & {
|
|
82
|
+
[P in keyof FilterConditionally<TSpyEvents, `Function#${any}#Console`> &
|
|
83
|
+
string as `waitFor${P}`]: <T = any>(
|
|
84
|
+
param?: PrettifyForDisplay<
|
|
85
|
+
WaitForParams<PrettifyForDisplay<FunctionConsoleSpyEvent<T>>>
|
|
86
|
+
>
|
|
87
|
+
) => FunctionConsoleSpyHandler<T>;
|
|
88
|
+
} & {
|
|
89
|
+
[P in keyof FilterConditionally<TSpyEvents, `Function#${any}#Response`> &
|
|
90
|
+
string as `waitFor${P}`]: <T = any>(
|
|
91
|
+
param?: PrettifyForDisplay<
|
|
92
|
+
WaitForParams<PrettifyForDisplay<FunctionResponseSpyEvent<T>>>
|
|
93
|
+
> // filter?: (event: FunctionResponseSpyEvent<T>) => boolean
|
|
94
|
+
) => FunctionResponseSpyHandler<T>;
|
|
95
|
+
} & {
|
|
96
|
+
stop: () => void;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
type FilterConditionally<Source, Condition> = Pick<
|
|
100
|
+
Source,
|
|
101
|
+
{
|
|
102
|
+
[K in keyof Source]: Source[K] extends Condition ? K : never;
|
|
103
|
+
}[keyof Source]
|
|
104
|
+
>;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/* eslint-disable no-prototype-builtins */
|
|
2
|
+
import { Credentials } from '@aws-sdk/types';
|
|
3
|
+
import { getWebSocketUrl } from 'serverless-spy-common/getWebSocketUrl';
|
|
4
|
+
import { FunctionRequestSpyEvent } from 'serverless-spy-common/spyEvents/FunctionRequestSpyEvent';
|
|
5
|
+
import { SpyEvent } from 'serverless-spy-common/spyEvents/SpyEvent';
|
|
6
|
+
import { SpyMessage } from 'serverless-spy-common/spyEvents/SpyMessage';
|
|
7
|
+
import WebSocket from 'ws';
|
|
8
|
+
import { SpyListener } from './SpyListener';
|
|
9
|
+
|
|
10
|
+
type ServerlessSpyListenerParams = {
|
|
11
|
+
serverlessSpyWsUrl: string;
|
|
12
|
+
credentials?: Credentials;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export async function createServerlessSpyListener<TSpyEvents>(
|
|
16
|
+
params: ServerlessSpyListenerParams
|
|
17
|
+
) {
|
|
18
|
+
const urlSigned = await getWebSocketUrl(
|
|
19
|
+
params.serverlessSpyWsUrl,
|
|
20
|
+
params.credentials
|
|
21
|
+
);
|
|
22
|
+
const ws = new WebSocket(urlSigned);
|
|
23
|
+
const messages: SpyMessageStorage[] = [];
|
|
24
|
+
let trackers: Tracker[] = [];
|
|
25
|
+
let closed = false;
|
|
26
|
+
const functionPrefix = 'waitFor';
|
|
27
|
+
|
|
28
|
+
ws.on('open', () => {
|
|
29
|
+
console.log('connected ' + new Date().toISOString());
|
|
30
|
+
});
|
|
31
|
+
ws.on('message', (data) => {
|
|
32
|
+
console.log(`From server: ${data}`);
|
|
33
|
+
|
|
34
|
+
if (closed) return;
|
|
35
|
+
const message = JSON.parse(data.toString()) as SpyMessageStorage;
|
|
36
|
+
|
|
37
|
+
message.serviceKeyForFunction = message.serviceKey.replace(/#/g, '');
|
|
38
|
+
|
|
39
|
+
if (message.serviceKey.startsWith('Function')) {
|
|
40
|
+
message.functionContextAwsRequestId = (
|
|
41
|
+
message.data as FunctionRequestSpyEvent
|
|
42
|
+
).context.awsRequestId;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
messages.push(message);
|
|
46
|
+
resolveOldTrackerWithNewMessage(message);
|
|
47
|
+
});
|
|
48
|
+
ws.on('close', () => {
|
|
49
|
+
// console.log("disconnected " + new Date().toISOString());
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const trackerMatchMessage = (
|
|
53
|
+
tracker: Tracker,
|
|
54
|
+
message: SpyMessageStorage
|
|
55
|
+
) => {
|
|
56
|
+
if (tracker.finished) return;
|
|
57
|
+
|
|
58
|
+
if (
|
|
59
|
+
(tracker.serviceKey && tracker.serviceKey === message.serviceKey) ||
|
|
60
|
+
(tracker.serviceKeyForFunction &&
|
|
61
|
+
tracker.serviceKeyForFunction === message.serviceKeyForFunction)
|
|
62
|
+
) {
|
|
63
|
+
if (trackerMatchCondition(tracker, message)) {
|
|
64
|
+
tracker.finished = true;
|
|
65
|
+
|
|
66
|
+
const spyAndJestMatchers: any = {
|
|
67
|
+
getData: () => message.data,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const serviceKeyForFunction = tracker.serviceKeyForFunction;
|
|
71
|
+
if (
|
|
72
|
+
serviceKeyForFunction &&
|
|
73
|
+
serviceKeyForFunction.startsWith('Function') &&
|
|
74
|
+
(serviceKeyForFunction.endsWith('Request') ||
|
|
75
|
+
serviceKeyForFunction.endsWith('Console'))
|
|
76
|
+
) {
|
|
77
|
+
let serviceKeyForFunctionResponse = serviceKeyForFunction;
|
|
78
|
+
|
|
79
|
+
if (serviceKeyForFunctionResponse.endsWith('Request')) {
|
|
80
|
+
serviceKeyForFunctionResponse =
|
|
81
|
+
serviceKeyForFunctionResponse.substring(
|
|
82
|
+
0,
|
|
83
|
+
serviceKeyForFunctionResponse.length - 'Request'.length
|
|
84
|
+
);
|
|
85
|
+
} else if (serviceKeyForFunctionResponse.endsWith('Console')) {
|
|
86
|
+
serviceKeyForFunctionResponse =
|
|
87
|
+
serviceKeyForFunctionResponse.substring(
|
|
88
|
+
0,
|
|
89
|
+
serviceKeyForFunctionResponse.length - 'Console'.length
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
serviceKeyForFunctionResponse += 'Response';
|
|
94
|
+
|
|
95
|
+
spyAndJestMatchers.followedByResponse = (paramsW: WaitForParams) => {
|
|
96
|
+
return createWaitForXXXFunc(
|
|
97
|
+
serviceKeyForFunctionResponse,
|
|
98
|
+
paramsW,
|
|
99
|
+
(message.data as FunctionRequestSpyEvent).context.awsRequestId
|
|
100
|
+
)();
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const proxy = new Proxy(spyAndJestMatchers, {
|
|
105
|
+
get: function (target: any, objectKey: string) {
|
|
106
|
+
if (target.hasOwnProperty(objectKey)) {
|
|
107
|
+
return target[objectKey];
|
|
108
|
+
} else if (objectKey !== 'then') {
|
|
109
|
+
return function () {
|
|
110
|
+
const jestFunctionToExecute = (expect(message.data) as any)[
|
|
111
|
+
objectKey
|
|
112
|
+
];
|
|
113
|
+
jestFunctionToExecute.apply(undefined, arguments);
|
|
114
|
+
return proxy;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
tracker.promiseResolve(proxy);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const resolveTrackerInOldMessages = (tracker: Tracker) => {
|
|
128
|
+
for (const message of messages) {
|
|
129
|
+
if (trackerMatchMessage(tracker, message)) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return false;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const resolveOldTrackerWithNewMessage = (message: SpyMessageStorage) => {
|
|
138
|
+
for (let index = 0; index < trackers.length; index++) {
|
|
139
|
+
const tracker = trackers[index];
|
|
140
|
+
if (trackerMatchMessage(tracker, message)) {
|
|
141
|
+
trackers = trackers.splice(index, 1);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return false;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const spyListener = {} as SpyListener<TSpyEvents>;
|
|
150
|
+
|
|
151
|
+
spyListener.stop = () => {
|
|
152
|
+
closed = true;
|
|
153
|
+
ws.close();
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const proxy = new Proxy(spyListener, {
|
|
157
|
+
get: function (target: any, objectKey: string) {
|
|
158
|
+
if (target.hasOwnProperty(objectKey)) {
|
|
159
|
+
return target[objectKey];
|
|
160
|
+
} else if (
|
|
161
|
+
typeof objectKey === 'string' &&
|
|
162
|
+
objectKey.startsWith(functionPrefix)
|
|
163
|
+
) {
|
|
164
|
+
const paramsW = arguments[0] as WaitForParams;
|
|
165
|
+
const serviceKeyForFunction = objectKey.substring(
|
|
166
|
+
functionPrefix.length
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
return createWaitForXXXFunc(serviceKeyForFunction, paramsW);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return proxy as SpyListener<TSpyEvents>;
|
|
175
|
+
|
|
176
|
+
function trackerMatchCondition(tracker: Tracker, message: SpyMessageStorage) {
|
|
177
|
+
const matchCondition =
|
|
178
|
+
(tracker.condition && tracker.condition(message.data)) ||
|
|
179
|
+
!tracker.condition;
|
|
180
|
+
|
|
181
|
+
const matchRequestId =
|
|
182
|
+
(tracker.functionContextAwsRequestId &&
|
|
183
|
+
tracker.functionContextAwsRequestId ===
|
|
184
|
+
message.functionContextAwsRequestId) ||
|
|
185
|
+
!tracker.functionContextAwsRequestId;
|
|
186
|
+
|
|
187
|
+
if (tracker.functionContextAwsRequestId) {
|
|
188
|
+
console.log(
|
|
189
|
+
`${tracker.functionContextAwsRequestId} - ${message.functionContextAwsRequestId}`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return matchCondition && matchRequestId;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function createWaitForXXXFunc(
|
|
197
|
+
serviceKeyForFunction: string,
|
|
198
|
+
paramsW: WaitForParams<SpyEvent>,
|
|
199
|
+
functionContextAwsRequestId?: string
|
|
200
|
+
) {
|
|
201
|
+
let tracker: Tracker;
|
|
202
|
+
|
|
203
|
+
const promise = new Promise((resolve, reject) => {
|
|
204
|
+
tracker = {
|
|
205
|
+
finished: false,
|
|
206
|
+
promiseResolve: resolve,
|
|
207
|
+
promiseReject: reject,
|
|
208
|
+
serviceKeyForFunction,
|
|
209
|
+
functionContextAwsRequestId,
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return function waitForXXXFunc() {
|
|
214
|
+
tracker.condition = paramsW?.condition;
|
|
215
|
+
|
|
216
|
+
const timer = setTimeout(() => {
|
|
217
|
+
if (tracker.finished) return;
|
|
218
|
+
tracker.finished = true;
|
|
219
|
+
tracker.promiseReject(
|
|
220
|
+
new Error(
|
|
221
|
+
`Timeout waiting for Serverless Spy message ${serviceKeyForFunction}`
|
|
222
|
+
)
|
|
223
|
+
);
|
|
224
|
+
}, paramsW?.timoutMs || 5000);
|
|
225
|
+
|
|
226
|
+
promise.finally(() => {
|
|
227
|
+
clearTimeout(timer);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (!resolveTrackerInOldMessages(tracker)) {
|
|
231
|
+
trackers.push(tracker);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return promise;
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface WaitForParams<TSpyEvent extends SpyEvent = SpyEvent> {
|
|
240
|
+
condition?: (event: TSpyEvent) => boolean;
|
|
241
|
+
timoutMs?: number;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
type Tracker = {
|
|
245
|
+
promiseResolve: (data: any) => void;
|
|
246
|
+
promiseReject: (data: any) => void;
|
|
247
|
+
finished: boolean;
|
|
248
|
+
serviceKey?: string;
|
|
249
|
+
serviceKeyForFunction?: string;
|
|
250
|
+
condition?: (data: any) => boolean;
|
|
251
|
+
timoutMs?: number;
|
|
252
|
+
functionContextAwsRequestId?: string;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
type SpyMessageStorage = SpyMessage & {
|
|
256
|
+
serviceKeyForFunction: string;
|
|
257
|
+
functionContextAwsRequestId?: string;
|
|
258
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './createServerlessSpyListener';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
// import { ServerlessSpyListener } from "./ServerlessSpyListener";
|
|
3
|
+
|
|
4
|
+
type CustomMatcherResult = {
|
|
5
|
+
message: () => string;
|
|
6
|
+
pass: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const toReceiveEvent = async (
|
|
10
|
+
spy: any,
|
|
11
|
+
serviceKey: string,
|
|
12
|
+
condition?: (data: any) => boolean
|
|
13
|
+
): Promise<CustomMatcherResult> => {
|
|
14
|
+
console.log('NOTRI');
|
|
15
|
+
|
|
16
|
+
await sleep(3000);
|
|
17
|
+
|
|
18
|
+
// console.log("SPY", spy);
|
|
19
|
+
// const events = await spy.awaitEvents((events) => {
|
|
20
|
+
// return events.some((event) => event["detail-type"] === expected);
|
|
21
|
+
// });
|
|
22
|
+
|
|
23
|
+
// const pass = events.some((event) => event["detail-type"] === expected);
|
|
24
|
+
|
|
25
|
+
// const message = pass
|
|
26
|
+
// ? () => {
|
|
27
|
+
// return (
|
|
28
|
+
// matcherHint("toHaveEventWithDetailType", "eventsSpy", "detail-type") +
|
|
29
|
+
// "\n\n" +
|
|
30
|
+
// `Expected: not ${printExpected(expected)}\n` +
|
|
31
|
+
// `Number of events: ${printReceived(events.length)}`
|
|
32
|
+
// );
|
|
33
|
+
// }
|
|
34
|
+
// : () => {
|
|
35
|
+
// return (
|
|
36
|
+
// matcherHint("toHaveEventWithDetailType", "eventsSpy", "detail-type") +
|
|
37
|
+
// "\n\n" +
|
|
38
|
+
// `Expected: ${printExpected(expected)}\n` +
|
|
39
|
+
// (events.length > 0
|
|
40
|
+
// ? `Received: ${printReceived(events[0]?.["detail-type"])}`
|
|
41
|
+
// : `Number of events: ${printReceived(events.length)}`)
|
|
42
|
+
// );
|
|
43
|
+
// };
|
|
44
|
+
|
|
45
|
+
return { message: () => 'OK', pass: true };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function sleep(ms: number) {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
setTimeout(resolve, ms);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
*/
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "serverless-spy-listener",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"author": "",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"ws": "^8.8.1",
|
|
13
|
+
"serverless-spy-common": "*",
|
|
14
|
+
"@aws-sdk/types": "^3.127.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/ws": "^8.5.3"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// import * as matchers from './matchers';
|
|
2
|
+
|
|
3
|
+
// if (expect !== undefined) {
|
|
4
|
+
// expect.extend(matchers);
|
|
5
|
+
// } else {
|
|
6
|
+
// /* eslint-disable no-console */
|
|
7
|
+
// console.error(
|
|
8
|
+
// "Unable to find Jest's global expect." +
|
|
9
|
+
// '\nPlease check you have added jest-extended correctly to your jest configuration.' +
|
|
10
|
+
// '\nSee https://github.com/jest-community/jest-extended#setup for help.'
|
|
11
|
+
// );
|
|
12
|
+
// /* eslint-enable no-console */
|
|
13
|
+
// }
|
|
14
|
+
|
|
15
|
+
// declare global {
|
|
16
|
+
// namespace jest {
|
|
17
|
+
// interface Matchers<R> {
|
|
18
|
+
// toReceiveEvent(serviceKey: string, condition?: (data: any) => boolean): R;
|
|
19
|
+
// }
|
|
20
|
+
// }
|
|
21
|
+
// }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "Node 16",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"lib": ["es2021"],
|
|
6
|
+
"module": "esnext",
|
|
7
|
+
"target": "es2021",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"resolveJsonModule": true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "Node 16",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"lib": ["es2021"],
|
|
6
|
+
"module": "esnext",
|
|
7
|
+
"target": "es2021",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"resolveJsonModule": true
|
|
15
|
+
}
|
|
16
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "serverless-spy",
|
|
3
|
+
"repository": {
|
|
4
|
+
"type": "git",
|
|
5
|
+
"url": "git@github.com:ServerlessLife/serverless-spy.git"
|
|
6
|
+
},
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "npx projen build",
|
|
9
|
+
"bump": "npx projen bump",
|
|
10
|
+
"clobber": "npx projen clobber",
|
|
11
|
+
"compat": "npx projen compat",
|
|
12
|
+
"compile": "npx projen compile",
|
|
13
|
+
"default": "npx projen default",
|
|
14
|
+
"docgen": "npx projen docgen",
|
|
15
|
+
"eject": "npx projen eject",
|
|
16
|
+
"eslint": "npx projen eslint",
|
|
17
|
+
"package": "npx projen package",
|
|
18
|
+
"package-all": "npx projen package-all",
|
|
19
|
+
"package:js": "npx projen package:js",
|
|
20
|
+
"post-compile": "npx projen post-compile",
|
|
21
|
+
"post-upgrade": "npx projen post-upgrade",
|
|
22
|
+
"pre-compile": "npx projen pre-compile",
|
|
23
|
+
"release": "npx projen release",
|
|
24
|
+
"test": "npx projen test",
|
|
25
|
+
"test:update": "npx projen test:update",
|
|
26
|
+
"test:watch": "npx projen test:watch",
|
|
27
|
+
"unbump": "npx projen unbump",
|
|
28
|
+
"upgrade": "npx projen upgrade",
|
|
29
|
+
"watch": "npx projen watch",
|
|
30
|
+
"projen": "npx projen"
|
|
31
|
+
},
|
|
32
|
+
"author": {
|
|
33
|
+
"name": "Marko (ServerlessLife.com)",
|
|
34
|
+
"email": "marko@serverlesslife.com",
|
|
35
|
+
"organization": false
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/jest": "^27",
|
|
39
|
+
"@types/node": "^14",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^5",
|
|
41
|
+
"@typescript-eslint/parser": "^5",
|
|
42
|
+
"aws-cdk-lib": "2.37.1",
|
|
43
|
+
"constructs": "10.0.5",
|
|
44
|
+
"eslint": "^8",
|
|
45
|
+
"eslint-config-prettier": "^8.5.0",
|
|
46
|
+
"eslint-import-resolver-node": "^0.3.6",
|
|
47
|
+
"eslint-import-resolver-typescript": "^3.4.0",
|
|
48
|
+
"eslint-plugin-import": "^2.26.0",
|
|
49
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
50
|
+
"jest": "^27",
|
|
51
|
+
"jest-junit": "^13",
|
|
52
|
+
"jsii": "^1.63.2",
|
|
53
|
+
"jsii-diff": "^1.63.2",
|
|
54
|
+
"jsii-docgen": "^7.0.67",
|
|
55
|
+
"jsii-pacmak": "^1.63.2",
|
|
56
|
+
"json-schema": "^0.4.0",
|
|
57
|
+
"npm-check-updates": "^15",
|
|
58
|
+
"prettier": "^2.7.1",
|
|
59
|
+
"projen": "^0.61.7",
|
|
60
|
+
"standard-version": "^9",
|
|
61
|
+
"ts-jest": "^27",
|
|
62
|
+
"typescript": "^4.7.4"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"aws-cdk-lib": "^2.37.1",
|
|
66
|
+
"constructs": "^10.0.5"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"@aws-cdk/aws-apigatewayv2-alpha": "2.37.1-alpha.0",
|
|
70
|
+
"@aws-cdk/aws-apigatewayv2-integrations-alpha": "2.37.1-alpha.0"
|
|
71
|
+
},
|
|
72
|
+
"keywords": [
|
|
73
|
+
"cdk"
|
|
74
|
+
],
|
|
75
|
+
"main": "lib/index.js",
|
|
76
|
+
"license": "Apache-2.0",
|
|
77
|
+
"version": "0.0.0",
|
|
78
|
+
"jest": {
|
|
79
|
+
"testMatch": [
|
|
80
|
+
"<rootDir>/src/**/__tests__/**/*.ts?(x)",
|
|
81
|
+
"<rootDir>/(test|src)/**/*(*.)@(spec|test).ts?(x)"
|
|
82
|
+
],
|
|
83
|
+
"clearMocks": true,
|
|
84
|
+
"collectCoverage": true,
|
|
85
|
+
"coverageReporters": [
|
|
86
|
+
"json",
|
|
87
|
+
"lcov",
|
|
88
|
+
"clover",
|
|
89
|
+
"cobertura",
|
|
90
|
+
"text"
|
|
91
|
+
],
|
|
92
|
+
"coverageDirectory": "coverage",
|
|
93
|
+
"coveragePathIgnorePatterns": [
|
|
94
|
+
"/node_modules/"
|
|
95
|
+
],
|
|
96
|
+
"testPathIgnorePatterns": [
|
|
97
|
+
"/node_modules/"
|
|
98
|
+
],
|
|
99
|
+
"watchPathIgnorePatterns": [
|
|
100
|
+
"/node_modules/"
|
|
101
|
+
],
|
|
102
|
+
"reporters": [
|
|
103
|
+
"default",
|
|
104
|
+
[
|
|
105
|
+
"jest-junit",
|
|
106
|
+
{
|
|
107
|
+
"outputDirectory": "test-reports"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
],
|
|
111
|
+
"preset": "ts-jest",
|
|
112
|
+
"globals": {
|
|
113
|
+
"ts-jest": {
|
|
114
|
+
"tsconfig": "tsconfig.dev.json"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"types": "lib/index.d.ts",
|
|
119
|
+
"stability": "stable",
|
|
120
|
+
"jsii": {
|
|
121
|
+
"outdir": "dist",
|
|
122
|
+
"targets": {},
|
|
123
|
+
"tsc": {
|
|
124
|
+
"outDir": "lib",
|
|
125
|
+
"rootDir": "src"
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"overrides": {
|
|
129
|
+
"@types/prettier": "2.6.0"
|
|
130
|
+
},
|
|
131
|
+
"//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"."
|
|
132
|
+
}
|