banker 0.0.3
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.
- data/.gitignore +9 -0
- data/.rvmrc +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +7 -0
- data/Guardfile +10 -0
- data/LICENSE +23 -0
- data/README.md +79 -0
- data/Rakefile +2 -0
- data/banker.gemspec +25 -0
- data/lib/banker.rb +14 -0
- data/lib/banker/account.rb +16 -0
- data/lib/banker/barclaycard_uk.rb +96 -0
- data/lib/banker/barclays.rb +89 -0
- data/lib/banker/base.rb +28 -0
- data/lib/banker/capital_one_uk.rb +88 -0
- data/lib/banker/credit_expert_uk.rb +112 -0
- data/lib/banker/error.rb +5 -0
- data/lib/banker/lloyds_tsb_uk.rb +130 -0
- data/lib/banker/version.rb +3 -0
- data/spec/banker/account_spec.rb +32 -0
- data/spec/banker/barclaycard_uk_spec.rb +167 -0
- data/spec/banker/barclays_spec.rb +225 -0
- data/spec/banker/base_spec.rb +35 -0
- data/spec/banker/capital_one_uk_spec.rb +134 -0
- data/spec/banker/credit_expert_uk_spec.rb +78 -0
- data/spec/banker/lloyds_tsb_uk_spec.rb +53 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/barclaycard_uk/data.ofx +180 -0
- data/spec/support/barclays/data.ofx +86 -0
- data/spec/support/credit_expert_uk/MCC.aspx.html +1914 -0
- data/spec/support/credit_expert_uk/MCCLogin.aspx.html +458 -0
- data/spec/support/credit_expert_uk/MCCLoginMemorableWord.aspx.html +360 -0
- data/spec/support/lloyds_tsb_uk/account_overview_personal.html +328 -0
- data/spec/support/lloyds_tsb_uk/entermemorableinformation.jsp.html +148 -0
- data/spec/support/lloyds_tsb_uk/interstitialpage.jsp.html +155 -0
- data/spec/support/lloyds_tsb_uk/login.jsp.html +281 -0
- metadata +167 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Banker::Barclays do
|
4
|
+
|
5
|
+
LOGIN_URL = "https://bank.barclays.co.uk/olb/auth/LoginLink.action"
|
6
|
+
EXPORT_URL = "https://bank.barclays.co.uk/olb/balances/ExportDataStep1.action"
|
7
|
+
|
8
|
+
let(:support_files) {File.expand_path('../../support/barclays/',__FILE__)}
|
9
|
+
let(:mechanize) {mock('mechanize') }
|
10
|
+
let(:form) {mock('form')}
|
11
|
+
let(:button) {mock('button')}
|
12
|
+
let(:check) {mock('check')}
|
13
|
+
let(:ofx) {
|
14
|
+
f = File.open(File.expand_path('data.ofx', support_files), 'r:iso-8859-1')
|
15
|
+
OFX(f.read)
|
16
|
+
}
|
17
|
+
let(:args) { { surname: 'Doe',
|
18
|
+
membership_number: '2010827349273',
|
19
|
+
passcode: '82736',
|
20
|
+
memorable_word: 'testing' } }
|
21
|
+
|
22
|
+
subject { Banker::Barclays }
|
23
|
+
|
24
|
+
describe 'Respond To' do
|
25
|
+
before do
|
26
|
+
subject.any_instance.stub(:params)
|
27
|
+
subject.any_instance.stub(:authenticate!)
|
28
|
+
subject.any_instance.stub(:download!)
|
29
|
+
subject.any_instance.stub(:delivery)
|
30
|
+
end
|
31
|
+
|
32
|
+
it { subject.new(args).should respond_to(:accounts) }
|
33
|
+
it { subject.new(args).should respond_to(:ofx) }
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'Parameters' do
|
37
|
+
before do
|
38
|
+
subject.any_instance.stub(:authenticate!)
|
39
|
+
subject.any_instance.stub(:download!)
|
40
|
+
subject.any_instance.stub(:delivery)
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'Valid Params' do
|
44
|
+
it { expect{ subject.new(args) }.to_not raise_error }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'Invalid Params' do
|
48
|
+
keys = %w(surname membership_number passcode memorable_word)
|
49
|
+
|
50
|
+
keys.each do |key|
|
51
|
+
it "should raise InvalidParams when #{key} is not passed" do
|
52
|
+
msg = "missing parameters `#{key}` "
|
53
|
+
expect{ subject.new(args.delete_if { |k,v| k if k == key.to_sym })}.
|
54
|
+
to raise_error(Banker::Error::InvalidParams, msg)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'Method Calls' do
|
61
|
+
before do
|
62
|
+
subject.any_instance.stub(:params)
|
63
|
+
subject.any_instance.stub(:authenticate!)
|
64
|
+
subject.any_instance.stub(:download!)
|
65
|
+
subject.any_instance.stub(:delivery)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should Call params Method" do
|
69
|
+
subject.any_instance.should_receive(:params)
|
70
|
+
Banker::Barclays.new({})
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should Call authenticate! Method" do
|
74
|
+
subject.any_instance.should_receive(:authenticate!)
|
75
|
+
Banker::Barclays.new({})
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should Call download_account_data! Method" do
|
79
|
+
subject.any_instance.should_receive(:download!)
|
80
|
+
Banker::Barclays.new({})
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#authenticate!" do
|
85
|
+
before do
|
86
|
+
Mechanize.stub(:new).and_return(mechanize.as_null_object)
|
87
|
+
Mechanize.any_instance.stub(get: mechanize)
|
88
|
+
mechanize.stub(form_with: form.as_null_object)
|
89
|
+
subject.any_instance.stub(:OFX).and_return(ofx)
|
90
|
+
subject.any_instance.stub(:get_letter).and_return('s')
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should call to LOGIN_URL' do
|
94
|
+
mechanize.should_receive(:get).with(LOGIN_URL).
|
95
|
+
and_return(mechanize.as_null_object)
|
96
|
+
|
97
|
+
subject.new(args)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should find the form element' do
|
101
|
+
mechanize.should_receive(:form_with).with( action: 'LoginLink.action' ).
|
102
|
+
and_return(form.as_null_object)
|
103
|
+
|
104
|
+
subject.new(args)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should fill in the form" do
|
108
|
+
form.should_receive(:[]=).with('surname', 'Doe')
|
109
|
+
form.should_receive(:[]=).with('membershipNumber', '2010827349273')
|
110
|
+
|
111
|
+
subject.new(args)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should submit" do
|
115
|
+
Mechanize.stub(:new).and_return(mechanize.as_null_object)
|
116
|
+
|
117
|
+
form.should_receive(:buttons).exactly(5).times.and_return([button])
|
118
|
+
mechanize.should_receive(:submit).exactly(5).times.with(form, button).
|
119
|
+
and_return(mechanize.as_null_object)
|
120
|
+
|
121
|
+
subject.new(args)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should find the form element' do
|
125
|
+
mechanize.should_receive(:form_with).with( action: 'LoginStep1i.action' ).
|
126
|
+
and_return(form.as_null_object)
|
127
|
+
|
128
|
+
subject.new(args)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should check passcode radio button" do
|
132
|
+
form.should_receive(:radiobuttons).and_return(check)
|
133
|
+
check.should_receive(:first).and_return(check)
|
134
|
+
check.should_receive(:check).and_return(check)
|
135
|
+
|
136
|
+
subject.new(args)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should submit" do
|
140
|
+
Mechanize.stub(:new).and_return(mechanize.as_null_object)
|
141
|
+
|
142
|
+
form.should_receive(:buttons).exactly(5).times.and_return([button])
|
143
|
+
mechanize.should_receive(:submit).exactly(5).times.with(form, button).
|
144
|
+
and_return(mechanize.as_null_object)
|
145
|
+
|
146
|
+
subject.new(args)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should find the form element' do
|
150
|
+
mechanize.should_receive(:form_with).with( action: 'LoginStep2.action' ).
|
151
|
+
and_return(form.as_null_object)
|
152
|
+
|
153
|
+
subject.new(args)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should fill in the form" do
|
157
|
+
form.should_receive(:[]=).with('passcode', '82736')
|
158
|
+
form.should_receive(:[]=).with("firstMemorableCharacter", "s")
|
159
|
+
form.should_receive(:[]=).with("secondMemorableCharacter", "s")
|
160
|
+
|
161
|
+
subject.new(args)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#download!' do
|
166
|
+
before do
|
167
|
+
subject.any_instance.stub(:authenticate!)
|
168
|
+
subject.any_instance.stub(:delivery)
|
169
|
+
subject.any_instance.stub(:OFX).and_return(ofx)
|
170
|
+
Mechanize.stub(:new).and_return(mechanize.as_null_object)
|
171
|
+
Mechanize.any_instance.stub(get: mechanize)
|
172
|
+
mechanize.stub(form_with: form.as_null_object)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should call to EXPORT_URL' do
|
176
|
+
mechanize.should_receive(:get).with(EXPORT_URL).
|
177
|
+
and_return(mechanize.as_null_object)
|
178
|
+
|
179
|
+
subject.new(args)
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'should find the form element' do
|
183
|
+
form_url = "/olb/balances/ExportDataStep1.action"
|
184
|
+
mechanize.should_receive(:form_with).with( action: form_url ).
|
185
|
+
and_return(form.as_null_object)
|
186
|
+
|
187
|
+
subject.new(args)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should fill in the form" do
|
191
|
+
form.should_receive(:[]=).with('reqSoftwarePkgCode', '6')
|
192
|
+
form.should_receive(:[]=).with('productIdentifier', 'All')
|
193
|
+
|
194
|
+
subject.new(args)
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should find the other form element' do
|
198
|
+
form_url = "/olb/balances/ExportDataStep2All.action"
|
199
|
+
mechanize.should_receive(:form_with).with( action: form_url ).
|
200
|
+
and_return(form.as_null_object)
|
201
|
+
|
202
|
+
subject.new(args)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should parse ofx body' do
|
206
|
+
subject.any_instance.should_receive(:OFX).and_return(ofx)
|
207
|
+
|
208
|
+
subject.new(args)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#delivery()' do
|
213
|
+
let(:obj) { subject.new(args).accounts.first }
|
214
|
+
|
215
|
+
before do
|
216
|
+
subject.any_instance.stub(:authenticate!)
|
217
|
+
subject.any_instance.stub(:download!).and_return(ofx)
|
218
|
+
end
|
219
|
+
|
220
|
+
it { obj.uid.should == 'febcbc946e71cb09820c152c727b9b90' }
|
221
|
+
it { obj.name.should == 'Barclays' }
|
222
|
+
it { obj.amount.should == 410010 }
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Banker::Base do
|
4
|
+
describe "#params" do
|
5
|
+
it "raises Invalid Parameters if any defined parameters are missing" do
|
6
|
+
expect{
|
7
|
+
subject.keys = ['test']
|
8
|
+
subject.params({})
|
9
|
+
}.to raise_error(Banker::Error::InvalidParams,
|
10
|
+
"missing parameters `test` ")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#get" do
|
15
|
+
let(:mechanize) {mock('mechanize')}
|
16
|
+
let(:logger) {mock('logger')}
|
17
|
+
it "should assign agent with a new instance of Mechanize" do
|
18
|
+
Mechanize.should_receive(:new).and_return(mechanize)
|
19
|
+
Logger.should_receive(:new).and_return(logger)
|
20
|
+
|
21
|
+
mechanize.should_receive(:user_agent=).with("Mozilla/5.0 (Banker)")
|
22
|
+
mechanize.should_receive(:log=).with(logger)
|
23
|
+
mechanize.should_receive(:force_default_encoding=).with("utf8")
|
24
|
+
mechanize.should_receive(:get).with("http://google.com")
|
25
|
+
|
26
|
+
subject.get("http://google.com")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#get_letter" do
|
31
|
+
it "gets the index 1st character from a string" do
|
32
|
+
subject.get_letter("bank",1).should eql "b"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Banker::CapitalOneUK do
|
5
|
+
let(:mechanize) {mock('mechanize')}
|
6
|
+
let(:node) {mock('node')}
|
7
|
+
let(:form) {mock('form')}
|
8
|
+
let(:button) {mock('button')}
|
9
|
+
|
10
|
+
subject { Banker::CapitalOneUK}
|
11
|
+
|
12
|
+
before do
|
13
|
+
subject.any_instance.stub(:params)
|
14
|
+
subject.any_instance.stub(:authenticate!)
|
15
|
+
subject.any_instance.stub(:get_data)
|
16
|
+
end
|
17
|
+
|
18
|
+
it {subject.new().should respond_to(:accounts)}
|
19
|
+
|
20
|
+
context "Parameters" do
|
21
|
+
before do
|
22
|
+
subject.any_instance.unstub(:params)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises InvalidParams when email is missing" do
|
26
|
+
expect{
|
27
|
+
subject.new
|
28
|
+
}.to raise_error(Banker::Error::InvalidParams,
|
29
|
+
"missing parameters `username` `password` ")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "raises InvalidParams when password is missing" do
|
33
|
+
expect{
|
34
|
+
subject.new(email: 'test@test.com')
|
35
|
+
}.to raise_error(Banker::Error::InvalidParams)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'accepts email and password' do
|
39
|
+
expect{
|
40
|
+
subject.new(email: 'test@test.com', password: 'superduper')
|
41
|
+
}.to raise_error(Banker::Error::InvalidParams)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "calls" do
|
46
|
+
|
47
|
+
it "calls authenticate!" do
|
48
|
+
subject.any_instance.should_receive(:authenticate!)
|
49
|
+
subject.new
|
50
|
+
end
|
51
|
+
|
52
|
+
it "calls get_data" do
|
53
|
+
subject.any_instance.should_receive(:get_data)
|
54
|
+
subject.new
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "private" do
|
59
|
+
before do
|
60
|
+
Mechanize.stub(:new).and_return(mechanize.as_null_object)
|
61
|
+
mechanize.stub(form_with: form.as_null_object)
|
62
|
+
mechanize.stub(:at).and_return(node.as_null_object)
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#authenticate!" do
|
66
|
+
before do
|
67
|
+
subject.any_instance.unstub(:authenticate!)
|
68
|
+
subject.any_instance.stub(:get_letter)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "uses LOGIN_ENDPOINT" do
|
72
|
+
mechanize.should_receive(:get).
|
73
|
+
with("https://www.capitaloneonline.co.uk/CapitalOne_Consumer/Login.do").
|
74
|
+
and_return(mechanize)
|
75
|
+
subject.new
|
76
|
+
end
|
77
|
+
|
78
|
+
it "finds by form name" do
|
79
|
+
mechanize.should_receive(:form_with).with(
|
80
|
+
name: "logonForm"
|
81
|
+
).and_return(form)
|
82
|
+
subject.new
|
83
|
+
end
|
84
|
+
|
85
|
+
it "fills in form inputs" do
|
86
|
+
mechanize.should_receive(:at).with("#sign_in_box .password").
|
87
|
+
and_return(node)
|
88
|
+
node.should_receive(:content).
|
89
|
+
and_return("1st 2nd 3rd")
|
90
|
+
subject.any_instance.unstub(:get_letter)
|
91
|
+
|
92
|
+
form.should_receive(:[]=).with("username", "joebloggs")
|
93
|
+
form.should_receive(:[]=).with("password.randomCharacter0", "s")
|
94
|
+
form.should_receive(:[]=).with("password.randomCharacter1", "u")
|
95
|
+
form.should_receive(:[]=).with("password.randomCharacter2", "p")
|
96
|
+
subject.new(username: 'joebloggs', password: 'superduper')
|
97
|
+
end
|
98
|
+
|
99
|
+
it "submits form" do
|
100
|
+
form.should_receive(:buttons).and_return([button])
|
101
|
+
mechanize.should_receive(:submit).with(form, button)
|
102
|
+
subject.new
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#get_data" do
|
107
|
+
before do
|
108
|
+
subject.any_instance.stub(:get_letter)
|
109
|
+
|
110
|
+
subject.any_instance.unstub(:authenticate!)
|
111
|
+
subject.any_instance.unstub(:get_data)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "finds account balance" do
|
115
|
+
mechanize.should_receive(:at).
|
116
|
+
with("table[summary='account summary'] tr:nth-child(1) td.normalText:nth-child(2)").
|
117
|
+
and_return(node)
|
118
|
+
node.should_receive(:content).
|
119
|
+
at_least(:once).
|
120
|
+
and_return("£900.10")
|
121
|
+
subject.new
|
122
|
+
end
|
123
|
+
it "finds account limit" do
|
124
|
+
mechanize.should_receive(:at).
|
125
|
+
with("table[summary='account summary'] tr:nth-child(2) td.normalText:nth-child(2)").
|
126
|
+
and_return(node)
|
127
|
+
node.should_receive(:content).
|
128
|
+
at_least(:once).
|
129
|
+
and_return("£950.50")
|
130
|
+
subject.new
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Banker::CreditExpertUK do
|
4
|
+
let(:support_files) {File.expand_path('../../support/credit_expert_uk/',__FILE__)}
|
5
|
+
|
6
|
+
let(:mcclogin) {
|
7
|
+
File.read(
|
8
|
+
File.expand_path('MCCLogin.aspx.html', support_files)
|
9
|
+
)
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:mcclogin_memorable_word) {
|
13
|
+
File.read(
|
14
|
+
File.expand_path('MCCLoginMemorableWord.aspx.html', support_files)
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:mcc) {
|
19
|
+
File.read(
|
20
|
+
File.expand_path('MCC.aspx.html', support_files)
|
21
|
+
)
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
subject {Banker::CreditExpertUK.new(:username => "Bloggs",
|
26
|
+
:password => "123456",
|
27
|
+
:memorable_word => "superduper")}
|
28
|
+
|
29
|
+
before do
|
30
|
+
stub_request(
|
31
|
+
:get,
|
32
|
+
'https://www.creditexpert.co.uk/MCCLogin.aspx'
|
33
|
+
).to_return(
|
34
|
+
:status => 200,
|
35
|
+
:body => mcclogin,
|
36
|
+
:headers => {
|
37
|
+
'Content-Type' => 'text/html'
|
38
|
+
}
|
39
|
+
)
|
40
|
+
|
41
|
+
stub_request(
|
42
|
+
:post,
|
43
|
+
'https://www.creditexpert.co.uk/MCCLogin.aspx'
|
44
|
+
).to_return(
|
45
|
+
:status => 200,
|
46
|
+
:body => mcclogin_memorable_word,
|
47
|
+
:headers => {
|
48
|
+
'Content-Type' => 'text/html'
|
49
|
+
}
|
50
|
+
)
|
51
|
+
|
52
|
+
stub_request(
|
53
|
+
:post,
|
54
|
+
%r{https://www.creditexpert.co.uk/MCCLoginMemorableWord.aspx}
|
55
|
+
).to_return(
|
56
|
+
:status => 200,
|
57
|
+
:body => mcc,
|
58
|
+
:headers => {
|
59
|
+
'Content-Type' => 'text/html'
|
60
|
+
}
|
61
|
+
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '.new' do
|
66
|
+
it{ subject.username.should eql 'Bloggs' }
|
67
|
+
it{ subject.password.should eql '123456' }
|
68
|
+
it{ subject.memorable_word.should eql 'superduper' }
|
69
|
+
it{ subject.score.should eql 648 }
|
70
|
+
|
71
|
+
it "should authenticate account" do
|
72
|
+
subject
|
73
|
+
|
74
|
+
WebMock.should have_requested(:get, 'https://www.creditexpert.co.uk/MCCLogin.aspx')
|
75
|
+
WebMock.should have_requested(:post, 'https://www.creditexpert.co.uk/MCCLogin.aspx')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|