ideal-payment 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/.travis.yml +14 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +67 -0
- data/LICENSE +21 -0
- data/README.md +148 -0
- data/Vagrantfile +35 -0
- data/certs/bestandsnaam.cer +25 -0
- data/certs/bestandsnaam.key +30 -0
- data/certs/ideal.cer +18 -0
- data/ideal.gemspec +31 -0
- data/init.rb +1 -0
- data/lib/ideal.rb +21 -0
- data/lib/ideal/acquirers.rb +18 -0
- data/lib/ideal/gateway.rb +377 -0
- data/lib/ideal/response.rb +274 -0
- data/lib/ideal/version.rb +5 -0
- data/provision.sh +24 -0
- data/spec/expectation_xml/directory_request.xml +25 -0
- data/spec/expectation_xml/status_request.xml +28 -0
- data/spec/expectation_xml/transaction_request.xml +38 -0
- data/spec/fixtures.yml +7 -0
- data/spec/remote_spec.rb +205 -0
- data/spec/spec.rb +500 -0
- data/spec/test_xml/error_response.xml +12 -0
- data/spec/test_xml/large_directory_response.xml +36 -0
- data/spec/test_xml/small_directory_response.xml +17 -0
- data/spec/test_xml/status_response_succeeded.xml +20 -0
- data/spec/test_xml/status_response_succeeded_incorrect.xml +18 -0
- data/spec/test_xml/transaction_response.xml +15 -0
- metadata +157 -0
    
        data/provision.sh
    ADDED
    
    | @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            #!/bin/bash
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # This improves performance since the Google DNS is much quicker than the local Vagrant Virtualbox combination
         | 
| 4 | 
            +
            printf "nameserver 8.8.8.8\nnameserver 8.8.4.4" > /etc/resolv.conf
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            echo "Updating the Operating System..."
         | 
| 7 | 
            +
            sudo apt-get update >> /tmp/provision.log 2>&1
         | 
| 8 | 
            +
            sudo apt-get upgrade -y >> /tmp/provision.log 2>&1
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            echo "Installing extra packages..."
         | 
| 11 | 
            +
            sudo apt-get install curl wget git g++ libreadline6-dev zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 autoconf libgdbm-dev libncurses5-dev automake libtool bison pkg-config libffi-dev -y >> /tmp/provision.log 2>&1
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            echo "Installing rvm..."
         | 
| 14 | 
            +
            curl -sSL https://get.rvm.io | bash -s stable --ruby >> /tmp/provision.log 2>&1
         | 
| 15 | 
            +
            source /usr/local/rvm/scripts/rvm
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            echo "Installing Ruby-2.1.2..."
         | 
| 18 | 
            +
            rvm install ruby-2.1.2 >> /tmp/provision.log 2>&1
         | 
| 19 | 
            +
            rvm use ruby-2.1.2 --default >> /tmp/provision.log 2>&1
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            cd /vagrant && bundle install >> /tmp/provision.log 2>&1
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            echo ""
         | 
| 24 | 
            +
            echo "And we are done! Check /tmp/provision.log for a full log file \`vagrant ssh -c \"cat /tmp/provision.log\"\`"
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 2 | 
            +
            <DirectoryReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
         | 
| 3 | 
            +
              <createDateTimestamp>created_at_timestamp</createDateTimestamp>
         | 
| 4 | 
            +
              <Merchant>
         | 
| 5 | 
            +
                <merchantID>002054205</merchantID>
         | 
| 6 | 
            +
                <subID>0</subID>
         | 
| 7 | 
            +
              </Merchant>
         | 
| 8 | 
            +
              <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
         | 
| 9 | 
            +
                <SignedInfo>
         | 
| 10 | 
            +
                  <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 11 | 
            +
                  <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
         | 
| 12 | 
            +
                  <Reference URI="">
         | 
| 13 | 
            +
                    <Transforms>
         | 
| 14 | 
            +
                      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
         | 
| 15 | 
            +
                    </Transforms>
         | 
| 16 | 
            +
                    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
         | 
| 17 | 
            +
                    <DigestValue>digest_value</DigestValue>
         | 
| 18 | 
            +
                  </Reference>
         | 
| 19 | 
            +
                </SignedInfo>
         | 
| 20 | 
            +
                <SignatureValue>signature_value</SignatureValue>
         | 
| 21 | 
            +
                <KeyInfo>
         | 
| 22 | 
            +
                  <KeyName>fingerprint</KeyName>
         | 
| 23 | 
            +
                </KeyInfo>
         | 
| 24 | 
            +
              </Signature>
         | 
| 25 | 
            +
            </DirectoryReq>
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 2 | 
            +
            <AcquirerStatusReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
         | 
| 3 | 
            +
              <createDateTimestamp>created_at_timestamp</createDateTimestamp>
         | 
| 4 | 
            +
              <Merchant>
         | 
| 5 | 
            +
                <merchantID>002054205</merchantID>
         | 
| 6 | 
            +
                <subID>0</subID>
         | 
| 7 | 
            +
              </Merchant>
         | 
| 8 | 
            +
              <Transaction>
         | 
| 9 | 
            +
                <transactionID>transaction_id</transactionID>
         | 
| 10 | 
            +
              </Transaction>
         | 
| 11 | 
            +
              <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
         | 
| 12 | 
            +
                <SignedInfo>
         | 
| 13 | 
            +
                  <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 14 | 
            +
                  <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
         | 
| 15 | 
            +
                  <Reference URI="">
         | 
| 16 | 
            +
                    <Transforms>
         | 
| 17 | 
            +
                      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
         | 
| 18 | 
            +
                    </Transforms>
         | 
| 19 | 
            +
                    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
         | 
| 20 | 
            +
                    <DigestValue>digest_value</DigestValue>
         | 
| 21 | 
            +
                  </Reference>
         | 
| 22 | 
            +
                </SignedInfo>
         | 
| 23 | 
            +
                <SignatureValue>signature_value</SignatureValue>
         | 
| 24 | 
            +
                <KeyInfo>
         | 
| 25 | 
            +
                  <KeyName>fingerprint</KeyName>
         | 
| 26 | 
            +
                </KeyInfo>
         | 
| 27 | 
            +
              </Signature>
         | 
| 28 | 
            +
            </AcquirerStatusReq>
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 2 | 
            +
            <AcquirerTrxReq xmlns="http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1" version="3.3.1">
         | 
| 3 | 
            +
              <createDateTimestamp>created_at_timestamp</createDateTimestamp>
         | 
| 4 | 
            +
              <Issuer>
         | 
