UNPKG

daraja

Version:

A NodeJS library to simplify integration with Safaricom's Daraja M-Pesa API

635 lines (597 loc) 20 kB
const chai = require('chai'); const chaiAsPromised = require('chai-as-promised'); const nock = require('nock'); const api = require('../dist/lib/api'); chai.use(chaiAsPromised); const { expect } = chai; describe('API', () => { after(() => { nock.cleanAll(); }); describe('getEnvPath()', () => { it('should return the correct path for the environment', () => { expect(api.getEnvPath('production')).to.equal('api'); }); }); describe('generateToken()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .get('/oauth/v1/generate') .basicAuth({ user: 'consumerKey', pass: 'consumerSecret' }) .query({ grant_type: 'client_credentials' }) .reply(200, { access_token: 'accessToken', expires_in: '3599' }); nock('https://sandbox.safaricom.co.ke') .get('/oauth/v1/generate') .basicAuth({ user: 'invalidKey', pass: 'invalidSecret' }) .query({ grant_type: 'client_credentials' }) .reply(400); }); it('should resolve to an object containing the \'access_token\' and \'expires_in\' properties', () => expect( api.generateToken('sandbox', 'consumerKey', 'consumerSecret') ).to.eventually.deep.equal({ access_token: 'accessToken', expires_in: '3599' })); it('should throw an error if the credentials are invalid', () => expect(api.generateToken('sandbox', 'invalidKey', 'invalidSecret')).to .eventually.be.rejected); }); describe('mpesaExpressRequest()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/stkpush/v1/processrequest', { BusinessShortCode: 123456, Password: 'password', Timestamp: '20190109164054', TransactionType: 'CustomerPayBillOnline', Amount: 100, PartyA: 254712345678, PartyB: 123456, PhoneNumber: 254712345678, CallBackURL: 'http://callbackurl.com', AccountReference: 'accountref', TransactionDesc: 'transactiondesc' }) .reply(200, { MerchantRequestID: 'merchantRequestId', CheckoutRequestID: 'checkoutRequestId', ResponseCode: '0', ResponseDescription: 'Success. Request accepted for processing', CustomerMessage: 'Success. Request accepted for processing' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/stkpush/v1/processrequest', { BusinessShortCode: 123456, Password: 'password', Timestamp: '20190109164054', TransactionType: 'invalid transaction type', Amount: 100, PartyA: 254712345678, PartyB: 123456, PhoneNumber: 254712345678, CallBackURL: 'http://callbackurl.com', AccountReference: 'accountref', TransactionDesc: 'transactiondesc' }) .reply(400); }); it('should resolve to an object containing the \'MerchantRequestID\' and \'CheckoutRequestID\' properties', () => expect( api.mpesaExpressRequest( 'sandbox', 'accessToken', 123456, 'password', '20190109164054', 'CustomerPayBillOnline', 100, 254712345678, 123456, 254712345678, 'http://callbackurl.com', 'accountref', 'transactiondesc' ) ).to.eventually.deep.equal({ MerchantRequestID: 'merchantRequestId', CheckoutRequestID: 'checkoutRequestId', ResponseCode: '0', ResponseDescription: 'Success. Request accepted for processing', CustomerMessage: 'Success. Request accepted for processing' })); it('should throw an error if the parameters are incorrect', () => expect( api.mpesaExpressRequest( 'sandbox', 'accessToken', 123456, 'password', '20190109164054', 'invalid transaction type', 100, 254712345678, 123456, 254712345678, 'http://callbackurl.com', 'accountref', 'transactiondesc' ) ).to.eventually.be.rejected); }); describe('mpesaExpressQuery()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/stkpushquery/v1/query', { BusinessShortCode: 123456, Password: 'password', Timestamp: '20190109164054', CheckoutRequestID: 'checkoutRequestId' }) .reply(200, { ResponseCode: '0', ResponseDescription: 'The service request has been accepted successsfully', MerchantRequestID: 'merchantRequestId', CheckoutRequestID: 'checkoutRequestId', ResultCode: '1032', ResultDesc: '[STK_CB - ]Request cancelled by user' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/stkpushquery/v1/query', { BusinessShortCode: 123456, Password: 'password', Timestamp: '20190109164054', CheckoutRequestID: 'invalidCheckoutRequestId' }) .reply(400); }); it('should resolve to an object containing the \'ResultCode\' and \'ResultDesc\' properties', () => expect( api.mpesaExpressQuery( 'sandbox', 'accessToken', 123456, 'password', '20190109164054', 'checkoutRequestId' ) ).to.eventually.deep.equal({ ResponseCode: '0', ResponseDescription: 'The service request has been accepted successsfully', MerchantRequestID: 'merchantRequestId', CheckoutRequestID: 'checkoutRequestId', ResultCode: '1032', ResultDesc: '[STK_CB - ]Request cancelled by user' })); it('should throw an error if the parameters are incorrect', () => expect( api.mpesaExpressQuery( 'sandbox', 'accessToken', 123456, 'password', '20190109164054', 'invalidCheckoutRequestId' ) ).to.eventually.be.rejected); }); describe('c2bRegisterUrl()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/c2b/v1/registerurl', { ValidationURL: 'http://validationurl.com', ConfirmationURL: 'http://confirmationurl.com', ResponseType: 'Completed', ShortCode: 123456 }) .reply(200, { ConversationID: '', OriginatorCoversationID: '', ResponseDescription: 'success' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/c2b/v1/registerurl', { ValidationURL: 'http://validationurl.com', ConfirmationURL: 'http://confirmationurl.com', ResponseType: 'Incorrect', ShortCode: 123456 }) .reply(400); }); it('should resolve to an object containing the \'ResponseDescription\' property', () => expect( api.c2bRegisterUrl( 'sandbox', 'accessToken', 'http://validationurl.com', 'http://confirmationurl.com', 'Completed', 123456 ) ).to.eventually.deep.equal({ ConversationID: '', OriginatorCoversationID: '', ResponseDescription: 'success' })); it('should throw an error if the parameters are incorrect', () => expect( api.c2bRegisterUrl( 'sandbox', 'accessToken', 'http://validationurl.com', 'http://confirmationurl.com', 'Incorrect', 123456 ) ).to.eventually.be.rejected); }); describe('c2bSimulateTransaction()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/c2b/v1/simulate', { CommandID: 'CustomerPayBillOnline', Amount: 100, Msisdn: 254712345678, BillRefNumber: 'BillRef', ShortCode: 123456 }) .reply(200, { ConversationID: 'conversationId', OriginatorCoversationID: 'originatorConversationId', ResponseDescription: 'Accept the service request successfully.' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/c2b/v1/simulate', { CommandID: 'Invalid Command ID', Amount: 100, Msisdn: 254712345678, BillRefNumber: 'BillRef', ShortCode: 123456 }) .reply(400); }); it('should resolve to an object containing the \'ResponseDescription\' property', () => expect( api.c2bSimulateTransaction( 'accessToken', 'CustomerPayBillOnline', 100, 254712345678, 'BillRef', 123456 ) ).to.eventually.deep.equal({ ConversationID: 'conversationId', OriginatorCoversationID: 'originatorConversationId', ResponseDescription: 'Accept the service request successfully.' })); it('should throw an error if the parameters are incorrect', () => expect( api.c2bSimulateTransaction( 'accessToken', 'Invalid Command ID', 100, 254712345678, 'BillRef', 123456 ) ).to.eventually.be.rejected); }); describe('b2cPaymentRequest()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/b2c/v1/paymentrequest', { InitiatorName: 'initiator', SecurityCredential: 'credential', CommandID: 'BusinessPayment', Amount: 100, PartyA: 123456, PartyB: 254712345678, Remarks: 'remarks', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com', Occassion: 'occassion' }) .reply(200, { ConversationID: 'conversationId', OriginatorConversationID: 'originatorConversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/b2c/v1/paymentrequest', { InitiatorName: 'initiator', SecurityCredential: 'credential', CommandID: 'Invalid CommandID', Amount: 100, PartyA: 123456, PartyB: 254712345678, Remarks: 'remarks', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com', Occassion: 'occassion' }) .reply(400); }); it('should resolve to an object containing the \'ResponseDescription\' property', () => expect( api.b2cPaymentRequest( 'sandbox', 'accessToken', 'initiator', 'credential', 'BusinessPayment', 100, 123456, 254712345678, 'remarks', 'http://timeouturl.com', 'http://resulturl.com', 'occassion' ) ).to.eventually.deep.equal({ ConversationID: 'conversationId', OriginatorConversationID: 'originatorConversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' })); it('should throw an error if the parameters are incorrect', () => expect( api.b2cPaymentRequest( 'sandbox', 'accessToken', 'initiator', 'credential', 'Invalid CommandID', 100, 123456, 254712345678, 'remarks', 'http://timeouturl.com', 'http://resulturl.com', 'occassion' ) ).to.eventually.be.rejected); }); describe('accountBalanceRequest()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/accountbalance/v1/query', { CommandID: 'AccountBalance', PartyA: 123456, IdentifierType: 4, Remarks: 'remarks', Initiator: 'initiator', SecurityCredential: 'credential', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com' }) .reply(200, { OriginatorConversationID: 'originatorConversationId', ConversationID: 'conversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/accountbalance/v1/query', { CommandID: 'Invalid Command ID', PartyA: 123456, IdentifierType: 4, Remarks: 'remarks', Initiator: 'initiator', SecurityCredential: 'credential', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com' }) .reply(400); }); it('should resolve to an object containing the \'ResponseDescription\' property', () => expect( api.accountBalanceRequest( 'sandbox', 'accessToken', 'AccountBalance', 123456, 4, 'remarks', 'initiator', 'credential', 'http://timeouturl.com', 'http://resulturl.com' ) ).to.eventually.deep.equal({ OriginatorConversationID: 'originatorConversationId', ConversationID: 'conversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' })); it('should throw an error if the parameters are incorrect', () => expect( api.accountBalanceRequest( 'sandbox', 'accessToken', 'Invalid Command ID', 123456, 4, 'remarks', 'initiator', 'credential', 'http://timeouturl.com', 'http://resulturl.com' ) ).to.eventually.be.rejected); }); describe('transactionStatusRequest()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/transactionstatus/v1/query', { CommandID: 'TransactionStatusQuery', PartyA: 123456, IdentifierType: 4, Remarks: 'remarks', Initiator: 'initiator', SecurityCredential: 'credential', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com', TransactionID: 'MX00000000', Occasion: 'occassion' }) .reply(200, { OriginatorConversationID: 'originatorConversationId', ConversationID: 'conversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/transactionstatus/v1/query', { CommandID: 'Invalid Command ID', PartyA: 123456, IdentifierType: 4, Remarks: 'remarks', Initiator: 'initiator', SecurityCredential: 'credential', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com', TransactionID: 'MX00000000', Occasion: 'occassion' }) .reply(400); }); it('should resolve to an object containing the \'ResponseDescription\' property', () => expect( api.transactionStatusRequest( 'sandbox', 'accessToken', 'TransactionStatusQuery', 123456, 4, 'remarks', 'initiator', 'credential', 'http://timeouturl.com', 'http://resulturl.com', 'MX00000000', 'occassion' ) ).to.eventually.deep.equal({ OriginatorConversationID: 'originatorConversationId', ConversationID: 'conversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' })); it('should throw an error if the parameters are incorrect', () => expect( api.transactionStatusRequest( 'sandbox', 'accessToken', 'TransactionStatusQuery', 123456, 4, 'remarks', 'initiator', 'credential', 'http://timeouturl.com', 'http://resulturl.com', 'MX00000000', 'occassion' ) ).to.eventually.be.rejected); }); describe('reversalRequest()', () => { before(() => { nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/reversal/v1/request', { CommandID: 'TransactionReversal', ReceiverParty: 123456, ReceiverIdentifierType: 11, Remarks: 'remarks', Initiator: 'initiator', SecurityCredential: 'credential', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com', TransactionID: 'MX00000000', Occasion: 'occassion' }) .reply(200, { OriginatorConversationID: 'originatorConversationId', ConversationID: 'conversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' }); nock('https://sandbox.safaricom.co.ke') .matchHeader('Authorization', 'Bearer accessToken') .post('/mpesa/reversal/v1/request', { CommandID: 'Invalid Command ID', ReceiverParty: 123456, ReceiverIdentifierType: 11, Remarks: 'remarks', Initiator: 'initiator', SecurityCredential: 'credential', QueueTimeOutURL: 'http://timeouturl.com', ResultURL: 'http://resulturl.com', TransactionID: 'MX00000000', Occasion: 'occassion' }) .reply(400); }); it('should resolve to an object containing the \'ResponseDescription\' property', () => expect( api.reversalRequest( 'sandbox', 'accessToken', 'TransactionReversal', 123456, 11, 'remarks', 'initiator', 'credential', 'http://timeouturl.com', 'http://resulturl.com', 'MX00000000', 'occassion' ) ).to.eventually.deep.equal({ OriginatorConversationID: 'originatorConversationId', ConversationID: 'conversationId', ResponseCode: '0', ResponseDescription: 'Accept the service request successfully.' })); it('should throw an error if the parameters are incorrect', () => expect( api.reversalRequest( 'sandbox', 'accessToken', 'Invalid Command ID', 123456, 11, 'remarks', 'initiator', 'credential', 'http://timeouturl.com', 'http://resulturl.com', 'MX00000000', 'occassion' ) ).to.eventually.be.rejected); }); });