@slates/test 1.0.0-rc.28 → 1.0.0-rc.29

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/index.cjs CHANGED
@@ -33,6 +33,8 @@ __export(index_exports, {
33
33
  getMcpCompatibleToolSchemaCases: () => getMcpCompatibleToolSchemaCases,
34
34
  getSlateContract: () => getSlateContract,
35
35
  getVitestExpect: () => getVitestExpect,
36
+ listSlateOptionListOptions: () => listSlateOptionListOptions,
37
+ listSlateTriggerGroupSelectionOptions: () => listSlateTriggerGroupSelectionOptions,
36
38
  loadSlatesProfile: () => loadSlatesProfile,
37
39
  loadSlatesRuntimeContext: () => loadSlatesRuntimeContext,
38
40
  mapSlateTriggerEvent: () => mapSlateTriggerEvent,
@@ -278,6 +280,16 @@ var pollSlateTriggerGroupEvents = async (d) => {
278
280
  selection: d.selection
279
281
  });
280
282
  };
283
+ var listSlateTriggerGroupSelectionOptions = async (d) => {
284
+ let { client, ...input } = d;
285
+ client.ensureSession();
286
+ return client.listTriggerGroupSelectionOptions(input);
287
+ };
288
+ var listSlateOptionListOptions = async (d) => {
289
+ let { client, ...input } = d;
290
+ client.ensureSession();
291
+ return client.listOptionListOptions(input);
292
+ };
281
293
  var connectSlateTriggerGroupGateway = async (d) => {
282
294
  d.client.ensureSession();
283
295
  return d.client.connectTriggerGroupGateway({
@@ -14916,6 +14928,8 @@ var describeMcpCompatibleToolSchemas = (name, source) => {
14916
14928
  getMcpCompatibleToolSchemaCases,
14917
14929
  getSlateContract,
14918
14930
  getVitestExpect,
14931
+ listSlateOptionListOptions,
14932
+ listSlateTriggerGroupSelectionOptions,
14919
14933
  loadSlatesProfile,
14920
14934
  loadSlatesRuntimeContext,
14921
14935
  mapSlateTriggerEvent,
package/dist/index.d.cts CHANGED
@@ -662,6 +662,91 @@ declare let pollSlateTriggerGroupEvents: (d: {
662
662
  } | undefined;
663
663
  }[] | undefined;
664
664
  }>;
665
+ declare let listSlateTriggerGroupSelectionOptions: (d: {
666
+ client: SlatesTestClient;
667
+ triggerGroupId: string;
668
+ field: string;
669
+ query?: string | null;
670
+ pageToken?: any;
671
+ selection?: Record<string, any>;
672
+ }) => Promise<{
673
+ options: {
674
+ value: string | number;
675
+ label: string;
676
+ description?: string | undefined;
677
+ }[];
678
+ nextPageToken: any;
679
+ requestTraces?: {
680
+ startedAt: string;
681
+ durationMs: number;
682
+ request: {
683
+ method: string;
684
+ url: string;
685
+ headers?: Record<string, string> | undefined;
686
+ body?: {
687
+ text: string;
688
+ contentType?: string | undefined;
689
+ truncated?: boolean | undefined;
690
+ } | undefined;
691
+ };
692
+ response?: {
693
+ status: number;
694
+ statusText?: string | undefined;
695
+ headers?: Record<string, string> | undefined;
696
+ body?: {
697
+ text: string;
698
+ contentType?: string | undefined;
699
+ truncated?: boolean | undefined;
700
+ } | undefined;
701
+ } | undefined;
702
+ error?: {
703
+ message: string;
704
+ code?: string | undefined;
705
+ } | undefined;
706
+ }[] | undefined;
707
+ }>;
708
+ declare let listSlateOptionListOptions: (d: {
709
+ client: SlatesTestClient;
710
+ optionListId: string;
711
+ query?: string | null;
712
+ pageToken?: any;
713
+ params?: Record<string, any>;
714
+ }) => Promise<{
715
+ options: {
716
+ value: string | number;
717
+ label: string;
718
+ description?: string | undefined;
719
+ }[];
720
+ nextPageToken: any;
721
+ requestTraces?: {
722
+ startedAt: string;
723
+ durationMs: number;
724
+ request: {
725
+ method: string;
726
+ url: string;
727
+ headers?: Record<string, string> | undefined;
728
+ body?: {
729
+ text: string;
730
+ contentType?: string | undefined;
731
+ truncated?: boolean | undefined;
732
+ } | undefined;
733
+ };
734
+ response?: {
735
+ status: number;
736
+ statusText?: string | undefined;
737
+ headers?: Record<string, string> | undefined;
738
+ body?: {
739
+ text: string;
740
+ contentType?: string | undefined;
741
+ truncated?: boolean | undefined;
742
+ } | undefined;
743
+ } | undefined;
744
+ error?: {
745
+ message: string;
746
+ code?: string | undefined;
747
+ } | undefined;
748
+ }[] | undefined;
749
+ }>;
665
750
  declare let connectSlateTriggerGroupGateway: (d: {
666
751
  client: SlatesTestClient;
667
752
  triggerGroupId: string;
@@ -897,6 +982,7 @@ declare let mapSlateTriggerEvent: (d: {
897
982
  type: string;
898
983
  id: string;
899
984
  output: Record<string, any>;
985
+ attributes?: Record<string, string[]> | undefined;
900
986
  requestTraces?: {
901
987
  startedAt: string;
902
988
  durationMs: number;
@@ -939,4 +1025,4 @@ declare let getMcpCompatibleToolSchemaCases: (source: ToolSchemaSource) => Reado
939
1025
  declare let expectMcpCompatibleToolSchema: (tool: ToolSchemaTarget) => void;
940
1026
  declare let describeMcpCompatibleToolSchemas: (name: string, source: ToolSchemaSource) => void;
941
1027
 
942
- export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, authenticateSlateTriggerGroupWebhookDelivery, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expandSlateTriggerGroupWebhook, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, renewSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
1028
+ export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, authenticateSlateTriggerGroupWebhookDelivery, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expandSlateTriggerGroupWebhook, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, listSlateOptionListOptions, listSlateTriggerGroupSelectionOptions, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, renewSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
package/dist/index.d.ts CHANGED
@@ -662,6 +662,91 @@ declare let pollSlateTriggerGroupEvents: (d: {
662
662
  } | undefined;
663
663
  }[] | undefined;
664
664
  }>;
665
+ declare let listSlateTriggerGroupSelectionOptions: (d: {
666
+ client: SlatesTestClient;
667
+ triggerGroupId: string;
668
+ field: string;
669
+ query?: string | null;
670
+ pageToken?: any;
671
+ selection?: Record<string, any>;
672
+ }) => Promise<{
673
+ options: {
674
+ value: string | number;
675
+ label: string;
676
+ description?: string | undefined;
677
+ }[];
678
+ nextPageToken: any;
679
+ requestTraces?: {
680
+ startedAt: string;
681
+ durationMs: number;
682
+ request: {
683
+ method: string;
684
+ url: string;
685
+ headers?: Record<string, string> | undefined;
686
+ body?: {
687
+ text: string;
688
+ contentType?: string | undefined;
689
+ truncated?: boolean | undefined;
690
+ } | undefined;
691
+ };
692
+ response?: {
693
+ status: number;
694
+ statusText?: string | undefined;
695
+ headers?: Record<string, string> | undefined;
696
+ body?: {
697
+ text: string;
698
+ contentType?: string | undefined;
699
+ truncated?: boolean | undefined;
700
+ } | undefined;
701
+ } | undefined;
702
+ error?: {
703
+ message: string;
704
+ code?: string | undefined;
705
+ } | undefined;
706
+ }[] | undefined;
707
+ }>;
708
+ declare let listSlateOptionListOptions: (d: {
709
+ client: SlatesTestClient;
710
+ optionListId: string;
711
+ query?: string | null;
712
+ pageToken?: any;
713
+ params?: Record<string, any>;
714
+ }) => Promise<{
715
+ options: {
716
+ value: string | number;
717
+ label: string;
718
+ description?: string | undefined;
719
+ }[];
720
+ nextPageToken: any;
721
+ requestTraces?: {
722
+ startedAt: string;
723
+ durationMs: number;
724
+ request: {
725
+ method: string;
726
+ url: string;
727
+ headers?: Record<string, string> | undefined;
728
+ body?: {
729
+ text: string;
730
+ contentType?: string | undefined;
731
+ truncated?: boolean | undefined;
732
+ } | undefined;
733
+ };
734
+ response?: {
735
+ status: number;
736
+ statusText?: string | undefined;
737
+ headers?: Record<string, string> | undefined;
738
+ body?: {
739
+ text: string;
740
+ contentType?: string | undefined;
741
+ truncated?: boolean | undefined;
742
+ } | undefined;
743
+ } | undefined;
744
+ error?: {
745
+ message: string;
746
+ code?: string | undefined;
747
+ } | undefined;
748
+ }[] | undefined;
749
+ }>;
665
750
  declare let connectSlateTriggerGroupGateway: (d: {
666
751
  client: SlatesTestClient;
667
752
  triggerGroupId: string;
@@ -897,6 +982,7 @@ declare let mapSlateTriggerEvent: (d: {
897
982
  type: string;
898
983
  id: string;
899
984
  output: Record<string, any>;
985
+ attributes?: Record<string, string[]> | undefined;
900
986
  requestTraces?: {
901
987
  startedAt: string;
902
988
  durationMs: number;
@@ -939,4 +1025,4 @@ declare let getMcpCompatibleToolSchemaCases: (source: ToolSchemaSource) => Reado
939
1025
  declare let expectMcpCompatibleToolSchema: (tool: ToolSchemaTarget) => void;
940
1026
  declare let describeMcpCompatibleToolSchemas: (name: string, source: ToolSchemaSource) => void;
941
1027
 
942
- export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, authenticateSlateTriggerGroupWebhookDelivery, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expandSlateTriggerGroupWebhook, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, renewSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
1028
+ export { type ExpectedSlateAction, type ExpectedSlateTriggerGroup, type SlatesRuntimeContext, type SlatesTestClient, authenticateSlateTriggerGroupWebhookDelivery, connectSlateTriggerGroupGateway, createLocalSlateTestClient, createSlatesTestClient, describeMcpCompatibleToolSchemas, expandSlateTriggerGroupWebhook, expectMcpCompatibleToolSchema, expectSlateContract, expectSlateError, expectToolCall, getMcpCompatibleToolSchemaCases, getSlateContract, getVitestExpect, listSlateOptionListOptions, listSlateTriggerGroupSelectionOptions, loadSlatesProfile, loadSlatesRuntimeContext, mapSlateTriggerEvent, pollSlateTriggerGroupEvents, processSlateTriggerGroupWebhook, receiveSlateTriggerGroupGatewayFrames, registerSlateTriggerGroupWebhook, renewSlateTriggerGroupWebhook, unregisterSlateTriggerGroupWebhook, withSlateProfile };
@@ -243,6 +243,16 @@ var pollSlateTriggerGroupEvents = async (d) => {
243
243
  selection: d.selection
244
244
  });
245
245
  };
246
+ var listSlateTriggerGroupSelectionOptions = async (d) => {
247
+ let { client, ...input } = d;
248
+ client.ensureSession();
249
+ return client.listTriggerGroupSelectionOptions(input);
250
+ };
251
+ var listSlateOptionListOptions = async (d) => {
252
+ let { client, ...input } = d;
253
+ client.ensureSession();
254
+ return client.listOptionListOptions(input);
255
+ };
246
256
  var connectSlateTriggerGroupGateway = async (d) => {
247
257
  d.client.ensureSession();
248
258
  return d.client.connectTriggerGroupGateway({
@@ -14880,6 +14890,8 @@ export {
14880
14890
  getMcpCompatibleToolSchemaCases,
14881
14891
  getSlateContract,
14882
14892
  getVitestExpect,
14893
+ listSlateOptionListOptions,
14894
+ listSlateTriggerGroupSelectionOptions,
14883
14895
  loadSlatesProfile,
14884
14896
  loadSlatesRuntimeContext,
14885
14897
  mapSlateTriggerEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/test",
3
- "version": "1.0.0-rc.28",
3
+ "version": "1.0.0-rc.29",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -40,11 +40,11 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@lowerdeck/testing-tools": "latest",
43
- "@slates/client": "1.0.0-rc.33",
44
- "@slates/profiles": "1.0.0-rc.29"
43
+ "@slates/client": "1.0.0-rc.34",
44
+ "@slates/profiles": "1.0.0-rc.30"
45
45
  },
46
46
  "devDependencies": {
47
- "@slates/provider": "1.0.0-rc.34",
47
+ "@slates/provider": "1.0.0-rc.35",
48
48
  "@slates/tsconfig": "1.0.0-rc.1",
49
49
  "typescript": "5.8.2",
50
50
  "vitest": "^3.1.2",
@@ -0,0 +1,194 @@
1
+ import {
2
+ optionList,
3
+ Slate,
4
+ SlateAuth,
5
+ SlateConfig,
6
+ SlateSpecification,
7
+ triggerGroup
8
+ } from '@slates/provider';
9
+ import { describe, expect, it } from 'vitest';
10
+ import { z } from 'zod';
11
+ import {
12
+ createLocalSlateTestClient,
13
+ listSlateOptionListOptions,
14
+ listSlateTriggerGroupSelectionOptions
15
+ } from './index';
16
+
17
+ let fixture = () => {
18
+ let calls: { auth: unknown; config: unknown; input: any }[] = [];
19
+ let auth = SlateAuth.create<{ token: string }>()
20
+ .output(z.object({ token: z.string() }))
21
+ .addTokenAuth({
22
+ type: 'auth.token',
23
+ key: 'token',
24
+ name: 'Token',
25
+ inputSchema: z.object({ token: z.string() }),
26
+ getOutput: async ctx => ({ output: ctx.input })
27
+ });
28
+ let spec = SlateSpecification.create({
29
+ key: 'files',
30
+ name: 'Files',
31
+ description: 'Option list contract',
32
+ auth,
33
+ config: SlateConfig.create(z.object({ tenant: z.string() }))
34
+ });
35
+ let files = optionList(spec, {
36
+ key: 'files',
37
+ paramsSchema: z.object({
38
+ kind: z.enum(['sheet', 'doc']),
39
+ limit: z.number().int().default(10)
40
+ }),
41
+ list: async ctx => {
42
+ calls.push({ auth: ctx.auth, config: ctx.config, input: ctx.input });
43
+ return {
44
+ options: [
45
+ {
46
+ value: `${ctx.input.params.kind}-1`,
47
+ label: `${ctx.auth.token} ${ctx.config.tenant}`
48
+ }
49
+ ],
50
+ nextPageToken: ctx.input.pageToken ? undefined : { offset: 1 }
51
+ };
52
+ }
53
+ });
54
+ let folders = optionList(spec, {
55
+ key: 'folders',
56
+ list: async ctx => {
57
+ calls.push({ auth: ctx.auth, config: ctx.config, input: ctx.input });
58
+ return { options: [] };
59
+ }
60
+ });
61
+ let watch = triggerGroup(spec, {
62
+ key: 'watch',
63
+ name: 'Watch',
64
+ selectionSchema: z.object({ fileId: z.string(), folderId: z.string() })
65
+ })
66
+ .polling({ pollEvents: async () => ({ events: [] }) })
67
+ .routingMatchers(async () => [])
68
+ .selectionOptions({
69
+ fileId: {
70
+ list: async () => ({ options: [{ value: 'own', label: 'Own' }] }),
71
+ linked: { slate: 'acme/drive', optionList: 'files', params: { kind: 'sheet' } }
72
+ },
73
+ folderId: { linked: { slate: 'acme/drive', optionList: 'folders' } }
74
+ })
75
+ .build();
76
+ let slate = Slate.create({
77
+ spec,
78
+ tools: [],
79
+ triggers: [],
80
+ triggerGroups: [watch],
81
+ optionLists: [files, folders]
82
+ });
83
+ let client = createLocalSlateTestClient({
84
+ slate,
85
+ state: {
86
+ config: { tenant: 'tenant' },
87
+ auth: { authenticationMethodId: 'token', output: { token: 'credential' } }
88
+ }
89
+ });
90
+
91
+ return { client, calls };
92
+ };
93
+
94
+ describe('option list protocol helpers', () => {
95
+ it('lists an exported option list with parsed params, auth and config', async () => {
96
+ let { client, calls } = fixture();
97
+
98
+ let first = await listSlateOptionListOptions({
99
+ client,
100
+ optionListId: 'files',
101
+ query: ' budget ',
102
+ params: { kind: 'sheet' }
103
+ });
104
+ expect(first).toEqual({
105
+ options: [{ value: 'sheet-1', label: 'credential tenant' }],
106
+ nextPageToken: { offset: 1 }
107
+ });
108
+ expect(calls.at(-1)).toEqual({
109
+ auth: { token: 'credential' },
110
+ config: { tenant: 'tenant' },
111
+ input: { query: 'budget', pageToken: null, params: { kind: 'sheet', limit: 10 } }
112
+ });
113
+
114
+ let last = await listSlateOptionListOptions({
115
+ client,
116
+ optionListId: 'files',
117
+ query: ' ',
118
+ pageToken: { offset: 1 },
119
+ params: { kind: 'doc', limit: 5 }
120
+ });
121
+ expect(last.nextPageToken).toBeNull();
122
+ expect(calls.at(-1)?.input).toEqual({
123
+ query: null,
124
+ pageToken: { offset: 1 },
125
+ params: { kind: 'doc', limit: 5 }
126
+ });
127
+
128
+ await listSlateOptionListOptions({ client, optionListId: 'folders' });
129
+ expect(calls.at(-1)?.input).toEqual({ query: null, pageToken: null, params: {} });
130
+ });
131
+
132
+ it('rejects unknown option lists, invalid params and unknown param keys', async () => {
133
+ let { client, calls } = fixture();
134
+
135
+ await expect(
136
+ listSlateOptionListOptions({ client, optionListId: 'missing' })
137
+ ).rejects.toThrow('Invalid option list ID: missing');
138
+ await expect(
139
+ listSlateOptionListOptions({ client, optionListId: 'files', params: { kind: 'pdf' } })
140
+ ).rejects.toThrow('Invalid params for option list "files"');
141
+ await expect(
142
+ listSlateOptionListOptions({ client, optionListId: 'files' })
143
+ ).rejects.toThrow('Invalid params for option list "files"');
144
+ await expect(
145
+ listSlateOptionListOptions({
146
+ client,
147
+ optionListId: 'files',
148
+ params: { kind: 'sheet', mimeType: 'sheet' }
149
+ })
150
+ ).rejects.toThrow('Invalid params for option list "files"');
151
+ await expect(
152
+ listSlateOptionListOptions({
153
+ client,
154
+ optionListId: 'folders',
155
+ params: { kind: 'sheet' }
156
+ })
157
+ ).rejects.toThrow('Invalid params for option list "folders"');
158
+ expect(calls).toEqual([]);
159
+ });
160
+
161
+ it('advertises linked sources and only lists fields with their own list', async () => {
162
+ let { client } = fixture();
163
+ let schema = (await client.getTriggerGroup('watch')).triggerGroup.selectionSchema;
164
+
165
+ expect(schema?.properties.fileId).toMatchObject({
166
+ 'x-slates-options': true,
167
+ 'x-slates-options-linked': {
168
+ slate: 'acme/drive',
169
+ optionList: 'files',
170
+ params: { kind: 'sheet' }
171
+ }
172
+ });
173
+ expect(schema?.properties.folderId).not.toHaveProperty('x-slates-options');
174
+ expect(schema?.properties.folderId['x-slates-options-linked']).toEqual({
175
+ slate: 'acme/drive',
176
+ optionList: 'folders',
177
+ params: {}
178
+ });
179
+
180
+ let own = await listSlateTriggerGroupSelectionOptions({
181
+ client,
182
+ triggerGroupId: 'watch',
183
+ field: 'fileId'
184
+ });
185
+ expect(own.options).toEqual([{ value: 'own', label: 'Own' }]);
186
+ await expect(
187
+ listSlateTriggerGroupSelectionOptions({
188
+ client,
189
+ triggerGroupId: 'watch',
190
+ field: 'folderId'
191
+ })
192
+ ).rejects.toThrow('has no options for selection field: folderId');
193
+ });
194
+ });
package/src/runtime.ts CHANGED
@@ -391,6 +391,31 @@ export let pollSlateTriggerGroupEvents = async (d: {
391
391
  });
392
392
  };
393
393
 
394
+ export let listSlateTriggerGroupSelectionOptions = async (d: {
395
+ client: SlatesTestClient;
396
+ triggerGroupId: string;
397
+ field: string;
398
+ query?: string | null;
399
+ pageToken?: any;
400
+ selection?: Record<string, any>;
401
+ }) => {
402
+ let { client, ...input } = d;
403
+ client.ensureSession();
404
+ return client.listTriggerGroupSelectionOptions(input);
405
+ };
406
+
407
+ export let listSlateOptionListOptions = async (d: {
408
+ client: SlatesTestClient;
409
+ optionListId: string;
410
+ query?: string | null;
411
+ pageToken?: any;
412
+ params?: Record<string, any>;
413
+ }) => {
414
+ let { client, ...input } = d;
415
+ client.ensureSession();
416
+ return client.listOptionListOptions(input);
417
+ };
418
+
394
419
  export let connectSlateTriggerGroupGateway = async (d: {
395
420
  client: SlatesTestClient;
396
421
  triggerGroupId: string;
@@ -12,6 +12,7 @@ import {
12
12
  authenticateSlateTriggerGroupWebhookDelivery,
13
13
  createLocalSlateTestClient,
14
14
  expandSlateTriggerGroupWebhook,
15
+ listSlateTriggerGroupSelectionOptions,
15
16
  pollSlateTriggerGroupEvents,
16
17
  processSlateTriggerGroupWebhook,
17
18
  registerSlateTriggerGroupWebhook,
@@ -149,15 +150,28 @@ let fixture = (
149
150
  })
150
151
  .routingMatchers(async () => [{ tenant: 'tenant' }])
151
152
  .build();
152
- let poll = triggerGroup(spec, { key: 'poll', name: 'Poll', selectionSchema })
153
+ let pollBuilder = triggerGroup(spec, { key: 'poll', name: 'Poll', selectionSchema })
153
154
  .polling({
154
155
  pollEvents: async ctx => {
155
156
  record('poll', ctx);
156
157
  return { events: [], updatedState: ctx.input.state };
157
158
  }
158
159
  })
159
- .routingMatchers(async () => [])
160
- .build();
160
+ .routingMatchers(async () => []);
161
+ if (selectionSchema) {
162
+ pollBuilder.selectionOptions({
163
+ resource: {
164
+ list: async ctx => {
165
+ record('options', ctx);
166
+ return {
167
+ options: [{ value: 'a', label: 'Resource A' }],
168
+ nextPageToken: ctx.input.pageToken ? null : 'next'
169
+ };
170
+ }
171
+ }
172
+ });
173
+ }
174
+ let poll = pollBuilder.build();
161
175
  let matches = 0;
162
176
  let selectedInput = z.object({
163
177
  kind: z.string().optional(),
@@ -473,6 +487,49 @@ describe('trigger lifecycle protocol helpers', () => {
473
487
  expect(defaults.contexts.at(-1)?.input.selection).toEqual({ resource: 'explicit' });
474
488
  });
475
489
 
490
+ it('lists options for a marked selection field from an incomplete selection', async () => {
491
+ let { client, contexts } = fixture({ selection: 'required' });
492
+ let marked = (await client.getTriggerGroup('poll')).triggerGroup.selectionSchema;
493
+ let unmarked = (await client.getTriggerGroup('webhook')).triggerGroup.selectionSchema;
494
+ expect(marked?.properties.resource['x-slates-options']).toBe(true);
495
+ expect(unmarked?.properties.resource).not.toHaveProperty('x-slates-options');
496
+
497
+ let first = await listSlateTriggerGroupSelectionOptions({
498
+ client,
499
+ triggerGroupId: 'poll',
500
+ field: 'resource',
501
+ query: ' res ',
502
+ selection: { other: 'entered' }
503
+ });
504
+ expect(first).toMatchObject({
505
+ options: [{ value: 'a', label: 'Resource A' }],
506
+ nextPageToken: 'next'
507
+ });
508
+ expect(contexts.at(-1)).toMatchObject({
509
+ operation: 'options',
510
+ input: { query: 'res', pageToken: null, selection: { other: 'entered' } }
511
+ });
512
+
513
+ let last = await listSlateTriggerGroupSelectionOptions({
514
+ client,
515
+ triggerGroupId: 'poll',
516
+ field: 'resource',
517
+ pageToken: 'next'
518
+ });
519
+ expect(last.nextPageToken).toBeNull();
520
+ expect(contexts.at(-1)?.input).toMatchObject({ query: null, selection: {} });
521
+
522
+ for (let target of [
523
+ { triggerGroupId: 'poll', field: 'missing' },
524
+ { triggerGroupId: 'poll', field: 'constructor' },
525
+ { triggerGroupId: 'webhook', field: 'resource' }
526
+ ]) {
527
+ await expect(
528
+ listSlateTriggerGroupSelectionOptions({ client, ...target })
529
+ ).rejects.toThrow('has no options');
530
+ }
531
+ });
532
+
476
533
  it('keeps groups without selection, expansion, or renewal backward compatible', async () => {
477
534
  let { client, contexts } = fixture({ legacy: true });
478
535
  await registerSlateTriggerGroupWebhook({ client, ...registrationInput });