@slates/test 1.0.0-rc.10
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/config.cjs +31 -0
- package/dist/config.d.cts +6 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.module.js +6 -0
- package/dist/index.cjs +14859 -0
- package/dist/index.d.cts +641 -0
- package/dist/index.d.ts +641 -0
- package/dist/index.module.js +14828 -0
- package/package.json +53 -0
- package/src/config.ts +5 -0
- package/src/index.test.ts +579 -0
- package/src/index.ts +2 -0
- package/src/runtime.ts +410 -0
- package/src/schema.ts +75 -0
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@slates/test",
|
|
3
|
+
"version": "1.0.0-rc.10",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"files": [
|
|
8
|
+
"src/**",
|
|
9
|
+
"dist/**",
|
|
10
|
+
"README.md",
|
|
11
|
+
"package.json"
|
|
12
|
+
],
|
|
13
|
+
"author": "Tobias Herber",
|
|
14
|
+
"license": "FSL 1.1",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"source": "src/index.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"require": "./dist/index.cjs",
|
|
21
|
+
"import": "./dist/index.module.js",
|
|
22
|
+
"default": "./dist/index.module.js"
|
|
23
|
+
},
|
|
24
|
+
"./config": {
|
|
25
|
+
"types": "./dist/config.d.ts",
|
|
26
|
+
"require": "./dist/config.cjs",
|
|
27
|
+
"import": "./dist/config.module.js",
|
|
28
|
+
"default": "./dist/config.module.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"main": "./dist/index.cjs",
|
|
32
|
+
"module": "./dist/index.module.js",
|
|
33
|
+
"types": "dist/index.d.ts",
|
|
34
|
+
"unpkg": "./dist/index.module.js",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "vitest run --passWithNoTests",
|
|
37
|
+
"build": "tsup --config tsup.config.ts",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"biome:check": "biome check --write src"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@lowerdeck/testing-tools": "latest",
|
|
43
|
+
"@slates/client": "1.0.0-rc.13",
|
|
44
|
+
"@slates/profiles": "1.0.0-rc.11"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@slates/provider": "1.0.0-rc.16",
|
|
48
|
+
"@slates/tsconfig": "1.0.0-rc.1",
|
|
49
|
+
"typescript": "5.8.2",
|
|
50
|
+
"vitest": "^3.1.2",
|
|
51
|
+
"zod": "^4.2"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import { openSlatesCliStore } from '@slates/profiles';
|
|
2
|
+
import {
|
|
3
|
+
createTextAttachment,
|
|
4
|
+
Slate,
|
|
5
|
+
SlateAuth,
|
|
6
|
+
SlateConfig,
|
|
7
|
+
SlateSpecification,
|
|
8
|
+
SlateTool,
|
|
9
|
+
SlateTrigger
|
|
10
|
+
} from '@slates/provider';
|
|
11
|
+
import { mkdtemp, rm, writeFile } from 'fs/promises';
|
|
12
|
+
import { tmpdir } from 'os';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import {
|
|
17
|
+
createLocalSlateTestClient,
|
|
18
|
+
expectSlateContract,
|
|
19
|
+
expectSlateError,
|
|
20
|
+
expectToolCall,
|
|
21
|
+
handleSlateTriggerWebhook,
|
|
22
|
+
loadSlatesRuntimeContext,
|
|
23
|
+
mapSlateTriggerEvent,
|
|
24
|
+
pollSlateTriggerEvents,
|
|
25
|
+
registerSlateTriggerWebhook,
|
|
26
|
+
unregisterSlateTriggerWebhook
|
|
27
|
+
} from './index';
|
|
28
|
+
|
|
29
|
+
(globalThis as typeof globalThis & { expect?: typeof expect }).expect = expect;
|
|
30
|
+
|
|
31
|
+
let tempDirs: string[] = [];
|
|
32
|
+
|
|
33
|
+
let createTempDir = async () => {
|
|
34
|
+
let dir = await mkdtemp(path.join(tmpdir(), 'slates-test-'));
|
|
35
|
+
tempDirs.push(dir);
|
|
36
|
+
return dir;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
afterEach(async () => {
|
|
40
|
+
delete process.env.SLATES_INTEGRATION;
|
|
41
|
+
delete process.env.SLATES_PROFILE_ID;
|
|
42
|
+
delete process.env.SLATES_STORE_PATH;
|
|
43
|
+
delete process.env.SLATES_STORE_ROOT_DIR;
|
|
44
|
+
delete process.env.SLATES_TEST_CONTEXT_PATH;
|
|
45
|
+
await Promise.all(tempDirs.splice(0).map(dir => rm(dir, { recursive: true, force: true })));
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
let createDemoSlate = () => {
|
|
49
|
+
let config = SlateConfig.create(
|
|
50
|
+
z.object({
|
|
51
|
+
prefix: z.string()
|
|
52
|
+
})
|
|
53
|
+
).getDefaultConfig(() => ({
|
|
54
|
+
prefix: 'Hello'
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
let auth = SlateAuth.create<{ token: string }>()
|
|
58
|
+
.output(
|
|
59
|
+
z.object({
|
|
60
|
+
token: z.string()
|
|
61
|
+
})
|
|
62
|
+
)
|
|
63
|
+
.addTokenAuth({
|
|
64
|
+
type: 'auth.token',
|
|
65
|
+
key: 'token_auth',
|
|
66
|
+
name: 'Token Auth',
|
|
67
|
+
inputSchema: z.object({
|
|
68
|
+
token: z.string()
|
|
69
|
+
}),
|
|
70
|
+
getOutput: async ctx => ({
|
|
71
|
+
output: {
|
|
72
|
+
token: ctx.input.token
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
let spec = SlateSpecification.create({
|
|
78
|
+
key: 'demo-slate',
|
|
79
|
+
name: 'Demo Slate',
|
|
80
|
+
description: 'A tiny test slate',
|
|
81
|
+
config,
|
|
82
|
+
auth
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
let echo = SlateTool.create(spec, {
|
|
86
|
+
key: 'echo',
|
|
87
|
+
name: 'Echo',
|
|
88
|
+
tags: {
|
|
89
|
+
readOnly: false
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
.input(
|
|
93
|
+
z.object({
|
|
94
|
+
name: z.string()
|
|
95
|
+
})
|
|
96
|
+
)
|
|
97
|
+
.output(
|
|
98
|
+
z.object({
|
|
99
|
+
greeting: z.string(),
|
|
100
|
+
token: z.string()
|
|
101
|
+
})
|
|
102
|
+
)
|
|
103
|
+
.handleInvocation(async ctx => ({
|
|
104
|
+
output: {
|
|
105
|
+
greeting: `${ctx.config.prefix} ${ctx.input.name}`,
|
|
106
|
+
token: ctx.auth.token
|
|
107
|
+
},
|
|
108
|
+
message: 'done'
|
|
109
|
+
}))
|
|
110
|
+
.build();
|
|
111
|
+
|
|
112
|
+
let fail = SlateTool.create(spec, {
|
|
113
|
+
key: 'fail',
|
|
114
|
+
name: 'Fail'
|
|
115
|
+
})
|
|
116
|
+
.input(
|
|
117
|
+
z.object({
|
|
118
|
+
reason: z.string()
|
|
119
|
+
})
|
|
120
|
+
)
|
|
121
|
+
.output(z.object({}))
|
|
122
|
+
.handleInvocation(async ctx => {
|
|
123
|
+
throw new Error(ctx.input.reason);
|
|
124
|
+
})
|
|
125
|
+
.build();
|
|
126
|
+
|
|
127
|
+
let attachmentEcho = SlateTool.create(spec, {
|
|
128
|
+
key: 'attachment_echo',
|
|
129
|
+
name: 'Attachment Echo',
|
|
130
|
+
tags: {
|
|
131
|
+
readOnly: true
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
.input(
|
|
135
|
+
z.object({
|
|
136
|
+
mimeType: z.string().optional()
|
|
137
|
+
})
|
|
138
|
+
)
|
|
139
|
+
.output(
|
|
140
|
+
z.object({
|
|
141
|
+
size: z.number()
|
|
142
|
+
})
|
|
143
|
+
)
|
|
144
|
+
.handleInvocation(async ctx => ({
|
|
145
|
+
output: {
|
|
146
|
+
size: 5
|
|
147
|
+
},
|
|
148
|
+
message: 'attached',
|
|
149
|
+
attachments: [createTextAttachment('hello', ctx.input.mimeType)]
|
|
150
|
+
}))
|
|
151
|
+
.build();
|
|
152
|
+
|
|
153
|
+
let downloadLink = SlateTool.create(spec, {
|
|
154
|
+
key: 'download_link',
|
|
155
|
+
name: 'Download Link',
|
|
156
|
+
tags: {
|
|
157
|
+
readOnly: true
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
.input(z.object({}))
|
|
161
|
+
.output(
|
|
162
|
+
z.object({
|
|
163
|
+
downloadUrl: z.string()
|
|
164
|
+
})
|
|
165
|
+
)
|
|
166
|
+
.handleInvocation(async () => ({
|
|
167
|
+
output: {
|
|
168
|
+
downloadUrl: 'https://example.com/files/demo.txt'
|
|
169
|
+
},
|
|
170
|
+
message: 'linked'
|
|
171
|
+
}))
|
|
172
|
+
.build();
|
|
173
|
+
|
|
174
|
+
let webhookEcho = SlateTrigger.create(spec, {
|
|
175
|
+
key: 'webhook_echo',
|
|
176
|
+
name: 'Webhook Echo'
|
|
177
|
+
})
|
|
178
|
+
.input(
|
|
179
|
+
z.object({
|
|
180
|
+
value: z.string()
|
|
181
|
+
})
|
|
182
|
+
)
|
|
183
|
+
.output(
|
|
184
|
+
z.object({
|
|
185
|
+
echoed: z.string()
|
|
186
|
+
})
|
|
187
|
+
)
|
|
188
|
+
.webhook({
|
|
189
|
+
autoRegisterWebhook: async ctx => ({
|
|
190
|
+
registrationDetails: {
|
|
191
|
+
webhookBaseUrl: ctx.input.webhookBaseUrl,
|
|
192
|
+
channelId: 'channel-1'
|
|
193
|
+
},
|
|
194
|
+
state: {
|
|
195
|
+
registered: true
|
|
196
|
+
}
|
|
197
|
+
}),
|
|
198
|
+
autoUnregisterWebhook: async ctx => {
|
|
199
|
+
if (ctx.input.registrationDetails?.channelId !== 'channel-1') {
|
|
200
|
+
throw new Error('Unexpected channel');
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
handleRequest: async ctx => {
|
|
204
|
+
if (ctx.request.headers.get('x-demo-event') === 'ignore') {
|
|
205
|
+
return { inputs: [] };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
inputs: [
|
|
210
|
+
{
|
|
211
|
+
value: (await ctx.request.text()) || 'empty'
|
|
212
|
+
}
|
|
213
|
+
],
|
|
214
|
+
updatedState: {
|
|
215
|
+
lastEvent: ctx.request.headers.get('x-demo-event') ?? 'unknown'
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
},
|
|
219
|
+
handleEvent: async ctx => ({
|
|
220
|
+
type: 'demo.webhook',
|
|
221
|
+
id: `webhook-${ctx.input.value}`,
|
|
222
|
+
output: {
|
|
223
|
+
echoed: ctx.input.value
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
})
|
|
227
|
+
.build();
|
|
228
|
+
|
|
229
|
+
let pollEcho = SlateTrigger.create(spec, {
|
|
230
|
+
key: 'poll_echo',
|
|
231
|
+
name: 'Poll Echo'
|
|
232
|
+
})
|
|
233
|
+
.input(
|
|
234
|
+
z.object({
|
|
235
|
+
value: z.string()
|
|
236
|
+
})
|
|
237
|
+
)
|
|
238
|
+
.output(
|
|
239
|
+
z.object({
|
|
240
|
+
echoed: z.string()
|
|
241
|
+
})
|
|
242
|
+
)
|
|
243
|
+
.polling({
|
|
244
|
+
pollEvents: async ctx => ({
|
|
245
|
+
inputs: ctx.input.state?.seen ? [] : [{ value: 'poll-value' }],
|
|
246
|
+
updatedState: {
|
|
247
|
+
seen: true
|
|
248
|
+
}
|
|
249
|
+
}),
|
|
250
|
+
handleEvent: async ctx => ({
|
|
251
|
+
type: 'demo.poll',
|
|
252
|
+
id: `poll-${ctx.input.value}`,
|
|
253
|
+
output: {
|
|
254
|
+
echoed: ctx.input.value
|
|
255
|
+
}
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
.build();
|
|
259
|
+
|
|
260
|
+
return Slate.create({
|
|
261
|
+
spec,
|
|
262
|
+
tools: [echo, fail, attachmentEcho, downloadLink],
|
|
263
|
+
triggers: [webhookEcho, pollEcho]
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
describe('@slates/test', () => {
|
|
268
|
+
it('loads runtime context from the CLI handoff file', async () => {
|
|
269
|
+
let cwd = await createTempDir();
|
|
270
|
+
let store = await openSlatesCliStore({
|
|
271
|
+
cwd,
|
|
272
|
+
scope: {
|
|
273
|
+
key: 'integrations/demo',
|
|
274
|
+
name: 'demo'
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
let profile = store.upsertProfile({
|
|
278
|
+
name: 'Demo',
|
|
279
|
+
target: {
|
|
280
|
+
type: 'local',
|
|
281
|
+
entry: './demo-slate.mjs',
|
|
282
|
+
exportName: 'provider'
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
await store.save();
|
|
286
|
+
|
|
287
|
+
let runtimeContextPath = path.join(cwd, 'runtime.json');
|
|
288
|
+
await writeFile(
|
|
289
|
+
runtimeContextPath,
|
|
290
|
+
JSON.stringify({
|
|
291
|
+
integration: 'integrations/demo',
|
|
292
|
+
profileId: profile.id,
|
|
293
|
+
storePath: store.storePath,
|
|
294
|
+
cliDir: store.dirPath
|
|
295
|
+
}),
|
|
296
|
+
'utf-8'
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
process.env.SLATES_TEST_CONTEXT_PATH = runtimeContextPath;
|
|
300
|
+
|
|
301
|
+
let context = await loadSlatesRuntimeContext({ cwd });
|
|
302
|
+
expect(context.integration).toBe('integrations/demo');
|
|
303
|
+
expect(context.profileId).toBe(profile.id);
|
|
304
|
+
expect(context.profile?.target.type).toBe('local');
|
|
305
|
+
expect(context.storePath).toBe(store.storePath);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('loads only the selected auth method from the runtime context', async () => {
|
|
309
|
+
let cwd = await createTempDir();
|
|
310
|
+
let store = await openSlatesCliStore({
|
|
311
|
+
cwd,
|
|
312
|
+
scope: {
|
|
313
|
+
key: 'integrations/demo',
|
|
314
|
+
name: 'demo'
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
let profile = store.upsertProfile({
|
|
318
|
+
name: 'Demo',
|
|
319
|
+
target: {
|
|
320
|
+
type: 'local',
|
|
321
|
+
entry: './demo-slate.mjs',
|
|
322
|
+
exportName: 'provider'
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
store.upsertAuth(profile.id, {
|
|
326
|
+
authMethodId: 'oauth',
|
|
327
|
+
authMethodName: 'Bot OAuth',
|
|
328
|
+
authType: 'auth.oauth',
|
|
329
|
+
input: {},
|
|
330
|
+
output: {
|
|
331
|
+
token: 'bot-token'
|
|
332
|
+
},
|
|
333
|
+
scopes: ['chat:write']
|
|
334
|
+
});
|
|
335
|
+
store.upsertAuth(profile.id, {
|
|
336
|
+
authMethodId: 'user_oauth',
|
|
337
|
+
authMethodName: 'User OAuth',
|
|
338
|
+
authType: 'auth.oauth',
|
|
339
|
+
input: {},
|
|
340
|
+
output: {
|
|
341
|
+
token: 'user-token'
|
|
342
|
+
},
|
|
343
|
+
scopes: ['search:read']
|
|
344
|
+
});
|
|
345
|
+
await store.save();
|
|
346
|
+
|
|
347
|
+
let runtimeContextPath = path.join(cwd, 'runtime.json');
|
|
348
|
+
await writeFile(
|
|
349
|
+
runtimeContextPath,
|
|
350
|
+
JSON.stringify({
|
|
351
|
+
integration: 'integrations/demo',
|
|
352
|
+
profileId: profile.id,
|
|
353
|
+
authMethodId: 'user_oauth',
|
|
354
|
+
storePath: store.storePath,
|
|
355
|
+
cliDir: store.dirPath
|
|
356
|
+
}),
|
|
357
|
+
'utf-8'
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
process.env.SLATES_TEST_CONTEXT_PATH = runtimeContextPath;
|
|
361
|
+
|
|
362
|
+
let context = await loadSlatesRuntimeContext({ cwd });
|
|
363
|
+
expect(context.authMethodId).toBe('user_oauth');
|
|
364
|
+
expect(Object.keys(context.profile?.auth ?? {})).toEqual(['user_oauth']);
|
|
365
|
+
expect(context.profile?.auth.user_oauth?.output.token).toBe('user-token');
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('creates local slate clients and asserts provider contracts', async () => {
|
|
369
|
+
let client = createLocalSlateTestClient({
|
|
370
|
+
slate: createDemoSlate(),
|
|
371
|
+
state: {
|
|
372
|
+
config: {
|
|
373
|
+
prefix: 'Hi'
|
|
374
|
+
},
|
|
375
|
+
auth: {
|
|
376
|
+
authenticationMethodId: 'token_auth',
|
|
377
|
+
output: {
|
|
378
|
+
token: 'secret-token'
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
let contract = await expectSlateContract({
|
|
385
|
+
client,
|
|
386
|
+
provider: {
|
|
387
|
+
id: 'demo-slate',
|
|
388
|
+
name: 'Demo Slate',
|
|
389
|
+
description: 'A tiny test slate'
|
|
390
|
+
},
|
|
391
|
+
toolIds: ['echo', 'fail', 'attachment_echo', 'download_link'],
|
|
392
|
+
triggerIds: ['webhook_echo', 'poll_echo'],
|
|
393
|
+
authMethodIds: ['token_auth'],
|
|
394
|
+
tools: [
|
|
395
|
+
{ id: 'echo', readOnly: false, destructive: false },
|
|
396
|
+
{ id: 'fail', readOnly: false, destructive: false },
|
|
397
|
+
{ id: 'attachment_echo', readOnly: true, destructive: false },
|
|
398
|
+
{ id: 'download_link', readOnly: true, destructive: false }
|
|
399
|
+
],
|
|
400
|
+
triggers: [
|
|
401
|
+
{ id: 'webhook_echo', invocationType: 'webhook' },
|
|
402
|
+
{ id: 'poll_echo', invocationType: 'polling' }
|
|
403
|
+
]
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
expect(contract.configSchema.properties.prefix.type).toBe('string');
|
|
407
|
+
|
|
408
|
+
await expectToolCall({
|
|
409
|
+
client,
|
|
410
|
+
toolId: 'echo',
|
|
411
|
+
input: {
|
|
412
|
+
name: 'Tobias'
|
|
413
|
+
},
|
|
414
|
+
output: {
|
|
415
|
+
greeting: 'Hi Tobias',
|
|
416
|
+
token: 'secret-token'
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
let attachmentResult = await client.invokeTool('attachment_echo', {
|
|
421
|
+
mimeType: 'text/plain'
|
|
422
|
+
});
|
|
423
|
+
expect(attachmentResult.attachments).toEqual([
|
|
424
|
+
{
|
|
425
|
+
mimeType: 'text/plain',
|
|
426
|
+
content: {
|
|
427
|
+
type: 'content',
|
|
428
|
+
encoding: 'utf-8',
|
|
429
|
+
content: 'hello'
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
]);
|
|
433
|
+
|
|
434
|
+
let downloadResult = await client.invokeTool('download_link', {});
|
|
435
|
+
expect(downloadResult.attachments).toEqual([
|
|
436
|
+
{
|
|
437
|
+
content: {
|
|
438
|
+
type: 'url',
|
|
439
|
+
url: 'https://example.com/files/demo.txt'
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
]);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('wraps trigger webhook flows and error assertions', async () => {
|
|
446
|
+
let client = createLocalSlateTestClient({
|
|
447
|
+
slate: createDemoSlate(),
|
|
448
|
+
state: {
|
|
449
|
+
config: {
|
|
450
|
+
prefix: 'Hi'
|
|
451
|
+
},
|
|
452
|
+
auth: {
|
|
453
|
+
authenticationMethodId: 'token_auth',
|
|
454
|
+
output: {
|
|
455
|
+
token: 'secret-token'
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
let registration = await registerSlateTriggerWebhook({
|
|
462
|
+
client,
|
|
463
|
+
triggerId: 'webhook_echo',
|
|
464
|
+
webhookBaseUrl: 'https://example.com/hooks/google-calendar'
|
|
465
|
+
});
|
|
466
|
+
expect(registration).toMatchObject({
|
|
467
|
+
registrationDetails: {
|
|
468
|
+
webhookBaseUrl: 'https://example.com/hooks/google-calendar',
|
|
469
|
+
channelId: 'channel-1'
|
|
470
|
+
},
|
|
471
|
+
state: {
|
|
472
|
+
registered: true
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
let ignored = await handleSlateTriggerWebhook({
|
|
477
|
+
client,
|
|
478
|
+
triggerId: 'webhook_echo',
|
|
479
|
+
url: 'https://example.com/hooks/google-calendar',
|
|
480
|
+
headers: {
|
|
481
|
+
'x-demo-event': 'ignore'
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
expect(ignored.inputs).toEqual([]);
|
|
485
|
+
|
|
486
|
+
let handled = await handleSlateTriggerWebhook({
|
|
487
|
+
client,
|
|
488
|
+
triggerId: 'webhook_echo',
|
|
489
|
+
url: 'https://example.com/hooks/google-calendar',
|
|
490
|
+
headers: {
|
|
491
|
+
'x-demo-event': 'created'
|
|
492
|
+
},
|
|
493
|
+
body: 'payload-value'
|
|
494
|
+
});
|
|
495
|
+
expect(handled).toMatchObject({
|
|
496
|
+
inputs: [{ value: 'payload-value' }],
|
|
497
|
+
updatedState: {
|
|
498
|
+
lastEvent: 'created'
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
let mapped = await mapSlateTriggerEvent({
|
|
503
|
+
client,
|
|
504
|
+
triggerId: 'webhook_echo',
|
|
505
|
+
input: {
|
|
506
|
+
value: 'payload-value'
|
|
507
|
+
},
|
|
508
|
+
type: 'demo.webhook',
|
|
509
|
+
output: {
|
|
510
|
+
echoed: 'payload-value'
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
expect(mapped.id).toBe('webhook-payload-value');
|
|
514
|
+
|
|
515
|
+
await unregisterSlateTriggerWebhook({
|
|
516
|
+
client,
|
|
517
|
+
triggerId: 'webhook_echo',
|
|
518
|
+
webhookBaseUrl: 'https://example.com/hooks/google-calendar',
|
|
519
|
+
registrationDetails: registration.registrationDetails
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
await expectSlateError(
|
|
523
|
+
() =>
|
|
524
|
+
client.invokeTool('fail', {
|
|
525
|
+
reason: 'intentional failure'
|
|
526
|
+
}),
|
|
527
|
+
{ code: 'internal.unexpected', kind: 'internal', status: 500 }
|
|
528
|
+
);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it('wraps trigger polling flows', async () => {
|
|
532
|
+
let client = createLocalSlateTestClient({
|
|
533
|
+
slate: createDemoSlate(),
|
|
534
|
+
state: {
|
|
535
|
+
config: {
|
|
536
|
+
prefix: 'Hi'
|
|
537
|
+
},
|
|
538
|
+
auth: {
|
|
539
|
+
authenticationMethodId: 'token_auth',
|
|
540
|
+
output: {
|
|
541
|
+
token: 'secret-token'
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
let initialPoll = await pollSlateTriggerEvents({
|
|
548
|
+
client,
|
|
549
|
+
triggerId: 'poll_echo'
|
|
550
|
+
});
|
|
551
|
+
expect(initialPoll).toMatchObject({
|
|
552
|
+
inputs: [{ value: 'poll-value' }],
|
|
553
|
+
updatedState: {
|
|
554
|
+
seen: true
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
let mapped = await mapSlateTriggerEvent({
|
|
559
|
+
client,
|
|
560
|
+
triggerId: 'poll_echo',
|
|
561
|
+
input: initialPoll.inputs[0]!,
|
|
562
|
+
type: 'demo.poll',
|
|
563
|
+
output: {
|
|
564
|
+
echoed: 'poll-value'
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
expect(mapped.id).toBe('poll-poll-value');
|
|
568
|
+
|
|
569
|
+
let repeatedPoll = await pollSlateTriggerEvents({
|
|
570
|
+
client,
|
|
571
|
+
triggerId: 'poll_echo',
|
|
572
|
+
state: initialPoll.updatedState
|
|
573
|
+
});
|
|
574
|
+
expect(repeatedPoll.inputs).toEqual([]);
|
|
575
|
+
expect(repeatedPoll.updatedState).toEqual({
|
|
576
|
+
seen: true
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
});
|
package/src/index.ts
ADDED