| 5 | 
            +
                <issuerID>issuer_id</issuerID>
         | 
| 6 | 
            +
              </Issuer>
         | 
| 7 | 
            +
              <Merchant>
         | 
| 8 | 
            +
                <merchantID>002054205</merchantID>
         | 
| 9 | 
            +
                <subID>0</subID>
         | 
| 10 | 
            +
                <merchantReturnURL>return_url</merchantReturnURL>
         | 
| 11 | 
            +
              </Merchant>
         | 
| 12 | 
            +
              <Transaction>
         | 
| 13 | 
            +
                <purchaseID>purchase_id</purchaseID>
         | 
| 14 | 
            +
                <amount>amount</amount>
         | 
| 15 | 
            +
                <currency>EUR</currency>
         | 
| 16 | 
            +
                <expirationPeriod>expiration_period</expirationPeriod>
         | 
| 17 | 
            +
                <language>nl</language>
         | 
| 18 | 
            +
                <description>description</description>
         | 
| 19 | 
            +
                <entranceCode>entrance_code</entranceCode>
         | 
| 20 | 
            +
              </Transaction>
         | 
| 21 | 
            +
              <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
         | 
| 22 | 
            +
                <SignedInfo>
         | 
| 23 | 
            +
                  <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 24 | 
            +
                  <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
         | 
| 25 | 
            +
                  <Reference URI="">
         | 
| 26 | 
            +
                    <Transforms>
         | 
| 27 | 
            +
                      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
         | 
| 28 | 
            +
                    </Transforms>
         | 
| 29 | 
            +
                    <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
         | 
| 30 | 
            +
                    <DigestValue>digest_value</DigestValue>
         | 
| 31 | 
            +
                  </Reference>
         | 
| 32 | 
            +
                </SignedInfo>
         | 
| 33 | 
            +
                <SignatureValue>signature_value</SignatureValue>
         | 
| 34 | 
            +
                <KeyInfo>
         | 
| 35 | 
            +
                  <KeyName>fingerprint</KeyName>
         | 
| 36 | 
            +
                </KeyInfo>
         | 
| 37 | 
            +
              </Signature>
         | 
| 38 | 
            +
            </AcquirerTrxReq>
         | 
    
        data/spec/fixtures.yml
    ADDED
    
    
    
        data/spec/remote_spec.rb
    ADDED
    
    | @@ -0,0 +1,205 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            require 'coveralls'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Coveralls.wear!
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'rubygems'
         | 
| 7 | 
            +
            require 'ideal'
         | 
| 8 | 
            +
            require 'yaml'
         | 
| 9 | 
            +
            require 'mocha'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class Idealtest
         | 
| 12 | 
            +
              describe Ideal do
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                before(:each) do
         | 
| 15 | 
            +
                  setup_ideal_gateway(fixtures('default'))
         | 
| 16 | 
            +
                  Ideal::Gateway.environment = :test
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  @gateway = Ideal::Gateway.new
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  @@issuer ||= {id: 'RABONL2U'}
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  @valid_options = {
         | 
| 23 | 
            +
                      :issuer_id => @@issuer[:id],
         | 
| 24 | 
            +
                      :expiration_period => 'PT10M',
         | 
| 25 | 
            +
                      :return_url => 'http://return_to.example.com',
         | 
| 26 | 
            +
                      :order_id => '123456789012',
         | 
| 27 | 
            +
                      :currency => 'EUR',
         | 
| 28 | 
            +
                      :description => 'A classic Dutch windmill',
         | 
| 29 | 
            +
                      :entrance_code => '1234'
         | 
| 30 | 
            +
                  }
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
             | 
| 34 | 
            +
                describe 'requests' do
         | 
| 35 | 
            +
                  it 'should go to the test environment' do
         | 
| 36 | 
            +
                    expect(@gateway.issuers.test?).to be true
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                describe 'valid requests' do
         | 
| 41 | 
            +
                  it 'should proceed' do
         | 
| 42 | 
            +
                    response = @gateway.setup_purchase(550, @valid_options)
         | 
| 43 | 
            +
                    expect(response.success?).to be true
         | 
| 44 | 
            +
                    expect(response.service_url).not_to be nil
         | 
| 45 | 
            +
                    expect(response.transaction_id).not_to be nil
         | 
| 46 | 
            +
                    expect(response.order_id).to eq(@valid_options[:order_id])
         | 
| 47 | 
            +
                    expect(response.verified?).to be true
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                describe 'invalid requests' do
         | 
| 52 | 
            +
                  it 'should be rejected' do
         | 
| 53 | 
            +
                    response = @gateway.setup_purchase('0;5', @valid_options)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    expect(response.success?).to eq false
         | 
| 56 | 
            +
                    expect(response.error_code).to eq('BR1210')
         | 
| 57 | 
            +
                    expect(response.error_message).not_to be nil
         | 
| 58 | 
            +
                    expect(response.consumer_error_message).not_to be nil
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                describe 'valid requests but incorrectly signed' do
         | 
| 63 | 
            +
                  it 'should be rejected' do
         | 
| 64 | 
            +
                    allow_any_instance_of(Xmldsig::SignedDocument).to receive(:validate).and_return(false)
         | 
| 65 | 
            +
                    response = capture_transaction(:success)
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    expect(response.verified?).to be false
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                ###
         | 
| 72 | 
            +
                #
         | 
| 73 | 
            +
                # These are the 7 integration tests of ING which need to be ran sucessfuly
         | 
| 74 | 
            +
                # _before_ you'll get access to the live environment.
         | 
| 75 | 
            +
                #
         | 
| 76 | 
            +
                # See test_transaction_id for info on how the remote tests are ran.
         | 
| 77 | 
            +
                #
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                describe '#issuers' do
         | 
| 80 | 
            +
                  it 'return a list of iDeal issuers' do
         | 
| 81 | 
            +
                    issuer_list = @gateway.issuers.list
         | 
| 82 | 
            +
                    expect(issuer_list.length).to eq(2)
         | 
| 83 | 
            +
                    expect(issuer_list[0][:id]).to eq('INGBNL2A')
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
             | 
| 88 | 
            +
                describe 'successful transaction' do
         | 
| 89 | 
            +
                  it 'should be successful' do
         | 
| 90 | 
            +
                    res = capture_transaction(:success)
         | 
| 91 | 
            +
                    expect(res.success?).to be true
         | 
| 92 | 
            +
                    expect(res.status).to eq(:success)
         | 
| 93 | 
            +
                    expect(res.verified?).to be true
         | 
