nihaopay-ruby 0.1.0

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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +22 -0
  4. data/README.md +344 -0
  5. data/lib/nihaopay-ruby.rb +29 -0
  6. data/lib/nihaopay/configure.rb +14 -0
  7. data/lib/nihaopay/credit_card.rb +27 -0
  8. data/lib/nihaopay/errors.rb +6 -0
  9. data/lib/nihaopay/merchant.rb +47 -0
  10. data/lib/nihaopay/mixins/api.rb +41 -0
  11. data/lib/nihaopay/mixins/queryable.rb +41 -0
  12. data/lib/nihaopay/query.rb +61 -0
  13. data/lib/nihaopay/secure_pay/ali_pay.rb +11 -0
  14. data/lib/nihaopay/secure_pay/base.rb +48 -0
  15. data/lib/nihaopay/secure_pay/union_pay.rb +11 -0
  16. data/lib/nihaopay/secure_pay/we_chat_pay.rb +11 -0
  17. data/lib/nihaopay/transactions/authorize.rb +37 -0
  18. data/lib/nihaopay/transactions/base.rb +78 -0
  19. data/lib/nihaopay/transactions/cancel.rb +28 -0
  20. data/lib/nihaopay/transactions/capture.rb +29 -0
  21. data/lib/nihaopay/transactions/purchase.rb +11 -0
  22. data/lib/nihaopay/transactions/refund.rb +31 -0
  23. data/lib/nihaopay/transactions/release.rb +28 -0
  24. data/lib/nihaopay/util/hash_util.rb +30 -0
  25. data/lib/nihaopay/version.rb +3 -0
  26. data/spec/credit_card_spec.rb +56 -0
  27. data/spec/merchant_spec.rb +142 -0
  28. data/spec/mixins/api_spec.rb +81 -0
  29. data/spec/mixins/queryable_spec.rb +95 -0
  30. data/spec/query_spec.rb +129 -0
  31. data/spec/secure_pay/ali_pay_spec.rb +112 -0
  32. data/spec/secure_pay/union_pay_spec.rb +13 -0
  33. data/spec/secure_pay/we_chat_pay_spec.rb +13 -0
  34. data/spec/spec_helper.rb +7 -0
  35. data/spec/transactions/authorize_spec.rb +115 -0
  36. data/spec/transactions/base_spec.rb +184 -0
  37. data/spec/transactions/cancel_spec.rb +83 -0
  38. data/spec/transactions/capture_spec.rb +85 -0
  39. data/spec/transactions/purchase_spec.rb +7 -0
  40. data/spec/transactions/refund_spec.rb +98 -0
  41. data/spec/transactions/release_spec.rb +83 -0
  42. data/spec/util/hash_util_spec.rb +22 -0
  43. metadata +187 -0
