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,56 +1,37 @@
1
- module PageMagic
2
- class Element
3
- describe Query do
4
- include_context :webapp_fixture
1
+ # frozen_string_literal: true
5
2
 
6
- let(:page) do
7
- elements_page = Class.new do
8
- include PageMagic
9
- url '/elements'
10
- end
11
- elements_page.visit(application: rack_app).current_page
12
- end
13
-
14
- describe '#execute' do
15
- context 'no results found' do
16
- subject do
17
- QueryBuilder.find(:link).build(css: 'wrong')
18
- end
3
+ RSpec.describe PageMagic::Element::Query do
4
+ describe '#execute' do
5
+ it 'calls find' do
6
+ subject = described_class.new
7
+ allow(subject).to receive(:find)
19
8
 
20
- it 'raises an error' do
21
- expected_message = 'Unable to find css "wrong"'
22
- expect { subject.execute(page.browser) }.to raise_exception(ElementMissingException, expected_message)
23
- end
24
- end
25
-
26
- context 'to many results returned' do
27
- subject do
28
- QueryBuilder.find(:link).build(css: 'a')
29
- end
9
+ subject.execute(:capybara_element)
10
+ expect(subject).to have_received(:find).with(:capybara_element)
11
+ end
30
12
 
31
- it 'raises an error' do
32
- expected_message = 'Ambiguous match, found 2 elements matching css "a"'
33
- expect { subject.execute(page.browser) }.to raise_error AmbiguousQueryException, expected_message
34
- end
35
- end
13
+ context 'when a formatter supplied' do
14
+ it 'uses it' do
15
+ subject = described_class.new
16
+ allow(subject).to receive(:find) { |_r, &formatter| formatter.call(:result) }
36
17
 
37
- context 'multiple results found' do
38
- subject do
39
- QueryBuilder.find(:link).build({ css: 'a' }, {}, multiple_results: true)
40
- end
18
+ result = subject.execute(:capybara_element) { |capybara_result| "formatter_called_on_#{capybara_result}" }
19
+ expect(result).to eq('formatter_called_on_result')
20
+ end
21
+ end
41
22
 
42
- it 'returns an array' do
43
- result = subject.execute(page.browser)
44
- expect(result).to be_a(Array)
45
- expect(result.size).to eq(2)
23
+ context 'when no results are found' do
24
+ subject(:query_class) do
25
+ Class.new(described_class) do
26
+ def find(element)
27
+ element.find('missing')
46
28
  end
47
29
  end
30
+ end
48
31
 
49
- it 'returns the result of the capybara query' do
50
- query = QueryBuilder.find(:link).build(id: 'form_link')
51
- result = query.execute(page.browser)
52
- expect(result.text).to eq('link in a form')
53
- end
32
+ it 'Returns `NotFound`' do
33
+ element = PageMagic::Element.load('<html></html>')
34
+ expect(query_class.new.execute(element)).to be_a(PageMagic::Element::NotFound)
54
35
  end
55
36
  end
56
37
  end
@@ -1,155 +1,165 @@
1
- module PageMagic
2
- class Element
3
- describe Selector do
4
- describe '.find' do
5
- it 'returns the constant with the given name' do
6
- expect(Selector.find(:css)).to be(described_class::CSS)
7
- end
8
-
9
- context 'selector not found' do
10
- it 'raises an exception' do
11
- expect { Selector.find(:invalid) }.to raise_exception(UnsupportedCriteriaException)
12
- end
13
- end
14
- end
15
-
16
- describe '#build' do
17
- it 'puts the locator and element type in to the result' do
18
- expect(subject.build(:field, :locator)).to eq([:locator])
19
- end
1
+ # frozen_string_literal: true
20
2
 
21
- context 'exact is set to true' do
22
- subject do
23
- described_class.new(exact: true)
24
- end
3
+ RSpec.describe PageMagic::Element::Selector do
4
+ describe '.find' do
5
+ it 'returns the constant with the given name' do
6
+ expect(described_class.find(:css)).to be(described_class::CSS)
7
+ end
25
8
 
26
- it 'includes the requirement for the match to be exact' do
27
- expect(subject.build(:field, :locator)).to include(exact: true)
28
- end
29
- end
9
+ context 'when selector not found' do
10
+ it 'raises an exception' do
11
+ expect { described_class.find(:invalid) }.to raise_exception(PageMagic::UnsupportedCriteriaException)
12
+ end
13
+ end
14
+ end
30
15
 
31
- context 'supports_type flag set to true in constructor' do
32
- subject do
33
- described_class.new(supports_type: true)
34
- end
35
- it 'includes the element type in the result' do
36
- expect(subject.build(:field, :locator)).to eq([:field, :locator])
37
- end
38
- end
16
+ describe '#build' do
17
+ it 'puts the locator and element type in to the result' do
18
+ expect(described_class.new.build(:field, :locator)).to have_attributes(
19
+ args: [:locator]
20
+ )
21
+ end
39
22
 
