page_magic 1.2.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +23 -4
  3. data/.simplecov +5 -3
  4. data/.zsh_config +6 -0
  5. data/Dockerfile +11 -0
  6. data/Gemfile +13 -13
  7. data/Gemfile.lock +135 -144
  8. data/Makefile +17 -0
  9. data/README.md +48 -4
  10. data/Rakefile +12 -2
  11. data/VERSION +1 -1
  12. data/circle.yml +4 -2
  13. data/lib/active_support/core_ext/object/to_query.rb +84 -0
  14. data/lib/page_magic.rb +22 -20
  15. data/lib/page_magic/class_methods.rb +5 -2
  16. data/lib/page_magic/comparator.rb +37 -0
  17. data/lib/page_magic/comparator/fuzzy.rb +23 -0
  18. data/lib/page_magic/comparator/literal.rb +22 -0
  19. data/lib/page_magic/comparator/null.rb +26 -0
  20. data/lib/page_magic/comparator/parameter_map.rb +52 -0
  21. data/lib/page_magic/driver.rb +3 -0
  22. data/lib/page_magic/drivers.rb +6 -5
  23. data/lib/page_magic/drivers/poltergeist.rb +2 -0
  24. data/lib/page_magic/drivers/rack_test.rb +3 -1
  25. data/lib/page_magic/drivers/selenium.rb +4 -2
  26. data/lib/page_magic/element.rb +35 -15
  27. data/lib/page_magic/element/locators.rb +8 -5
  28. data/lib/page_magic/element/not_found.rb +38 -0
  29. data/lib/page_magic/element/query.rb +21 -20
  30. data/lib/page_magic/element/query/multiple_results.rb +21 -0
  31. data/lib/page_magic/element/query/prefetched_result.rb +26 -0
  32. data/lib/page_magic/element/query/single_result.rb +20 -0
  33. data/lib/page_magic/element/selector.rb +41 -16
  34. data/lib/page_magic/element/selector/methods.rb +18 -0
  35. data/lib/page_magic/element/selector/model.rb +21 -0
  36. data/lib/page_magic/element_context.rb +7 -21
  37. data/lib/page_magic/element_definition_builder.rb +20 -24
  38. data/lib/page_magic/elements.rb +65 -68
  39. data/lib/page_magic/elements/config.rb +103 -0
  40. data/lib/page_magic/elements/inheritance_hooks.rb +15 -0
  41. data/lib/page_magic/elements/types.rb +25 -0
  42. data/lib/page_magic/exceptions.rb +6 -1
  43. data/lib/page_magic/instance_methods.rb +8 -3
  44. data/lib/page_magic/mapping.rb +79 -0
  45. data/lib/page_magic/session.rb +15 -35
  46. data/lib/page_magic/session_methods.rb +3 -1
  47. data/lib/page_magic/transitions.rb +49 -0
  48. data/lib/page_magic/utils/string.rb +18 -0
  49. data/lib/page_magic/utils/url.rb +20 -0
  50. data/lib/page_magic/wait_methods.rb +3 -0
  51. data/lib/page_magic/watcher.rb +12 -17
  52. data/lib/page_magic/watchers.rb +31 -15
  53. data/page_magic.gemspec +17 -13
  54. data/spec/lib/active_support/core_ext/object/to_query_test.rb +78 -0
  55. data/spec/page_magic/class_methods_spec.rb +66 -37
  56. data/spec/page_magic/comparator/fuzzy_spec.rb +44 -0
  57. data/spec/page_magic/comparator/literal_spec.rb +41 -0
  58. data/spec/page_magic/comparator/null_spec.rb +35 -0
  59. data/spec/page_magic/comparator/parameter_map_spec.rb +75 -0
  60. data/spec/page_magic/driver_spec.rb +26 -28
  61. data/spec/page_magic/drivers/poltergeist_spec.rb +6 -7
  62. data/spec/page_magic/drivers/rack_test_spec.rb +6 -9
  63. data/spec/page_magic/drivers/selenium_spec.rb +11 -12
  64. data/spec/page_magic/drivers_spec.rb +38 -29
  65. data/spec/page_magic/element/locators_spec.rb +28 -25
  66. data/spec/page_magic/element/not_found_spec.rb +24 -0
  67. data/spec/page_magic/element/query/multiple_results_spec.rb +14 -0
  68. data/spec/page_magic/element/query/single_result_spec.rb +21 -0
  69. data/spec/page_magic/element/query_spec.rb +26 -45
  70. data/spec/page_magic/element/selector_spec.rb +120 -110
  71. data/spec/page_magic/element_context_spec.rb +47 -87
  72. data/spec/page_magic/element_definition_builder_spec.rb +14 -71
  73. data/spec/page_magic/element_spec.rb +256 -0
  74. data/spec/page_magic/elements/config_spec.rb +200 -0
  75. data/spec/page_magic/elements_spec.rb +90 -127
  76. data/spec/page_magic/instance_methods_spec.rb +65 -63
  77. data/spec/page_magic/mapping_spec.rb +181 -0
  78. data/spec/page_magic/session_methods_spec.rb +29 -25
  79. data/spec/page_magic/session_spec.rb +109 -199
  80. data/spec/page_magic/transitions_spec.rb +43 -0
  81. data/spec/page_magic/utils/string_spec.rb +29 -0
  82. data/spec/page_magic/utils/url_spec.rb +9 -0
  83. data/spec/page_magic/wait_methods_spec.rb +16 -22
  84. data/spec/page_magic/watcher_spec.rb +22 -0
  85. data/spec/page_magic/watchers_spec.rb +58 -62
  86. data/spec/page_magic_spec.rb +31 -30
  87. data/spec/spec_helper.rb +9 -2
  88. data/spec/support/shared_contexts.rb +3 -1
  89. data/spec/support/shared_examples.rb +17 -17
  90. metadata +101 -48
  91. data/lib/page_magic/element/query_builder.rb +0 -48
  92. data/lib/page_magic/element/selector_methods.rb +0 -13
  93. data/lib/page_magic/matcher.rb +0 -121
  94. data/spec/element_spec.rb +0 -249
  95. data/spec/page_magic/element/query_builder_spec.rb +0 -108
  96. data/spec/page_magic/matcher_spec.rb +0 -336
  97. data/spec/support/shared_contexts/files_context.rb +0 -7
  98. data/spec/support/shared_contexts/nested_elements_html_context.rb +0 -16
  99. data/spec/support/shared_contexts/rack_application_context.rb +0 -9
  100. data/spec/support/shared_contexts/webapp_fixture_context.rb +0 -39
  101. data/spec/watcher_spec.rb +0 -61
