page_record 0.0.1

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.
@@ -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