| 94 | 
            +
                    expect(res.consumer_iban).to eq('NL17RABO0213698412')
         | 
| 95 | 
            +
                    expect(res.consumer_name).to eq('Hr E G H Küppers en/of MW M.J. Küppers-Veeneman')
         | 
| 96 | 
            +
                    expect(res.consumer_bic).to eq('RABONL2U')
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                describe 'cancelled transaction' do
         | 
| 101 | 
            +
                  it 'should be cancelled' do
         | 
| 102 | 
            +
                    res = capture_transaction(:cancelled)
         | 
| 103 | 
            +
                    expect(res.success?).to be false
         | 
| 104 | 
            +
                    expect(res.status).to eq(:cancelled)
         | 
| 105 | 
            +
                    expect(res.verified?).to be true
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                describe 'expired transaction' do
         | 
| 110 | 
            +
                  it 'should be expired' do
         | 
| 111 | 
            +
                    res = capture_transaction(:expired)
         | 
| 112 | 
            +
                    expect(res.success?).to be false
         | 
| 113 | 
            +
                    expect(res.status).to eq(:expired)
         | 
| 114 | 
            +
                    expect(res.verified?).to be true
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                describe 'open transaction' do
         | 
| 119 | 
            +
                  it 'should be open' do
         | 
| 120 | 
            +
                    res = capture_transaction(:open)
         | 
| 121 | 
            +
                    expect(res.success?).to be false
         | 
| 122 | 
            +
                    expect(res.status).to eq(:open)
         | 
| 123 | 
            +
                    expect(res.verified?).to be true
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                describe 'failed transaction' do
         | 
| 128 | 
            +
                  it 'should be failure' do
         | 
| 129 | 
            +
                    res = capture_transaction(:failure)
         | 
| 130 | 
            +
                    expect(res.success?).to be false
         | 
| 131 | 
            +
                    expect(res.status).to eq(:failure)
         | 
| 132 | 
            +
                    expect(res.verified?).to be true
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                describe 'server_error transaction' do
         | 
| 137 | 
            +
                  it 'should be server_error' do
         | 
| 138 | 
            +
                    res = capture_transaction(:server_error)
         | 
| 139 | 
            +
                    expect(res.success?).to be false
         | 
| 140 | 
            +
                    expect(res.verified?).to be true
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                private
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                # Shortcut method which does a #setup_purchase through #test_transaction and
         | 
| 147 | 
            +
                # captures the resulting transaction and returns the capture response.
         | 
| 148 | 
            +
                def capture_transaction(type)
         | 
| 149 | 
            +
                  @gateway.capture test_transaction(type).transaction_id
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                # Calls #setup_purchase with the amount corresponding to the named test and
         | 
| 153 | 
            +
                # returns the response. Before returning an assertion will be ran to test
         | 
| 154 | 
            +
                # whether or not the transaction was successful.
         | 
| 155 | 
            +
                def test_transaction(type)
         | 
| 156 | 
            +
                  amount = case type
         | 
| 157 | 
            +
                             when :success then
         | 
| 158 | 
            +
                               1.00
         | 
| 159 | 
            +
                             when :cancelled then
         | 
| 160 | 
            +
                               2.00
         | 
| 161 | 
            +
                             when :expired then
         | 
| 162 | 
            +
                               3.00
         | 
| 163 | 
            +
                             when :open then
         | 
| 164 | 
            +
                               4.00
         | 
| 165 | 
            +
                             when :failure then
         | 
| 166 | 
            +
                               5.00
         | 
| 167 | 
            +
                             when :server_error then
         | 
| 168 | 
            +
                               7.00
         | 
| 169 | 
            +
                           end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  response = @gateway.setup_purchase(amount, @valid_options)
         | 
| 172 | 
            +
                  expect(response.success?).to be true
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                  log('RESP', response.service_url)
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                  response
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                def fixtures(key)
         | 
| 180 | 
            +
                  file = File.join(File.dirname(__FILE__), 'fixtures.yml')
         | 
| 181 | 
            +
                  fixtures ||= YAML.load(File.read(file))
         | 
| 182 | 
            +
                  @fixture = fixtures[key] || raise(StandardError, "No fixture data was found for key '#{key}'")
         | 
| 183 | 
            +
                  @fixture['private_key_file'] = File.join(File.dirname(__FILE__), @fixture['private_key_file'])
         | 
| 184 | 
            +
                  @fixture['private_certificate_file'] = File.join(File.dirname(__FILE__), @fixture['private_certificate_file'])
         | 
| 185 | 
            +
                  @fixture['ideal_certificate_file'] = File.join(File.dirname(__FILE__), @fixture['ideal_certificate_file'])
         | 
| 186 | 
            +
                  @fixture
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                # Setup the gateway by providing a hash of attributes and values.
         | 
| 190 | 
            +
                def setup_ideal_gateway(fixture)
         | 
| 191 | 
            +
                  fixture = fixture.dup
         | 
| 192 | 
            +
                  # The passphrase needs to be set first, otherwise the key won't initialize properly
         | 
| 193 | 
            +
                  if passphrase = fixture.delete('passphrase')
         | 
| 194 | 
            +
                    Ideal::Gateway.passphrase = passphrase
         | 
| 195 | 
            +
                  end
         | 
| 196 | 
            +
                  fixture.each { |key, value| Ideal::Gateway.send("#{key}=", value) }
         | 
| 197 | 
            +
                  Ideal::Gateway.live_url = nil
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
              end
         | 
| 201 | 
            +
            end
         | 
| 202 | 
            +
             | 
| 203 | 
            +
            def log(a, b)
         | 
| 204 | 
            +
              #$stderr.write("#{a}: #{b}")
         | 
| 205 | 
            +
            end
         | 
    
        data/spec/spec.rb
    ADDED
    
    | @@ -0,0 +1,500 @@ | |
| 1 | 
            +
            require 'coveralls'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Coveralls.wear!
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require 'rubygems'
         | 
| 6 | 
            +
            require 'ideal'
         | 
| 7 | 
            +
            require 'yaml'
         | 
| 8 | 
            +
            require 'mocha'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            def strip_whitespace(str)
         | 
| 12 | 
            +
              str.gsub('/\s/m', '')
         | 
| 13 | 
            +
            end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            class GeneralMethodTest
         | 
| 16 | 
            +
              describe Ideal do
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                before(:all) do
         | 
| 19 | 
            +
                  file = File.join(File.dirname(__FILE__), 'fixtures.yml')
         | 
| 20 | 
            +
                  fixtures ||= YAML.load(File.read(file))
         | 