@@ -1,36 +1,40 @@
1
- module PageMagic
2
- describe SessionMethods do
3
- include_context :webapp_fixture
4
- let(:session) { PageMagic.session(application: rack_app, url: '/page1') }
5
- subject do
6
- OpenStruct.new(session: session).tap do |o|
7
- o.extend(described_class)
8
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+ RSpec.describe PageMagic::SessionMethods do
5
+ subject(:session_methods) do
6
+ OpenStruct.new(session: session).tap do |o|
7
+ o.extend(described_class)
9
8
  end
9
+ end
10
+
11
+ let(:session) do
12
+ rack_app = instance_double(Proc, call: [200, {}, ['<html><head><title>page1</title></head></html>']])
13
+ PageMagic.session(application: rack_app, url: '/page1')
14
+ end
10
15
 
11
- describe '#execute_script' do
12
- it 'returns the output of Session#execute_script' do
13
- expect(session.raw_session).to receive(:execute_script).with(:script).and_return(:result)
14
- expect(subject.execute_script(:script)).to eq(:result)
15
- end
16
+ describe '#execute_script' do
17
+ it 'returns the output of Session#execute_script' do
18
+ allow(session.raw_session).to receive(:execute_script).with(:script).and_return(:result)
19
+ expect(session_methods.execute_script(:script)).to eq(:result)
16
20
  end
21
+ end
17
22
 
