Files
midtrans-gateway/tests/unit/notification.service.test.js
2026-02-18 16:03:43 +07:00

94 lines
4.3 KiB
JavaScript

const mockPaymentFindOne = jest.fn();
const mockOrderFindByPk = jest.fn();
const mockOrderFindOne = jest.fn();
jest.mock('../../../../models/migration', () => ({
Payment: { findOne: mockPaymentFindOne, update: jest.fn() },
Order: { findByPk: mockOrderFindByPk, findOne: mockOrderFindOne, update: jest.fn() }
}));
jest.mock('../../models/migration', () => ({
Payment: { findOne: mockPaymentFindOne, update: jest.fn() },
Order: { findByPk: mockOrderFindByPk, findOne: mockOrderFindOne, update: jest.fn() }
}));
const notificationService = require('../../app/modules/notification/services/notification.service');
const crypto = require('crypto');
describe('NotificationService', () => {
const serverKey = 'SB-Mid-server-test';
beforeEach(() => {
jest.clearAllMocks();
process.env.MIDTRANS_SERVER_KEY = serverKey;
});
describe('verifySignature', () => {
it('should return true for a valid signature', () => {
const payload = { order_id: 'I-123', status_code: '200', gross_amount: '10.00', signature_key: '' };
const data = payload.order_id + payload.status_code + payload.gross_amount + serverKey;
payload.signature_key = crypto.createHash('sha512').update(data).digest('hex');
expect(notificationService.verifySignature(payload)).toBe(true);
});
it('should return false for invalid signature', () => {
const payload = { order_id: 'I-123', status_code: '200', gross_amount: '10.00', signature_key: 'wrong' };
expect(notificationService.verifySignature(payload)).toBe(false);
});
});
describe('processNotification', () => {
it('should update order to COMPLETED on settlement', async () => {
const payload = { order_id: 'I-123', transaction_status: 'settlement', fraud_status: 'accept' };
const mockUpdateOrder = jest.fn();
const mockUpdatePayment = jest.fn();
const mockPayment = { order_id: 'u-123', update: mockUpdatePayment };
const mockOrder = { id: 'u-123', status: 'PENDING', payment_status: 'PENDING', update: mockUpdateOrder };
mockPaymentFindOne.mockResolvedValue(mockPayment);
mockOrderFindByPk.mockResolvedValue(mockOrder);
await notificationService.processNotification(payload);
expect(mockUpdateOrder).toHaveBeenCalledWith(expect.objectContaining({ status: 'COMPLETED', payment_status: 'PAID' }));
expect(mockUpdatePayment).toHaveBeenCalledWith(expect.objectContaining({ status: 'SUCCESS' }));
});
it('should update order to FAILED on deny/cancel/expire', async () => {
const payload = { order_id: 'I-123', transaction_status: 'expire' };
const mockUpdate = jest.fn();
const mockOrder = { id: 'u-123', status: 'PENDING', update: mockUpdate };
mockPaymentFindOne.mockResolvedValue(null);
mockOrderFindOne.mockResolvedValue(mockOrder);
await notificationService.processNotification(payload);
expect(mockUpdate).toHaveBeenCalledWith(expect.objectContaining({ status: 'FAILED', payment_status: 'REJECT' }));
});
it('should update to PENDING on pending status', async () => {
const payload = { order_id: 'I-123', transaction_status: 'pending' };
const mockUpdate = jest.fn();
const mockOrder = { id: 'u-123', status: 'PENDING', payment_status: 'PENDING', update: mockUpdate };
mockPaymentFindOne.mockResolvedValue(null);
mockOrderFindOne.mockResolvedValue(mockOrder);
await notificationService.processNotification(payload);
// If already pending, it should skip update
expect(mockUpdate).not.toHaveBeenCalled();
});
it('should warn if order not found', async () => {
const payload = { order_id: 'unknown' };
mockPaymentFindOne.mockResolvedValue(null);
mockOrderFindOne.mockResolvedValue(null);
mockOrderFindByPk.mockResolvedValue(null);
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
await notificationService.processNotification(payload);
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('tidak ditemukan'));
consoleSpy.mockRestore();
});
});
});