| 21 | 
            +
                  @fixture = fixtures['default'] || raise(StandardError, 'No fixture data was found for key "default"')
         | 
| 22 | 
            +
                  @fixture['private_key_file'] = File.join(File.dirname(__FILE__), @fixture['private_key_file'])
         | 
| 23 | 
            +
                  @fixture['private_certificate_file'] = File.join(File.dirname(__FILE__), @fixture['private_certificate_file'])
         | 
| 24 | 
            +
                  @fixture['ideal_certificate_file'] = File.join(File.dirname(__FILE__), @fixture['ideal_certificate_file'])
         | 
| 25 | 
            +
                  # The passphrase needs to be set first, otherwise the key won't initialize properly
         | 
| 26 | 
            +
                  if (passphrase = @fixture.delete('passphrase')) # Yes the = is intended, not ==
         | 
| 27 | 
            +
                    Ideal::Gateway.passphrase = passphrase
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  @fixture.each { |key, value| Ideal::Gateway.send("#{key}=", value) }
         | 
| 30 | 
            +
                  Ideal::Gateway.live_url = nil
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                describe '#merchant_id' do
         | 
| 34 | 
            +
                  it 'returns the set merchant id' do
         | 
| 35 | 
            +
                    expect(Ideal::Gateway.merchant_id).to eq('002054205')
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                describe '#url' do
         | 
| 40 | 
            +
                  it 'returns the set test url from the fixture' do
         | 
| 41 | 
            +
                    expect(Ideal::Gateway.test_url).to eq('https://idealtest.rabobank.nl/ideal/iDEALv3')
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                describe '#url' do
         | 
| 46 | 
            +
                  it 'returns the ideal url for issuer ING' do
         | 
| 47 | 
            +
                    Ideal::Gateway.acquirer = :ing
         | 
| 48 | 
            +
                    expect(Ideal::Gateway.live_url).to eq('https://ideal.secure-ing.com/ideal/iDEALv3')
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                describe '#url' do
         | 
| 53 | 
            +
                  it 'returns the ideal url for issuer Rabobank' do
         | 
| 54 | 
            +
                    Ideal::Gateway.acquirer = :rabobank
         | 
| 55 | 
            +
                    expect(Ideal::Gateway.live_url).to eq('https://ideal.rabobank.nl/ideal/iDEALv3')
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                describe '#url' do
         | 
| 60 | 
            +
                  it 'returns the ideal url for issuer ABN Amro' do
         | 
| 61 | 
            +
                    Ideal::Gateway.acquirer = :abnamro
         | 
| 62 | 
            +
                    expect(Ideal::Gateway.live_url).to eq('https://abnamro.ideal-payment.de/ideal/iDeal')
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                describe '#acquirer' do
         | 
| 67 | 
            +
                  it 'throws an error if the acquirer is non existent' do
         | 
| 68 | 
            +
                    expect { Ideal::Gateway.acquirer = :nonexistent }.to raise_error(ArgumentError)
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                describe '#private_certificate' do
         | 
| 73 | 
            +
                  it 'returns the currently loaded private certificate' do
         | 
| 74 | 
            +
                    private_cert_file = File.read(@fixture['private_certificate_file'])
         | 
| 75 | 
            +
                    private_cert = OpenSSL::X509::Certificate.new(private_cert_file)
         | 
| 76 | 
            +
                    expect(Ideal::Gateway.private_certificate.to_text).to eq(private_cert.to_text)
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                describe '#' do
         | 
| 81 | 
            +
                  it 'returns the private key' do
         | 
| 82 | 
            +
                    private_key_file = File.read(@fixture['private_key_file'])
         | 
| 83 | 
            +
                    private_key = OpenSSL::PKey::RSA.new(private_key_file, Ideal::Gateway.passphrase)
         | 
| 84 | 
            +
                    expect(Ideal::Gateway.private_key.to_text).to eq(private_key.to_text)
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
            end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            class GeneralTest
         | 
| 92 | 
            +
              describe Ideal do
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                before(:each) do
         | 
| 95 | 
            +
                  file = File.join(File.dirname(__FILE__), 'fixtures.yml')
         | 
| 96 | 
            +
                  fixtures ||= YAML.load(File.read(file))
         | 
| 97 | 
            +
                  @fixture = fixtures['default'] || raise(StandardError, 'No fixture data was found for key "default"')
         | 
| 98 | 
            +
                  @fixture['private_key_file'] = File.join(File.dirname(__FILE__), @fixture['private_key_file'])
         | 
| 99 | 
            +
                  @fixture['private_certificate_file'] = File.join(File.dirname(__FILE__), @fixture['private_certificate_file'])
         | 
| 100 | 
            +
                  @fixture['ideal_certificate_file'] = File.join(File.dirname(__FILE__), @fixture['ideal_certificate_file'])
         | 
| 101 | 
            +
                  # The passphrase needs to be set first, otherwise the key won't initialize properly
         | 
| 102 | 
            +
                  if (passphrase = @fixture.delete('passphrase')) # Yes the = is intended, not ==
         | 
| 103 | 
            +
                    Ideal::Gateway.passphrase = passphrase
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                  @fixture.each { |key, value| Ideal::Gateway.send("#{key}=", value) }
         | 
| 106 | 
            +
                  Ideal::Gateway.live_url = nil
         | 
| 107 | 
            +
                  @gateway = Ideal::Gateway.new
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                describe '#initialize' do
         | 
| 111 | 
            +
                  it 'has a sub_id of 0 when just initialized or picks the supplied value' do
         | 
| 112 | 
            +
                    expect(Ideal::Gateway.new.sub_id).to eq(0)
         | 
| 113 | 
            +
                    expect(Ideal::Gateway.new(:sub_id => 1).sub_id).to eq(1)
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                describe '#send' do
         | 
| 118 | 
            +
                  it 'returns the test_url if the test mode is active' do
         | 
| 119 | 
            +
                    gateway = Ideal::Gateway.new
         | 
| 120 | 
            +
                    Ideal::Gateway.acquirer = :rabobank
         | 
| 121 | 
            +
                    Ideal::Gateway.environment = :test
         | 
| 122 | 
            +
                    expect(gateway.send(:request_url)).to eq(Ideal::Gateway.test_url)
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                describe '#send' do
         | 
| 127 | 
            +
                  it 'returns the live_url if the test mode is inactive' do
         | 
| 128 | 
            +
                    gateway = Ideal::Gateway.new
         | 
| 129 | 
            +
                    Ideal::Gateway.acquirer = :rabobank
         | 
