page_magic 2.0.0.alpha1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -2
  3. data/.zsh_config +5 -5
  4. data/Dockerfile +2 -1
  5. data/Gemfile +2 -1
  6. data/Gemfile.lock +9 -5
  7. data/Makefile +7 -3
  8. data/README.md +16 -4
  9. data/VERSION +1 -1
  10. data/lib/active_support/core_ext/object/to_query.rb +6 -6
  11. data/lib/page_magic.rb +15 -16
  12. data/lib/page_magic/class_methods.rb +1 -1
  13. data/lib/page_magic/comparator.rb +37 -0
  14. data/lib/page_magic/comparator/fuzzy.rb +23 -0
  15. data/lib/page_magic/comparator/literal.rb +22 -0
  16. data/lib/page_magic/comparator/null.rb +26 -0
  17. data/lib/page_magic/comparator/parameter_map.rb +52 -0
  18. data/lib/page_magic/drivers.rb +2 -2
  19. data/lib/page_magic/element.rb +19 -8
  20. data/lib/page_magic/element/locators.rb +4 -4
  21. data/lib/page_magic/element/not_found.rb +38 -0
  22. data/lib/page_magic/element/query.rb +19 -27
  23. data/lib/page_magic/element/query/multiple_results.rb +21 -0
  24. data/lib/page_magic/element/query/prefetched_result.rb +26 -0
  25. data/lib/page_magic/element/query/single_result.rb +20 -0
  26. data/lib/page_magic/element/selector.rb +38 -16
  27. data/lib/page_magic/element/selector/methods.rb +18 -0
  28. data/lib/page_magic/element/selector/model.rb +21 -0
  29. data/lib/page_magic/element_context.rb +5 -21
  30. data/lib/page_magic/element_definition_builder.rb +17 -24
  31. data/lib/page_magic/elements.rb +62 -102
  32. data/lib/page_magic/elements/config.rb +103 -0
  33. data/lib/page_magic/elements/inheritance_hooks.rb +15 -0
  34. data/lib/page_magic/elements/types.rb +25 -0
  35. data/lib/page_magic/exceptions.rb +3 -0
  36. data/lib/page_magic/instance_methods.rb +2 -2
  37. data/lib/page_magic/mapping.rb +79 -0
  38. data/lib/page_magic/session.rb +10 -32
  39. data/lib/page_magic/session_methods.rb +1 -1
  40. data/lib/page_magic/transitions.rb +49 -0
  41. data/lib/page_magic/utils/string.rb +4 -0
  42. data/lib/page_magic/utils/url.rb +20 -0
  43. data/lib/page_magic/watcher.rb +10 -17
  44. data/lib/page_magic/watchers.rb +28 -15
  45. data/spec/page_magic/class_methods_spec.rb +64 -37
  46. data/spec/page_magic/comparator/fuzzy_spec.rb +44 -0
  47. data/spec/page_magic/comparator/literal_spec.rb +41 -0
  48. data/spec/page_magic/comparator/null_spec.rb +35 -0
  49. data/spec/page_magic/comparator/parameter_map_spec.rb +75 -0
  50. data/spec/page_magic/driver_spec.rb +25 -29
  51. data/spec/page_magic/drivers/poltergeist_spec.rb +4 -7
  52. data/spec/page_magic/drivers/rack_test_spec.rb +4 -9
  53. data/spec/page_magic/drivers/selenium_spec.rb +9 -12
  54. data/spec/page_magic/drivers_spec.rb +36 -29
  55. data/spec/page_magic/element/locators_spec.rb +26 -25
  56. data/spec/page_magic/element/not_found_spec.rb +24 -0
  57. data/spec/page_magic/element/query/multiple_results_spec.rb +14 -0
  58. data/spec/page_magic/element/query/single_result_spec.rb +21 -0
  59. data/spec/page_magic/element/query_spec.rb +26 -47
  60. data/spec/page_magic/element/selector_spec.rb +118 -110
  61. data/spec/page_magic/element_context_spec.rb +46 -88
  62. data/spec/page_magic/element_definition_builder_spec.rb +12 -71
  63. data/spec/page_magic/element_spec.rb +256 -0
  64. data/spec/page_magic/elements/config_spec.rb +200 -0
  65. data/spec/page_magic/elements_spec.rb +87 -138
  66. data/spec/page_magic/instance_methods_spec.rb +63 -63
  67. data/spec/page_magic/mapping_spec.rb +181 -0
  68. data/spec/page_magic/session_methods_spec.rb +27 -25
  69. data/spec/page_magic/session_spec.rb +109 -198
  70. data/spec/page_magic/transitions_spec.rb +43 -0
  71. data/spec/page_magic/utils/string_spec.rb +20 -27
  72. data/spec/page_magic/utils/url_spec.rb +9 -0
  73. data/spec/page_magic/wait_methods_spec.rb +14 -22
  74. data/spec/page_magic/watcher_spec.rb +22 -0
  75. data/spec/page_magic/watchers_spec.rb +56 -62
  76. data/spec/page_magic_spec.rb +27 -24
  77. data/spec/spec_helper.rb +7 -3
  78. data/spec/support/shared_examples.rb +15 -17
  79. metadata +48 -15
  80. data/lib/page_magic/element/query_builder.rb +0 -61
  81. data/lib/page_magic/element/selector_methods.rb +0 -16
  82. data/lib/page_magic/matcher.rb +0 -130
  83. data/spec/element_spec.rb +0 -251
  84. data/spec/page_magic/element/query_builder_spec.rb +0 -110
  85. data/spec/page_magic/matcher_spec.rb +0 -338
  86. data/spec/support/shared_contexts/files_context.rb +0 -9
  87. data/spec/support/shared_contexts/nested_elements_html_context.rb +0 -18
  88. data/spec/support/shared_contexts/rack_application_context.rb +0 -11
  89. data/spec/support/shared_contexts/webapp_fixture_context.rb +0 -41
  90. data/spec/watcher_spec.rb +0 -64