@@ -0,0 +1,129 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Nihaopay::Query do
4
+ before do
5
+ Nihaopay.test_mode = true
6
+ Nihaopay.token = token
7
+ end
8
+ let(:token) { '6c4dc4828474fa73c5f438a9eb2f' }
9
+ let(:q) { described_class.new }
10
+
11
+ describe '#limit' do
12
+ it 'should set @limit' do
13
+ q2 = q.limit(5)
14
+ expect(q2).to eq q
15
+ expect(q2.instance_variable_get(:@limit)).to eq 5
16
+ end
17
+ end
18
+
19
+ describe '#before' do
20
+ it 'should set @ending_before' do
21
+ q2 = q.before('2016-07-01T01:00:00Z')
22
+ expect(q2).to eq q
23
+ expect(q2.instance_variable_get(:@ending_before)).to eq '2016-07-01T01:00:00Z'
24
+ end
25
+ end
26
+
27
+ describe '#after' do
28
+ it 'should set @starting_after' do
29
+ q2 = q.after('2016-07-01T01:00:00Z')
30
+ expect(q2).to eq q
31
+ expect(q2.instance_variable_get(:@starting_after)).to eq '2016-07-01T01:00:00Z'
32
+ end
33
+ end
34
+
35
+ describe '#fetch' do
36
+ before { q.limit(5).before('2016-07-01T01:00:00Z').after('2016-06-01T01:00:00Z') }
37
+
38
+ context 'when options not passed' do
39
+ let(:expected_options) do
40
+ { limit: 5,
41
+ starting_after: '2016-06-01T01:00:00Z',
42
+ ending_before: '2016-07-01T01:00:00Z' }
43
+ end
44
+ it { expect(described_class).to receive(:fetch).with(expected_options) }
45
+ after { q.fetch }
46
+ end
47
+
48
+ context 'when options passed' do
49
+ let(:expected_options) { { limit: 3 } }
50
+ it { expect(described_class).to receive(:fetch).with(expected_options) }
51
+ after { q.fetch(limit: 3) }
52
+ end
53
+ end
54
+
55
+ describe '.fetch' do
56
+ before do
57
+ allow(response).to receive(:parsed_response) { parsed_response }
58
+ allow(HTTParty).to receive(:get) { response }
59
+ end
60
+ let(:response) { Object.new }
61
+ let(:parsed_response) do
62
+ { 'transactions' => [{ 'id' => '20160718111604002633', 'type' => 'charge', 'status' => 'success' },
63
+ { 'id' => '20160718111604002634', 'type' => 'charge', 'status' => 'failure' }] }
64
+ end
65
+ let(:url) { 'http://api.test.nihaopay.com/v1.1/transactions' }
66
+ let(:headers) { { 'Authorization' => "Bearer #{token}" } }
67
+
68
+ context 'when options not passed' do
69
+ it { expect(HTTParty).to receive(:get).with(url, headers: headers) }
70
+ after { described_class.fetch }
71
+ end
72
+
73
+ context 'when query present' do
74
+ let(:options) { { limit: 5, starting_after: '2016-07-01T01:00:00Z' } }
75
+ it { expect(HTTParty).to receive(:get).with(url, headers: headers, query: options) }
76
+ after { described_class.fetch(options) }
77
+ end
78
+
79
+ context 'with invalid options' do
80
+ let(:options) { { foo: :bar } }
81
+ it { expect(HTTParty).to receive(:get).with(url, headers: headers) }
82
+ after { described_class.fetch(options) }
83
+ end
84
+
85
+ context 'with blank values' do
86
+ let(:options) { { limit: nil, starting_after: '' } }
87
+ it { expect(HTTParty).to receive(:get).with(url, headers: headers) }
88
+ after { described_class.fetch(options) }
89
+ end
90
+
91
+ describe '.build_transactions' do
92
+ context 'when response does not contain :transactions' do
93
+ let(:parsed_response) do
94
+ { 'id' => '20160718111604002633', 'type' => 'charge', 'status' => 'success' }
95
+ end
96
+ it { expect { described_class.fetch }.to raise_error(Nihaopay::TransactionLookUpError) }
97
+ end
98
+
99
+ context 'when response contains :transactions' do
100
+ it 'should return collection of transaction objects' do
101
+ txns = described_class.fetch
102
+ expect(txns.size).to eq 2
103
+ expect(txns[0]).to be_a Nihaopay::Transactions::Base
104
+ expect(txns[0].transaction_id).to eq '20160718111604002633'
105
+ expect(txns[0].type).to eq 'charge'
106
+ expect(txns[0].status).to eq 'success'
107
+ expect(txns[1]).to be_a Nihaopay::Transactions::Base
108
+ expect(txns[1].transaction_id).to eq '20160718111604002634'
109
+ expect(txns[1].type).to eq 'charge'
110
+ expect(txns[1].status).to eq 'failure'
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ describe '.url' do
117
+ it { expect(described_class.url).to eq 'http://api.test.nihaopay.com/v1.1/transactions' }
118
+ end
119
+
120
+ describe '.request_headers' do
121
+ let(:expected_headers) { { 'Authorization' => "Bearer #{token}" } }
122
+ it { expect(described_class.request_headers).to eq expected_headers }
123
+ end
124
+
125
+ describe '.query_params' do
126
+ let(:options) { { limit: 5, starting_after: nil, foo: :bar } }
127
+ it { expect(described_class.query_params(options)).to eq(limit: 5) }
128
+ end
129
+ end
@@ -0,0 +1,112 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Nihaopay::SecurePay::AliPay do
4
+ before do
5
+ Nihaopay.test_mode = true
6
+ Nihaopay.token = token
7
+ end
8
+ let(:token) { '6c4dc4828474fa73c5f438a9eb2f' }
9
+
10
+ describe '.vendor' do
11
+ it { expect(described_class.vendor).to eq :alipay }
12
+ end
13
+
14
+ describe '.start' do
15
+ let(:url) { 'http://api.test.nihaopay.com/v1.1/transactions/securepay' }
16
+ let(:headers) { { 'Authorization' => "Bearer #{token}" } }
17
+
18
+ context 'without options' do
19
+ let(:body) { 'amount=1000&currency=JPY&vendor=alipay&reference=&ipn_url=&callback_url=' }
20
+ let(:response) { OpenStruct.new(code: 200, body: '<html></html>') }
21
+ it { expect(HTTParty).to receive(:post).with(url, headers: headers, body: body) { response } }
22
+ after { described_class.start(1000, 'JPY') }
23
+ end
24
+
25
+ context 'with options' do
26
+ let(:options) do
27
+ { reference: '3461fcc31aec471780ad1a4dc6111947',
28
+ ipn_url: 'http://website.com/ipn',
29
+ callback_url: 'http://website.com/callback' }
30
+ end
31
+ let(:body) do
32
+ 'amount=1000'\
33
+ '&currency=JPY'\
34
+ '&vendor=alipay'\
35
+ '&reference=3461fcc31aec471780ad1a4dc61119'\
36
+ '&ipn_url=http://website.com/ipn'\
37
+ '&callback_url=http://website.com/callback'
38
+ end
39
+ let(:response) { OpenStruct.new(code: 200, body: '<html></html>') }
40
+ it { expect(HTTParty).to receive(:post).with(url, headers: headers, body: body) { response } }
41
+ after { described_class.start(1000, 'JPY', options) }
42
+ end
43
+
44
+ context 'with :token in options' do
45
+ let(:options) do
46
+ { token: '6c4dc4828474fa73c5f438a9eb2g',
47
+ reference: '3461fcc31aec471780ad1a4dc6111947',
48
+ ipn_url: 'http://website.com/ipn',
49
+ callback_url: 'http://website.com/callback' }
50
+ end
51
+ let(:headers) { { 'Authorization' => 'Bearer 6c4dc4828474fa73c5f438a9eb2g' } }
52
+ let(:body) do
53
+ 'amount=1000'\
54
+ '&currency=JPY'\
55
+ '&vendor=alipay'\
56
+ '&reference=3461fcc31aec471780ad1a4dc61119'\
57
+ '&ipn_url=http://website.com/ipn'\
58
+ '&callback_url=http://website.com/callback'
59
+ end
60
+ let(:response) { OpenStruct.new(code: 200, body: '<html></html>') }
61
+ it { expect(HTTParty).to receive(:post).with(url, headers: headers, body: body) { response } }
62
+ after do
63
+ described_class.start(1000, 'JPY', options)
64
+ described_class.instance_variable_set(:@token, nil)
65
+ end
66
+ end
67
+
68
+ context 'with failure response' do
69
+ let(:body) { 'amount=1000&currency=JPY&vendor=alipay&reference=&ipn_url=&callback_url=' }
70
+ let(:response) { OpenStruct.new(code: 401, body: '<html></html>', parsed_response: { message: 'Unauthorized' }) }
71
+ before { allow(HTTParty).to receive(:post) { response } }
72
+ it { expect { described_class.start(1000, 'JPY') }.to raise_error ::Nihaopay::SecurePayTransactionError }
73
+ end
74
+ end
75
+
76
+ describe '.request_url' do
77
+ let(:expected) { 'http://api.test.nihaopay.com/v1.1/transactions/securepay' }
78
+ it { expect(described_class.request_url).to eq expected }
79
+ end
80
+
81
+ describe '.request_headers' do
82
+ let(:expected) { { 'Authorization' => "Bearer #{token}" } }
83
+ it { expect(described_class.request_headers).to eq expected }
84
+ end
85
+
86
+ describe '.request_params' do
87
+ context 'when refrence more than 30 chars' do
88
+ let(:options) do
89
+ { reference: '3461fcc31aec471780ad1a4dc6111947',
90
+ ipn_url: 'http://website.com/ipn',
91
+ callback_url: 'http://website.com/callback' }
92
+ end
93
+ subject { described_class.request_params(1000, 'JPY', options) }
94
+ it { expect(subject[:reference]).to eq '3461fcc31aec471780ad1a4dc61119' }
95
+ end
96
+
97
+ context 'when options not in required format' do
98
+ let(:options) do
99
+ { reference: :a3461fcc,
100
+ ipn_url: 'http://website.com/ipn',
101
+ callback_url: 'http://website.com/callback' }
102
+ end
103
+ subject { described_class.request_params(1000.3, :JPY, options) }
104
+ it { expect(subject[:amount]).to eq 1000 }
105
+ it { expect(subject[:currency]).to eq 'JPY' }
106
+ it { expect(subject[:vendor]).to eq 'alipay' }
107
+ it { expect(subject[:reference]).to eq 'a3461fcc' }
108
+ it { expect(subject[:ipn_url]).to eq 'http://website.com/ipn' }
109
+ it { expect(subject[:callback_url]).to eq 'http://website.com/callback' }
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,13 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Nihaopay::SecurePay::UnionPay do
4
+ before do
5
+ Nihaopay.test_mode = true
6
+ Nihaopay.token = token
7
+ end
8
+ let(:token) { '6c4dc4828474fa' }
9
+
10
+ describe '.vendor' do
11
+ it { expect(described_class.vendor).to eq :unionpay }
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Nihaopay::SecurePay::WeChatPay do
4
+ before do
5
+ Nihaopay.test_mode = true
6
+ Nihaopay.token = token
7
+ end
8
+ let(:token) { '6c4dc4828474fa' }
9
+
10
+ describe '.vendor' do
11
+ it { expect(described_class.vendor).to eq :wechatpay }
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'nihaopay-ruby'
4
+
5
+ RSpec.configure do |config|
6
+ config.order = 'random'
7
+ end
@@ -0,0 +1,115 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Nihaopay::Transactions::Authorize do
4
+ before do
5
+ Nihaopay.test_mode = true
6
+ Nihaopay.token = token
7
+ end
8
+ let(:token) { '6c4dc4828474f' }
9
+
10
+ describe '.start' do
11
+ before do
12
+ allow(response).to receive(:parsed_response) { parsed_response }
13
+ allow(HTTParty).to receive(:post) { response }
14
+ end
15
+ let(:cc_attrs) { { number: '6221558812340000', expiry_year: 17, expiry_month: 11, cvv: '123' } }
16
+ let(:cc) { Nihaopay::CreditCard.new(cc_attrs) }
17
+ let(:url) { 'http://api.test.nihaopay.com/v1.1/transactions/expresspay' }
18
+ let(:headers) do
19
+ { 'Authorization' => "Bearer #{token}",
20
+ 'Content-Type' => 'application/x-www-form-urlencoded' }
21
+ end
22
+ let(:response) { Object.new }
23
+ let(:parsed_response) do
24
+ { 'id' => '20160714132438002485',
25
+ 'status' => 'success',
26
+ 'reference' => '3461fcc31aec471780ad1a4dc6111947',
27
+ 'currency' => 'JPY',
28
+ 'amount' => 1000,
29
+ 'captured' => false }
30
+ end
31
+
32
+ context 'without options' do
33
+ let(:body) do
34
+ 'card_number=6221558812340000'\
35
+ '&card_exp_year=17'\
36
+ '&card_exp_month=11'\
37
+ '&card_cvv=123'\
38
+ '&capture=false'\
39
+ '&amount=1000'\
40
+ '&currency=USD'
41
+ end
42
+ it { expect(HTTParty).to receive(:post).with(url, headers: headers, body: body) }
43
+ after { described_class.start(1000, cc) }
44
+ end
45
+
46
+ context 'with options' do
47
+ let(:options) do
48
+ { currency: 'USD',
49
+ description: 'Lorem ipsum',
50
+ note: 'To self',
51
+ reference: '111111' }
52
+ end
53
+ let(:body) do
54
+ 'card_number=6221558812340000'\
55
+ '&card_exp_year=17'\
56
+ '&card_exp_month=11'\
57
+ '&card_cvv=123'\
58
+ '&currency=USD'\
59
+ '&description=Lorem ipsum'\
60
+ '&note=To self'\
61
+ '&reference=111111'\
62
+ '&capture=false'\
63
+ '&amount=1000'
64
+ end
65
+ it { expect(HTTParty).to receive(:post).with(url, headers: headers, body: body) }
66
+ after { described_class.start(1000, cc, options) }
67
+ end
68
+
69
+ context 'with invalid options' do
70
+ let(:options) { { foo: :bar } }
71
+ let(:body) do
72
+ 'card_number=6221558812340000'\
73
+ '&card_exp_year=17'\
74
+ '&card_exp_month=11'\
75
+ '&card_cvv=123'\
76
+ '&capture=false'\
77
+ '&amount=1000'\
78
+ '&currency=USD'
79
+ end
80
+ it { expect(HTTParty).to receive(:post).with(url, headers: headers, body: body) }
81
+ after { described_class.start(1000, cc, options) }
82
+ end
83
+
84
+ context 'with :token in options' do
85
+ let(:options) { { token: 'ec471780ad1' } }
86
+ let(:headers) do
87
+ { 'Authorization' => 'Bearer ec471780ad1',
88
+ 'Content-Type' => 'application/x-www-form-urlencoded' }
89
+ end
90
+ let(:body) do
91
+ 'card_number=6221558812340000'\
92
+ '&card_exp_year=17'\
93
+ '&card_exp_month=11'\
94
+ '&card_cvv=123'\
95
+ '&capture=false'\
96
+ '&amount=1000'\
97
+ '&currency=USD'
98
+ end
99
+ it { expect(HTTParty).to receive(:post).with(url, headers: headers, body: body) }
100
+ after do
101
+ described_class.start(1000, cc, options)
102
+ described_class.instance_variable_set(:@token, nil)
103
+ end
104
+ end
105
+
106
+ describe '.build_from_response!' do
107
+ it 'should return transaction object' do
108
+ txn = described_class.start(1000, cc)
109
+ expect(txn).to be_a Nihaopay::Transactions::Base
110
+ expect(txn.transaction_id).to eq '20160714132438002485'
111
+ expect(txn.status).to eq 'success'
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,184 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Nihaopay::Transactions::Base do
4
+ before do
5
+ Nihaopay.test_mode = true
6
+ Nihaopay.token = token
7
+ end
8
+ let(:token) { 'merchanttoken1' }
9
+ let(:txn_id) { '20160714132438002485' }
10
+ let(:attrs) do
11
+ { token: token,
12
+ transaction_id: txn_id,
13
+ type: 'charge',
14
+ status: 'success',
15
+ amount: 1000,
16
+ currency: 'JPY',
17
+ time: '2016-06-01T01:00:00Z',
18
+ reference: 'reference',
19
+ note: 'note-to-self' }
20
+ end
21
+ let(:base) { described_class.new(attrs) }
22
+
23
+ describe '.attr_accessor' do
24
+ subject { base }
25
+ it { is_expected.to respond_to :token= }
26
+ it { is_expected.to respond_to :token }
27
+ it { is_expected.to respond_to :transaction_id= }
28
+ it { is_expected.to respond_to :transaction_id }
29
+ it { is_expected.to respond_to :type= }
30
+ it { is_expected.to respond_to :type }
31
+ it { is_expected.to respond_to :status= }
32
+ it { is_expected.to respond_to :status }
33
+ it { is_expected.to respond_to :captured= }
34
+ it { is_expected.to respond_to :captured }
35
+ it { is_expected.to respond_to :reference= }
36
+ it { is_expected.to respond_to :reference }
37
+ it { is_expected.to respond_to :currency= }
38
+ it { is_expected.to respond_to :currency }
39
+ it { is_expected.to respond_to :amount= }
40
+ it { is_expected.to respond_to :amount }
41
+ it { is_expected.to respond_to :note= }
42
+ it { is_expected.to respond_to :note }
43
+ it { is_expected.to respond_to :time= }
44
+ it { is_expected.to respond_to :time }
45
+ end
46
+
47
+ describe '#initialize' do
48
+ context 'when attributes not passed' do
49
+ subject { described_class.new }
50
+ it { is_expected.to be_a Nihaopay::Transactions::Base }
51
+ end
52
+
53
+ context 'when attributes passed' do
54
+ subject { base }
55
+ it { is_expected.to be_a Nihaopay::Transactions::Base }
56
+ it { expect(subject.token).to eq token }
57
+ it { expect(subject.transaction_id).to eq txn_id }
58
+ it { expect(subject.type).to eq 'charge' }
59
+ it { expect(subject.status).to eq 'success' }
60
+ it { expect(subject.currency).to eq 'JPY' }
61
+ it { expect(subject.reference).to eq 'reference' }
62
+ it { expect(subject.amount).to eq 1000 }
63
+ it { expect(subject.note).to eq 'note-to-self' }
64
+ it { expect(subject.time).to eq '2016-06-01T01:00:00Z' }
65
+ end
66
+
67
+ context 'with invalid attributes' do
68
+ subject { described_class.new(foo: :bar) }
69
+ it { is_expected.to be_a Nihaopay::Transactions::Base }
70
+ end
71
+ end
72
+
73
+ describe '#capture' do
74
+ it { expect(Nihaopay::Transactions::Capture).to receive(:start).with(txn_id, 1000, 'JPY', token: token) }
75
+ after { base.capture }
76
+ end
77
+
78
+ describe '#partial_capture' do
79
+ it { expect(Nihaopay::Transactions::Capture).to receive(:start).with(txn_id, 500, 'JPY', token: token) }
80
+ after { base.partial_capture(500) }
81
+ end
82
+
83
+ describe '#release' do
84
+ it { expect(Nihaopay::Transactions::Release).to receive(:start).with(txn_id, token: token) }
85
+ after { base.release }
86
+ end
87
+
88
+ describe '#cancel' do
89
+ it { expect(Nihaopay::Transactions::Cancel).to receive(:start).with(txn_id, token: token) }
90
+ after { base.cancel }
91
+ end
92
+
93
+ describe '#refund' do
94
+ context 'without options' do
95
+ it { expect(Nihaopay::Transactions::Refund).to receive(:start).with(txn_id, 1000, 'JPY', token: token) }
96
+ after { base.refund }
97
+ end
98
+
99
+ context 'with options' do
100
+ let(:expected_opts) { { reason: 'out of stock', token: token } }
101
+ it { expect(Nihaopay::Transactions::Refund).to receive(:start).with(txn_id, 1000, 'JPY', expected_opts) }
102
+ after { base.refund(reason: 'out of stock') }
103
+ end
104
+ end
105
+
106
+ describe '#partial_refund' do
107
+ context 'without options' do
108
+ it { expect(Nihaopay::Transactions::Refund).to receive(:start).with(txn_id, 500, 'JPY', token: token) }
109
+ after { base.partial_refund(500) }
110
+ end
111
+
112
+ context 'with options' do
113
+ let(:expected_opts) { { reason: 'out of stock', token: token } }
114
+ it { expect(Nihaopay::Transactions::Refund).to receive(:start).with(txn_id, 500, 'JPY', expected_opts) }
115
+ after { base.partial_refund(500, reason: 'out of stock') }
116
+ end
117
+ end
118
+
119
+ describe '.request_headers' do
120
+ let(:expectation) do
121
+ { 'Authorization' => "Bearer #{token}",
122
+ 'Content-Type' => 'application/x-www-form-urlencoded' }
123
+ end
124
+ it { expect(described_class.request_headers).to eq expectation }
125
+ end
126
+
127
+ describe '.build' do
128
+ context 'when options not passed' do
129
+ subject { described_class.build }
130
+ it { is_expected.to be_a Nihaopay::Transactions::Base }
131
+ it { expect(subject.token).to eq token }
132
+ end
133
+
134
+ context 'with options' do
135
+ let(:options) do
136
+ opts = attrs.merge(id: '123456', token: 'merchanttoken2', captured: true)
137
+ opts.delete(:transaction_id)
138
+ opts
139
+ end
140
+ subject { described_class.build(options) }
141
+ it { is_expected.to be_a Nihaopay::Transactions::Base }
142
+ it { expect(subject.transaction_id).to eq '123456' }
143
+ it { expect(subject.token).to eq 'merchanttoken2' }
144
+ it { expect(subject.captured).to be true }
145
+ end
146
+
147
+ context 'with options with string keys' do
148
+ let(:options) do
149
+ opts = Nihaopay::HashUtil.stringify_keys(attrs)
150
+ opts['id'] = '123456'
151
+ opts.delete('transaction_id')
152
+ opts
153
+ end
154
+ subject { described_class.build(options) }
155
+ it { is_expected.to be_a Nihaopay::Transactions::Base }
156
+ it { expect(subject.transaction_id).to eq '123456' }
157
+ end
158
+
159
+ context 'without token' do
160
+ let(:options) do
161
+ opts = attrs
162
+ opts[:id] = '123456'
163
+ opts.delete(:transaction_id)
164
+ opts.delete(:token)
165
+ opts
166
+ end
167
+ subject { described_class.build(options) }
168
+ it { is_expected.to be_a Nihaopay::Transactions::Base }
169
+ it { expect(subject.token).to eq 'merchanttoken1' }
170
+ end
171
+ end
172
+
173
+ describe '.valid_attributes' do
174
+ let(:expectation) do
175
+ %i(token transaction_id type status captured currency reference amount note time)
176
+ end
177
+ it { expect(described_class.valid_attributes).to eq expectation }
178
+ end
179
+
180
+ describe '.response_keys_map' do
181
+ let(:expectation) { { id: :transaction_id } }
182
+ it { expect(described_class.response_keys_map).to eq expectation }
183
+ end
184
+ end