| 130 | 
            +
                    Ideal::Gateway.environment = :live
         | 
| 131 | 
            +
                    expect(gateway.send(:request_url)).to eq(Ideal::Gateway.live_url)
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                describe '#send' do
         | 
| 136 | 
            +
                  it 'sends the correct created at datestamp' do
         | 
| 137 | 
            +
                    timestamp = '2011-11-28T16:30:00.000Z' # Exact time inventid was founded
         | 
| 138 | 
            +
                    allow_any_instance_of(Time).to receive(:gmtime).and_return(DateTime.parse(timestamp))
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                    expect(@gateway.send(:created_at_timestamp)).to eq(timestamp)
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                describe '#send' do
         | 
| 145 | 
            +
                  it 'generates a correct digest' do
         | 
| 146 | 
            +
                    sha256 = OpenSSL::Digest::SHA256.new
         | 
| 147 | 
            +
                    allow_any_instance_of(OpenSSL::Digest::SHA256).to receive(:new).and_return(sha256)
         | 
| 148 | 
            +
                    xml = Nokogiri::XML::Builder.new do |xml|
         | 
| 149 | 
            +
                      xml.request do |innerxml|
         | 
| 150 | 
            +
                        xml.content 'digest test'
         | 
| 151 | 
            +
                        @gateway.send(:sign!, innerxml)
         | 
| 152 | 
            +
                      end
         | 
| 153 | 
            +
                    end
         | 
| 154 | 
            +
                    digest_value = xml.doc.at_xpath('//xmlns:DigestValue', 'xmlns' => 'http://www.w3.org/2000/09/xmldsig#').text
         | 
| 155 | 
            +
                    xml.doc.at_xpath('//xmlns:Signature', 'xmlns' => 'http://www.w3.org/2000/09/xmldsig#').remove
         | 
| 156 | 
            +
                    canonical = xml.doc.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
         | 
| 157 | 
            +
                    digest = sha256.digest canonical
         | 
| 158 | 
            +
                    expected_digest_value = strip_whitespace(Base64.encode64(digest.strip)) # .strip does not remove the \n
         | 
| 159 | 
            +
                    expect(expected_digest_value).to eq(digest_value)
         | 
| 160 | 
            +
                  end
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
            #=begin
         | 
| 164 | 
            +
                describe '#send' do
         | 
| 165 | 
            +
                  it 'generates a correct signature' do
         | 
| 166 | 
            +
                    sha256 = OpenSSL::Digest::SHA256.new
         | 
| 167 | 
            +
                    allow_any_instance_of(OpenSSL::Digest::SHA256).to receive(:new).and_return(sha256)
         | 
| 168 | 
            +
                    xml1 = Nokogiri::XML::Builder.new do |xml|
         | 
| 169 | 
            +
                      xml.request do |innerxml|
         | 
| 170 | 
            +
                        xml.content 'signature test'
         | 
| 171 | 
            +
                        @gateway.send(:sign!, innerxml)
         | 
| 172 | 
            +
                      end
         | 
| 173 | 
            +
                    end
         | 
| 174 | 
            +
                    signature_value = @gateway.send(:signature_value, xml1.doc)
         | 
| 175 | 
            +
                    xml2 = xml1.doc.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
         | 
| 176 | 
            +
                    signature = Ideal::Gateway.private_key.sign(sha256, xml2)
         | 
| 177 | 
            +
                    expected_signature_value = strip_whitespace(Base64.encode64(signature))
         | 
| 178 | 
            +
                    expect(signature_value).to eq(expected_signature_value)
         | 
| 179 | 
            +
                  end
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
            #=end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                describe '#send' do
         | 
| 184 | 
            +
                  it 'generates a correct fingerprint' do
         | 
| 185 | 
            +
                    certificate_file = File.read(@fixture['private_certificate_file'])
         | 
| 186 | 
            +
                    expected_token = Digest::SHA1.hexdigest(OpenSSL::X509::Certificate.new(certificate_file).to_der)
         | 
| 187 | 
            +
                    expect(@gateway.send(:fingerprint)).to eq(expected_token)
         | 
| 188 | 
            +
                  end
         | 
| 189 | 
            +
                end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                describe '#send' do
         | 
| 192 | 
            +
                  it 'performs an SSL POST and returns the correct response' do
         | 
| 193 | 
            +
                    Ideal::Gateway.environment = :test
         | 
| 194 | 
            +
                    allow_any_instance_of(Ideal::Response).to receive(:new).with('response', :test => true)
         | 
| 195 | 
            +
                    allow(@gateway).to receive(:ssl_post).with(@gateway.request_url, 'data').and_return('<x>response</x>')
         | 
| 196 | 
            +
                    @gateway.send(:post_data, @gateway.request_url, 'data', Ideal::Response)
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
              end
         | 
| 201 | 
            +
            end
         | 
| 202 | 
            +
             | 
| 203 | 
            +
            class XmlTest
         | 
| 204 | 
            +
              describe Ideal do
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                before(:each) do
         | 
| 207 | 
            +
                  @gateway = Ideal::Gateway.new
         | 
| 208 | 
            +
                  allow(@gateway).to receive(:created_at_timestamp).and_return('created_at_timestamp')
         | 
| 209 | 
            +
                  allow(@gateway).to receive(:digest_value).and_return('digest_value')
         | 
| 210 | 
            +
                  allow(@gateway).to receive(:signature_value).and_return('signature_value')
         | 
| 211 | 
            +
                  allow(@gateway).to receive(:fingerprint).and_return('fingerprint')
         | 
| 212 | 
            +
                end
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                describe Ideal do
         | 
| 215 | 
            +
                  it 'creates a correct TransactionRequestXml' do
         | 
| 216 | 
            +
                    options = {
         | 
| 217 | 
            +
                        issuer_id: 'issuer_id',
         | 
| 218 | 
            +
                        return_url: 'return_url',
         | 
| 219 | 
            +
                        order_id: 'purchase_id',
         | 
| 220 | 
            +
                        expiration_period: 'expiration_period',
         | 
| 221 | 
            +
                        description: 'description',
         | 
| 222 | 
            +
                        entrance_code: 'entrance_code'
         | 
| 223 | 
            +
                    }
         | 
| 224 | 
            +
                    xml = @gateway.send(:build_transaction_request, 'amount', options)
         | 
| 225 | 
            +
                    expected_response = Nokogiri::XML.parse(File.read(File.join(File.dirname(__FILE__), 'expectation_xml/transaction_request.xml')))
         | 
