Openstatus www.openstatus.dev
at 4c0f4c00a38753a5d0dfd7e7b7b7706dec6f1503 124 lines 3.9 kB view raw
1import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"; 2import { sendTest } from "./index"; 3 4describe("Webhook sendTest", () => { 5 // biome-ignore lint/suspicious/noExplicitAny: <explanation> 6 let fetchMock: any = undefined; 7 8 beforeEach(() => { 9 fetchMock = spyOn(global, "fetch"); 10 }); 11 12 afterEach(() => { 13 if (fetchMock) { 14 fetchMock.mockClear(); 15 fetchMock.mockRestore(); 16 } 17 }); 18 19 test("should send test webhook successfully", async () => { 20 const url = "https://example.com/webhook"; 21 fetchMock.mockResolvedValue(new Response(null, { status: 200 })); 22 23 const result = await sendTest({ url }); 24 25 expect(result).toBe(true); 26 expect(fetchMock).toHaveBeenCalledTimes(1); 27 expect(fetchMock).toHaveBeenCalledWith( 28 url, 29 expect.objectContaining({ 30 method: "post", 31 body: expect.any(String), 32 headers: { "Content-Type": "application/json" }, 33 }), 34 ); 35 36 const callArgs = fetchMock.mock.calls[0]; 37 const body = JSON.parse(callArgs[1].body); 38 expect(body).toMatchObject({ 39 monitor: { 40 id: 1, 41 name: "test", 42 url: "http://openstat.us", 43 }, 44 status: "recovered", 45 statusCode: 200, 46 latency: 1337, 47 }); 48 expect(body.cronTimestamp).toBeTypeOf("number"); 49 }); 50 51 test("should send test webhook with headers", async () => { 52 const url = "https://example.com/webhook"; 53 const headers = [ 54 { key: "Authorization", value: "Bearer token123" }, 55 { key: "Content-Type", value: "application/json" }, 56 ]; 57 fetchMock.mockResolvedValue(new Response(null, { status: 200 })); 58 59 const result = await sendTest({ url, headers }); 60 61 expect(result).toBe(true); 62 expect(fetchMock).toHaveBeenCalledTimes(1); 63 expect(fetchMock).toHaveBeenCalledWith( 64 url, 65 expect.objectContaining({ 66 method: "post", 67 body: expect.any(String), 68 headers: { 69 Authorization: "Bearer token123", 70 "Content-Type": "application/json", 71 }, 72 }), 73 ); 74 }); 75 76 test("should throw error when response is not ok", async () => { 77 const url = "https://example.com/webhook"; 78 fetchMock.mockResolvedValue(new Response(null, { status: 400 })); 79 80 await expect(sendTest({ url })).rejects.toThrow("Failed to send test"); 81 expect(fetchMock).toHaveBeenCalledTimes(1); 82 }); 83 84 test("should throw error when fetch fails", async () => { 85 const url = "https://example.com/webhook"; 86 const networkError = new Error("Network error"); 87 fetchMock.mockRejectedValue(networkError); 88 89 await expect(sendTest({ url })).rejects.toThrow("Failed to send test"); 90 expect(fetchMock).toHaveBeenCalledTimes(1); 91 }); 92 93 test("should send test webhook with empty headers array", async () => { 94 const url = "https://example.com/webhook"; 95 const headers: { key: string; value: string }[] = []; 96 fetchMock.mockResolvedValue(new Response(null, { status: 200 })); 97 98 const result = await sendTest({ url, headers }); 99 100 expect(result).toBe(true); 101 expect(fetchMock).toHaveBeenCalledTimes(1); 102 const callArgs = fetchMock.mock.calls[0]; 103 // Empty headers array should result in empty object after transformHeaders 104 expect(callArgs[1].headers).toEqual({}); 105 }); 106 107 test("should send test webhook with 500 status code", async () => { 108 const url = "https://example.com/webhook"; 109 fetchMock.mockResolvedValue(new Response(null, { status: 500 })); 110 111 await expect(sendTest({ url })).rejects.toThrow("Failed to send test"); 112 expect(fetchMock).toHaveBeenCalledTimes(1); 113 }); 114 115 test("should send test webhook with 201 status code (success)", async () => { 116 const url = "https://example.com/webhook"; 117 fetchMock.mockResolvedValue(new Response(null, { status: 201 })); 118 119 const result = await sendTest({ url }); 120 121 expect(result).toBe(true); 122 expect(fetchMock).toHaveBeenCalledTimes(1); 123 }); 124});