packages feed

paynow-zw-0.1.0.0: test/Spec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes       #-}

import          Test.Hspec

import           Data.Either
import UnliftIO
import Network.Payments.Paynow

-- | Run the tests for the paynow library
main :: IO ()
main = hspec $ do
  describe "PaynowTransaction" transactionSpec 
  describe "Transaction Hashing" hashingSpec
  describe "Response Parsing" responseSpec
  describe "Paynow Client" clientSpec

defaultConfig :: PaynowConfig
defaultConfig = defaultProdConfig "1201"
                    "3e9fed89-60e1-4ce5-ab6e-6b1eb2d4f977"
                    "http://localhost:3000/result"
                    "http://localhost:3000/return"

runWithDefaultClientConfig :: (MonadUnliftIO m) => (PaynowClient m -> PaynowConfig -> m a) -> m a
runWithDefaultClientConfig f = do
    f client config
    where
        config = defaultConfig
        client = newPaynowClient config

runWithDefaultClient :: (MonadUnliftIO m) => (PaynowClient m -> m a) -> m a
runWithDefaultClient f = runWithDefaultClientConfig (\cl _ -> f cl)


testRef :: Ref
testRef = "TEST REF"

testAmount :: Amount
testAmount = 99.99

testEmail :: Email
testEmail = "customer@gmail.com"

testVMCDetails :: VMC
testVMCDetails = VMC (Card "4111111111111111" "588" "2023" "Trevor Sibanda") (BillingAddress "Address Line 1" "Line 2" "City" "Zimbabwe" Nothing)

testPollResponse = "reference=01&paynowreference=15650881&amount=99.00&status=Cancelled&pollurl=https%3a%2f%2fwww.paynow.co.zw%2fInterface%2fCheckPayment%2f%3fguid%3dd80b830d-623b-4948-9ab1-aae4950929bd&hash=E4F6E55CF3408EBDF0F59951E9E7B74C17CD9798A8AE5DA7B5D68D04F014E40753C438AA55445EB42FD9E455EE7FFA7BF752AD6791DE878DAEF4B486A345EAC"

testClassicCheckoutResponse = "status=Ok&browserurl=https%3a%2f%2fwww.paynow.co.zw%2fPayment%2fConfirmPayment%2f15655543%2fsibandatrevor%40gmail.com%2f%2f&pollurl=https%3a%2f%2fwww.paynow.co.zw%2fInterface%2fCheckPayment%2f%3fguid%3ddece867e-5a40-4961-bf0e-5d691c2a97f8&hash=83B31644B176661DC643CEDD480ADF3C0DECC9E2A00B004B8DC37B6A88A2A246D1A3DE57D5BA41B61BBA2FE2580CEFDCDEE30698200B88CD85D62FE75E76CD4B"

testExpressCheckoutResponse = "status=Ok&instructions=Dial+*151*2*4%23+and+enter+your+EcoCash+PIN.+Once+you+have+authorized+the+payment+via+your+handset%2c+please+click+Check+For+Payment+below+to+conclude+this+transaction&paynowreference=15655549&pollurl=https%3a%2f%2fwww.paynow.co.zw%2fInterface%2fCheckPayment%2f%3fguid%3dc9f51998-3bbd-48b4-9107-819794c75ef8&hash=6DB1869C5C3961ADDF616B0476660E6D76E9071855ACAFA974F751A67600E0AD7416040518825BB235FF4AF3B57FD50A80884FB438DE8A2A6FAC62C71BECB51F"

clientSpec :: Spec
clientSpec = do
    it "should wrap exceptions in a PaynowError" $ do
        let client = newPaynowClient defaultConfig { pncEndpoint = "not-a-valid-url" }
        payment <- newClassicCheckout client testRef testAmount testEmail Nothing
        result <- processTx client payment
        result `shouldSatisfy` isLeft

responseSpec :: Spec
responseSpec = do
    it "should parse a successful express checkout response" $ do
        case serverResponseToResult testExpressCheckoutResponse of
            Right result -> 
                 result `shouldBe` InitExpressPaymentSuccess Okay "15655549" "Dial+*151*2*4#+and+enter+your+EcoCash+PIN.+Once+you+have+authorized+the+payment+via+your+handset,+please+click+Check+For+Payment+below+to+conclude+this+transaction" "https://www.paynow.co.zw/Interface/CheckPayment/?guid=c9f51998-3bbd-48b4-9107-819794c75ef8" "6DB1869C5C3961ADDF616B0476660E6D76E9071855ACAFA974F751A67600E0AD7416040518825BB235FF4AF3B57FD50A80884FB438DE8A2A6FAC62C71BECB51F"
            _ -> expectationFailure "Expected a successful poll response"  

    it "should parse a successful classic checkout response" $ do
        case serverResponseToResult testClassicCheckoutResponse of
            Right result -> 
                 result `shouldBe` InitClassicCheckoutSuccess Okay "https://www.paynow.co.zw/Payment/ConfirmPayment/15655543/sibandatrevor@gmail.com//" "https://www.paynow.co.zw/Interface/CheckPayment/?guid=dece867e-5a40-4961-bf0e-5d691c2a97f8" "83B31644B176661DC643CEDD480ADF3C0DECC9E2A00B004B8DC37B6A88A2A246D1A3DE57D5BA41B61BBA2FE2580CEFDCDEE30698200B88CD85D62FE75E76CD4B"
            _ -> expectationFailure "Expected a successful poll response"

    it "should successfully parse a poll response" $ do
        case serverResponseToResult testPollResponse of
            Right result -> 
                 result `shouldBe` PollPaymentSuccess Cancelled "15650881" "01"  99.00  "https://www.paynow.co.zw/Interface/CheckPayment/?guid=d80b830d-623b-4948-9ab1-aae4950929bd" "E4F6E55CF3408EBDF0F59951E9E7B74C17CD9798A8AE5DA7B5D68D04F014E40753C438AA55445EB42FD9E455EE7FFA7BF752AD6791DE878DAEF4B486A345EAC"
            _ -> expectationFailure "Expected a successful poll response"

    it "should fail gracefully on bad input" $ do
        serverResponseToResult "bad input" `shouldSatisfy` isLeft
        
  