18
- describe '#page' do
19
- it 'returns the current page of the session' do
20
- expect(subject.page).to eq(session.current_page)
21
- end
23
+ describe '#page' do
24
+ it 'returns the current page of the session' do
25
+ expect(session_methods.page).to eq(session.current_page)
22
26
  end
27
+ end
23
28
 
24
- describe '#path' do
25
- it 'returns the path of the session' do
26
- expect(subject.path).to eq(session.current_path)
27
- end
29
+ describe '#path' do
30
+ it 'returns the path of the session' do
31
+ expect(session_methods.path).to eq(session.current_path)
28
32
  end
33
+ end
29
34
 
30
- describe '#url' do
31
- it 'returns the url of the session' do
32
- expect(subject.url).to eq(session.current_url)
33
- end
35
+ describe '#url' do
36
+ it 'returns the url of the session' do
37
+ expect(session_methods.url).to eq(session.current_url)
34
38
  end
35
39
  end
36
40
  end
@@ -1,254 +1,164 @@
1
- # rubocop:disable Metrics/ModuleLength
2
- module PageMagic
3
- describe Session do
4
- let(:page) do
5
- Class.new do
6
- include PageMagic
7
- url 'http://url.com'
8
- end
9
- end
10
-
11
- subject { described_class.new(browser) }
1
+ # frozen_string_literal: true
12
2
 
13
- let(:url) { page.url }
14
- let(:browser) { double('browser', current_url: "#{url}/somepath", visit: nil, current_path: :current_path) }
3
+ RSpec.describe PageMagic::Session do
4
+ subject(:session) { described_class.new(browser, 'http://base.url') }
15
5
 
16
- describe '#current_page' do
17
- let(:another_page_class) do
18
- Class.new do
19
- include PageMagic
20
- url 'http://www.example.com/another_page1'
21
- end
22
- end
6
+ let(:page) do
7
+ Class.new do
8
+ include PageMagic
9
+ end
10
+ end
23
11
 
24
- before do
25
- subject.define_page_mappings '/another_page1' => another_page_class
26
- subject.visit(page, url: url)
12
+ let(:browser) do
13
+ rack_application = Class.new do
14
+ def self.call(_env)
15
+ [200, {}, ['ok']]
27
16
  end
17
+ end
28
18
 
29
- context 'page url has not changed' do
30
- it 'returns the original page' do
31
- allow(browser).to receive(:current_url).and_return(page.url)
32
- expect(subject.current_page).to be_an_instance_of(page)
33
- end
34
- end
19
+ Capybara::Session.new(:rack_test, rack_application)
20
+ end
35
21
 
36
- context 'page url has changed' do
37
- it 'returns the mapped page object' do
38
- allow(browser).to receive(:current_url).and_return(another_page_class.url)
39
- expect(subject.current_page).to be_an_instance_of(another_page_class)
40
- end
22
+ describe '#current_page' do
23
+ let(:another_page_class) do
24
+ Class.new do
25
+ include PageMagic
41
26
  end
42
27
  end
43
28
 
44
- describe '#current_path' do
45
- it "returns the browser's current path" do
46
- expect(subject.current_path).to eq(browser.current_path)
47
- end
29
+ it 'returns the current page' do
30
+ session.visit(page, url: 'http://base.url')
31
+ expect(session.current_page).to be_an_instance_of(page)
48
32
  end
49
33
 
50
- describe '#current_url' do
51
- it "returns the browser's current url" do
52
- expect(subject.current_url).to eq(browser.current_url)
34
+ context 'when the page url has changed' do
35
+ it 'returns the mapped page object' do
36
+ session.define_page_mappings '/another_page1' => another_page_class
37
+ browser.visit('/another_page1')
38
+ expect(session.current_page).to be_an_instance_of(another_page_class)
53
39
  end
54
40
  end
41
+ end
55
42
 
