Files
insforge--insforge/backend/tests/unit/razorpay-catalog.service.test.ts
wehub-resource-sync 3a28426bf4
Lint and Format Check / lint-and-format (push) Failing after 0s
Check Migrations / Check for duplicate migration numbers (push) Failing after 1s
CI Pre-merge Check / CI Pre-merge Check (push) Failing after 2m17s
chore: import upstream snapshot with attribution
2026-07-13 12:23:40 +08:00

159 lines
4.3 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const {
mockPoolQuery,
mockCreateItem,
mockUpdateItem,
mockCreatePlan,
mockCreateRazorpayProvider,
mockWithPaymentSessionAdvisoryLock,
} = vi.hoisted(() => ({
mockPoolQuery: vi.fn(),
mockCreateItem: vi.fn(),
mockUpdateItem: vi.fn(),
mockCreatePlan: vi.fn(),
mockCreateRazorpayProvider: vi.fn(),
mockWithPaymentSessionAdvisoryLock: vi.fn(),
}));
vi.mock('../../src/infra/database/database.manager', () => ({
DatabaseManager: {
getInstance: () => ({
getPool: () => ({
query: mockPoolQuery,
}),
}),
},
}));
vi.mock('../../src/services/payments/payments-advisory-lock', () => ({
withPaymentSessionAdvisoryLock: mockWithPaymentSessionAdvisoryLock,
}));
vi.mock('../../src/services/payments/razorpay/config.service', () => ({
RazorpayConfigService: {
getInstance: () => ({
createRazorpayProvider: mockCreateRazorpayProvider,
}),
},
}));
import { RazorpayCatalogService } from '../../src/services/payments/razorpay/catalog.service';
describe('RazorpayCatalogService', () => {
beforeEach(() => {
vi.clearAllMocks();
mockWithPaymentSessionAdvisoryLock.mockImplementation(async (_pool, _lockName, task) => task());
mockCreateRazorpayProvider.mockResolvedValue({
createItem: mockCreateItem,
updateItem: mockUpdateItem,
createPlan: mockCreatePlan,
});
});
it('creates and mirrors a native Razorpay item', async () => {
mockCreateItem.mockResolvedValue({
id: 'item_123',
active: true,
amount: 25000,
unit_amount: 25000,
currency: 'INR',
name: 'Invoice item',
description: null,
type: 'invoice',
created_at: 1767225600,
});
mockPoolQuery.mockResolvedValueOnce({ rows: [], rowCount: 1 });
const result = await RazorpayCatalogService.getInstance().createItem({
environment: 'test',
name: 'Invoice item',
amount: 25000,
currency: 'INR',
});
expect(mockCreateItem).toHaveBeenCalledWith(
expect.objectContaining({
name: 'Invoice item',
amount: 25000,
currency: 'INR',
})
);
expect(mockPoolQuery).toHaveBeenCalledWith(
expect.stringMatching(/INSERT INTO payments\.razorpay_items/i),
expect.arrayContaining(['test', 'item_123', 'Invoice item', null, true, 25000, 25000, 'inr'])
);
expect(result.item).toEqual(
expect.objectContaining({
itemId: 'item_123',
currency: 'inr',
})
);
});
it('creates and mirrors a native Razorpay plan with its embedded item', async () => {
mockCreatePlan.mockResolvedValue({
id: 'plan_123',
entity: 'plan',
period: 'monthly',
interval: 1,
item: {
id: 'item_plan_123',
name: 'Pro monthly',
description: null,
amount: 199900,
unit_amount: 199900,
currency: 'INR',
active: true,
},
notes: { tier: 'pro' },
created_at: 1767225600,
});
mockPoolQuery
.mockResolvedValueOnce({ rows: [], rowCount: 1 })
.mockResolvedValueOnce({ rows: [], rowCount: 1 });
const result = await RazorpayCatalogService.getInstance().createPlan({
environment: 'test',
period: 'monthly',
interval: 1,
item: {
name: 'Pro monthly',
amount: 199900,
currency: 'INR',
},
notes: { tier: 'pro' },
});
expect(mockCreatePlan).toHaveBeenCalledWith(
expect.objectContaining({
period: 'monthly',
interval: 1,
item: expect.objectContaining({
name: 'Pro monthly',
amount: 199900,
currency: 'INR',
}),
notes: { tier: 'pro' },
})
);
expect(mockPoolQuery).toHaveBeenNthCalledWith(
1,
expect.stringMatching(/INSERT INTO payments\.razorpay_items/i),
expect.arrayContaining(['test', 'item_plan_123', 'Pro monthly'])
);
expect(mockPoolQuery).toHaveBeenNthCalledWith(
2,
expect.stringMatching(/INSERT INTO payments\.razorpay_plans/i),
expect.arrayContaining(['test', 'plan_123', 'item_plan_123', 'monthly', 1])
);
expect(result.plan).toEqual(
expect.objectContaining({
planId: 'plan_123',
itemId: 'item_plan_123',
notes: { tier: 'pro' },
})
);
});
});