transactionSpec :: Spec
transactionSpec = do

    it "should override the default return url" $ do
        runWithDefaultClientConfig $ \client config -> do
            let txdata = TxData Nothing Nothing (Just "https://api.com/override_return_url")
            payment <- newClassicCheckout client testRef testAmount testEmail (Just txdata)
            (snd $ urlParamsWithHash payment config) `shouldBe` "resulturl=http%3A%2F%2Flocalhost%3A3000%2Fresult&returnurl=https%3A%2F%2Fapi.com%2Foverride_return_url&reference=TEST%20REF&amount=99.99&id=1201&authemail=customer%40gmail.com&status=Message&hash=1C236C65D6DA213FE2F1F0B6472C6B15787CE1F5D9001ED698FEBDCC0FDFDBDFAD2310BDCB6ED8245E65BCA48D17E48F11666172BC894422DC3146582EBED2DC"

    it "should override the default result url" $ do
        runWithDefaultClientConfig $ \client config -> do
            let txdata = TxData Nothing (Just "https://api.com/override_result_url") Nothing
            payment <- newClassicCheckout client testRef testAmount testEmail (Just txdata)
            (snd $ urlParamsWithHash payment config) `shouldBe` "resulturl=https%3A%2F%2Fapi.com%2Foverride_result_url&returnurl=http%3A%2F%2Flocalhost%3A3000%2Freturn&reference=TEST%20REF&amount=99.99&id=1201&authemail=customer%40gmail.com&status=Message&hash=0AA2A87F4B0564341FCB47E9C3A0CCCECFE1E0F2A8DB6029081AB8D350CB189A631589279613B1A71EFA0511189C756368537EE717EC982BE8A1449AF44BC1D5"

    it "should include the additional info" $ do
        runWithDefaultClientConfig $ \client config -> do
            let txdata = TxData (Just "additional info to pass") Nothing Nothing
            payment <- newClassicCheckout client testRef testAmount testEmail (Just txdata)
            (snd $ urlParamsWithHash payment config) `shouldBe` "resulturl=http%3A%2F%2Flocalhost%3A3000%2Fresult&returnurl=http%3A%2F%2Flocalhost%3A3000%2Freturn&reference=TEST%20REF&amount=99.99&id=1201&additionalinfo=additional%20info%20to%20pass&authemail=customer%40gmail.com&status=Message&hash=2EE631E7F58FDCF10C3FC2602604DECE1E443A4F3A2D1FE05B9672C1A384FDA369FC4E529BDEDA30D651F974FFAFE9CDF494D2F176519F567E9675FE3804AEC1"
    


hashingSpec :: Spec
hashingSpec = do
    -- See https://developers.paynow.co.zw/docs/generating_hash.html        
    it "should generate sha512 hash correctly" $ do
        let payload = "1201TEST REF99.99A test ticket transactionhttp://www.google.com/search?q=returnurlhttp://www.google.com/search?q=resulturlMessage3e9fed89-60e1-4ce5-ab6e-6b1eb2d4f977"
            expectedHash = "2A033FC38798D913D42ECB786B9B19645ADEDBDE788862032F1BD82CF3B92DEF84F316385D5B40DBB35F1A4FD7D5BFE73835174136463CDD48C9366B0749C689"
        sha1Hex payload `shouldBe` expectedHash


    it "should generate a hash for a ClassicCheckout transaction" $ do
        runWithDefaultClient $ \client -> do
            payment <- newClassicCheckout client testRef testAmount testEmail Nothing
            hash <- txHash client payment
            hash `shouldBe` "79176952B0F3A8EA27B5FF22E1568B396A37017E65EFD1130A85175AB163C2894E5D97BC154184CE20CEC9C7B01456247FA7D942B583412DD42634579ABD9C33"

    it "should generate a hash for a Ecocash/ExpressCheckout transaction" $ do
        runWithDefaultClient $ \client -> do
            payment <- newExpressCheckout client (Ecocash "0783102754") testRef testAmount testEmail Nothing
            hash <- txHash client payment
            hash `shouldBe` "7FCBF1103BA1B6E6EA026DCE955200CEA23F69E42A023050457ED3E0B4489459FB4313ADD1446047F1AA9F3E0CE8E5FADCC3C4DAB386636A09DB560BD01506A3"

    it "should generate a hash for a OneMoney/ExpressCheckout transaction" $ do
        runWithDefaultClient $ \client -> do
            payment <- newExpressCheckout client (OneMoney "0783102754") testRef testAmount testEmail Nothing
            hash <- txHash client payment
            hash `shouldBe` "7E1770DC2A5BA3A9498B995F3096F9DCB83F6992816B7B1E418C0B1888ADF30252BF2175240209C53025E7025033202C6C07395707EF39C8B3349E136DE3CAEB"
 
    it "should generate a hash for a VMC/ExpressCheckout transaction" $ do
        runWithDefaultClient $ \client -> do
            payment <- newExpressCheckout client (VisaMastercard testVMCDetails) testRef testAmount testEmail Nothing
            hash <- txHash client payment
            hash `shouldBe` "79176952B0F3A8EA27B5FF22E1568B396A37017E65EFD1130A85175AB163C2894E5D97BC154184CE20CEC9C7B01456247FA7D942B583412DD42634579ABD9C33"