40
- context 'formatter supplied to constructor' do
41
- subject do
42
- described_class.new do |param|
43
- "formatted_#{param}".to_sym
44
- end
45
- end
46
- it 'uses the formatter' do
47
- expect(subject.build(:field, :locator)).to eq([:formatted_locator])
48
- end
49
- end
23
+ context 'when exact matching is required' do
24
+ it 'is added to options' do
25
+ expect(described_class.new(exact: true).build(:field, :locator)).to have_attributes(
26
+ options: { exact: true }
27
+ )
28
+ end
29
+ end
50
30
 
51
- context 'name supplied to constructor' do
52
- subject do
53
- described_class.new(:css)
54
- end
31
+ context 'when supports_type true' do
32
+ it 'includes the element type' do
33
+ expect(described_class.new(supports_type: true).build(:field, :locator)).to have_attributes(
34
+ args: %i[field locator]
35
+ )
36
+ end
37
+ end
55
38
 
56
- it 'is added to the result' do
57
- expect(subject.build(:field, :locator)).to eq([:css, :locator])
58
- end
39
+ # TODO: - new class?
40
+ context 'when selector formatter is provided' do
41
+ subject(:selector) do
42
+ described_class.new do |param|
43
+ "formatted_#{param}".to_sym
59
44
  end
60
45
  end
61
46
 
62
- describe '#initialize' do
63
- it 'sets exact to false by default' do
64
- expect(subject.exact).to eq(false)
65
- end
47
+ it 'uses the formatter' do
48
+ expect(selector.build(:field, :locator)).to have_attributes(
49
+ args: [:formatted_locator]
50
+ )
66
51
  end
67
52
  end
68
53
 
69
- class Selector
70
- shared_examples 'named selector' do |options|
71
- it 'adds name to the result' do
72
- expected = [described_class.name, :locator, options].compact
73
- expect(described_class.build(:element_type, :locator)).to eq(expected)
74
- end
54
+ context 'when type supplied' do
55
+ it 'is added to the result' do
56
+ expect(described_class.new(:css).build(:field, :locator)).to have_attributes(
57
+ args: %i[css locator]
58
+ )
75
59
  end
60
+ end
61
+ end
76
62
 
77
- shared_examples 'anonymous selector' do
78
- it 'does not have a name' do
79
- expect(described_class.name).to eq(nil)
80
- end
63
+ describe '#initialize' do
64
+ context 'when exact' do
65
+ it 'sets the option' do
66
+ subject = described_class.new(exact: true).build(:element_type, {})
67
+ expect(subject.options).to eq({ exact: true })
81
68
  end
69
+ end
70
+ end
82
71
 
83
- shared_examples 'element type selector' do
84
- it 'adds the element type to the result' do
85
- expect(described_class.supports_type).to eq(true)
86
- end
72
+ describe 'predefined selectors' do
73
+ shared_examples 'a selector' do |named: false, **options|
74
+ def selector_name
75
+ self.class.metadata[:parent_example_group][:description].to_sym
87
76
  end
88
77
 
89
- shared_examples 'non element type selector' do
90
- it 'adds the element type to the result' do
91
- expect(described_class.supports_type).to eq(false)
92
- end
78
+ subject do
79
+ described_class.find(selector_name).build(:element_type, :locator)
93
80
  end
94
81
 
95
- describe NAME do
96
- it_behaves_like 'anonymous selector'
97
- it_behaves_like 'non element type selector'
82
+ it 'contains the selector args' do
83
+ name_arg = named && (named == true ? selector_name : named)
98
84
 
99
- it 'formats locators' do
100
- button_name = 'my_button'
101
- expect(described_class.build(:button, button_name)).to eq(["*[name='#{button_name}']"])
102
- end
85
+ expected_args = [name_arg, :locator].compact
86
+ expect(subject.args).to eq(expected_args)
103
87
  end
104
88
 
105
- describe XPATH do
106
- it_behaves_like 'named selector'
107
- it_behaves_like 'non element type selector'
89
+ it 'contains the options' do
90
+ expect(subject.options).to eq(options)
108
91
  end
92
+ end
109
93
 
110
- describe ID do
111
- it_behaves_like 'named selector'
112
- it_behaves_like 'non element type selector'
113
- end
94
+ let(:capybara_element) do
95
+ html_source = <<~HTML_SOURCE
96
+ <a href='#'>a link</a>
114
97
 
115
- describe LABEL do
116
- it_behaves_like 'named selector', exact: true
117
- it_behaves_like 'non element type selector'
118
- end
119
98
 
