@checkstack/integration-webex-backend 0.0.34 → 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.
@@ -1,383 +0,0 @@
1
- import { describe, it, expect, beforeEach, mock, spyOn } from "bun:test";
2
- import {
3
- webexProvider,
4
- WebexConnectionSchema,
5
- WebexSubscriptionSchema,
6
- } from "./provider";
7
-
8
- /**
9
- * Unit tests for the Webex Integration Provider.
10
- *
11
- * Tests cover:
12
- * - Config schema validation
13
- * - Connection testing
14
- * - Room options resolution
15
- * - Event delivery
16
- */
17
-
18
- // Mock logger
19
- const mockLogger = {
20
- debug: mock(() => {}),
21
- info: mock(() => {}),
22
- warn: mock(() => {}),
23
- error: mock(() => {}),
24
- };
25
-
26
- describe("Webex Integration Provider", () => {
27
- beforeEach(() => {
28
- mockLogger.debug.mockClear();
29
- mockLogger.info.mockClear();
30
- mockLogger.warn.mockClear();
31
- mockLogger.error.mockClear();
32
- });
33
-
34
- // ─────────────────────────────────────────────────────────────────────────
35
- // Provider Metadata
36
- // ─────────────────────────────────────────────────────────────────────────
37
-
38
- describe("metadata", () => {
39
- it("has correct basic metadata", () => {
40
- expect(webexProvider.id).toBe("webex");
41
- expect(webexProvider.displayName).toBe("Webex");
42
- expect(webexProvider.description).toContain("Webex");
43
- expect(webexProvider.icon).toBe("MessageSquare");
44
- });
45
-
46
- it("has versioned config and connection schemas", () => {
47
- expect(webexProvider.config).toBeDefined();
48
- expect(webexProvider.config.version).toBe(1);
49
- expect(webexProvider.connectionSchema).toBeDefined();
50
- expect(webexProvider.connectionSchema?.version).toBe(1);
51
- });
52
-
53
- it("has documentation", () => {
54
- expect(webexProvider.documentation).toBeDefined();
55
- expect(webexProvider.documentation?.setupGuide).toContain("Webex Bot");
56
- });
57
- });
58
-
59
- // ─────────────────────────────────────────────────────────────────────────
60
- // Config Schema Validation
61
- // ─────────────────────────────────────────────────────────────────────────
62
-
63
- describe("connection schema", () => {
64
- it("requires bot token", () => {
65
- expect(() => {
66
- WebexConnectionSchema.parse({});
67
- }).toThrow();
68
- });
69
-
70
- it("accepts valid connection config", () => {
71
- const result = WebexConnectionSchema.parse({
72
- botToken: "test-bot-token-abc123",
73
- });
74
- expect(result.botToken).toBe("test-bot-token-abc123");
75
- });
76
- });
77
-
78
- describe("subscription schema", () => {
79
- it("requires connectionId and roomId", () => {
80
- expect(() => {
81
- WebexSubscriptionSchema.parse({});
82
- }).toThrow();
83
-
84
- expect(() => {
85
- WebexSubscriptionSchema.parse({ connectionId: "conn-1" });
86
- }).toThrow();
87
- });
88
-
89
- it("accepts valid subscription config", () => {
90
- const result = WebexSubscriptionSchema.parse({
91
- connectionId: "conn-1",
92
- roomId: "room-123",
93
- });
94
- expect(result.connectionId).toBe("conn-1");
95
- expect(result.roomId).toBe("room-123");
96
- expect(result.messageTemplate).toBeUndefined();
97
- });
98
-
99
- it("accepts optional message template", () => {
100
- const result = WebexSubscriptionSchema.parse({
101
- connectionId: "conn-1",
102
- roomId: "room-123",
103
- messageTemplate: "Event: {{event.eventId}}",
104
- });
105
- expect(result.messageTemplate).toBe("Event: {{event.eventId}}");
106
- });
107
- });
108
-
109
- // ─────────────────────────────────────────────────────────────────────────
110
- // Test Connection
111
- // ─────────────────────────────────────────────────────────────────────────
112
-
113
- describe("testConnection", () => {
114
- it("returns success for valid token", async () => {
115
- const mockFetch = spyOn(globalThis, "fetch").mockImplementation(
116
- (async () => {
117
- return new Response(
118
- JSON.stringify({ id: "bot-123", displayName: "Test Bot" }),
119
- { status: 200 },
120
- );
121
- }) as unknown as typeof fetch,
122
- );
123
-
124
- try {
125
- const result = await webexProvider.testConnection!({
126
- botToken: "valid-token",
127
- });
128
-
129
- expect(result.success).toBe(true);
130
- expect(result.message).toContain("Test Bot");
131
- } finally {
132
- mockFetch.mockRestore();
133
- }
134
- });
135
-
136
- it("returns failure for invalid token", async () => {
137
- const mockFetch = spyOn(globalThis, "fetch").mockImplementation(
138
- (async () => {
139
- return new Response("Unauthorized", { status: 401 });
140
- }) as unknown as typeof fetch,
141
- );
142
-
143
- try {
144
- const result = await webexProvider.testConnection!({
145
- botToken: "invalid-token",
146
- });
147
-
148
- expect(result.success).toBe(false);
149
- expect(result.message).toContain("failed");
150
- } finally {
151
- mockFetch.mockRestore();
152
- }
153
- });
154
-
155
- it("returns failure for invalid config", async () => {
156
- // Explicitly mock fetch to simulate network error for empty token
157
- const mockFetch = spyOn(globalThis, "fetch").mockImplementation(
158
- (async () => {
159
- throw new TypeError("fetch failed");
160
- }) as unknown as typeof fetch,
161
- );
162
-
163
- try {
164
- const result = await webexProvider.testConnection!({
165
- botToken: "",
166
- });
167
-
168
- expect(result.success).toBe(false);
169
- expect(result.message).toContain("failed");
170
- } finally {
171
- mockFetch.mockRestore();
172
- }
173
- });
174
- });
175
-
176
- // ─────────────────────────────────────────────────────────────────────────
177
- // Get Connection Options
178
- // ─────────────────────────────────────────────────────────────────────────
179
-
180
- describe("getConnectionOptions", () => {
181
- it("returns room options when resolver matches", async () => {
182
- const mockFetch = spyOn(globalThis, "fetch").mockImplementation(
183
- (async () => {
184
- return new Response(
185
- JSON.stringify({
186
- items: [
187
- { id: "room-1", title: "Engineering", type: "group" },
188
- { id: "room-2", title: "DevOps", type: "group" },
189
- ],
190
- }),
191
- { status: 200 },
192
- );
193
- }) as unknown as typeof fetch,
194
- );
195
-
196
- try {
197
- const options = await webexProvider.getConnectionOptions!({
198
- resolverName: "roomOptions",
199
- connectionId: "conn-1",
200
- context: {},
201
- logger: mockLogger,
202
- getConnectionWithCredentials: async () => ({
203
- config: { botToken: "test-token" },
204
- }),
205
- });
206
-
207
- expect(options).toHaveLength(2);
208
- expect(options[0]).toEqual({ value: "room-1", label: "Engineering" });
209
- expect(options[1]).toEqual({ value: "room-2", label: "DevOps" });
210
- } finally {
211
- mockFetch.mockRestore();
212
- }
213
- });
214
-
215
- it("returns empty array for unknown resolver", async () => {
216
- const options = await webexProvider.getConnectionOptions!({
217
- resolverName: "unknownResolver",
218
- connectionId: "conn-1",
219
- context: {},
220
- logger: mockLogger,
221
- getConnectionWithCredentials: async () => ({
222
- config: { botToken: "test-token" },
223
- }),
224
- });
225
-
226
- expect(options).toEqual([]);
227
- });
228
-
229
- it("returns empty array when connection not found", async () => {
230
- const options = await webexProvider.getConnectionOptions!({
231
- resolverName: "roomOptions",
232
- connectionId: "conn-1",
233
- context: {},
234
- logger: mockLogger,
235
- getConnectionWithCredentials: async () => undefined,
236
- });
237
-
238
- expect(options).toEqual([]);
239
- });
240
- });
241
-
242
- // ─────────────────────────────────────────────────────────────────────────
243
- // Delivery
244
- // ─────────────────────────────────────────────────────────────────────────
245
-
246
- describe("deliver", () => {
247
- it("sends message to Webex room successfully", async () => {
248
- let capturedBody: string | undefined;
249
-
250
- const mockFetch = spyOn(globalThis, "fetch").mockImplementation((async (
251
- _url: RequestInfo | URL,
252
- options?: RequestInit,
253
- ) => {
254
- capturedBody = options?.body as string;
255
- return new Response(JSON.stringify({ id: "msg-456" }), {
256
- status: 200,
257
- });
258
- }) as unknown as typeof fetch);
259
-
260
- try {
261
- const result = await webexProvider.deliver({
262
- event: {
263
- eventId: "incident.created",
264
- payload: { incidentId: "inc-123", title: "Server Down" },
265
- timestamp: new Date().toISOString(),
266
- deliveryId: "del-789",
267
- },
268
- subscription: {
269
- id: "sub-1",
270
- name: "Incident Notifications",
271
- },
272
- providerConfig: {
273
- connectionId: "conn-1",
274
- roomId: "room-123",
275
- },
276
- logger: mockLogger,
277
- getConnectionWithCredentials: async () => ({
278
- id: "conn-1",
279
- config: { botToken: "test-token" },
280
- }),
281
- });
282
-
283
- expect(result.success).toBe(true);
284
- expect(result.externalId).toBe("msg-456");
285
-
286
- const parsedBody = JSON.parse(capturedBody!);
287
- expect(parsedBody.roomId).toBe("room-123");
288
- expect(parsedBody.markdown).toContain("incident.created");
289
- } finally {
290
- mockFetch.mockRestore();
291
- }
292
- });
293
-
294
- it("uses custom message template when provided", async () => {
295
- let capturedBody: string | undefined;
296
-
297
- const mockFetch = spyOn(globalThis, "fetch").mockImplementation((async (
298
- _url: RequestInfo | URL,
299
- options?: RequestInit,
300
- ) => {
301
- capturedBody = options?.body as string;
302
- return new Response(JSON.stringify({ id: "msg-456" }), {
303
- status: 200,
304
- });
305
- }) as unknown as typeof fetch);
306
-
307
- try {
308
- await webexProvider.deliver({
309
- event: {
310
- eventId: "incident.created",
311
- payload: { incidentId: "inc-123", title: "Server Down" },
312
- timestamp: new Date().toISOString(),
313
- deliveryId: "del-789",
314
- },
315
- subscription: {
316
- id: "sub-1",
317
- name: "Test Sub",
318
- },
319
- providerConfig: {
320
- connectionId: "conn-1",
321
- roomId: "room-123",
322
- messageTemplate:
323
- "🚨 **{{event.payload.title}}** - Incident {{event.payload.incidentId}}",
324
- },
325
- logger: mockLogger,
326
- getConnectionWithCredentials: async () => ({
327
- id: "conn-1",
328
- config: { botToken: "test-token" },
329
- }),
330
- });
331
-
332
- const parsedBody = JSON.parse(capturedBody!);
333
- expect(parsedBody.markdown).toBe(
334
- "🚨 **Server Down** - Incident inc-123",
335
- );
336
- } finally {
337
- mockFetch.mockRestore();
338
- }
339
- });
340
-
341
- it("returns error when connection not found", async () => {
342
- const result = await webexProvider.deliver({
343
- event: {
344
- eventId: "test.event",
345
- payload: {},
346
- timestamp: new Date().toISOString(),
347
- deliveryId: "del-1",
348
- },
349
- subscription: { id: "sub-1", name: "Test" },
350
- providerConfig: {
351
- connectionId: "nonexistent",
352
- roomId: "room-1",
353
- },
354
- logger: mockLogger,
355
- getConnectionWithCredentials: async () => undefined,
356
- });
357
-
358
- expect(result.success).toBe(false);
359
- expect(result.error).toContain("not found");
360
- });
361
-
362
- it("returns error when credentials not available", async () => {
363
- const result = await webexProvider.deliver({
364
- event: {
365
- eventId: "test.event",
366
- payload: {},
367
- timestamp: new Date().toISOString(),
368
- deliveryId: "del-1",
369
- },
370
- subscription: { id: "sub-1", name: "Test" },
371
- providerConfig: {
372
- connectionId: "conn-1",
373
- roomId: "room-1",
374
- },
375
- logger: mockLogger,
376
- // getConnectionWithCredentials not provided
377
- });
378
-
379
- expect(result.success).toBe(false);
380
- expect(result.error).toContain("not available");
381
- });
382
- });
383
- });