@lark-apaas/action-plugin-testing 0.1.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/LICENSE +13 -0
- package/README.md +187 -0
- package/dist/index.cjs +335 -0
- package/dist/index.d.cts +338 -0
- package/dist/index.d.ts +338 -0
- package/dist/index.js +314 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Lark Technologies Pte. Ltd. and/or its affiliates
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,provided that the above copyright notice and this permission notice appear in all copies.
|
|
6
|
+
|
|
7
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
8
|
+
IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
|
|
9
|
+
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
|
10
|
+
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
|
11
|
+
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
12
|
+
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
13
|
+
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# @lark-apaas/action-plugin-testing
|
|
2
|
+
|
|
3
|
+
Testing utilities for `@lark-apaas/action-plugin-core` — provides mock context, test runner, stream helpers, and schema validation tools.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -D @lark-apaas/action-plugin-testing
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createTestContext, createTestRunner } from '@lark-apaas/action-plugin-testing';
|
|
15
|
+
import plugin from './my-plugin';
|
|
16
|
+
|
|
17
|
+
const runner = createTestRunner(plugin);
|
|
18
|
+
const context = createTestContext();
|
|
19
|
+
|
|
20
|
+
// Run an action
|
|
21
|
+
const result = await runner.run('sayHello', context, { name: 'World' });
|
|
22
|
+
console.log(result); // { greeting: 'Hello, World!' }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## API
|
|
26
|
+
|
|
27
|
+
### Test Context
|
|
28
|
+
|
|
29
|
+
#### `createTestContext(options?)`
|
|
30
|
+
|
|
31
|
+
Creates a mock `ActionContext` for testing.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { createTestContext } from '@lark-apaas/action-plugin-testing';
|
|
35
|
+
|
|
36
|
+
// Default context
|
|
37
|
+
const ctx = createTestContext();
|
|
38
|
+
|
|
39
|
+
// Custom context
|
|
40
|
+
const ctx = createTestContext({
|
|
41
|
+
userId: 'user-123',
|
|
42
|
+
tenantId: 'tenant-456',
|
|
43
|
+
appId: 'app-789',
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Test Runner
|
|
48
|
+
|
|
49
|
+
#### `createTestRunner(plugin, options?)`
|
|
50
|
+
|
|
51
|
+
Wraps a plugin instance with convenience methods for testing.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { createTestRunner } from '@lark-apaas/action-plugin-testing';
|
|
55
|
+
|
|
56
|
+
const runner = createTestRunner(plugin);
|
|
57
|
+
|
|
58
|
+
// Unary action
|
|
59
|
+
const result = await runner.run('actionName', context, input);
|
|
60
|
+
|
|
61
|
+
// Stream action
|
|
62
|
+
const stream = runner.runStream('actionName', context, input);
|
|
63
|
+
|
|
64
|
+
// Schema access
|
|
65
|
+
const inputSchema = runner.getInputSchema('actionName');
|
|
66
|
+
const outputSchema = runner.getOutputSchema('actionName');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Mock Logger
|
|
70
|
+
|
|
71
|
+
#### `createMockLogger()`
|
|
72
|
+
|
|
73
|
+
Creates a logger that records all log entries for assertions.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { createMockLogger } from '@lark-apaas/action-plugin-testing';
|
|
77
|
+
|
|
78
|
+
const logger = createMockLogger();
|
|
79
|
+
const ctx = createTestContext({ logger });
|
|
80
|
+
|
|
81
|
+
await runner.run('action', ctx, input);
|
|
82
|
+
|
|
83
|
+
// Query logs
|
|
84
|
+
logger.getLogs(); // all entries
|
|
85
|
+
logger.getLogs('error'); // filter by level
|
|
86
|
+
logger.hasLog('error'); // check existence
|
|
87
|
+
logger.getLastLog('info'); // last entry of level
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Stream Helpers
|
|
91
|
+
|
|
92
|
+
Utilities for testing async iterable streams.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import {
|
|
96
|
+
collectStream,
|
|
97
|
+
collectStreamData,
|
|
98
|
+
collectStreamText,
|
|
99
|
+
firstChunk,
|
|
100
|
+
lastChunk,
|
|
101
|
+
countChunks,
|
|
102
|
+
assertStreamChunks,
|
|
103
|
+
assertEveryChunk,
|
|
104
|
+
} from '@lark-apaas/action-plugin-testing';
|
|
105
|
+
|
|
106
|
+
const stream = runner.runStream('chat', context, input);
|
|
107
|
+
|
|
108
|
+
// Collect all chunks
|
|
109
|
+
const chunks = await collectStream(stream);
|
|
110
|
+
|
|
111
|
+
// Extract data fields from StreamChunk items
|
|
112
|
+
const data = await collectStreamData(stream);
|
|
113
|
+
|
|
114
|
+
// Concatenate text content
|
|
115
|
+
const text = await collectStreamText(stream);
|
|
116
|
+
|
|
117
|
+
// Access specific chunks
|
|
118
|
+
const first = await firstChunk(stream);
|
|
119
|
+
const last = await lastChunk(stream);
|
|
120
|
+
|
|
121
|
+
// Count without storing
|
|
122
|
+
const count = await countChunks(stream);
|
|
123
|
+
|
|
124
|
+
// Assertions
|
|
125
|
+
await assertStreamChunks(stream, [expected1, expected2]);
|
|
126
|
+
await assertEveryChunk(stream, (chunk) => chunk.data.content.length > 0);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### StreamEvent Helpers
|
|
130
|
+
|
|
131
|
+
Utilities for testing `StreamEvent` streams.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import {
|
|
135
|
+
collectStreamEvents,
|
|
136
|
+
collectEventData,
|
|
137
|
+
waitForDone,
|
|
138
|
+
waitForError,
|
|
139
|
+
expectStreamCompletes,
|
|
140
|
+
expectStreamErrors,
|
|
141
|
+
expectAggregatedResult,
|
|
142
|
+
} from '@lark-apaas/action-plugin-testing';
|
|
143
|
+
|
|
144
|
+
// Collect and categorize events
|
|
145
|
+
const { dataEvents, doneEvent, errorEvent } = await collectStreamEvents(stream);
|
|
146
|
+
|
|
147
|
+
// Collect only data payloads
|
|
148
|
+
const data = await collectEventData(stream);
|
|
149
|
+
|
|
150
|
+
// Wait for completion / error
|
|
151
|
+
const meta = await waitForDone(stream);
|
|
152
|
+
const error = await waitForError(stream);
|
|
153
|
+
|
|
154
|
+
// Assertions
|
|
155
|
+
await expectStreamCompletes(stream);
|
|
156
|
+
await expectStreamErrors(stream, 'ERROR_CODE');
|
|
157
|
+
await expectAggregatedResult(stream, expectedResult);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Schema Validation
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { parseInput, expectInputRejected } from '@lark-apaas/action-plugin-testing';
|
|
164
|
+
|
|
165
|
+
// Validate input against action schema
|
|
166
|
+
const parsed = parseInput(runner, 'actionName', { name: 'test' });
|
|
167
|
+
|
|
168
|
+
// Assert invalid input is rejected
|
|
169
|
+
expectInputRejected(runner, 'actionName', { name: 123 });
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Types
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import type {
|
|
176
|
+
TestContextOptions,
|
|
177
|
+
TestRunner,
|
|
178
|
+
TestRunnerOptions,
|
|
179
|
+
MockLogger,
|
|
180
|
+
LogEntry,
|
|
181
|
+
StreamEventResult,
|
|
182
|
+
} from '@lark-apaas/action-plugin-testing';
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/context.ts
|
|
4
|
+
var silentLogger = {
|
|
5
|
+
log: () => {
|
|
6
|
+
},
|
|
7
|
+
error: () => {
|
|
8
|
+
},
|
|
9
|
+
warn: () => {
|
|
10
|
+
},
|
|
11
|
+
debug: () => {
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var consoleLogger = {
|
|
15
|
+
log: (...args) => console.log("[TEST]", ...args),
|
|
16
|
+
error: (...args) => console.error("[TEST]", ...args),
|
|
17
|
+
warn: (...args) => console.warn("[TEST]", ...args),
|
|
18
|
+
debug: (...args) => console.debug("[TEST]", ...args)
|
|
19
|
+
};
|
|
20
|
+
function createMockResponse(data = {}) {
|
|
21
|
+
return new Response(JSON.stringify(data), {
|
|
22
|
+
status: 200,
|
|
23
|
+
headers: { "Content-Type": "application/json" }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
var mockHttpClient = {
|
|
27
|
+
get: async () => createMockResponse(),
|
|
28
|
+
post: async () => createMockResponse(),
|
|
29
|
+
put: async () => createMockResponse(),
|
|
30
|
+
delete: async () => createMockResponse(),
|
|
31
|
+
patch: async () => createMockResponse()
|
|
32
|
+
};
|
|
33
|
+
function resolveLogger(logger) {
|
|
34
|
+
if (!logger || logger === "silent") {
|
|
35
|
+
return silentLogger;
|
|
36
|
+
}
|
|
37
|
+
if (logger === "console") {
|
|
38
|
+
return consoleLogger;
|
|
39
|
+
}
|
|
40
|
+
return logger;
|
|
41
|
+
}
|
|
42
|
+
function createTestContext(options) {
|
|
43
|
+
const {
|
|
44
|
+
userId = "test-user",
|
|
45
|
+
tenantId = "test-tenant",
|
|
46
|
+
appId = "test-app",
|
|
47
|
+
logger,
|
|
48
|
+
platformHttpClient = mockHttpClient,
|
|
49
|
+
isDebug = false
|
|
50
|
+
} = options ?? {};
|
|
51
|
+
return {
|
|
52
|
+
userContext: {
|
|
53
|
+
userId,
|
|
54
|
+
tenantId,
|
|
55
|
+
appId
|
|
56
|
+
},
|
|
57
|
+
logger: resolveLogger(logger),
|
|
58
|
+
platformHttpClient,
|
|
59
|
+
isDebug
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/runner.ts
|
|
64
|
+
function createTestRunner(plugin, config, options) {
|
|
65
|
+
const instance = plugin.create(config);
|
|
66
|
+
const defaultContextOptions = options?.defaultContext ?? {};
|
|
67
|
+
return {
|
|
68
|
+
async run(actionName, input, contextOverrides) {
|
|
69
|
+
const mergedContextOptions = {
|
|
70
|
+
...defaultContextOptions,
|
|
71
|
+
...contextOverrides
|
|
72
|
+
};
|
|
73
|
+
const context = createTestContext(mergedContextOptions);
|
|
74
|
+
return instance.run(actionName, context, input);
|
|
75
|
+
},
|
|
76
|
+
getInstance() {
|
|
77
|
+
return instance;
|
|
78
|
+
},
|
|
79
|
+
getInputSchema(actionName) {
|
|
80
|
+
return instance.getInputSchema(actionName);
|
|
81
|
+
},
|
|
82
|
+
getOutputSchema(actionName, input) {
|
|
83
|
+
return instance.getOutputSchema(actionName, input);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/mocks/logger.ts
|
|
89
|
+
function createMockLogger() {
|
|
90
|
+
const logs = [];
|
|
91
|
+
const createLogMethod = (level) => {
|
|
92
|
+
return (...args) => {
|
|
93
|
+
logs.push({
|
|
94
|
+
level,
|
|
95
|
+
args,
|
|
96
|
+
timestamp: Date.now()
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
log: createLogMethod("log"),
|
|
102
|
+
error: createLogMethod("error"),
|
|
103
|
+
warn: createLogMethod("warn"),
|
|
104
|
+
debug: createLogMethod("debug"),
|
|
105
|
+
getLogs() {
|
|
106
|
+
return [...logs];
|
|
107
|
+
},
|
|
108
|
+
getLogsByLevel(level) {
|
|
109
|
+
return logs.filter((log) => log.level === level);
|
|
110
|
+
},
|
|
111
|
+
clear() {
|
|
112
|
+
logs.length = 0;
|
|
113
|
+
},
|
|
114
|
+
hasLog(level, messagePattern) {
|
|
115
|
+
return logs.some((log) => {
|
|
116
|
+
if (log.level !== level) return false;
|
|
117
|
+
return log.args.some((arg) => {
|
|
118
|
+
if (typeof arg !== "string") {
|
|
119
|
+
try {
|
|
120
|
+
arg = JSON.stringify(arg);
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (typeof messagePattern === "string") {
|
|
126
|
+
return arg.includes(messagePattern);
|
|
127
|
+
}
|
|
128
|
+
return messagePattern.test(arg);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/stream.ts
|
|
136
|
+
async function collectStream(stream) {
|
|
137
|
+
const chunks = [];
|
|
138
|
+
for await (const chunk of stream) {
|
|
139
|
+
chunks.push(chunk);
|
|
140
|
+
}
|
|
141
|
+
return chunks;
|
|
142
|
+
}
|
|
143
|
+
async function collectStreamData(stream) {
|
|
144
|
+
const chunks = [];
|
|
145
|
+
for await (const chunk of stream) {
|
|
146
|
+
chunks.push(chunk.data);
|
|
147
|
+
}
|
|
148
|
+
return chunks;
|
|
149
|
+
}
|
|
150
|
+
async function collectStreamText(stream) {
|
|
151
|
+
let result = "";
|
|
152
|
+
for await (const chunk of stream) {
|
|
153
|
+
result += chunk.data.content;
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
async function firstChunk(stream) {
|
|
158
|
+
for await (const chunk of stream) {
|
|
159
|
+
return chunk;
|
|
160
|
+
}
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
async function lastChunk(stream) {
|
|
164
|
+
let last;
|
|
165
|
+
for await (const chunk of stream) {
|
|
166
|
+
last = chunk;
|
|
167
|
+
}
|
|
168
|
+
return last;
|
|
169
|
+
}
|
|
170
|
+
async function countChunks(stream) {
|
|
171
|
+
let count = 0;
|
|
172
|
+
for await (const _item of stream) {
|
|
173
|
+
count++;
|
|
174
|
+
}
|
|
175
|
+
return count;
|
|
176
|
+
}
|
|
177
|
+
async function assertStreamChunks(stream, expected) {
|
|
178
|
+
const actual = await collectStream(stream);
|
|
179
|
+
if (actual.length !== expected.length) {
|
|
180
|
+
throw new Error(`Expected ${expected.length} chunks, but got ${actual.length}`);
|
|
181
|
+
}
|
|
182
|
+
for (let i = 0; i < expected.length; i++) {
|
|
183
|
+
const actualStr = JSON.stringify(actual[i]);
|
|
184
|
+
const expectedStr = JSON.stringify(expected[i]);
|
|
185
|
+
if (actualStr !== expectedStr) {
|
|
186
|
+
throw new Error(`Chunk ${i} mismatch:
|
|
187
|
+
Expected: ${expectedStr}
|
|
188
|
+
Actual: ${actualStr}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function assertEveryChunk(stream, predicate) {
|
|
193
|
+
let index = 0;
|
|
194
|
+
for await (const chunk of stream) {
|
|
195
|
+
if (!predicate(chunk, index)) {
|
|
196
|
+
throw new Error(`Chunk ${index} failed assertion: ${JSON.stringify(chunk)}`);
|
|
197
|
+
}
|
|
198
|
+
index++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/stream-events.ts
|
|
203
|
+
async function collectStreamEvents(stream) {
|
|
204
|
+
const events = [];
|
|
205
|
+
const data = [];
|
|
206
|
+
let done;
|
|
207
|
+
let error;
|
|
208
|
+
for await (const event of stream) {
|
|
209
|
+
events.push(event);
|
|
210
|
+
switch (event.type) {
|
|
211
|
+
case "data":
|
|
212
|
+
data.push(event.data);
|
|
213
|
+
break;
|
|
214
|
+
case "done":
|
|
215
|
+
done = event;
|
|
216
|
+
break;
|
|
217
|
+
case "error":
|
|
218
|
+
error = event;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
events,
|
|
224
|
+
data,
|
|
225
|
+
done,
|
|
226
|
+
error,
|
|
227
|
+
completed: done !== void 0 && error === void 0
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
async function collectEventData(stream) {
|
|
231
|
+
const data = [];
|
|
232
|
+
for await (const event of stream) {
|
|
233
|
+
if (event.type === "data") {
|
|
234
|
+
data.push(event.data);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return data;
|
|
238
|
+
}
|
|
239
|
+
async function waitForDone(stream) {
|
|
240
|
+
for await (const event of stream) {
|
|
241
|
+
if (event.type === "done") {
|
|
242
|
+
return event.metadata;
|
|
243
|
+
}
|
|
244
|
+
if (event.type === "error") {
|
|
245
|
+
throw new Error(`Stream ended with error: [${event.error.code}] ${event.error.message}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
throw new Error("Stream ended without done or error event");
|
|
249
|
+
}
|
|
250
|
+
async function waitForError(stream) {
|
|
251
|
+
for await (const event of stream) {
|
|
252
|
+
if (event.type === "error") {
|
|
253
|
+
return event.error;
|
|
254
|
+
}
|
|
255
|
+
if (event.type === "done") {
|
|
256
|
+
throw new Error("Expected stream to error, but it completed successfully");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
throw new Error("Stream ended without done or error event");
|
|
260
|
+
}
|
|
261
|
+
async function expectStreamCompletes(stream) {
|
|
262
|
+
const result = await collectStreamEvents(stream);
|
|
263
|
+
if (!result.completed) {
|
|
264
|
+
if (result.error) {
|
|
265
|
+
throw new Error(
|
|
266
|
+
`Expected stream to complete, but got error: [${result.error.error.code}] ${result.error.error.message}`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
throw new Error("Expected stream to complete, but no done event received");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async function expectStreamErrors(stream, expectedCode) {
|
|
273
|
+
const result = await collectStreamEvents(stream);
|
|
274
|
+
if (!result.error) {
|
|
275
|
+
throw new Error("Expected stream to error, but it completed successfully");
|
|
276
|
+
}
|
|
277
|
+
if (expectedCode && result.error.error.code !== expectedCode) {
|
|
278
|
+
throw new Error(`Expected error code "${expectedCode}", but got "${result.error.error.code}"`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async function expectAggregatedResult(stream, expected) {
|
|
282
|
+
const metadata = await waitForDone(stream);
|
|
283
|
+
const actual = JSON.stringify(metadata.aggregated);
|
|
284
|
+
const expectedStr = JSON.stringify(expected);
|
|
285
|
+
if (actual !== expectedStr) {
|
|
286
|
+
throw new Error(`Aggregated result mismatch:
|
|
287
|
+
Expected: ${expectedStr}
|
|
288
|
+
Actual: ${actual}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// src/schema.ts
|
|
293
|
+
function parseInput(instance, actionName, input) {
|
|
294
|
+
const schema = instance.getInputSchema(actionName);
|
|
295
|
+
if (!schema) {
|
|
296
|
+
throw new Error(`Action "${actionName}" not found`);
|
|
297
|
+
}
|
|
298
|
+
return schema.parse(input);
|
|
299
|
+
}
|
|
300
|
+
function expectInputRejected(instance, actionName, input) {
|
|
301
|
+
const schema = instance.getInputSchema(actionName);
|
|
302
|
+
if (!schema) {
|
|
303
|
+
throw new Error(`Action "${actionName}" not found`);
|
|
304
|
+
}
|
|
305
|
+
let threw = false;
|
|
306
|
+
try {
|
|
307
|
+
schema.parse(input);
|
|
308
|
+
} catch {
|
|
309
|
+
threw = true;
|
|
310
|
+
}
|
|
311
|
+
if (!threw) {
|
|
312
|
+
throw new Error(`Expected input to be rejected: ${JSON.stringify(input)}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
exports.assertEveryChunk = assertEveryChunk;
|
|
317
|
+
exports.assertStreamChunks = assertStreamChunks;
|
|
318
|
+
exports.collectEventData = collectEventData;
|
|
319
|
+
exports.collectStream = collectStream;
|
|
320
|
+
exports.collectStreamData = collectStreamData;
|
|
321
|
+
exports.collectStreamEvents = collectStreamEvents;
|
|
322
|
+
exports.collectStreamText = collectStreamText;
|
|
323
|
+
exports.countChunks = countChunks;
|
|
324
|
+
exports.createMockLogger = createMockLogger;
|
|
325
|
+
exports.createTestContext = createTestContext;
|
|
326
|
+
exports.createTestRunner = createTestRunner;
|
|
327
|
+
exports.expectAggregatedResult = expectAggregatedResult;
|
|
328
|
+
exports.expectInputRejected = expectInputRejected;
|
|
329
|
+
exports.expectStreamCompletes = expectStreamCompletes;
|
|
330
|
+
exports.expectStreamErrors = expectStreamErrors;
|
|
331
|
+
exports.firstChunk = firstChunk;
|
|
332
|
+
exports.lastChunk = lastChunk;
|
|
333
|
+
exports.parseInput = parseInput;
|
|
334
|
+
exports.waitForDone = waitForDone;
|
|
335
|
+
exports.waitForError = waitForError;
|