| 226 | 
            +
                    actual_response = Nokogiri::XML.parse(xml)
         | 
| 227 | 
            +
                    expect(actual_response.to_s).to eq(expected_response.to_s)
         | 
| 228 | 
            +
                  end
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                describe Ideal do
         | 
| 232 | 
            +
                  it 'creates a correct StatusRequestXml' do
         | 
| 233 | 
            +
                    options = {
         | 
| 234 | 
            +
                        transaction_id: 'transaction_id'
         | 
| 235 | 
            +
                    }
         | 
| 236 | 
            +
                    xml = @gateway.send(:build_status_request, options)
         | 
| 237 | 
            +
                    expected_response = Nokogiri::XML.parse(File.read(File.join(File.dirname(__FILE__), 'expectation_xml/status_request.xml')))
         | 
| 238 | 
            +
                    actual_response = Nokogiri::XML.parse(xml)
         | 
| 239 | 
            +
                    expect(actual_response.to_s).to eq(expected_response.to_s)
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
                end
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                describe Ideal do
         | 
| 244 | 
            +
                  it 'creates a correct DirectoryRequestXml' do
         | 
| 245 | 
            +
                    xml = @gateway.send(:build_directory_request)
         | 
| 246 | 
            +
                    expected_response = Nokogiri::XML.parse(File.read(File.join(File.dirname(__FILE__), 'expectation_xml/directory_request.xml')))
         | 
| 247 | 
            +
                    actual_response = Nokogiri::XML.parse(xml)
         | 
| 248 | 
            +
                    expect(actual_response.to_s).to eq(expected_response.to_s)
         | 
| 249 | 
            +
                  end
         | 
| 250 | 
            +
                end
         | 
| 251 | 
            +
              end
         | 
| 252 | 
            +
            end
         | 
| 253 | 
            +
             | 
| 254 | 
            +
            class ErrorHandlingTest
         | 
| 255 | 
            +
              describe Ideal do
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                before(:each) do
         | 
| 258 | 
            +
                  @gateway = Ideal::Gateway.new
         | 
| 259 | 
            +
                  allow(@gateway).to receive(:created_at_timestamp).and_return('created_at_timestamp')
         | 
| 260 | 
            +
                  allow(@gateway).to receive(:digest_value).and_return('digest_value')
         | 
| 261 | 
            +
                  allow(@gateway).to receive(:signature_value).and_return('signature_value')
         | 
| 262 | 
            +
                  allow(@gateway).to receive(:fingerprint).and_return('fingerprint')
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                  @transaction_id = '1234567890123456'
         | 
| 265 | 
            +
                end
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                describe '#send' do
         | 
| 268 | 
            +
                  it 'accepts a valid request with valid options' do
         | 
| 269 | 
            +
                    expect(@gateway.send(:build_transaction_request, 4321, VALID_PURCHASE_OPTIONS)).to be_truthy
         | 
| 270 | 
            +
                  end
         | 
| 271 | 
            +
                end
         | 
| 272 | 
            +
             | 
| 273 | 
            +
                describe '#send' do
         | 
| 274 | 
            +
                  it 'should error on erroneously long fields in a transaction request' do
         | 
| 275 | 
            +
                    expect { @gateway.send(:build_transaction_request, 1234567890123, VALID_PURCHASE_OPTIONS) }.to raise_error(ArgumentError) # 13 chars
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                    [
         | 
| 278 | 
            +
                        [:order_id, '12345678901234567'], # 17 chars,
         | 
| 279 | 
            +
                        [:description, '123456789012345678901234567890123'], # 33 chars
         | 
| 280 | 
            +
                        [:entrance_code, '12345678901234567890123456789012345678901'] # 41
         | 
| 281 | 
            +
                    ].each do |key, value|
         | 
| 282 | 
            +
                      options = VALID_PURCHASE_OPTIONS.dup
         | 
| 283 | 
            +
                      options[key] = value
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                      expect { @gateway.send(:build_transaction_request, 4321, options) }.to raise_error(ArgumentError)
         | 
| 286 | 
            +
                    end
         | 
| 287 | 
            +
                  end
         | 
| 288 | 
            +
                end
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                describe '#send' do
         | 
| 291 | 
            +
                  it 'should error on a missing required field in a transaction request' do
         | 
| 292 | 
            +
                    options = VALID_PURCHASE_OPTIONS.dup
         | 
| 293 | 
            +
                    options.keys.each do |key|
         | 
| 294 | 
            +
                      options.delete(key)
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                      expect { @gateway.send(:build_transaction_request, 100, options) }.to raise_error(ArgumentError)
         | 
| 297 | 
            +
                    end
         | 
| 298 | 
            +
                  end
         | 
| 299 | 
            +
                end
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                describe '#send' do
         | 
| 302 | 
            +
                  it 'should error on inappropriate characters for a transaction request' do
         | 
| 303 | 
            +
                    expect { @gateway.send(:build_transaction_request, 'graphème', VALID_PURCHASE_OPTIONS) }.to raise_error(ArgumentError)
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                    [:order_id, :description, :entrance_code].each do |key, value|
         | 
| 306 | 
            +
                      options = VALID_PURCHASE_OPTIONS.dup
         | 
| 307 | 
            +
                      options[key] = 'graphème'
         | 
| 308 | 
            +
             | 
| 309 | 
            +
                      expect { @gateway.send(:build_transaction_request, 4321, options) }.to raise_error(ArgumentError)
         | 
| 310 | 
            +
                    end
         | 
| 311 | 
            +
                  end
         | 
| 312 | 
            +
                end
         | 
| 313 | 
            +
             | 
| 314 | 
            +
                describe '#send' do
         | 
| 315 | 
            +
                  it 'should error on missing required options for a status request' do
         | 
| 316 | 
            +
                    expect { @gateway.send(:build_status_request, {}) }.to raise_error(ArgumentError)
         | 
| 317 | 
            +
                  end
         | 
| 318 | 
            +
                end
         | 
| 319 | 
            +
             | 
| 320 | 
            +
              end
         | 
| 321 | 
            +
            end
         | 
| 322 | 
            +
             | 
| 323 | 
            +
            class ResponseTest
         | 
| 324 | 
            +
              describe Ideal do
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                before(:each) do
         | 
| 327 | 
            +
                  file = File.join(File.dirname(__FILE__), 'test_xml/large_directory_response.xml')
         | 
| 328 | 
            +
                  @xml = File.read(file)
         | 
| 329 | 
            +
                  @response = Ideal::Response.new(@xml)
         | 
| 330 | 
            +
                end
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                describe '#test' do
         | 
