page_record 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,434 @@
1
+ require_relative './spec_helper'
2
+
3
+ describe PageRecord::PageRecord do
4
+
5
+ include_context "page with single table with 3 records" # Default context
6
+
7
+ before do
8
+ class TeamPage < PageRecord::PageRecord; end
9
+ PageRecord::PageRecord.page = page
10
+ end
11
+
12
+ describe ".type" do
13
+
14
+ before do
15
+ class CamelCase
16
+ def self.attribute_names
17
+ [ 'id' , 'name', 'points', 'ranking', 'goals']
18
+ end
19
+ end
20
+ class CamelCasePage < PageRecord::PageRecord; end
21
+ end
22
+
23
+ it "returns the internal type of the class" do
24
+ pending
25
+ expect( CamelCasePage.type).to eq "camel_case"
26
+ end
27
+
28
+ end
29
+
30
+
31
+ describe ".attributes" do
32
+ before do
33
+ class TeamPage < PageRecord::PageRecord
34
+ attributes ['country', 'stadium']
35
+ end
36
+ end
37
+
38
+ after do
39
+ Object.send(:remove_const, :TeamPage)
40
+ end
41
+
42
+ subject { TeamPage}
43
+
44
+ it "clears all old class methods" do
45
+ expect(subject).not_to respond_to(:find_by_name)
46
+ expect(subject).not_to respond_to(:find_by_ranking)
47
+ end
48
+
49
+ it "adds new class methods to class " do
50
+ expect(subject).to respond_to(:find_by_country)
51
+ expect(subject).to respond_to(:find_by_stadium)
52
+ end
53
+
54
+ it "clears all old instance methods" do
55
+ expect(subject.new(1)).not_to respond_to(:name)
56
+ expect(subject.new(1)).not_to respond_to(:ranking)
57
+ end
58
+
59
+ it "adds new class methods to class " do
60
+ expect(subject.new(1)).to respond_to(:country)
61
+ expect(subject.new(1)).to respond_to(:stadium)
62
+ end
63
+
64
+ end
65
+
66
+
67
+
68
+ describe ".page=" do
69
+ before do
70
+ PageRecord::PageRecord.page = nil # reset for the spec
71
+ end
72
+
73
+ subject {PageRecord::PageRecord.page = page }
74
+
75
+ it "sets the page when called on PageRecord::PageRecord" do
76
+ expect{PageRecord::PageRecord.page = page}.to change{PageRecord::PageRecord.page}.from(nil).to(page)
77
+ end
78
+
79
+ it "sets the page when called on subclass" do
80
+ expect{TeamPage.page = page}.to change{PageRecord::PageRecord.page}.from(nil).to(page)
81
+ end
82
+
83
+
84
+ end
85
+
86
+ describe ".page" do
87
+
88
+
89
+ it "gets the page on PageRecord::PageRecord" do
90
+ expect(PageRecord::PageRecord.page).to eq page
91
+ end
92
+
93
+ it "gets the page on subclass" do
94
+ expect(TeamPage.page).to eq page
95
+ end
96
+
97
+ end
98
+
99
+
100
+
101
+ describe ".all" do
102
+
103
+
104
+ subject {TeamPage.all( selector, filter) }
105
+
106
+ context "one set of records available on the page" do
107
+ let(:selector) {""}
108
+ let(:filter) {""}
109
+
110
+ it_behaves_like "valid call of .all"
111
+
112
+ context "with a filter" do
113
+ let(:filter) {".champions_league"}
114
+
115
+ it "returns only the elements that contain the filter css" do
116
+ expect( subject.map {|c| c.name}).not_to include('Feijenoord')
117
+ expect( subject.map {|c| c.name}).to include(*['Ajax', 'PSV'])
118
+ end
119
+
120
+
121
+ end
122
+
123
+
124
+ end
125
+
126
+ context "No records available on the page" do
127
+
128
+ include_context "page without records"
129
+ let(:selector) {""}
130
+ let(:filter) {""}
131
+
132
+
133
+ it "returns an empty Array" do
134
+ expect(subject).to eq []
135
+ end
136
+
137
+ end
138
+
139
+ context "multiple sets of records avialable on the page" do
140
+ include_context "page with two tables with 3 records"
141
+
142
+ context "without selector" do
143
+ let(:selector) {""}
144
+ let(:filter) {""}
145
+
146
+
147
+ it "raises error PageRecord::MultipleRecords" do
148
+ expect{subject}.to raise_error(PageRecord::MultipleRecords)
149
+ end
150
+
151
+ end
152
+
153
+ it_behaves_like "handles invalid selectors"
154
+
155
+ context "with a correct selector" do
156
+
157
+ let(:selector) {"#first-table"}
158
+ let(:filter) {""}
159
+
160
+ it_behaves_like "valid call of .all"
161
+
162
+ end
163
+
164
+ end
165
+
166
+ end
167
+
168
+
169
+ describe "inherited class" do
170
+
171
+ subject {TeamPage.new(1) }
172
+
173
+ it "responds to all attributes of corresponding AR Class" do
174
+ Team.attribute_names.each do |attribute|
175
+ expect(subject).to respond_to(attribute)
176
+ end
177
+ end
178
+
179
+ it "responds <attribute>? of corresponding AR Class" do
180
+ Team.attribute_names.each do |attribute|
181
+ expect(subject).to respond_to("#{attribute}?")
182
+ end
183
+ end
184
+
185
+ #
186
+ # Checks a bug
187
+ it "leaves attribute_names of host class intact"
188
+
189
+
190
+ end
191
+
192
+ describe "action method on class" do
193
+ pending
194
+ end
195
+
196
+
197
+ describe ".find" do
198
+
199
+ subject {TeamPage.find(record_number, selector, filter) }
200
+ let(:selector) { ""}
201
+ let(:filter) {""}
202
+
203
+ context "find without an id" do
204
+ pending
205
+ end
206
+
207
+ context "one found on the page" do
208
+
209
+ let(:record_number) { 1}
210
+
211
+ it_behaves_like "a valid call of .find"
212
+
213
+
214
+ it_behaves_like "it handles filters"
215
+
216
+
217
+ end
218
+
219
+ context "multiple record found on the page" do
220
+
221
+ let(:record_number) { 1}
222
+ include_context "page with duplicate records"
223
+
224
+ subject {TeamPage.find(1) }
225
+
226
+ it "raises error PageRecord::MultipleRecords" do
227
+ expect{subject}.to raise_error(PageRecord::MultipleRecords)
228
+ end
229
+
230
+ end
231
+
232
+
233
+ context "no record on the page" do
234
+
235
+ let(:record_number) { 37373}
236
+
237
+ it "raises error PageRecord::RecordNotFound" do
238
+ expect{subject}.to raise_error(PageRecord::RecordNotFound)
239
+ end
240
+
241
+ end
242
+
243
+ context "multiple sets of records available on the page" do
244
+ include_context "page with two tables with 3 records"
245
+ let(:record_number) {1}
246
+
247
+ context "without selector" do
248
+ let(:selector) {""}
249
+
250
+ it "raises error PageRecord::MultipleRecords" do
251
+ expect{subject}.to raise_error(PageRecord::MultipleRecords)
252
+ end
253
+
254
+ end
255
+
256
+ it_behaves_like "handles invalid selectors"
257
+
258
+ context "with a correct selector" do
259
+
260
+ let(:selector) {"#first-table"}
261
+ it_behaves_like "a valid call of .find"
262
+
263
+ end
264
+
265
+ end
266
+
267
+ end
268
+
269
+ describe "find_by..." do
270
+
271
+ subject { TeamPage.find_by_name(name, selector, filter)}
272
+ let(:selector) { ""}
273
+ let(:filter) {""}
274
+
275
+ context "no record on page" do
276
+ let(:name) {"unknown name"}
277
+
278
+ it "raises error PageRecord::RecordNotFound" do
279
+ expect{subject}.to raise_error(PageRecord::RecordNotFound)
280
+ end
281
+
282
+ end
283
+
284
+ context "multiple records on page" do
285
+ let(:name) {"Ajax"}
286
+ include_context "page with duplicate records"
287
+
288
+ it "raises error PageRecord::MultipleRecords" do
289
+ expect{subject}.to raise_error(PageRecord::MultipleRecords)
290
+ end
291
+
292
+ end
293
+
294
+ context "one record on page" do
295
+ let(:name) {"Ajax"}
296
+
297
+ it_behaves_like "a valid call of .find"
298
+ it_behaves_like "it handles filters"
299
+
300
+ end
301
+
302
+ context "multiple sets of records avialable on the page" do
303
+ include_context "page with two tables with 3 records"
304
+ let(:name) {"Ajax"}
305
+
306
+ context "without selector" do
307
+ let(:selector) {""}
308
+
309
+ it "raises error PageRecord::MultipleRecords" do
310
+ expect{subject}.to raise_error(PageRecord::MultipleRecords)
311
+ end
312
+
313
+ end
314
+
315
+ it_behaves_like "handles invalid selectors"
316
+
317
+ context "with a correct selector" do
318
+
319
+ let(:selector) {"#first-table"}
320
+ let(:name) {"Ajax"}
321
+ it_behaves_like "a valid call of .find"
322
+
323
+ end
324
+
325
+ end
326
+
327
+
328
+
329
+ end
330
+
331
+ describe "#...? " do
332
+
333
+ subject {TeamPage.find(1)}
334
+
335
+ context "attribute is on page" do
336
+
337
+ it "returns the dom object" do
338
+ expect( subject.name?.class).to eq Capybara::Node::Element
339
+ end
340
+ end
341
+
342
+ context "attribute not on page" do
343
+
344
+ it "raises error PageRecord::AttributeNotFound" do
345
+ expect{subject.goals?}.to raise_error(PageRecord::AttributeNotFound)
346
+ end
347
+
348
+ end
349
+ end
350
+
351
+ describe "#... valid attribute getter" do
352
+
353
+ subject {TeamPage.find(1)}
354
+ include_context "page with single table with 3 records"
355
+
356
+ context "attribute is on page" do
357
+
358
+ it "returns a the value on the page" do
359
+ expect( subject.name).to eq 'Ajax'
360
+ end
361
+ end
362
+
363
+ context "attribute not on page" do
364
+
365
+ it "raises error PageRecord::AttributeNotFound" do
366
+ expect{subject.goals}.to raise_error(PageRecord::AttributeNotFound)
367
+ end
368
+
369
+ end
370
+
371
+
372
+ end
373
+
374
+ describe "#... valid attribute setter" do
375
+
376
+ subject {record.name = 'FC Utrecht'}
377
+ let(:record) { TeamPage.find(1)}
378
+
379
+
380
+ context "attribute is an input field" do
381
+ include_context "page one record in a form"
382
+
383
+ it "sets the attribute to specified value" do
384
+ expect{subject}.to change{record.name}.from(nil).to('FC Utrecht')
385
+ end
386
+ end
387
+
388
+ context "attribute is an input field" do
389
+ include_context "page one record"
390
+
391
+ it "raises error PageRecord::NotInputField" do
392
+ expect{subject}.to raise_error(PageRecord::NotInputField)
393
+ end
394
+
395
+ end
396
+
397
+ end
398
+
399
+ describe "#... action methods" do
400
+
401
+ let(:record) { TeamPage.find(1)}
402
+ include_context "page one record in a form"
403
+
404
+ context "action exists on page" do
405
+ subject {record.create}
406
+
407
+ it "clicks on the specified action element" do
408
+ expect{subject}.not_to raise_error(PageRecord::NotInputField) # TODO can we make it better?
409
+ end
410
+
411
+
412
+ end
413
+
414
+ context "action doesn't exist on page" do
415
+ subject {record.unkown}
416
+
417
+ it "raises error NoMethodError" do
418
+ expect{subject}.to raise_error(NoMethodError)
419
+ end
420
+ end
421
+
422
+
423
+ end
424
+
425
+ describe "#...? action methods" do
426
+ pending
427
+ end
428
+
429
+ describe ".attributes" do
430
+ pending
431
+ end
432
+
433
+
434
+ end
@@ -0,0 +1,33 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'coveralls'
8
+ Coveralls.wear!
9
+ require 'page_record'
10
+ require 'capybara'
11
+ require 'capybara/dsl'
12
+ include Capybara::DSL
13
+
14
+ require_relative './support/test_app'
15
+ require_relative './support/team'
16
+ require_relative './support/shared_contexts'
17
+ require_relative './support/shared_examples'
18
+
19
+ Capybara.app = TestApp
20
+ Capybara.app_host = nil
21
+
22
+
23
+ RSpec.configure do |config|
24
+ config.treat_symbols_as_metadata_keys_with_true_values = true
25
+ config.run_all_when_everything_filtered = true
26
+ config.filter_run :focus
27
+
28
+ # Run specs in random order to surface order dependencies. If you find an
29
+ # order dependency and want to debug it, you can fix the order by providing
30
+ # the seed, which is printed after each run.
31
+ # --seed 1234
32
+ config.order = 'random'
33
+ end
@@ -0,0 +1,37 @@
1
+ shared_context "page with single table with 3 records" do
2
+ before do
3
+ visit "/page-with-single-table-with-3-records"
4
+ end
5
+ end
6
+
7
+ shared_context "page with two tables with 3 records" do
8
+ before do
9
+ visit "/page-with-two-tables-with-3-records"
10
+ end
11
+ end
12
+
13
+
14
+ shared_context "page without records" do
15
+ before do
16
+ visit "/page-without-records"
17
+ end
18
+ end
19
+
20
+ shared_context "page with duplicate records" do
21
+ before do
22
+ visit "/page-with-duplicate-records"
23
+ end
24
+ end
25
+
26
+ shared_context "page one record in a form" do
27
+ before do
28
+ visit "/page-one-record-in-a-form"
29
+ end
30
+ end
31
+
32
+
33
+ shared_context "page one record" do
34
+ before do
35
+ visit "/page-one-record"
36
+ end
37
+ end
@@ -0,0 +1,71 @@
1
+ shared_examples "valid call of .all" do
2
+
3
+ it "returns an Array" do
4
+ expect(subject.class).to eq Array
5
+ end
6
+
7
+ it "returns the inheriting class in the Array" do
8
+ subject.each do |record|
9
+ expect( record.class).to eq TeamPage
10
+ end
11
+ end
12
+
13
+ it "returns an element for each record on the page" do
14
+ expect( subject.count).to eq 3
15
+ end
16
+
17
+ end
18
+
19
+
20
+ shared_examples "it handles filters" do
21
+ context "specified record contains specified filter" do
22
+ let(:filter) {".champions_league"}
23
+
24
+ it_behaves_like "a valid call of .find"
25
+
26
+ end
27
+
28
+ context "specified record doesn't contain specified filter" do
29
+ let(:filter) {".euro_league"}
30
+
31
+ it "raises error PageRecord::RecordNotFound" do
32
+ expect{subject}.to raise_error(PageRecord::RecordNotFound)
33
+ end
34
+ end
35
+ end
36
+
37
+
38
+ shared_examples "handles invalid selectors" do
39
+ context "with an non existing selector" do
40
+
41
+ let(:selector) {"#non-existing-table"}
42
+ let(:filter) {""}
43
+
44
+
45
+ it "raises error PageRecord::RecordNotFound" do
46
+ expect{subject}.to raise_error(PageRecord::RecordNotFound)
47
+ end
48
+ end
49
+
50
+ context "with an undetermined selector" do
51
+
52
+ let(:selector) {".team-table"}
53
+ let(:filter) {""}
54
+
55
+
56
+ it "raises error PageRecord::MultipleRecords" do
57
+ expect{subject}.to raise_error(PageRecord::MultipleRecords)
58
+ end
59
+
60
+ end
61
+ end
62
+
63
+ shared_examples "a valid call of .find" do
64
+ it "returns the inheriting class" do
65
+ expect(subject.class).to eq TeamPage
66
+ end
67
+
68
+ it "returns the record identified by the id" do
69
+ expect(subject.id).to eq '1'
70
+ end
71
+ end
@@ -0,0 +1,6 @@
1
+ # @private This is just a class for testing
2
+ class Team
3
+ def self.attribute_names
4
+ [ 'id' , 'name', 'points', 'ranking', 'goals']
5
+ end
6
+ end
@@ -0,0 +1,24 @@
1
+ require 'sinatra/base'
2
+
3
+
4
+ # @private This is just a test class
5
+ class TestApp < Sinatra::Base
6
+
7
+ set :root, File.dirname(__FILE__)
8
+ set :raise_errors, true
9
+ # set :show_exceptions, false
10
+
11
+
12
+ get '/*' do
13
+ viewname = params[:splat].first # eg "some/path/here"
14
+ if File.exist?("#{settings.root}/views/#{viewname}.erb")
15
+ erb :"#{viewname}"
16
+ else
17
+ "can't find view #{viewname}"
18
+ end
19
+ end
20
+ end
21
+
22
+ if __FILE__ == $0
23
+ Rack::Handler::WEBrick.run TestApp, :Port => 8070
24
+ end
@@ -0,0 +1,4 @@
1
+ <form data-team-id='1'>
2
+ <input data-attribute-for='name'>
3
+ <button data-action-for='create'>
4
+ </form>
@@ -0,0 +1,3 @@
1
+ <div data-team-id='1'>
2
+ <div data-attribute-for='name'></div>
3
+ </div>
@@ -0,0 +1,8 @@
1
+ <table>
2
+ <tr data-team-id='1'>
3
+ <td data-attribute-for='name'>Ajax</td>
4
+ </tr>
5
+ <tr data-team-id='1'>
6
+ <td data-attribute-for='name'>Ajax</td>
7
+ </tr>
8
+ </table>
@@ -0,0 +1,17 @@
1
+ <table>
2
+ <tr data-team-id='1' class='champions_league'>
3
+ <td data-attribute-for='ranking'>1</td>
4
+ <td data-attribute-for='name'>Ajax</td>
5
+ <td data-attribute-for='points'>10</td>
6
+ </tr>
7
+ <tr data-team-id='2' class='champions_league'>
8
+ <td data-attribute-for='ranking'>2</td>
9
+ <td data-attribute-for='name'>PSV</td>
10
+ <td data-attribute-for='points'>8</td>
11
+ </tr>
12
+ <tr data-team-id='3'>
13
+ <td data-attribute-for='ranking'>3</td>
14
+ <td data-attribute-for='name'>Feijenoord</td>
15
+ <td data-attribute-for='points'>6</td>
16
+ </tr>
17
+ </table>
@@ -0,0 +1,38 @@
1
+ <div class='team-table'>
2
+ <table id='first-table'>
3
+ <tr data-team-id='1' class='champions_league'>
4
+ <td data-attribute-for='ranking'>1</td>
5
+ <td data-attribute-for='name'>Ajax</td>
6
+ <td data-attribute-for='points'>10</td>
7
+ </tr>
8
+ <tr data-team-id='2' class='champions_league'>
9
+ <td data-attribute-for='ranking'>2</td>
10
+ <td data-attribute-for='name'>PSV</td>
11
+ <td data-attribute-for='points'>8</td>
12
+ </tr>
13
+ <tr data-team-id='3' class='euro_league'>
14
+ <td data-attribute-for='ranking'>3</td>
15
+ <td data-attribute-for='name'>Feijenoord</td>
16
+ <td data-attribute-for='points'>6</td>
17
+ </tr>
18
+ </table>
19
+ </div>
20
+ <div class='team-table'>
21
+ <table id='second-table'>
22
+ <tr data-team-id='1' class='champions_league'>
23
+ <td data-attribute-for='ranking'>1</td>
24
+ <td data-attribute-for='name'>Ajax</td>
25
+ <td data-attribute-for='points'>10</td>
26
+ </tr>
27
+ <tr data-team-id='2' class='champions_league'>
28
+ <td data-attribute-for='ranking'>2</td>
29
+ <td data-attribute-for='name'>PSV</td>
30
+ <td data-attribute-for='points'>8</td>
31
+ </tr>
32
+ <tr data-team-id='3' class='euro_league'>
33
+ <td data-attribute-for='ranking'>3</td>
34
+ <td data-attribute-for='name'>Feijenoord</td>
35
+ <td data-attribute-for='points'>6</td>
36
+ </tr>
37
+ </table>
38
+ </div>
@@ -0,0 +1,2 @@
1
+ <table>
2
+ </table