120
- describe TEXT do
121
- it_behaves_like 'anonymous selector'
122
- it_behaves_like 'element type selector'
99
+ <div id='form' class="form">
100
+ <a id='form_link' href='/page2'>link in a form</a>
101
+ <label>enter text
102
+ <input id='field_id' name='field_name' class='input_class' type='text' value='filled in'/>
103
+ </label>
104
+ <button id='form_button' type='submit' value='a button'/>
105
+ </form>
106
+ HTML_SOURCE
107
+ PageMagic::Element.load(html_source)
108
+ end
109
+
110
+ describe 'label' do
111
+ it_behaves_like 'a selector', named: :field, exact: true
112
+
113
+ it 'finds elements by label' do
114
+ selector = described_class.find(:label).build(:text_field, 'enter text')
115
+ query = PageMagic::Element::Query::SingleResult.new(*selector.args)
116
+ expect(query.execute(capybara_element)[:name]).to eq('field_name')
123
117
  end
124
118
  end
125
119
 
126
- context 'integration' do
127
- include_context :webapp_fixture
128
- let(:capybara_session) { Capybara::Session.new(:rack_test, rack_app).tap { |s| s.visit('/elements') } }
120
+ describe 'name' do
121
+ it 'formats locators' do
122
+ name = 'my_button'
123
+ expect(described_class::NAME.build(:element_type, name)).to have_attributes(
124
+ args: ["*[name='#{name}']"],
125
+ options: {}
126
+ )
127
+ end
129
128
 
130
129
  it 'finds elements by name' do
131
- query = QueryBuilder.find(:text_field).build(name: 'field_name')
132
- expect(query.execute(capybara_session)[:name]).to eq('field_name')
130
+ selector = described_class.find(:name).build(:text_field, 'field_name')
131
+ query = PageMagic::Element::Query::SingleResult.new(*selector.args)
132
+ expect(query.execute(capybara_element)[:name]).to eq('field_name')
133
133
  end
134
+ end
135
+
136
+ describe 'xpath' do
137
+ it_behaves_like 'a selector', named: true
134
138
 
135
139
  it 'finds elements by xpath' do
136
- query = QueryBuilder.find(:element).build(xpath: '//div/label/input')
137
- expect(query.execute(capybara_session)[:name]).to eq('field_name')
140
+ selector = described_class.find(:xpath).build(:element, '//div/label/input')
141
+ query = PageMagic::Element::Query::SingleResult.new(*selector.args)
142
+ expect(query.execute(capybara_element)[:name]).to eq('field_name')
138
143
  end
144
+ end
145
+
146
+ describe 'id' do
147
+ it_behaves_like 'a selector', named: true
139
148
 
140
149
  it 'finds elements by id' do
141
- query = QueryBuilder.find(:text_field).build(id: 'field_id')
142
- expect(query.execute(capybara_session)[:name]).to eq('field_name')
150
+ selector = described_class.find(:id).build(:text_field, 'field_id')
151
+ query = PageMagic::Element::Query::SingleResult.new(*selector.args)
152
+ expect(query.execute(capybara_element)[:name]).to eq('field_name')
143
153
  end
154
+ end
144
155
 
145
- it 'finds elements by label' do
146
- query = QueryBuilder.find(:text_field).build(label: 'enter text')
147
- expect(query.execute(capybara_session)[:name]).to eq('field_name')
148
- end
156
+ describe 'text' do
157
+ it_behaves_like 'a selector', named: :element_type
149
158
 
150
159
  it 'finds elements by text' do
151
- query = QueryBuilder.find(:link).build(text: 'a link')
152
- expect(query.execute(capybara_session).text).to eq('a link')
160
+ selector = described_class.find(:text).build(:link, 'a link')
161
+ query = PageMagic::Element::Query::SingleResult.new(*selector.args)
162
+ expect(query.execute(capybara_element).text).to eq('a link')
153
163
  end
154
164
  end
155
165
  end
@@ -1,111 +1,71 @@
1
- module PageMagic
2
- describe ElementContext do
3
- include_context :webapp_fixture
1
+ # frozen_string_literal: true
4
2
 
5
- let!(:elements_page) do
6
- Class.new do
7
- include PageMagic
8
- url '/elements'
9
- link(:a_link, text: 'a link')
10
- link(:prefetched, Object.new)
11
- end
12
- end
13
-
14
- let(:page) do
15
- elements_page.visit(application: rack_app).current_page
16
- end
17
-
18
- subject do
19
- described_class.new(page)
20
- end
21
-
22
- let!(:session) do
23
- double('session', raw_session: double('browser'))
3
+ RSpec.describe PageMagic::ElementContext do
4
+ describe '#method_missing' do
5
+ let(:element_class) do
6
+ Class.new(PageMagic::Element)
24
7
  end
