feature/IO-2885-IntelliPay-App-Postback
- Add Tests
This commit is contained in:
48
package-lock.json
generated
48
package-lock.json
generated
@@ -75,6 +75,7 @@
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"globals": "^15.15.0",
|
||||
"mock-require": "^3.0.3",
|
||||
"p-limit": "^3.1.0",
|
||||
"prettier": "^3.5.3",
|
||||
"source-map-explorer": "^2.5.2",
|
||||
@@ -8402,9 +8403,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
|
||||
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -9535,6 +9536,40 @@
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/mock-require": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz",
|
||||
"integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-caller-file": "^1.0.2",
|
||||
"normalize-path": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mock-require/node_modules/get-caller-file": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
|
||||
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/mock-require/node_modules/normalize-path": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
|
||||
"integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"remove-trailing-separator": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/module-details-from-path": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz",
|
||||
@@ -10709,6 +10744,13 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/remove-trailing-separator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||
"integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"globals": "^15.15.0",
|
||||
"mock-require": "^3.0.3",
|
||||
"p-limit": "^3.1.0",
|
||||
"prettier": "^3.5.3",
|
||||
"source-map-explorer": "^2.5.2",
|
||||
|
||||
152
server/intellipay/lib/tests/handleCommentBasedPayment.test.js
Normal file
152
server/intellipay/lib/tests/handleCommentBasedPayment.test.js
Normal file
@@ -0,0 +1,152 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import mockRequire from "mock-require";
|
||||
|
||||
const gqlRequestMock = { request: vi.fn() };
|
||||
const getPaymentTypeMock = vi.fn(() => "American Express");
|
||||
const sendPaymentNotificationEmailMock = vi.fn();
|
||||
|
||||
let handleCommentBasedPayment;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Mock dependencies using mock-require BEFORE requiring the target module
|
||||
mockRequire("../../../graphql-client/graphql-client", {
|
||||
client: gqlRequestMock
|
||||
});
|
||||
|
||||
mockRequire("../getPaymentType", getPaymentTypeMock);
|
||||
mockRequire("../sendPaymentNotificationEmail", sendPaymentNotificationEmailMock);
|
||||
|
||||
// Now require the module under test
|
||||
handleCommentBasedPayment = require("../handleCommentBasedPayment");
|
||||
|
||||
// Chain your GraphQL mocks
|
||||
gqlRequestMock.request
|
||||
.mockResolvedValueOnce({
|
||||
jobs: [
|
||||
{
|
||||
id: "c1ffe09c-e7d4-46b3-aac5-f23e39563181",
|
||||
shopid: "bfec8c8c-b7f1-49e0-be4c-524455f4e582"
|
||||
}
|
||||
]
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
bodyshops_by_pk: {
|
||||
id: "bfec8c8c-b7f1-49e0-be4c-524455f4e582",
|
||||
intellipay_config: {
|
||||
payment_map: {
|
||||
amex: "American Express"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
insert_payments: {
|
||||
returning: [{ id: "5dfda3c4-c0a6-4b09-a73d-176ed0ac6499" }]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleCommentBasedPayment", () => {
|
||||
const mockLogger = { log: vi.fn() };
|
||||
const mockRes = { sendStatus: vi.fn() };
|
||||
|
||||
const values = {
|
||||
authcode: "5557301",
|
||||
total: "0.01",
|
||||
origin: "Dejavoo",
|
||||
paymentid: "24294378",
|
||||
cardtype: "Amex"
|
||||
};
|
||||
|
||||
const decodedComment = {
|
||||
payments: [{ jobid: "c1ffe09c-e7d4-46b3-aac5-f23e39563181", amount: 0.01 }],
|
||||
userEmail: "test@example.com"
|
||||
};
|
||||
|
||||
const logMeta = { op: "xyz123" };
|
||||
|
||||
it("processes comment-based payment and returns 200", async () => {
|
||||
await handleCommentBasedPayment(values, decodedComment, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(gqlRequestMock.request).toHaveBeenCalledTimes(3);
|
||||
expect(getPaymentTypeMock).toHaveBeenCalledWith({ amex: "American Express" }, "Amex");
|
||||
expect(sendPaymentNotificationEmailMock).not.toHaveBeenCalled();
|
||||
expect(mockRes.sendStatus).toHaveBeenCalledWith(200);
|
||||
});
|
||||
|
||||
it("sends notification if origin is OneLink and userEmail exists", async () => {
|
||||
const oneLinkValues = { ...values, origin: "OneLink" };
|
||||
|
||||
await handleCommentBasedPayment(oneLinkValues, decodedComment, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(sendPaymentNotificationEmailMock).toHaveBeenCalledWith(
|
||||
"test@example.com",
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
mockLogger,
|
||||
logMeta
|
||||
);
|
||||
|
||||
expect(mockRes.sendStatus).toHaveBeenCalledWith(200);
|
||||
});
|
||||
|
||||
it("handles decodedComment as a direct array", async () => {
|
||||
const arrayComment = [{ jobid: "c1ffe09c-e7d4-46b3-aac5-f23e39563181", amount: 0.01 }];
|
||||
|
||||
await handleCommentBasedPayment(values, arrayComment, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(gqlRequestMock.request).toHaveBeenCalledTimes(3);
|
||||
expect(mockRes.sendStatus).toHaveBeenCalledWith(200);
|
||||
});
|
||||
|
||||
it("does not send email if origin is OneLink but userEmail is missing", async () => {
|
||||
const commentWithoutEmail = {
|
||||
payments: decodedComment.payments
|
||||
// no userEmail
|
||||
};
|
||||
|
||||
const oneLinkValues = { ...values, origin: "OneLink" };
|
||||
|
||||
await handleCommentBasedPayment(oneLinkValues, commentWithoutEmail, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(sendPaymentNotificationEmailMock).not.toHaveBeenCalled();
|
||||
expect(mockRes.sendStatus).toHaveBeenCalledWith(200);
|
||||
});
|
||||
|
||||
it("logs important stages of the process", async () => {
|
||||
await handleCommentBasedPayment(values, decodedComment, mockLogger, logMeta, mockRes);
|
||||
|
||||
const logCalls = mockLogger.log.mock.calls.map(([tag]) => tag);
|
||||
|
||||
expect(logCalls).toContain("intellipay-postback-parsed-comment");
|
||||
expect(logCalls).toContain("intellipay-postback-payment-success");
|
||||
});
|
||||
|
||||
it("handles missing payment_map safely", async () => {
|
||||
gqlRequestMock.request.mockReset(); // 🧹 Clear previous .mockResolvedValueOnce calls
|
||||
|
||||
gqlRequestMock.request
|
||||
.mockResolvedValueOnce({
|
||||
jobs: [{ id: "job1", shopid: "shop1" }]
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
bodyshops_by_pk: {
|
||||
id: "shop1",
|
||||
intellipay_config: null
|
||||
}
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
insert_payments: {
|
||||
returning: [{ id: "payment1" }]
|
||||
}
|
||||
});
|
||||
|
||||
await handleCommentBasedPayment(values, decodedComment, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(getPaymentTypeMock).toHaveBeenCalledWith(undefined, "Amex");
|
||||
expect(mockRes.sendStatus).toHaveBeenCalledWith(200);
|
||||
});
|
||||
});
|
||||
129
server/intellipay/lib/tests/handleInvoiceBasedPayment.test.js
Normal file
129
server/intellipay/lib/tests/handleInvoiceBasedPayment.test.js
Normal file
@@ -0,0 +1,129 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import mockRequire from "mock-require";
|
||||
|
||||
const gqlRequestMock = { request: vi.fn() };
|
||||
const getPaymentTypeMock = vi.fn(() => "Visa");
|
||||
const handlePaymentValidationErrorMock = vi.fn();
|
||||
|
||||
let handleInvoiceBasedPayment;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
vi.clearAllMocks();
|
||||
|
||||
mockRequire("../../../graphql-client/graphql-client", {
|
||||
client: gqlRequestMock
|
||||
});
|
||||
|
||||
mockRequire("../getPaymentType", getPaymentTypeMock);
|
||||
mockRequire("../handlePaymentValidationError", handlePaymentValidationErrorMock);
|
||||
|
||||
handleInvoiceBasedPayment = require("../handleInvoiceBasedPayment");
|
||||
|
||||
gqlRequestMock.request
|
||||
.mockResolvedValueOnce({
|
||||
jobs: [
|
||||
{
|
||||
id: "job123",
|
||||
bodyshop: {
|
||||
id: "shop123",
|
||||
intellipay_config: {
|
||||
payment_map: {
|
||||
visa: "Visa"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
id: "payment123"
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
insert_payment_response: {
|
||||
returning: [{ id: "response123" }]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleInvoiceBasedPayment", () => {
|
||||
const mockLogger = { log: vi.fn() };
|
||||
const mockRes = { sendStatus: vi.fn() };
|
||||
|
||||
const values = {
|
||||
merchantid: "m123",
|
||||
invoice: "INV-001",
|
||||
total: 100.0,
|
||||
authcode: "AUTH123",
|
||||
cardtype: "visa",
|
||||
paymentid: "P789"
|
||||
};
|
||||
|
||||
const logMeta = { op: "abc123" };
|
||||
|
||||
it("processes a valid invoice-based payment", async () => {
|
||||
await handleInvoiceBasedPayment(values, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(gqlRequestMock.request).toHaveBeenCalledTimes(3);
|
||||
expect(getPaymentTypeMock).toHaveBeenCalledWith({ visa: "Visa" }, "visa");
|
||||
expect(mockRes.sendStatus).toHaveBeenCalledWith(200);
|
||||
expect(handlePaymentValidationErrorMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("handles missing merchantid with validation error", async () => {
|
||||
const invalidValues = { ...values, merchantid: undefined };
|
||||
|
||||
await handleInvoiceBasedPayment(invalidValues, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(handlePaymentValidationErrorMock).toHaveBeenCalledWith(
|
||||
mockRes,
|
||||
mockLogger,
|
||||
"intellipay-postback-no-merchantid",
|
||||
"Merchant ID is missing",
|
||||
logMeta
|
||||
);
|
||||
expect(gqlRequestMock.request).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("handles job not found with validation error", async () => {
|
||||
gqlRequestMock.request.mockReset();
|
||||
gqlRequestMock.request.mockResolvedValueOnce({ jobs: [] });
|
||||
|
||||
await handleInvoiceBasedPayment(values, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(handlePaymentValidationErrorMock).toHaveBeenCalledWith(
|
||||
mockRes,
|
||||
mockLogger,
|
||||
"intellipay-postback-job-not-found",
|
||||
"Job not found",
|
||||
logMeta
|
||||
);
|
||||
});
|
||||
|
||||
it("handles missing bodyshop with validation error", async () => {
|
||||
gqlRequestMock.request.mockReset();
|
||||
gqlRequestMock.request.mockResolvedValueOnce({
|
||||
jobs: [{ id: "job123", bodyshop: null }]
|
||||
});
|
||||
|
||||
await handleInvoiceBasedPayment(values, mockLogger, logMeta, mockRes);
|
||||
|
||||
expect(handlePaymentValidationErrorMock).toHaveBeenCalledWith(
|
||||
mockRes,
|
||||
mockLogger,
|
||||
"intellipay-postback-bodyshop-not-found",
|
||||
"Bodyshop not found",
|
||||
logMeta
|
||||
);
|
||||
});
|
||||
|
||||
it("logs all expected stages of the process", async () => {
|
||||
await handleInvoiceBasedPayment(values, mockLogger, logMeta, mockRes);
|
||||
|
||||
const logTags = mockLogger.log.mock.calls.map(([tag]) => tag);
|
||||
|
||||
expect(logTags).toContain("intellipay-postback-invoice-job-fetched");
|
||||
expect(logTags).toContain("intellipay-postback-invoice-payment-success");
|
||||
expect(logTags).toContain("intellipay-postback-invoice-response-success");
|
||||
});
|
||||
});
|
||||
@@ -1,10 +1,10 @@
|
||||
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");
|
||||
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
|
||||
Reference in New Issue
Block a user