Skip to content

Commit 7bf879d

Browse files
Copilothotlong
andcommitted
Add tests for new API protocol operations (Views, Permissions, Workflows, Realtime, Notifications, AI, i18n)
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 93211a4 commit 7bf879d

1 file changed

Lines changed: 204 additions & 1 deletion

File tree

packages/spec/src/api/protocol.test.ts

Lines changed: 204 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,59 @@ import {
1212
BatchDataRequestSchema,
1313
CreateManyDataResponseSchema,
1414
UpdateManyDataRequestSchema,
15-
DeleteManyDataRequestSchema
15+
DeleteManyDataRequestSchema,
16+
// Views
17+
ListViewsRequestSchema,
18+
ListViewsResponseSchema,
19+
GetViewRequestSchema,
20+
CreateViewRequestSchema,
21+
UpdateViewRequestSchema,
22+
DeleteViewRequestSchema,
23+
DeleteViewResponseSchema,
24+
// Permissions
25+
CheckPermissionRequestSchema,
26+
CheckPermissionResponseSchema,
27+
GetObjectPermissionsRequestSchema,
28+
GetObjectPermissionsResponseSchema,
29+
GetEffectivePermissionsResponseSchema,
30+
// Workflows
31+
GetWorkflowConfigRequestSchema,
32+
WorkflowStateSchema,
33+
GetWorkflowStateRequestSchema,
34+
WorkflowTransitionRequestSchema,
35+
WorkflowTransitionResponseSchema,
36+
WorkflowApproveRequestSchema,
37+
WorkflowRejectRequestSchema,
38+
// Realtime
39+
RealtimeConnectRequestSchema,
40+
RealtimeConnectResponseSchema,
41+
RealtimeSubscribeRequestSchema,
42+
RealtimeSubscribeResponseSchema,
43+
SetPresenceRequestSchema,
44+
GetPresenceResponseSchema,
45+
// Notifications
46+
RegisterDeviceRequestSchema,
47+
RegisterDeviceResponseSchema,
48+
NotificationPreferencesSchema,
49+
NotificationSchema,
50+
ListNotificationsRequestSchema,
51+
ListNotificationsResponseSchema,
52+
MarkNotificationsReadRequestSchema,
53+
// AI
54+
AiNlqRequestSchema,
55+
AiNlqResponseSchema,
56+
AiChatRequestSchema,
57+
AiChatResponseSchema,
58+
AiSuggestRequestSchema,
59+
AiSuggestResponseSchema,
60+
AiInsightsRequestSchema,
61+
AiInsightsResponseSchema,
62+
// i18n
63+
GetLocalesResponseSchema,
64+
GetTranslationsRequestSchema,
65+
GetTranslationsResponseSchema,
66+
GetFieldLabelsRequestSchema,
67+
GetFieldLabelsResponseSchema,
1668
} from './protocol.zod';
1769