25
8
 
26
- describe '#method_missing' do
27
- context 'method is a element defintion' do
28
- it 'returns the sub page element' do
29
- element = described_class.new(page).a_link
30
- expect(element.text).to eq('a link')
31
- end
32
-
33
- it 'passes arguments through to the element definition' do
34
- elements_page.links :pass_through, css: 'a' do |args|
35
- args[:passed_through] = true
36
- end
37
- args = {}
38
- described_class.new(page).pass_through(args)
39
- expect(args[:passed_through]).to eq(true)
40
- end
41
-
42
- it 'does not evaluate any of the other definitions' do
43
- elements_page.class_eval do
44
- link(:another_link, :selector) do
45
- raise('should not have been evaluated')
46
- end
47
- end
9
+ context 'when method is a element definition' do
10
+ it 'returns the sub page element' do
11
+ element_class.link(:a_link, text: 'a link')
12
+ element = described_class.new(element_class.load("<a href='#'>a link</a>")).a_link
13
+ expect(element.text).to eq('a link')
14
+ end
48
15
 
49
- described_class.new(page).a_link
50
- end
16
+ it 'passes arguments through to the element definition' do
17
+ element_class.link(:pass_through, css: 'a') { |args| args[:passed_through] = true }
51
18
 
52
- context 'more than one match found in the browser' do
53
- it 'returns an array of element definitions' do
54
- elements_page.links :links, css: 'a'
55
- links = described_class.new(page).links
56
- expect(links.find_all { |e| e.class == Element }.size).to eq(2)
57
- expect(links.collect(&:text)).to eq(['a link', 'link in a form'])
58
- end
59
- end
19
+ args = {}
20
+ described_class.new(element_class.load("<a href='#'>a link</a>")).pass_through(args)
21
+ expect(args[:passed_through]).to eq(true)
60
22
  end
61
23
 
62
- context 'method found on page_element' do
63
- it 'calls page_element method' do
64
- elements_page.class_eval do
65
- def page_method
66
- :called
67
- end
68
- end
24
+ it 'does not evaluate any of the other definitions' do
25
+ element_class.link(:a_link, text: 'a link')
26
+ element_class.link(:another_link, :selector) { raise('should not have been evaluated') }
69
27
 
70
- expect(described_class.new(page).page_method).to eq(:called)
71
- end
28
+ described_class.new(element_class.load("<a href='#'>a link</a>")).a_link
72
29
  end
30
+ end
73
31
 
74
- context 'element is prefetched' do
75
- it 'does not call find' do
76
- expect(subject).not_to receive(:find)
77
- described_class.new(page).prefetched
32
+ context 'when the method is found on page_element' do
33
+ it 'calls page_element method' do
34
+ element_class.define_method(:page_method) do
35
+ :called
78
36
  end
79
- end
80
37
 
81
- context 'method not found on page_element or as a element definition' do
82
- it 'raises an error' do
83
- expect { elements_page.missing_method }.to raise_error(NoMethodError)
84
- end
38
+ expect(described_class.new(element_class.load("<a href='#'>a link</a>")).page_method).to eq(:called)
85
39
  end
86
40
  end
87
41
 
88
- describe '#respond_to?' do
89
- let(:page_element) do
90
- Class.new(Element) do
91
- link(:a_link, css: '.link')
92
- end
42
+ context 'when the method is not found on page_element or as a element definition' do
43
+ it 'raises an error' do
44
+ expect do
45
+ described_class.new(PageMagic::Element.load('')).missing_method
46
+ end.to raise_error(PageMagic::ElementMissingException)
93
47
  end
48
+ end
49
+ end
94
50
 
95
- subject do
96
- described_class.new(page_element.new(session))
51
+ describe '#respond_to?' do
52
+ let(:page_element_class) do
53
+ Class.new(PageMagic::Element) do
54
+ link(:a_link, text: 'a link')
97
55
  end
56
+ end
98
57
 
99
- context 'page_element responds to method name' do
100
- it 'returns true' do
101
- expect(subject.respond_to?(:a_link)).to eq(true)
102
- end
58
+ context 'when the page_element responds to method name' do
59
+ it 'returns true' do
60
+ element = described_class.new(page_element_class.load("<a href='#'>a link</a>"))
61
+ expect(element).to respond_to(:a_link)
103
62
  end
63
+ end
104
64
 
105
- context 'method is not on page_element' do
106
- it 'calls super' do
107
- expect(subject.respond_to?(:methods)).to eq(true)
108
- end
65
+ context 'when the method is not on the page_element' do
66
+ it 'calls super' do
67
+ element = described_class.new(page_element_class.load("<a href='#'>a link</a>")).a_link
68
+ expect(element.text).to respond_to(:methods)
109
69
  end
110
70
  end
111
71
  end