56
- describe '#define_page_mappings' do
57
- context 'mapping includes a literal' do
58
- it 'creates a matcher to contain the specification' do
59
- subject.define_page_mappings path: :page
60
- expect(subject.transitions).to eq(Matcher.new(:path) => :page)
61
- end
62
- end
43
+ describe '#current_path' do
44
+ it "returns the browser's current path" do
45
+ browser.visit('/url')
46
+ expect(session.current_path).to eq(browser.current_path)
47
+ end
48
+ end
63
49
 
64
- context 'mapping is a matcher' do
65
- it 'leaves it intact' do
66
- expected_matcher = Matcher.new(:page)
67
- subject.define_page_mappings expected_matcher => :page
68
- expect(subject.transitions.key(:page)).to be(expected_matcher)
69
- end
70
- end
50
+ describe '#current_url' do
51
+ it "returns the browser's current url" do
52
+ browser.visit('/url')
53
+ expect(session.current_url).to eq(session.current_url)
71
54
  end
55
+ end
72
56
 
73
- describe '#execute_script' do
74
- it 'calls the execute script method on the capybara session' do
75
- expect(browser).to receive(:execute_script).with(:script).and_return(:result)
76
- expect(subject.execute_script(:script)).to be(:result)
57
+ describe '#define_page_mappings' do
58
+ context 'when the mapping includes a literal' do
59
+ it 'creates a matcher to contain the specification' do
60
+ session.define_page_mappings path: :page
61
+ expect(session.transitions.to_h).to include(PageMagic::Mapping.new(:path) => :page)
77
62
  end
63
+ end
78
64
 
79
- context 'Capybara session does not support #execute_script' do
80
- let(:browser) { Capybara::Driver::Base.new }
81
- it 'raises an error' do
82
- expected_message = described_class::UNSUPPORTED_OPERATION_MSG
83
- expect { subject.execute_script(:script) }.to raise_error(NotSupportedException, expected_message)
84
- end
65
+ context 'when the mapping is a matcher' do
66
+ it 'leaves it intact' do
67
+ expected_matcher = PageMagic::Mapping.new(:page)
68
+ session.define_page_mappings expected_matcher => :page
69
+ expect(session.transitions.key(:page)).to be(expected_matcher)
85
70
  end
86
71
  end
72
+ end
87
73
 
88
- describe '#find_mapped_page' do
89
- subject do
90
- described_class.new(nil)
91
- end
74
+ describe '#execute_script' do
75
+ it 'calls the execute script method on the capybara session' do
76
+ allow(browser).to receive(:execute_script).with(:script).and_return(:result)
77
+ expect(session.execute_script(:script)).to be(:result)
78
+ end
92
79
 
93
- context 'match found' do
94
- it 'returns the page class' do
95
- subject.define_page_mappings '/page' => :mapped_page_using_string
96
- expect(subject.instance_eval { find_mapped_page('/page') }).to be(:mapped_page_using_string)
97
- end
80
+ context 'when the Capybara session does not support #execute_script' do
81
+ let(:browser) { Capybara::Driver::Base.new }
98
82
 
99
- context 'more than one match is found' do
100
- it 'returns the most specific match' do
101
- subject.define_page_mappings %r{/page} => :mapped_page_using_regex, '/page' => :mapped_page_using_string
102
- expect(subject.instance_eval { find_mapped_page('/page') }).to eq(:mapped_page_using_string)
103
- end
104
- end
83
+ it 'raises an error' do
84
+ expected_message = described_class::UNSUPPORTED_OPERATION_MSG
85
+ expect { session.execute_script(:script) }.to raise_error(PageMagic::NotSupportedException, expected_message)
105
86
  end
87
+ end
88
+ end
106
89
 
107
- context 'mapping is not found' do
108
- it 'returns nil' do
109
- expect(subject.instance_eval { find_mapped_page('/fake_page') }).to be(nil)
90
+ describe '#method_missing' do
91
+ before do
92
+ page.class_eval do
93
+ def my_method
94
+ :called
110
95
  end
111
96
  end
112
97
  end
113
98
 
