317 lines
9.8 KiB
JavaScript
317 lines
9.8 KiB
JavaScript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
|
const getPaymentType = require("./lib/getPaymentType");
|
|
const decodeComment = require("./lib/decodeComment");
|
|
const getCptellerUrl = require("./lib/getCptellerUrl");
|
|
const handlePaymentValidationError = require("./lib/handlePaymentValidationError");
|
|
const getShopCredentials = require("./lib/getShopCredentials");
|
|
|
|
/**
|
|
* @description Decode a base64-encoded JSON comment
|
|
*/
|
|
describe("decodeComment", () => {
|
|
it("decodes a valid base64-encoded JSON comment", () => {
|
|
// {"test":"data"} encoded in base64
|
|
const encoded = "eyJ0ZXN0IjoiZGF0YSJ9";
|
|
const expected = { test: "data" };
|
|
expect(decodeComment(encoded)).toEqual(expected);
|
|
});
|
|
|
|
it("decodes a complex base64-encoded JSON with payments", () => {
|
|
// {"payments":[{"jobid":"123"}]} encoded in base64
|
|
const encoded = "eyJwYXltZW50cyI6W3siam9iaWQiOiIxMjMifV19";
|
|
const expected = { payments: [{ jobid: "123" }] };
|
|
expect(decodeComment(encoded)).toEqual(expected);
|
|
});
|
|
|
|
it("returns null when comment is null", () => {
|
|
expect(decodeComment(null)).toBeNull();
|
|
});
|
|
|
|
it("returns null when comment is undefined", () => {
|
|
expect(decodeComment(undefined)).toBeNull();
|
|
});
|
|
|
|
it("returns null when comment is an empty string", () => {
|
|
expect(decodeComment("")).toBeNull();
|
|
});
|
|
|
|
it("returns null when comment is malformed base64", () => {
|
|
expect(decodeComment("!@#$%")).toBeNull();
|
|
});
|
|
|
|
it("returns null when comment is valid base64 but not valid JSON", () => {
|
|
// "invalid" in base64 is "aW52YWxpZA=="
|
|
expect(decodeComment("aW52YWxpZA==")).toBeNull();
|
|
});
|
|
});
|
|
|
|
/**
|
|
* @description Get the payment type based on the card type
|
|
*/
|
|
describe("getPaymentType", () => {
|
|
it("returns mapped value when card type exists in mapping", () => {
|
|
const ipMapping = { visa: "Visa Card", amex: "American Express" };
|
|
expect(getPaymentType(ipMapping, "visa")).toBe("Visa Card");
|
|
});
|
|
|
|
it("returns original value when card type not in mapping", () => {
|
|
const ipMapping = { visa: "Visa Card" };
|
|
expect(getPaymentType(ipMapping, "mastercard")).toBe("mastercard");
|
|
});
|
|
|
|
it("handles lowercase conversion", () => {
|
|
const ipMapping = { visa: "Visa Card" };
|
|
expect(getPaymentType(ipMapping, "VISA")).toBe("Visa Card");
|
|
});
|
|
|
|
it("handles null mapping", () => {
|
|
expect(getPaymentType(null, "visa")).toBe("visa");
|
|
});
|
|
|
|
it("handles undefined mapping", () => {
|
|
expect(getPaymentType(undefined, "visa")).toBe("visa");
|
|
});
|
|
|
|
it("handles empty string card type", () => {
|
|
const ipMapping = { visa: "Visa Card" };
|
|
expect(getPaymentType(ipMapping, "")).toBe("");
|
|
});
|
|
|
|
it("handles undefined card type", () => {
|
|
const ipMapping = { visa: "Visa Card" };
|
|
expect(getPaymentType(ipMapping, undefined)).toBe(undefined);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* @description Get the CPTeller URL based on environment and parameters
|
|
*/
|
|
describe("getCptellerUrl", () => {
|
|
const originalEnv = process.env.NODE_ENV;
|
|
|
|
afterEach(() => {
|
|
// Restore the original NODE_ENV after each test
|
|
process.env.NODE_ENV = originalEnv;
|
|
});
|
|
|
|
it("uses test domain in non-production environment", () => {
|
|
process.env.NODE_ENV = "";
|
|
const url = getCptellerUrl({ apiType: "webapi" });
|
|
expect(url).toEqual("https://test.cpteller.com/api/webapi.cfc");
|
|
});
|
|
|
|
it("uses secure domain in production environment", () => {
|
|
process.env.NODE_ENV = "production";
|
|
const url = getCptellerUrl({ apiType: "webapi" });
|
|
expect(url).toEqual("https://secure.cpteller.com/api/webapi.cfc");
|
|
});
|
|
|
|
it("adds version number for webapi type", () => {
|
|
process.env.NODE_ENV = "";
|
|
const url = getCptellerUrl({ apiType: "webapi", version: "26" });
|
|
expect(url).toEqual("https://test.cpteller.com/api/26/webapi.cfc");
|
|
});
|
|
|
|
it("constructs custapi URL without version number", () => {
|
|
process.env.NODE_ENV = "";
|
|
const url = getCptellerUrl({ apiType: "custapi", version: "26" });
|
|
expect(url).toEqual("https://test.cpteller.com/api/custapi.cfc");
|
|
});
|
|
|
|
it("adds query parameters to the URL", () => {
|
|
process.env.NODE_ENV = "";
|
|
const url = getCptellerUrl({
|
|
apiType: "webapi",
|
|
params: { method: "payment_refund", test: "value" }
|
|
});
|
|
expect(url).toEqual("https://test.cpteller.com/api/webapi.cfc?method=payment_refund&test=value");
|
|
});
|
|
|
|
it("handles empty params object", () => {
|
|
process.env.NODE_ENV = "";
|
|
const url = getCptellerUrl({ apiType: "webapi", params: {} });
|
|
expect(url).toEqual("https://test.cpteller.com/api/webapi.cfc");
|
|
});
|
|
|
|
it("defaults to webapi when no apiType is provided", () => {
|
|
process.env.NODE_ENV = "";
|
|
const url = getCptellerUrl({});
|
|
expect(url).toEqual("https://test.cpteller.com/api/webapi.cfc");
|
|
});
|
|
|
|
it("combines version and query parameters correctly", () => {
|
|
process.env.NODE_ENV = "";
|
|
const url = getCptellerUrl({
|
|
apiType: "webapi",
|
|
version: "26",
|
|
params: { method: "fee" }
|
|
});
|
|
expect(url).toEqual("https://test.cpteller.com/api/26/webapi.cfc?method=fee");
|
|
});
|
|
});
|
|
|
|
/**
|
|
* @description Get shop credentials from AWS Secrets Manager or environment variables
|
|
*/
|
|
|
|
describe("getShopCredentials", () => {
|
|
const originalEnv = { ...process.env };
|
|
let mockSend;
|
|
|
|
beforeEach(() => {
|
|
// Create a mock function for send
|
|
mockSend = vi.fn();
|
|
|
|
// Mock the entire AWS SDK module
|
|
vi.mock("@aws-sdk/client-secrets-manager", () => {
|
|
return {
|
|
SecretsManagerClient: vi.fn(() => ({
|
|
send: mockSend
|
|
})),
|
|
GetSecretValueCommand: vi.fn((input) => input)
|
|
};
|
|
});
|
|
|
|
// Setup test environment variables
|
|
process.env.INTELLIPAY_MERCHANTKEY = "test-merchant-key";
|
|
process.env.INTELLIPAY_APIKEY = "test-api-key";
|
|
|
|
// Clear module cache to ensure fresh mock is used
|
|
vi.resetModules();
|
|
});
|
|
|
|
afterEach(() => {
|
|
// Restore environment and clear mocks
|
|
process.env = { ...originalEnv };
|
|
vi.restoreAllMocks();
|
|
vi.unmock("@aws-sdk/client-secrets-manager");
|
|
});
|
|
|
|
it("returns environment variables in non-production environment", async () => {
|
|
process.env.NODE_ENV = "development";
|
|
|
|
const result = await getShopCredentials({ imexshopid: "12345" });
|
|
|
|
expect(result).toEqual({
|
|
merchantkey: "test-merchant-key",
|
|
apikey: "test-api-key"
|
|
});
|
|
expect(mockSend).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("returns undefined when imexshopid is missing in production", async () => {
|
|
process.env.NODE_ENV = "production";
|
|
|
|
const result = await getShopCredentials({ name: "Test Shop" });
|
|
|
|
expect(result).toBeUndefined();
|
|
expect(mockSend).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("returns undefined for null bodyshop in production", async () => {
|
|
process.env.NODE_ENV = "production";
|
|
|
|
const result = await getShopCredentials(null);
|
|
|
|
expect(result).toBeUndefined();
|
|
expect(mockSend).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("returns undefined for undefined bodyshop in production", async () => {
|
|
process.env.NODE_ENV = "production";
|
|
|
|
const result = await getShopCredentials(undefined);
|
|
|
|
expect(result).toBeUndefined();
|
|
expect(mockSend).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
/**
|
|
* @description Handle payment validation errors
|
|
*/
|
|
describe("handlePaymentValidationError", () => {
|
|
it("logs error and sends 400 response", () => {
|
|
// Create mock objects
|
|
const mockLog = vi.fn();
|
|
const mockLogger = { log: mockLog };
|
|
const mockRes = {
|
|
status: vi.fn().mockReturnThis(),
|
|
send: vi.fn().mockReturnThis()
|
|
};
|
|
|
|
// Test data
|
|
const logCode = "test-validation-error";
|
|
const message = "Invalid data";
|
|
const logMeta = { field: "test", value: 123 };
|
|
|
|
// Call the function
|
|
const result = handlePaymentValidationError(mockRes, mockLogger, logCode, message, logMeta);
|
|
|
|
// Verify logger.log was called correctly
|
|
expect(mockLog).toHaveBeenCalledWith(logCode, "ERROR", "api", null, { message, ...logMeta });
|
|
|
|
// Verify res.status was called with 400
|
|
expect(mockRes.status).toHaveBeenCalledWith(400);
|
|
|
|
// Verify res.send was called with correct message
|
|
expect(mockRes.send).toHaveBeenCalledWith(`Bad Request: ${message}`);
|
|
|
|
// Verify the function returns the response
|
|
expect(result).toBe(mockRes);
|
|
});
|
|
|
|
it("formats different error messages correctly", () => {
|
|
const mockLog = vi.fn();
|
|
const mockLogger = { log: mockLog };
|
|
const mockRes = {
|
|
status: vi.fn().mockReturnThis(),
|
|
send: vi.fn().mockReturnThis()
|
|
};
|
|
|
|
handlePaymentValidationError(mockRes, mockLogger, "error-code", "Custom error");
|
|
|
|
expect(mockRes.send).toHaveBeenCalledWith("Bad Request: Custom error");
|
|
});
|
|
|
|
it("passes different logCodes to logger", () => {
|
|
const mockLog = vi.fn();
|
|
const mockLogger = { log: mockLog };
|
|
const mockRes = {
|
|
status: vi.fn().mockReturnThis(),
|
|
send: vi.fn().mockReturnThis()
|
|
};
|
|
|
|
handlePaymentValidationError(mockRes, mockLogger, "custom-log-code", "Error message");
|
|
|
|
expect(mockLog).toHaveBeenCalledWith("custom-log-code", "ERROR", "api", null, { message: "Error message" });
|
|
});
|
|
|
|
it("works with minimal logMeta", () => {
|
|
const mockLog = vi.fn();
|
|
const mockLogger = { log: mockLog };
|
|
const mockRes = {
|
|
status: vi.fn().mockReturnThis(),
|
|
send: vi.fn().mockReturnThis()
|
|
};
|
|
|
|
handlePaymentValidationError(mockRes, mockLogger, "error-code", "Error message", {});
|
|
|
|
expect(mockLog).toHaveBeenCalledWith("error-code", "ERROR", "api", null, { message: "Error message" });
|
|
});
|
|
|
|
it("works with undefined logMeta", () => {
|
|
const mockLog = vi.fn();
|
|
const mockLogger = { log: mockLog };
|
|
const mockRes = {
|
|
status: vi.fn().mockReturnThis(),
|
|
send: vi.fn().mockReturnThis()
|
|
};
|
|
|
|
handlePaymentValidationError(mockRes, mockLogger, "error-code", "Error message");
|
|
|
|
expect(mockLog).toHaveBeenCalledWith("error-code", "ERROR", "api", null, { message: "Error message" });
|
|
});
|
|
});
|