@@ -1,38 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module PageMagic
4
- describe SessionMethods do
5
- include_context :webapp_fixture
6
- let(:session) { PageMagic.session(application: rack_app, url: '/page1') }
7
- subject do
8
- OpenStruct.new(session: session).tap do |o|
9
- o.extend(described_class)
10
- end
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)
11
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
12
15
 
13
- describe '#execute_script' do
14
- it 'returns the output of Session#execute_script' do
15
- expect(session.raw_session).to receive(:execute_script).with(:script).and_return(:result)
16
- expect(subject.execute_script(:script)).to eq(:result)
17
- 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)
18
20
  end
21
+ end
19
22
 
20
- describe '#page' do
21
- it 'returns the current page of the session' do
22
- expect(subject.page).to eq(session.current_page)
23
- 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)
24
26
  end
27
+ end
25
28
 
26
- describe '#path' do
27
- it 'returns the path of the session' do
28
- expect(subject.path).to eq(session.current_path)
29
- end
29
+ describe '#path' do
30
+ it 'returns the path of the session' do
31
+ expect(session_methods.path).to eq(session.current_path)
30
32
  end
33
+ end
31
34
 
32
- describe '#url' do
33
- it 'returns the url of the session' do
34
- expect(subject.url).to eq(session.current_url)
35
- end
35
+ describe '#url' do
36
+ it 'returns the url of the session' do
37
+ expect(session_methods.url).to eq(session.current_url)
36
38
  end
37
39
  end
38
40
  end
@@ -1,253 +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 = %i[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; end
159
- end
160
- 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)
161
124
  end
162
125
  end
126
+ end
163
127
 
164
- describe '#url' do
165
- let!(:base_url) { "http://example.com" }
166
- let!(:path) { 'home' }
167
- let!(:expected_url) { "#{base_url}/#{path}" }
168
-
169
- context 'base_url has a / on the end' do
170
- before do
171
- base_url << '/'
172
- end
173
-
174
- context 'path has / at the beginning' do
175
- it 'produces compound url' do
176
- expect(subject.send(:url, base_url, path)).to eq(expected_url)
177
- end
178
- end
179
-
180
- context 'path does not have / at the beginning' do
181
- it 'produces compound url' do
182
- expect(subject.send(:url, base_url, "/#{path}")).to eq(expected_url)
183
- end
184
- end
185
- end
186
-
187
- context 'current_url does not have a / on the end' do
188
- context 'path has / at the beginning' do
189
- it 'produces compound url' do
190
- expect(subject.send(:url, base_url, "/#{path}")).to eq(expected_url)
191
- end
192
- end
193
-
194
- context 'path does not have / at the beginning' do
195
- it 'produces compound url' do
196
- expect(subject.send(:url, base_url, path)).to eq(expected_url)
197
- end
198
- 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)
199
134
  end
200
- end
201
135
 
202
- describe '#visit' do
203
- let(:session) do
204
- allow(browser).to receive(:visit)
205
- 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')
206
141
  end
207
142
 
208
- context 'page supplied' do
209
- it 'sets the current page' do
210
- session.define_page_mappings '/page' => page
143
+ it 'raises an error when page no page mappings are found' do
144
+ expect do
211
145
  session.visit(page)
212
- expect(session.current_page).to be_a(page)
213
- end
214
-
215
- it 'uses the base url and the path in the page mappings' do
216
- session.define_page_mappings '/page' => page
217
- expect(browser).to receive(:visit).with("#{url}/page")
218
- session.visit(page)
219
- end
220
-
221
- context 'no mappings found' do
222
- it 'raises an error' do
223
- expect { session.visit(page) }.to raise_exception InvalidURLException, described_class::URL_MISSING_MSG
224
- end
225
- end
226
-
227
- context 'mapping is a regular expression' do
228
- it 'raises an error' do
229
- session.define_page_mappings(/mapping/ => page)
230
- expect { session.visit(page) }.to raise_exception InvalidURLException, described_class::REGEXP_MAPPING_MSG
231
- end
232
- end
146
+ end.to raise_exception PageMagic::InvalidURLException, described_class::URL_MISSING_MSG
147
+ end
233
148
 
234
- it 'calls the onload hook' do
235
- on_load_hook_called = false
236
- page.on_load do
237
- on_load_hook_called = true
238
- end
239
- session.define_page_mappings('/page' => page)
240
- session.visit(page)
241
- expect(on_load_hook_called).to eq(true)
242
- 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)
243
154
  end
155
+ end
244
156
 
245
- context 'url supplied' do
246
- it 'visits that url' do
247
- expected_url = 'http://url.com/page'
248
- expect(browser).to receive(:visit).with(expected_url)
249
- session.visit(url: expected_url)
250
- 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)
251
162
  end
252
163
  end
253
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