114
- describe '#matches' do
115
- subject do
116
- described_class.new(nil)
117
- end
118
-
119
- it 'returns matching page mappings' do
120
- subject.define_page_mappings '/page' => :mapped_page_using_string
121
- expect(subject.instance_eval { matches('/page') }).to eq([:mapped_page_using_string])
122
- end
99
+ it 'delegates to current page' do
100
+ session = described_class.new(browser).visit(page, url: 'http://base.url')
101
+ expect(session.my_method).to be(:called)
102
+ end
103
+ end
123
104
 
124
- context 'more than one match on path' do
125
- it 'orders the results by specificity ' do
126
- subject.define_page_mappings %r{/page} => :mapped_page_using_regex, '/page' => :mapped_page_using_string
127
- expected_result = [:mapped_page_using_string, :mapped_page_using_regex]
128
- expect(subject.instance_eval { matches('/page') }).to eq(expected_result)
129
- end
130
- end
105
+ describe '#respond_to?' do
106
+ it 'checks self' do
107
+ session = described_class.new(browser)
108
+ expect(session.respond_to?(:current_url)).to eq(true)
131
109
  end
132
110
 
133
- describe '#method_missing' do
134
- it 'should delegate to current page' do
111
+ context 'when method is not on self' do
112
+ before do
135
113
  page.class_eval do
136
114
  def my_method
137
115
  :called
138
116
  end
139
117
  end
140
-
141
- session = PageMagic::Session.new(browser).visit(page, url: url)
142
- expect(session.my_method).to be(:called)
143
- end
144
- end
145
-
146
- context '#respond_to?' do
147
- subject do
148
- PageMagic::Session.new(browser).tap do |s|
149
- allow(s).to receive(:current_page).and_return(page.new)
150
- end
151
- end
152
- it 'checks self' do
153
- expect(subject.respond_to?(:current_url)).to eq(true)
154
118
  end
155
119
 
156
120
  it 'checks the current page' do
157
- page.class_eval do
158
- def my_method
159
- end
160
- end
161
- expect(subject.respond_to?(:my_method)).to eq(true)
121
+ session = described_class.new(browser)
122
+ session.visit(page, url: '/')
123
+ expect(session.respond_to?(:my_method)).to eq(true)
162
124
  end
163
125
  end
126
+ end
164
127
 
165
- describe '#url' do
166
- let!(:base_url) { 'http://example.com' }
167
- let!(:path) { 'home' }
168
- let!(:expected_url) { "#{base_url}/#{path}" }
169
-
170
- context 'base_url has a / on the end' do
171
- before do
172
- base_url << '/'
173
- end
174
-
175
- context 'path has / at the beginning' do
176
- it 'produces compound url' do
177
- expect(subject.send(:url, base_url, path)).to eq(expected_url)
178
- end
179
- end
180
-
181
- context 'path does not have / at the beginning' do
182
- it 'produces compound url' do
183
- expect(subject.send(:url, base_url, "/#{path}")).to eq(expected_url)
184
- end
185
- end
186
- end
187
-
188
- context 'current_url does not have a / on the end' do
189
- context 'path has / at the beginning' do
190
- it 'produces compound url' do
191
- expect(subject.send(:url, base_url, "/#{path}")).to eq(expected_url)
192
- end
193
- end
194
-
195
- context 'path does not have / at the beginning' do
196
- it 'produces compound url' do
197
- expect(subject.send(:url, base_url, path)).to eq(expected_url)
198
- end
199
- end
128
+ describe '#visit' do
129
+ context 'when a page is supplied' do
130
+ it 'sets the current page' do
131
+ session.define_page_mappings '/page' => page
132
+ session.visit(page)
133
+ expect(session.current_page).to be_a(page)
200
134
  end
201
- end
202
135
 
203
- describe '#visit' do
204
- let(:session) do
205
- allow(browser).to receive(:visit)
206
- PageMagic::Session.new(browser, url)
136
+ it 'uses the base url and the path in the page mappings' do
137
+ session = described_class.new(browser, 'http://base.url')
138
+ session.define_page_mappings '/page' => page
139
+ session.visit(page)
140
+ expect(session.current_url).to eq('http://base.url/page')
207
141
  end
