Files
Amit SharmaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Keith Williams
353f71bdc6 feat: Sink url shortner for sms workflow reminders (#26608)
* feat: Sink url shortner for sms workflow reminders

* fix: remove hardcoded dub values

* update .env.example

* fix: unit tests

* chore: add tests for scheduleSmsReminder and utils

* review refactor

* fix: type check

* review refactor

* fix: update test to account for smsReminderNumber fallback from main

Co-Authored-By: unknown <>

* feat: add feature flag for sink and more tests to verify

* fix: type check

* use proper feature flags for sink

* Apply suggestion from @keithwillcode

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Keith Williams <[email protected]>
2026-03-16 20:51:28 +00:00

99 lines
3.3 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import type { SinkClient } from "../providers/SinkClient";
import { SinkShortener } from "../providers/SinkShortener";
vi.mock("@calcom/lib/logger", () => ({
default: {
getSubLogger: () => ({
debug: vi.fn(),
error: vi.fn(),
warn: vi.fn(),
}),
},
}));
function createMockClient(overrides: Partial<SinkClient> = {}): SinkClient {
return {
isConfigured: vi.fn().mockReturnValue(true),
createLink: vi.fn(),
createMany: vi.fn().mockResolvedValue([]),
...overrides,
} as unknown as SinkClient;
}
describe("SinkShortener", () => {
beforeEach(() => {
vi.clearAllMocks();
vi.unstubAllEnvs();
});
describe("isConfigured", () => {
it("returns true when both SINK_API_URL and SINK_API_KEY are set", () => {
vi.stubEnv("SINK_API_URL", "https://sink.test.com");
vi.stubEnv("SINK_API_KEY", "test-key");
expect(SinkShortener.isConfigured()).toBe(true);
});
it("returns false when SINK_API_URL is missing", () => {
vi.stubEnv("SINK_API_URL", "");
vi.stubEnv("SINK_API_KEY", "test-key");
expect(SinkShortener.isConfigured()).toBe(false);
});
it("returns false when SINK_API_KEY is missing", () => {
vi.stubEnv("SINK_API_URL", "https://sink.test.com");
vi.stubEnv("SINK_API_KEY", "");
expect(SinkShortener.isConfigured()).toBe(false);
});
});
describe("shortenMany", () => {
it("returns shortened links from client", async () => {
const client = createMockClient({
createMany: vi
.fn()
.mockResolvedValue([{ url: "https://example.com", shortLink: "https://sink.test.com/abc" }]),
});
const shortener = new SinkShortener(client);
const result = await shortener.shortenMany(["https://example.com"]);
expect(result).toEqual([{ shortLink: "https://sink.test.com/abc" }]);
});
it("falls back to original URL when shortLink is null", async () => {
const client = createMockClient({
createMany: vi.fn().mockResolvedValue([{ url: "https://example.com", shortLink: null }]),
});
const shortener = new SinkShortener(client);
const result = await shortener.shortenMany(["https://example.com"]);
expect(result).toEqual([{ shortLink: "https://example.com" }]);
});
it("returns original URLs on client error", async () => {
const client = createMockClient({
createMany: vi.fn().mockRejectedValue(new Error("API error")),
});
const shortener = new SinkShortener(client);
const result = await shortener.shortenMany(["https://example1.com", "https://example2.com"]);
expect(result).toEqual([{ shortLink: "https://example1.com" }, { shortLink: "https://example2.com" }]);
});
it("ignores options parameter", async () => {
const mockCreateMany = vi
.fn()
.mockResolvedValue([{ url: "https://example.com", shortLink: "https://sink.test.com/abc" }]);
const client = createMockClient({ createMany: mockCreateMany });
const shortener = new SinkShortener(client);
await shortener.shortenMany(["https://example.com"], { domain: "custom.com", folderId: "folder123" });
expect(mockCreateMany).toHaveBeenCalledWith(["https://example.com"]);
});
});
});