@critters/next
Version:
Secure bug reporting library for Next.js applications
220 lines (219 loc) • 9.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Unit tests for utility functions
*/
const utils_1 = require("../src/utils");
// Mock the crypto module
jest.mock("crypto", () => ({
createHmac: jest.fn().mockReturnValue({
update: jest.fn().mockReturnThis(),
digest: jest.fn().mockReturnValue("mocked-server-signature"),
}),
}));
// Mock crypto-js modules
jest.mock("crypto-js/hmac-sha256", () => jest.fn().mockReturnValue({
toString: jest.fn().mockReturnValue("mocked-browser-signature"),
}));
jest.mock("crypto-js/enc-hex", () => ({}));
describe("Utils", () => {
describe("generateSignature", () => {
// Store original window
const originalWindow = global.window;
beforeEach(() => {
// Reset window for each test
if (originalWindow === undefined) {
// @ts-ignore - Ignoring TypeScript error as we need to test with window undefined
global.window = undefined;
}
else {
global.window = originalWindow;
}
});
afterAll(() => {
// Restore original window after all tests
if (originalWindow === undefined) {
// @ts-ignore - Ignoring TypeScript error as we need to test with window undefined
global.window = undefined;
}
else {
global.window = originalWindow;
}
});
it("should return empty string if no secret key is provided", () => {
const result = (0, utils_1.generateSignature)("payload", undefined);
expect(result).toBe("");
});
it("should use server-side crypto in Node.js environment", () => {
// Simulate server environment (no window)
// @ts-ignore - Ignoring TypeScript error as we need to test with window undefined
global.window = undefined;
const result = (0, utils_1.generateSignature)("payload", "secret");
expect(result).toBe("mocked-server-signature");
});
it("should use browser-side crypto in browser environment", () => {
// Simulate browser environment
global.window = {};
const result = (0, utils_1.generateSignature)("payload", "secret");
expect(result).toBe("mocked-browser-signature");
});
});
describe("isBrowser and isServer", () => {
// Store original window
const originalWindow = global.window;
beforeEach(() => {
// Reset window for each test
if (originalWindow === undefined) {
// @ts-ignore - Ignoring TypeScript error as we need to test with window undefined
global.window = undefined;
}
else {
global.window = originalWindow;
}
});
afterAll(() => {
// Restore original window after all tests
if (originalWindow === undefined) {
// @ts-ignore - Ignoring TypeScript error as we need to test with window undefined
global.window = undefined;
}
else {
global.window = originalWindow;
}
});
it("should correctly detect browser environment", () => {
// Simulate browser environment
global.window = {};
expect((0, utils_1.isBrowser)()).toBe(true);
expect((0, utils_1.isServer)()).toBe(false);
});
it("should correctly detect server environment", () => {
// Simulate server environment
// @ts-ignore - Ignoring TypeScript error as we need to test with window undefined
global.window = undefined;
expect((0, utils_1.isBrowser)()).toBe(false);
expect((0, utils_1.isServer)()).toBe(true);
});
});
describe("formatError", () => {
it("should format Error objects", () => {
const error = new Error("Test error");
error.name = "TestError";
const formatted = (0, utils_1.formatError)(error);
expect(formatted.name).toBe("TestError");
expect(formatted.message).toBe("Test error");
expect(formatted.stack).toBeDefined();
});
it("should format string as error", () => {
const formatted = (0, utils_1.formatError)("Error string");
expect(formatted.name).toBe("Unknown Error");
expect(formatted.message).toBe("Error string");
expect(formatted.stack).toBeUndefined();
});
it("should handle non-string, non-Error values", () => {
const formatted = (0, utils_1.formatError)(123);
expect(formatted.name).toBe("Unknown Error");
expect(formatted.message).toBe("123");
expect(formatted.stack).toBeUndefined();
});
});
describe("safeStringify", () => {
it("should stringify simple objects", () => {
const obj = { a: 1, b: "string", c: true };
const result = (0, utils_1.safeStringify)(obj);
expect(result).toBe('{"a":1,"b":"string","c":true}');
});
it("should handle Error objects", () => {
const error = new Error("Test error");
error.name = "TestError";
const result = JSON.parse((0, utils_1.safeStringify)({ error }));
expect(result.error.name).toBe("TestError");
expect(result.error.message).toBe("Test error");
expect(result.error.stack).toBeDefined();
});
it("should handle circular references", () => {
const obj = { a: 1 };
obj.self = obj;
const result = JSON.parse((0, utils_1.safeStringify)(obj));
expect(result.a).toBe(1);
expect(result.self).toBe("[Circular Reference]");
});
});
describe("sanitizeData", () => {
it("should redact sensitive data", () => {
const data = {
username: "user1",
password: "secret123",
authToken: "abc123",
apiKey: "xyz789",
secretKey: "very-secret",
normal: "not-sensitive",
};
const sanitized = (0, utils_1.sanitizeData)(data);
expect(sanitized.username).toBe("user1");
expect(sanitized.password).toBe("[REDACTED]");
expect(sanitized.authToken).toBe("[REDACTED]");
expect(sanitized.apiKey).toBe("[REDACTED]");
expect(sanitized.secretKey).toBe("[REDACTED]");
expect(sanitized.normal).toBe("not-sensitive");
});
it("should recursively sanitize nested objects", () => {
const data = {
user: {
name: "John",
credentials: {
password: "secret123",
token: "abc123",
},
},
settings: {
theme: "dark",
},
};
const sanitized = (0, utils_1.sanitizeData)(data);
expect(sanitized.user.name).toBe("John");
expect(sanitized.user.credentials.password).toBe("[REDACTED]");
expect(sanitized.user.credentials.token).toBe("[REDACTED]");
expect(sanitized.settings.theme).toBe("dark");
});
it("should sanitize arrays of objects", () => {
const data = {
users: [
{ id: 1, name: "John", password: "secret1" },
{ id: 2, name: "Jane", password: "secret2" },
],
};
const sanitized = (0, utils_1.sanitizeData)(data);
expect(sanitized.users[0].id).toBe(1);
expect(sanitized.users[0].name).toBe("John");
expect(sanitized.users[0].password).toBe("[REDACTED]");
expect(sanitized.users[1].id).toBe(2);
expect(sanitized.users[1].name).toBe("Jane");
expect(sanitized.users[1].password).toBe("[REDACTED]");
});
it("should use custom sensitive keys if provided", () => {
const data = {
name: "John",
ssn: "123-45-6789",
creditCard: "1234-5678-9012-3456",
};
const sanitized = (0, utils_1.sanitizeData)(data, ["ssn", "creditCard"]);
expect(sanitized.name).toBe("John");
expect(sanitized.ssn).toBe("[REDACTED]");
expect(sanitized.creditCard).toBe("[REDACTED]");
});
});
describe("getTimestamp", () => {
it("should return ISO formatted date string", () => {
// Mock Date.now for consistent testing
const mockDate = new Date("2023-01-01T12:00:00Z");
jest
.spyOn(global, "Date")
.mockImplementation(() => mockDate);
const timestamp = (0, utils_1.getTimestamp)();
expect(timestamp).toBe("2023-01-01T12:00:00.000Z");
// Restore Date
jest.restoreAllMocks();
});
});
});