208
142
 
209
- context 'page supplied' do
210
- it 'sets the current page' do
211
- session.define_page_mappings '/page' => page
143
+ it 'raises an error when page no page mappings are found' do
144
+ expect do
212
145
  session.visit(page)
213
- expect(session.current_page).to be_a(page)
214
- end
215
-
216
- it 'uses the base url and the path in the page mappings' do
217
- session.define_page_mappings '/page' => page
218
- expect(browser).to receive(:visit).with("#{url}/page")
219
- session.visit(page)
220
- end
221
-
222
- context 'no mappings found' do
223
- it 'raises an error' do
224
- expect { session.visit(page) }.to raise_exception InvalidURLException, described_class::URL_MISSING_MSG
225
- end
226
- end
227
-
228
- context 'mapping is a regular expression' do
229
- it 'raises an error' do
230
- session.define_page_mappings(/mapping/ => page)
231
- expect { session.visit(page) }.to raise_exception InvalidURLException, described_class::REGEXP_MAPPING_MSG
232
- end
233
- end
146
+ end.to raise_exception PageMagic::InvalidURLException, described_class::URL_MISSING_MSG
147
+ end
234
148
 
235
- it 'calls the onload hook' do
236
- on_load_hook_called = false
237
- page.on_load do
238
- on_load_hook_called = true
239
- end
240
- session.define_page_mappings('/page' => page)
241
- session.visit(page)
242
- expect(on_load_hook_called).to eq(true)
243
- end
149
+ it 'calls the onload hook' do
150
+ on_load_hook_called = false
151
+ page.on_load { on_load_hook_called = true }
152
+ session.visit(page, url: 'http://base.url')
153
+ expect(on_load_hook_called).to eq(true)
244
154
  end
155
+ end
245
156
 
246
- context 'url supplied' do
247
- it 'visits that url' do
248
- expected_url = 'http://url.com/page'
249
- expect(browser).to receive(:visit).with(expected_url)
250
- session.visit(url: expected_url)
251
- end
157
+ context 'when `url` is supplied' do
158
+ it 'visits that url' do
159
+ expected_url = 'http://base.url/page'
160
+ session.visit(url: expected_url)
161
+ expect(browser.current_url).to eq(expected_url)
252
162
  end
253
163
  end
254
164
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe PageMagic::Transitions do
4
+ describe '#mapped_page' do
5
+ context 'when a match is match found' do
6
+ it 'returns the page class' do
7
+ mappings = described_class.new('/page' => :mapped_page_using_string)
8
+ expect(mappings.mapped_page('/page')).to be(:mapped_page_using_string)
9
+ end
10
+ end
11
+
12
+ context 'when more than one match is found' do
13
+ it 'returns the most specific match' do
14
+ mappings = described_class.new(%r{/page} => :mapped_page_using_regex, '/page' => :mapped_page_using_string)
15
+ expect(mappings.mapped_page('/page')).to eq(:mapped_page_using_string)
16
+ end
17
+ end
18
+
19
+ context 'when a mapping is not found' do
20
+ it 'returns nil' do
21
+ mappings = described_class.new({})
22
+ expect(mappings.mapped_page('/unmapped_page')).to be(nil)
23
+ end
24
+ end
25
+ end
26
+
27
+ describe '#url_for' do
28
+ it 'returns the url for the mapped page' do
29
+ page = Object.new
30
+ mappings = described_class.new('/mapping' => page)
31
+ expect(mappings.url_for(page, base_url: 'http://base.url')).to eq('http://base.url/mapping')
32
+ end
33
+
34
+ context 'when page mapping is a regular expression' do
35
+ it 'raises an error' do
36
+ page = Object.new
37
+ mappings = described_class.new(/mapping/ => page)
38
+ expect { mappings.url_for(page, base_url: 'http://base.url') }
39
+ .to raise_exception PageMagic::InvalidURLException, described_class::REGEXP_MAPPING_MSG
40
+ end
41
+ end
42
+ end
43
+ end