1870
describe('ObjectStack Protocol', () => {
@@ -115,4 +167,155 @@ describe('ObjectStack Protocol', () => {
115167
expect(DeleteManyDataRequestSchema.safeParse(deleteManyReq).success).toBe(true);
116168
});
117169

170+
it('validates Views operations', () => {
171+
expect(ListViewsRequestSchema.safeParse({ object: 'project', type: 'list' }).success).toBe(true);
172+
expect(ListViewsResponseSchema.safeParse({
173+
object: 'project',
174+
views: [{ list: { columns: [] } }],
175+
}).success).toBe(true);
176+
expect(GetViewRequestSchema.safeParse({ object: 'project', viewId: 'v1' }).success).toBe(true);
177+
expect(CreateViewRequestSchema.safeParse({
178+
object: 'project',
179+
data: { list: { columns: [] } },
180+
}).success).toBe(true);
181+
expect(UpdateViewRequestSchema.safeParse({
182+
object: 'project',
183+
viewId: 'v1',
184+
data: { list: { columns: [] } },
185+
}).success).toBe(true);
186+
expect(DeleteViewRequestSchema.safeParse({ object: 'project', viewId: 'v1' }).success).toBe(true);
187+
expect(DeleteViewResponseSchema.safeParse({ object: 'project', viewId: 'v1', success: true }).success).toBe(true);
188+
});
189+
190+
it('validates Permissions operations', () => {
191+
expect(CheckPermissionRequestSchema.safeParse({
192+
object: 'account',
193+
action: 'edit',
194+
recordId: 'a1',
195+
}).success).toBe(true);
196+
expect(CheckPermissionResponseSchema.safeParse({ allowed: false, reason: 'Insufficient privileges' }).success).toBe(true);
197+
expect(GetObjectPermissionsRequestSchema.safeParse({ object: 'account' }).success).toBe(true);
198+
expect(GetObjectPermissionsResponseSchema.safeParse({
199+
object: 'account',
200+
permissions: { allowCreate: true, allowRead: true, allowEdit: false, allowDelete: false },
201+
fieldPermissions: { email: { readable: true, editable: false } },
202+
}).success).toBe(true);
203+
expect(GetEffectivePermissionsResponseSchema.safeParse({
204+
objects: { account: { allowRead: true } },
205+
systemPermissions: ['manage_users', 'view_reports'],
206+
}).success).toBe(true);
207+
});
208+
209+
it('validates Workflow operations', () => {
210+
expect(GetWorkflowConfigRequestSchema.safeParse({ object: 'lead' }).success).toBe(true);
211+
const state = {
212+
currentState: 'open',
213+
availableTransitions: [
214+
{ name: 'approve', targetState: 'approved', label: 'Approve', requiresApproval: true },
215+
],
216+
history: [{
217+
fromState: 'draft', toState: 'open', action: 'submit',
218+
userId: 'u1', timestamp: '2024-01-15T10:00:00Z',
219+
}],
220+
};
221+
expect(WorkflowStateSchema.safeParse(state).success).toBe(true);
222+
expect(GetWorkflowStateRequestSchema.safeParse({ object: 'lead', recordId: 'l1' }).success).toBe(true);
223+
expect(WorkflowTransitionRequestSchema.safeParse({
224+
object: 'lead', recordId: 'l1', transition: 'approve', comment: 'Looks good',
225+
}).success).toBe(true);
226+
expect(WorkflowTransitionResponseSchema.safeParse({
227+
object: 'lead', recordId: 'l1', success: true, state,
228+
}).success).toBe(true);
229+
expect(WorkflowApproveRequestSchema.safeParse({
230+
object: 'lead', recordId: 'l1', comment: 'Approved',
231+
}).success).toBe(true);
232+
expect(WorkflowRejectRequestSchema.safeParse({
233+
object: 'lead', recordId: 'l1', reason: 'Missing info',
234+
}).success).toBe(true);
235+
});
236+
237+
it('validates Realtime operations', () => {
238+
expect(RealtimeConnectRequestSchema.safeParse({
239+
transport: 'websocket', channels: ['project.updates'], token: 'tok_abc',
240+
}).success).toBe(true);
241+
expect(RealtimeConnectResponseSchema.safeParse({
242+
connectionId: 'conn_1', transport: 'websocket', url: 'wss://rt.example.com',
243+
}).success).toBe(true);
244+
expect(RealtimeSubscribeRequestSchema.safeParse({
245+
channel: 'project.updates', events: ['record.created', 'record.updated'],
246+
}).success).toBe(true);
247+
expect(RealtimeSubscribeResponseSchema.safeParse({
248+
subscriptionId: 'sub_1', channel: 'project.updates',
249+
}).success).toBe(true);
250+
expect(SetPresenceRequestSchema.safeParse({
251+
channel: 'project.updates',
252+
state: { userId: 'u1', status: 'online', lastSeen: '2024-01-15T10:00:00Z' },
253+
}).success).toBe(true);
254+
expect(GetPresenceResponseSchema.safeParse({
255+
channel: 'project.updates',
256+
members: [{ userId: 'u1', status: 'online', lastSeen: '2024-01-15T10:00:00Z' }],
257+
}).success).toBe(true);
258+
});
259+
260+
it('validates Notification operations', () => {
261+
expect(RegisterDeviceRequestSchema.safeParse({
262+
token: 'fcm_token_xyz', platform: 'android', deviceId: 'dev_1', name: 'Pixel 8',
263+
}).success).toBe(true);
264+
expect(RegisterDeviceResponseSchema.safeParse({ deviceId: 'dev_1', success: true }).success).toBe(true);
265+
expect(NotificationPreferencesSchema.safeParse({
266+
email: true, push: true, inApp: true, digest: 'daily',
267+
channels: { alerts: { enabled: true, push: false } },
268+
}).success).toBe(true);
269+
expect(NotificationSchema.safeParse({
270+
id: 'n1', type: 'task_assigned', title: 'New Task', body: 'You were assigned a task',
271+
read: false, actionUrl: '/tasks/t1', createdAt: '2024-01-15T10:00:00Z',
272+
}).success).toBe(true);
273+
expect(ListNotificationsRequestSchema.safeParse({ read: false, limit: 10 }).success).toBe(true);
274+
expect(ListNotificationsResponseSchema.safeParse({
275+
notifications: [{ id: 'n1', type: 'info', title: 'Hi', body: 'Hello', read: false, createdAt: '2024-01-15T10:00:00Z' }],
276+
unreadCount: 1,
277+
}).success).toBe(true);
278+
expect(MarkNotificationsReadRequestSchema.safeParse({ ids: ['n1', 'n2'] }).success).toBe(true);
279+
});
280+
281+
it('validates AI operations', () => {
282+
expect(AiNlqRequestSchema.safeParse({ query: 'show me all open tasks', object: 'task' }).success).toBe(true);
283+
expect(AiNlqResponseSchema.safeParse({
284+
query: { object: 'task', where: { status: 'open' } },
285+
explanation: 'Find all tasks with open status', confidence: 0.92,
286+
}).success).toBe(true);
287+
expect(AiChatRequestSchema.safeParse({ message: 'How many tasks are overdue?', conversationId: 'c1' }).success).toBe(true);
288+
expect(AiChatResponseSchema.safeParse({
289+
message: 'There are 5 overdue tasks.', conversationId: 'c1',
290+
actions: [{ type: 'navigate', label: 'View overdue tasks' }],
291+
}).success).toBe(true);
292+
expect(AiSuggestRequestSchema.safeParse({ object: 'task', field: 'priority', partial: 'hi' }).success).toBe(true);
293+
expect(AiSuggestResponseSchema.safeParse({
294+
suggestions: [{ value: 'high', label: 'High', confidence: 0.95, reason: 'Matches partial input' }],
295+
}).success).toBe(true);
296+
expect(AiInsightsRequestSchema.safeParse({ object: 'task', type: 'trends' }).success).toBe(true);
297+
expect(AiInsightsResponseSchema.safeParse({
298+
insights: [{ type: 'trends', title: 'Task Completion Rate', description: 'Completion rate increased by 15% this month', confidence: 0.88 }],
299+
}).success).toBe(true);
300+
});
301+
302+
it('validates i18n operations', () => {
303+
expect(GetLocalesResponseSchema.safeParse({
304+
locales: [
305+
{ code: 'en-US', label: 'English (US)', isDefault: true },
306+
{ code: 'es-ES', label: 'Spanish (Spain)' },
307+
],
308+
}).success).toBe(true);
309+
expect(GetTranslationsRequestSchema.safeParse({ locale: 'en-US', namespace: 'objects' }).success).toBe(true);
310+
expect(GetTranslationsResponseSchema.safeParse({
311+
locale: 'en-US',
312+
translations: { objects: { task: { label: 'Task', pluralLabel: 'Tasks' } }, messages: { save: 'Save' } },
313+
}).success).toBe(true);
314+
expect(GetFieldLabelsRequestSchema.safeParse({ object: 'task', locale: 'en-US' }).success).toBe(true);
315+
expect(GetFieldLabelsResponseSchema.safeParse({
316+
object: 'task', locale: 'en-US',
317+
labels: { status: { label: 'Status', help: 'Current task status', options: { open: 'Open', closed: 'Closed' } } },
318+
}).success).toBe(true);
319+
});
320+
118321
});

0 commit comments

Comments
 (0)