diff --git a/src/chapa.ts b/src/chapa.ts index 31ac288..33080f8 100644 --- a/src/chapa.ts +++ b/src/chapa.ts @@ -25,6 +25,8 @@ import { InitializeResponse, RefundOptions, RefundResponse, + VerifyRefundOptions, + VerifyRefundResponse, TransferOptions, TransferResponse, VerifyOptions, @@ -40,6 +42,7 @@ import { validateGetTransactionLogsOptions, validateInitializeOptions, validateRefundOptions, + validateVerifyRefundOptions, validateTransferOptions, validateVerifyOptions, validateVerifyTransferOptions, @@ -88,6 +91,10 @@ interface IChapa { signal?: AbortSignal ): Promise; refund(options: RefundOptions, signal?: AbortSignal): Promise; + verifyRefund( + options: VerifyRefundOptions, + signal?: AbortSignal + ): Promise; verifyWebhook(payload: WebhookPayload | string, signature: string): boolean; } @@ -341,6 +348,20 @@ export class Chapa implements IChapa { }); } + async verifyRefund( + options: VerifyRefundOptions, + signal?: AbortSignal + ): Promise { + return withErrorHandling(async () => { + validateVerifyRefundOptions(options); + const response = await this.axiosInstance.get( + `${ChapaUrls.REFUND}/${options.ref_id}/verify`, + { signal } + ); + return response.data; + }); + } + verifyWebhook(payload: WebhookPayload | string, signature: string): boolean { if (!this.webhookSecret) { throw new Error('Webhook secret not configured'); diff --git a/src/interfaces/refund.interface.ts b/src/interfaces/refund.interface.ts index c5ed5bd..42557ee 100644 --- a/src/interfaces/refund.interface.ts +++ b/src/interfaces/refund.interface.ts @@ -14,3 +14,13 @@ export interface RefundResponse { status: string; data: Record; } + +export interface VerifyRefundOptions { + ref_id: string; +} + +export interface VerifyRefundResponse { + message: string; + status: string; + data: Record; +} diff --git a/src/validations/refund.validation.ts b/src/validations/refund.validation.ts index 87690a2..505e840 100644 --- a/src/validations/refund.validation.ts +++ b/src/validations/refund.validation.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { RefundOptions } from '../interfaces'; +import { RefundOptions, VerifyRefundOptions } from '../interfaces'; const refundSchema = z.object({ tx_ref: z.string(), @@ -16,3 +16,11 @@ const refundSchema = z.object({ export const validateRefundOptions = (options: RefundOptions) => { return refundSchema.parse(options); }; + +const verifyRefundSchema = z.object({ + ref_id: z.string(), +}); + +export const validateVerifyRefundOptions = (options: VerifyRefundOptions) => { + return verifyRefundSchema.parse(options); +}; diff --git a/test/refund.test.ts b/test/refund.test.ts index 4ff5f25..675c6db 100644 --- a/test/refund.test.ts +++ b/test/refund.test.ts @@ -81,3 +81,41 @@ describe('Refund', () => { expect(body.toString()).toBe(''); }); }); + +describe('Verify Refund', () => { + const mockGet = jest.fn(); + let chapa: Chapa; + + beforeEach(() => { + mockGet.mockReset(); + (axios.create as jest.Mock).mockReturnValue({ get: mockGet }); + chapa = new Chapa({ secretKey: 'test-secret-key' }); + }); + + it('should validate required ref_id', async () => { + await expect( + chapa.verifyRefund({} as any) + ).rejects.toThrow(); + expect(mockGet).not.toHaveBeenCalled(); + }); + + it('should call get method with correct url', async () => { + const options = { + ref_id: 'REF-1234', + }; + const responseData = { + message: 'ok', + status: 'success', + data: { amount: 100 }, + }; + mockGet.mockResolvedValue({ data: responseData }); + + const response = await chapa.verifyRefund(options); + + expect(response).toEqual(responseData); + expect(mockGet).toHaveBeenCalledTimes(1); + const [url, config] = mockGet.mock.calls[0]; + expect(url).toBe('/refund/REF-1234/verify'); + expect(config.signal).toBeUndefined(); + }); +});