| 333 | 
            +
                  it 'should set the environment correctly on instantiation or use the default' do
         | 
| 334 | 
            +
                    file = File.join(File.dirname(__FILE__), 'test_xml/large_directory_response.xml')
         | 
| 335 | 
            +
                    xml = File.read(file)
         | 
| 336 | 
            +
                    expect(Ideal::Response.new(xml, :test => true).test?).to be true
         | 
| 337 | 
            +
                    expect(Ideal::Response.new(xml, :test => false).test?).to be false
         | 
| 338 | 
            +
                    expect(Ideal::Response.new(xml).test?).to be false
         | 
| 339 | 
            +
                  end
         | 
| 340 | 
            +
                end
         | 
| 341 | 
            +
             | 
| 342 | 
            +
                describe 'response' do
         | 
| 343 | 
            +
                  it 'return a correct response body' do
         | 
| 344 | 
            +
                    file = File.join(File.dirname(__FILE__), 'test_xml/large_directory_response.xml')
         | 
| 345 | 
            +
                    xml = File.read(file)
         | 
| 346 | 
            +
                    response = Ideal::Response.new(xml)
         | 
| 347 | 
            +
                    expect(response.instance_variable_get(:@response).to_s).to eq(Nokogiri::XML.parse(xml).remove_namespaces!.root.to_s)
         | 
| 348 | 
            +
                    expect(response.success?).to be true
         | 
| 349 | 
            +
                    expect(response.error_message).to be nil
         | 
| 350 | 
            +
                    expect(response.error_code).to be nil
         | 
| 351 | 
            +
                  end
         | 
| 352 | 
            +
                end
         | 
| 353 | 
            +
             | 
| 354 | 
            +
                describe 'error' do
         | 
| 355 | 
            +
                  it 'gives an error if the response is incorrect' do
         | 
| 356 | 
            +
                    file = File.join(File.dirname(__FILE__), 'test_xml/error_response.xml')
         | 
| 357 | 
            +
                    xml = File.read(file)
         | 
| 358 | 
            +
                    response = Ideal::Response.new(xml)
         | 
| 359 | 
            +
             | 
| 360 | 
            +
                    expect(response.success?).to be false
         | 
| 361 | 
            +
                    expect(response.error_message).to eq('Failure in system')
         | 
| 362 | 
            +
                    expect(response.error_details).to eq('System generating error: issuer')
         | 
| 363 | 
            +
                    expect(response.consumer_error_message).to eq('Betalen met iDEAL is nu niet mogelijk.')
         | 
| 364 | 
            +
                    expect(response.error_code).to eq('SO1000')
         | 
| 365 | 
            +
                    [
         | 
| 366 | 
            +
                        ['IX1000', :xml],
         | 
| 367 | 
            +
                        ['SO1000', :system],
         | 
| 368 | 
            +
                        ['SE2000', :security],
         | 
| 369 | 
            +
                        ['BR1200', :value],
         | 
| 370 | 
            +
                        ['AP1000', :application]
         | 
| 371 | 
            +
                    ].each do |code, type|
         | 
| 372 | 
            +
                      allow(response).to receive(:error_code).and_return(code)
         | 
| 373 | 
            +
                      expect(response.error_type).to eq(type)
         | 
| 374 | 
            +
                    end
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                  end
         | 
| 377 | 
            +
                end
         | 
| 378 | 
            +
             | 
| 379 | 
            +
                describe 'directory' do
         | 
| 380 | 
            +
                  it 'returns the list of issuers' do
         | 
| 381 | 
            +
                    gateway = Ideal::Gateway.new
         | 
| 382 | 
            +
             | 
| 383 | 
            +
                    file = File.join(File.dirname(__FILE__), 'test_xml/small_directory_response.xml')
         | 
| 384 | 
            +
                    xml = File.read(file)
         | 
| 385 | 
            +
             | 
| 386 | 
            +
                    allow(gateway).to receive(:build_directory_request).and_return('the request body')
         | 
| 387 | 
            +
                    expect(gateway).to receive(:ssl_post).with(gateway.request_url, 'the request body').and_return(xml)
         | 
| 388 | 
            +
             | 
| 389 | 
            +
                    expected_issuers = [{:id => '1006', :country => 'RogierIsGaafLand', :name => 'ABN AMRO Bank'}]
         | 
| 390 | 
            +
             | 
| 391 | 
            +
                    directory_response = gateway.issuers
         | 
| 392 | 
            +
                    expect(directory_response).to be_a Ideal::DirectoryResponse
         | 
| 393 | 
            +
                    expect(directory_response.list).to eq(expected_issuers)
         | 
| 394 | 
            +
             | 
| 395 | 
            +
                    file = File.join(File.dirname(__FILE__), 'test_xml/large_directory_response.xml')
         | 
| 396 | 
            +
                    xml = File.read(file)
         | 
| 397 | 
            +
             | 
| 398 | 
            +
                    expected_issuers = [
         | 
| 399 | 
            +
                        {:id => '1006', :country => 'JoostIsCool', :name => 'ABN AMRO Bank'},
         | 
| 400 | 
            +
                        {:id => '1003', :country => 'JoostIsCool', :name => 'Postbank'},
         | 
| 401 | 
            +
                        {:id => '1005', :country => 'JoostIsCool', :name => 'Rabobank'},
         | 
| 402 | 
            +
                        {:id => '1017', :country => 'XmlIsCoolOhNee', :name => 'Asr bank'},
         | 
| 403 | 
            +
                        {:id => '1023', :country => 'XmlIsCoolOhNee', :name => 'Van Lanschot'}
         | 
| 404 | 
            +
                    ]
         | 
| 405 | 
            +
             | 
| 406 | 
            +
                    expect(gateway).to receive(:ssl_post).with(gateway.request_url, 'the request body').and_return(xml)
         | 
| 407 | 
            +
             | 
| 408 | 
            +
                    directory_response = gateway.issuers
         | 
| 409 | 
            +
                    expect(directory_response).to be_a Ideal::DirectoryResponse
         | 
| 410 | 
            +
                    expect(directory_response.list).to eq(expected_issuers)
         | 
| 411 | 
            +
                  end
         | 
| 412 | 
            +
                end
         | 
| 413 | 
            +
             | 
| 414 | 
            +
                describe 'purchase' do
         | 
| 415 | 
            +
                  it 'should return a valid transaction response' do
         | 
| 416 | 
            +
                    gateway = Ideal::Gateway.new
         | 
