page_magic 2.0.0.alpha1 → 2.0.0

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.
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,110 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PageMagic
4
- class Element
5
- describe QueryBuilder do
6
- it 'has a predefined query for each element type' do
7
- missing = PageMagic::Elements::TYPES.dup.delete_if { |type| type.to_s.end_with?('s') }.find_all do |type|
8
- described_class.constants.include?(type)
9
- end
10
- expect(missing).to be_empty
11
- end
12
-
13
- describe '.find' do
14
- it 'finds the constant with the given name' do
15
- expect(described_class.find(:button)).to be(described_class::BUTTON)
16
- end
17
-
18
- context 'constant not found' do
19
- it 'returns a default' do
20
- expect(described_class.find(:billy)).to be(described_class::ELEMENT)
21
- end
22
- end
23
- end
24
-
25
- describe '#build' do
26
- let(:selector) { Selector.new }
27
- before do
28
- expect(Selector).to receive(:find).with(:css).and_return(selector)
29
- end
30
- let(:locator) { { css: '.css' } }
31
-
32
- it 'builds a query using the correct selector' do
33
- expected = Query.new(locator.values)
34
- expect(subject.build(locator)).to eq(expected)
35
- end
36
-
37
- it 'adds options to the result' do
38
- expected = Query.new(locator.values.concat([:options]))
39
- expect(subject.build(locator, :options)).to eq(expected)
40
- end
41
-
42
- context 'selector support element type' do
43
- subject do
44
- described_class.new(:field)
45
- end
46
-
47
- it 'passes element type through to the selector' do
48
- expect(selector).to receive(:build).with(:field, '.css').and_call_original
49
- subject.build(locator)
50
- end
51
- end
52
- end
53
- end
54
-
55
- class QueryBuilder
56
- describe BUTTON do
57
- it 'has an element type' do
58
- expect(described_class.type).to eq(:button)
59
- end
60
- end
61
-
62
- describe ELEMENT do
63
- it ' does not has an element type' do
64
- expect(described_class.type).to be_nil
65
- end
66
- end
67
-
68
- describe LINK do
69
- it 'has an element type' do
70
- expect(described_class.type).to eq(:link)
71
- end
72
- end
73
-
74
- describe TEXT_FIELD do
75
- it 'has an element type' do
76
- expect(described_class.type).to eq(:field)
77
- end
78
-
79
- it 'the same as all form field types' do
80
- expect(described_class).to eq(CHECKBOX).and eq(SELECT_LIST).and eq(RADIO).and eq(TEXTAREA).and eq(FILE_FIELD).and eq(FILLABLE_FIELD).and eq(RADIO_BUTTON)
81
- end
82
- end
83
- end
84
-
85
- context 'integration' do
86
- include_context :webapp_fixture
87
- let(:capybara_session) { Capybara::Session.new(:rack_test, rack_app).tap { |s| s.visit('/elements') } }
88
-
89
- it 'finds fields' do
90
- query = QueryBuilder.find(:text_field).build({ name: 'field_name' })
91
- expect(query.execute(capybara_session).tag_name).to eq('input')
92
- end
93
-
94
- it 'finds buttons' do
95
- query = QueryBuilder.find(:button).build({ text: 'a button' })
96
- expect(query.execute(capybara_session).tag_name).to eq('button')
97
- end
98
-
99
- it 'finds links' do
100
- query = QueryBuilder.find(:link).build({ text: 'a link' })
101
- expect(query.execute(capybara_session).tag_name).to eq('a')
102
- end
103
-
104
- it 'finds elements' do
105
- query = QueryBuilder.find(:element).build({ name: 'field_name' })
106
- expect(query.execute(capybara_session).tag_name).to eq('input')
107
- end
108
- end
109
- end
110
- end
@@ -1,338 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # rubocop:disable Metrics/ModuleLength
4
- module PageMagic
5
- describe Matcher do
6
- describe '#initialize' do
7
- context 'no componentes specified' do
8
- it 'raises an exeception' do
9
- expect { described_class.new }.to raise_exception(MatcherInvalidException)
10
- end
11
- end
12
- end
13
- describe '#can_compute_uri?' do
14
- context 'regex in path' do
15
- it 'returns false' do
16
- expect(described_class.new(//).can_compute_uri?).to eq(false)
17
- end
18
- end
19
-
20
- context 'regex in parameters' do
21
- it 'returns false' do
22
- expect(described_class.new(parameters: { param: // }).can_compute_uri?).to eq(false)
23
- end
24
- end
25
-
26
- context 'regexp in fragment' do
27
- it 'returns false' do
28
- expect(described_class.new(fragment: //).can_compute_uri?).to eq(false)
29
- end
30
- end
31
-
32
- context 'regexp not present' do
33
- it 'returns true' do
34
- expect(described_class.new('/').can_compute_uri?).to eq(true)
35
- end
36
- end
37
- end
38
-
39
- describe 'compare' do
40
- subject { described_class.new('/') }
41
- context 'param 1 not nil' do
42
- context 'param 2 not nil' do
43
- context 'literal to fuzzy' do
44
- it 'returns -1' do
45
- expect(subject.instance_eval { compare('/', //) }).to eq(-1)
46
- end
47
- end
48
-
49
- context 'literal to literal' do
50
- it 'returns 0' do
51
- expect(subject.instance_eval { compare('/', '/') }).to eq(0)
52
- end
53
- end
54
-
55
- context 'fuzzy to fuzzy' do
56
- it 'returns 0' do
57
- expect(subject.instance_eval { compare(//, //) }).to eq(0)
58
- end
59
- end
60
-
61
- context 'fuzzy to literal' do
62
- it 'returns 1' do
63
- expect(subject.instance_eval { compare(//, '/') }).to eq(1)
64
- end
65
- end
66
- end
67
-
68
- context 'param2 is nil' do
69
- it 'returns -1' do
70
- expect(subject.instance_eval { compare('/', nil) }).to eq(-1)
71
- end
72
- end
73
- end
74
-
75
- context 'param1 is nil' do
76
- context 'param2 not nil' do
77
- it 'returns 1' do
78
- expect(subject.instance_eval { compare(nil, '/') }).to eq(1)
79
- end
80
- end
81
-
82
- context 'param2 nil' do
83
- it 'returns 0' do
84
- expect(subject.instance_eval { compare(nil, nil) }).to eq(0)
85
- end
86
- end
87
- end
88
- end
89
-
90
- describe 'compute_uri' do
91
- context 'path present' do
92
- it 'returns a uri' do
93
- expect(described_class.new('/').compute_uri).to eq('/')
94
- end
95
- end
96
-
97
- context 'params present' do
98
- context '1 param' do
99
- it 'returns a uri' do
100
- expect(described_class.new(parameters: { a: 1 }).compute_uri).to eq('?a=1')
101
- end
102
- end
103
-
104
- context 'more than 1 param' do
105
- it 'returns a uri' do
106
- expect(described_class.new(parameters: { a: 1, b: 2 }).compute_uri).to eq('?a=1&b=2')
107
- end
108
- end
109
- end
110
-
111
- context 'fragment present' do
112
- it 'returns a uri' do
113
- expect(described_class.new(fragment: 'fragment').compute_uri).to eq('#fragment')
114
- end
115
- end
116
- end
117
-
118
- describe '#matches?' do
119
- let(:matching_url) { 'http://www.example.com/path?foo=bar#fragment' }
120
- let(:incompatible_url) { 'http://www.example.com/mismatch?miss=match#mismatch' }
121
- context 'path requirement exists' do
122
- context 'path is literal' do
123
- subject do
124
- described_class.new('/path')
125
- end
126
- it 'returns true for an exact match' do
127
- expect(subject.match?(matching_url)).to eq(true)
128
- end
129
-
130
- it 'returns false when not an exact match' do
131
- expect(subject.match?(incompatible_url)).to eq(false)
132
- end
133
- end
134
-
135
- context 'path is regexp' do
136
- subject do
137
- described_class.new(/\d/)
138
- end
139
- it 'returns true for a match on the regexp' do
140
- expect(subject.match?('3')).to eq(true)
141
- end
142
-
143
- it 'returns false when regexp is not a match' do
144
- expect(subject.match?('/mismatch')).to eq(false)
145
- end
146
- end
147
- end
148
-
149
- context 'query string requirement exists' do
150
- context 'parameter requirement is a literal' do
151
- subject do
152
- described_class.new(parameters: { foo: 'bar' })
153
- end
154
-
155
- it 'returns true for a match' do
156
- expect(subject.match?(matching_url)).to eq(true)
157
- end
158
-
159
- it 'returns false when regexp is not a match' do
160
- expect(subject.match?(incompatible_url)).to eq(false)
161
- end
162
- end
163
-
164
- context 'parameter requirement is a regexp' do
165
- subject do
166
- described_class.new(parameters: { foo: /bar/ })
167
- end
168
-
169
- it 'returns true for a match on the regexp' do
170
- expect(subject.match?(matching_url)).to eq(true)
171
- end
172
-
173
- it 'returns false when regexp is not a match' do
174
- expect(subject.match?(incompatible_url)).to eq(false)
175
- end
176
- end
177
- end
178
-
179
- context 'fragment requirement exists' do
180
- context 'fragment requirement is a literal' do
181
- subject do
182
- described_class.new(fragment: 'fragment')
183
- end
184
-
185
- it 'returns true for a match' do
186
- expect(subject.match?(matching_url)).to eq(true)
187
- end
188
-
189
- it 'returns false when regexp is not a match' do
190
- expect(subject.match?(incompatible_url)).to eq(false)
191
- end
192
- end
193
-
194
- context 'fragment requirement is a regexp' do
195
- subject do
196
- described_class.new(fragment: /fragment/)
197
- end
198
-
199
- it 'returns true for a match on the regexp' do
200
- expect(subject.match?(matching_url)).to eq(true)
201
- end
202
-
203
- it 'returns false when regexp is not a match' do
204
- expect(subject.match?(incompatible_url)).to eq(false)
205
- end
206
- end
207
- end
208
- end
209
-
210
- describe '<=>' do
211
- let(:literal_path_matcher) { '/' }
212
- let(:fuzzy_path_matcher) { // }
213
- let(:literal_parameter_matchers) { { param: 'value' } }
214
- let(:fuzzy_parameter_matchers) { { param: // } }
215
-
216
- let(:literal_fragment_matcher) { 'fragment' }
217
- let(:fuzzy_fragment_matcher) { // }
218
-
219
- context 'path' do
220
- context 'path is of same class as path on other' do
221
- subject(:a) { described_class.new('/a') }
222
- subject(:b) { described_class.new('/b') }
223
- it 'returns self and other as equivalent' do
224
- expect(a <=> b).to eq(0)
225
- end
226
- end
227
-
228
- context 'path on other is fuzzy' do
229
- subject(:a) { described_class.new(literal_path_matcher) }
230
- subject(:b) { described_class.new(fuzzy_path_matcher) }
231
- it 'returns other as lesser' do
232
- expect(a <=> b).to eq(-1)
233
- end
234
- end
235
- end
236
-
237
- context 'parameters' do
238
- context 'parameters on self and other contain literal values' do
239
- subject(:a) do
240
- described_class.new(literal_path_matcher,
241
- parameters: literal_parameter_matchers)
242
- end
243
- subject(:b) do
244
- described_class.new(literal_path_matcher,
245
- parameters: literal_parameter_matchers)
246
- end
247
- it 'returns self and other as equivalent' do
248
- expect(a <=> b).to eq(0)
249
- end
250
- end
251
-
252
- context 'parameters on self literal values and other has fuzzy values' do
253
- subject(:a) do
254
- described_class.new(literal_path_matcher,
255
- parameters: literal_parameter_matchers)
256
- end
257
- subject(:b) do
258
- described_class.new(literal_path_matcher,
259
- parameters: fuzzy_parameter_matchers)
260
- end
261
- it 'returns other as lesser' do
262
- expect(a <=> b).to eq(-1)
263
- end
264
- end
265
- context 'parameters on self fuzzy values and other has literal values' do
266
- subject(:a) do
267
- described_class.new(literal_path_matcher,
268
- parameters: fuzzy_parameter_matchers)
269
- end
270
-
271
- subject(:b) do
272
- described_class.new(literal_path_matcher,
273
- parameters: literal_parameter_matchers)
274
- end
275
-
276
- it 'returns other as greater' do
277
- expect(a <=> b).to eq(1)
278
- end
279
- end
280
- end
281
-
282
- context 'fragment' do
283
- context 'fragment is of same class as path on other' do
284
- subject(:a) do
285
- described_class.new(literal_path_matcher,
286
- parameters: literal_parameter_matchers,
287
- fragment: literal_fragment_matcher)
288
- end
289
-
290
- subject(:b) do
291
- described_class.new(literal_path_matcher,
292
- parameters: literal_parameter_matchers,
293
- fragment: literal_fragment_matcher)
294
- end
295
-
296
- it 'returns self and other as equivalent' do
297
- expect(a <=> b).to eq(0)
298
- end
299
- end
300
-
301
- context 'fragment is literal on self and fuzzy on other' do
302
- subject(:a) do
303
- described_class.new(literal_path_matcher,
304
- parameters: literal_parameter_matchers,
305
- fragment: literal_fragment_matcher)
306
- end
307
-
308
- subject(:b) do
309
- described_class.new(literal_path_matcher,
310
- parameters: literal_parameter_matchers,
311
- fragment: fuzzy_fragment_matcher)
312
- end
313
-
314
- it 'returns other as lesser' do
315
- expect(a <=> b).to eq(-1)
316
- end
317
- end
318
-
319
- context 'fragment is fuzzy on self and literal on other' do
320
- subject(:a) do
321
- described_class.new(literal_path_matcher,
322
- parameters: literal_parameter_matchers,
323
- fragment: fuzzy_fragment_matcher)
324
- end
325
-
326
- subject(:b) do
327
- described_class.new(literal_path_matcher,
328
- parameters: literal_parameter_matchers,
329
- fragment: literal_fragment_matcher)
330
- end
331
- it 'returns other as lesser' do
332
- expect(a <=> b).to eq(1)
333
- end
334
- end
335
- end
336
- end
337
- end
338
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- shared_context :files do
4
- require 'tmpdir'
5
-
6
- def scratch_dir
7
- @dir ||= Dir.mktmpdir
8
- end
9
- end