Files
calendar/packages/lib/server/service/__tests__/VerificationTokenService.test.ts
T
Joe Au-YeungandGitHub e5ebf7feb4 fix: signup (#25334)
* Handle Stripe logic in `paymentCallback`

* Remove endpoint

* Do not send email verification email if premium username

* Remove logic from verify-view

* Callback send verification email

* Add `create` method to `VerificationToken` repository

* Create `VerificationTokenService`

* Early return if payment failed

* Refactor token generation

* Add tests

* Type fixes

* Type fixes
2025-11-21 19:51:19 +00:00

135 lines
4.1 KiB
TypeScript

import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
import { VerificationTokenRepository } from "@calcom/lib/server/repository/verificationToken";
import { VerificationTokenService } from "../VerificationTokenService";
vi.mock("@calcom/lib/server/repository/verificationToken", () => ({
VerificationTokenRepository: {
create: vi.fn(),
},
}));
describe("VerificationTokenService", () => {
const originalEnv = process.env;
beforeEach(() => {
vi.clearAllMocks();
process.env = { ...originalEnv };
process.env.NEXTAUTH_SECRET = "test-secret";
vi.mocked(VerificationTokenRepository.create).mockResolvedValue({
identifier: "test@example.com",
token: "hashed-token",
expires: new Date(),
} as any); // eslint-disable-line @typescript-eslint/no-explicit-any
});
afterEach(() => {
process.env = originalEnv;
});
describe("create", () => {
test("should create a verification token and return unhashed token", async () => {
const identifier = "test@example.com";
const expires = new Date(Date.now() + 86400 * 1000);
const result = await VerificationTokenService.create({
identifier,
expires,
});
expect(result).toBeTruthy();
expect(typeof result).toBe("string");
expect(result.length).toBeGreaterThan(0);
expect(VerificationTokenRepository.create).toHaveBeenCalled();
});
test("should call repository with correct identifier and expires", async () => {
const identifier = "user@example.com";
const expires = new Date("2025-12-31T23:59:59.000Z");
await VerificationTokenService.create({
identifier,
expires,
});
expect(VerificationTokenRepository.create).toHaveBeenCalledWith({
identifier,
token: expect.any(String),
expires,
});
const callArgs = vi.mocked(VerificationTokenRepository.create).mock.calls[0][0];
expect(callArgs.identifier).toBe(identifier);
expect(callArgs.expires).toBe(expires);
expect(callArgs.token).toBeTruthy();
});
test("should hash token with NEXTAUTH_SECRET", async () => {
const identifier = "test@example.com";
const expires = new Date(Date.now() + 86400 * 1000);
await VerificationTokenService.create({
identifier,
expires,
});
const callArgs = vi.mocked(VerificationTokenRepository.create).mock.calls[0][0];
// The hashed token should be a 64-character hex string (SHA-256)
expect(callArgs.token).toMatch(/^[a-f0-9]{64}$/);
});
test("should generate unique tokens on multiple calls", async () => {
const identifier = "test@example.com";
const expires = new Date(Date.now() + 86400 * 1000);
const result1 = await VerificationTokenService.create({
identifier,
expires,
});
const result2 = await VerificationTokenService.create({
identifier,
expires,
});
expect(result1).not.toBe(result2);
expect(VerificationTokenRepository.create).toHaveBeenCalledTimes(2);
});
test("should handle Date objects for expires", async () => {
const identifier = "test@example.com";
const expires = new Date(2025, 11, 31, 23, 59, 59);
await VerificationTokenService.create({
identifier,
expires,
});
expect(VerificationTokenRepository.create).toHaveBeenCalledWith({
identifier,
token: expect.any(String),
expires: expect.any(Date),
});
const callArgs = vi.mocked(VerificationTokenRepository.create).mock.calls[0][0];
expect(callArgs.expires).toBeInstanceOf(Date);
expect(callArgs.expires.getTime()).toBe(expires.getTime());
});
test("should generate 32-byte random token in hex format", async () => {
const identifier = "test@example.com";
const expires = new Date(Date.now() + 86400 * 1000);
const token = await VerificationTokenService.create({
identifier,
expires,
});
// 32 bytes = 64 hex characters
expect(token).toMatch(/^[a-f0-9]{64}$/);
});
});
});