| 417 | 
            +
                    file = File.join(File.dirname(__FILE__), 'test_xml/transaction_response.xml')
         | 
| 418 | 
            +
                    xml = File.read(file)
         | 
| 419 | 
            +
             | 
| 420 | 
            +
                    allow(gateway).to receive(:build_transaction_request).with(4321, VALID_PURCHASE_OPTIONS).and_return('the request body')
         | 
| 421 | 
            +
                    expect(gateway).to receive(:ssl_post).with(gateway.request_url, 'the request body').and_return(xml)
         | 
| 422 | 
            +
             | 
| 423 | 
            +
                    setup_purchase_response = gateway.setup_purchase(4321, VALID_PURCHASE_OPTIONS)
         | 
| 424 | 
            +
             | 
| 425 | 
            +
                    expect(setup_purchase_response).to be_a Ideal::TransactionResponse
         | 
| 426 | 
            +
             | 
| 427 | 
            +
                    expect(setup_purchase_response.service_url).to eq('https://ideal.example.com/long_service_url?X009=BETAAL&X010=20')
         | 
| 428 | 
            +
             | 
| 429 | 
            +
                    expect(setup_purchase_response.transaction_id).to eq('0001023456789112')
         | 
| 430 | 
            +
                    expect(setup_purchase_response.order_id).to eq('iDEAL-aankoop 21')
         | 
| 431 | 
            +
                  end
         | 
| 432 | 
            +
                end
         | 
| 433 | 
            +
             | 
| 434 | 
            +
              end
         | 
| 435 | 
            +
             | 
| 436 | 
            +
              describe 'purchase' do
         | 
| 437 | 
            +
                it 'should start a transaction at the acquirer' do
         | 
| 438 | 
            +
             | 
| 439 | 
            +
                  gateway = Ideal::Gateway.new
         | 
| 440 | 
            +
                  file = File.join(File.dirname(__FILE__), 'test_xml/transaction_response.xml')
         | 
| 441 | 
            +
                  xml = File.read(file)
         | 
| 442 | 
            +
             | 
| 443 | 
            +
                  allow(gateway).to receive(:build_transaction_request).with(4321, VALID_PURCHASE_OPTIONS).and_return('the request body')
         | 
| 444 | 
            +
                  expect(gateway).to receive(:ssl_post).with(gateway.request_url, 'the request body').and_return(xml)
         | 
| 445 | 
            +
             | 
| 446 | 
            +
                  setup_purchase_response = gateway.setup_purchase(4321, VALID_PURCHASE_OPTIONS)
         | 
| 447 | 
            +
             | 
| 448 | 
            +
                  expect(setup_purchase_response).to be_a(Ideal::TransactionResponse)
         | 
| 449 | 
            +
                  
         | 
| 450 | 
            +
                  expect(setup_purchase_response.service_url).to eq('https://ideal.example.com/long_service_url?X009=BETAAL&X010=20')
         | 
| 451 | 
            +
             | 
| 452 | 
            +
                  expect(setup_purchase_response.transaction_id).to eq('0001023456789112')
         | 
| 453 | 
            +
                  expect(setup_purchase_response.order_id).to eq('iDEAL-aankoop 21')
         | 
| 454 | 
            +
                end
         | 
| 455 | 
            +
              end
         | 
| 456 | 
            +
             | 
| 457 | 
            +
              describe 'capturePurchase' do
         | 
| 458 | 
            +
                it 'should do something correctly and not wrong' do
         | 
| 459 | 
            +
                  gateway = Ideal::Gateway.new
         | 
| 460 | 
            +
             | 
| 461 | 
            +
                  allow(gateway).to receive(:build_status_request).
         | 
| 462 | 
            +
                                        with(:transaction_id => '0001023456789112').and_return('the request body')
         | 
| 463 | 
            +
             | 
| 464 | 
            +
                  allow(gateway).to receive(:ssl_post).with(gateway.request_url, 'the request body').and_return(File.read(File.join(File.dirname(__FILE__), 'test_xml/status_response_succeeded.xml')))
         | 
| 465 | 
            +
                  expect(gateway.capture('0001023456789112')).to be_a Ideal::StatusResponse
         | 
| 466 | 
            +
             | 
| 467 | 
            +
                  allow_any_instance_of(Ideal::StatusResponse).to receive(:verified?).and_return(true)
         | 
| 468 | 
            +
                  capture_response = gateway.capture('0001023456789112')
         | 
| 469 | 
            +
                  expect(capture_response.success?).to be true
         | 
| 470 | 
            +
                end
         | 
| 471 | 
            +
              end
         | 
| 472 | 
            +
             | 
| 473 | 
            +
              describe 'capturePurchase' do
         | 
| 474 | 
            +
                it 'tololol' do
         | 
| 475 | 
            +
             | 
| 476 | 
            +
                  gateway = Ideal::Gateway.new
         | 
| 477 | 
            +
                  allow(gateway).to receive(:build_status_request).
         | 
| 478 | 
            +
                                        with(:transaction_id => '0001023456789112').and_return('the request body')
         | 
| 479 | 
            +
             | 
| 480 | 
            +
                  allow(gateway).to receive(:ssl_post).with(gateway.request_url, 'the request body').and_return(File.read(File.join(File.dirname(__FILE__), 'test_xml/status_response_succeeded_incorrect.xml')))
         | 
| 481 | 
            +
                  allow_any_instance_of(Ideal::StatusResponse).to receive(:verified?).and_return(false)
         | 
| 482 | 
            +
                  capture_response = gateway.capture('0001023456789112')
         | 
| 483 | 
            +
                  expect(capture_response.verified?).to be false
         | 
| 484 | 
            +
                  expect(capture_response.success?).to be false
         | 
| 485 | 
            +
                end
         | 
| 486 | 
            +
             | 
| 487 | 
            +
             | 
| 488 | 
            +
              end
         | 
| 489 | 
            +
            end
         | 
| 490 | 
            +
             | 
| 491 | 
            +
            # Defaults
         | 
| 492 | 
            +
             | 
| 493 | 
            +
            VALID_PURCHASE_OPTIONS = {
         | 
| 494 | 
            +
                :issuer_id => '99999IBAN',
         | 
| 495 | 
            +
                :expiration_period => 'PT10M',
         | 
| 496 | 
            +
                :return_url => 'https://example.inventid.net',
         | 
| 497 | 
            +
                :order_id => '1234567890',
         | 
| 498 | 
            +
                :description => 'A beautiful Eticket',
         | 
| 499 | 
            +
                :entrance_code => '1234'
         | 
| 500 | 
            +
            }
         |