Skip to content

Commit 518496c

Browse files
committed
[rb] Support using custom element classes
1 parent 02381bf commit 518496c

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

rb/lib/selenium/webdriver/remote/bridge.rb

+12-9
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class Bridge
3333

3434
class << self
3535
attr_reader :extra_commands
36-
attr_writer :locator_converter
36+
attr_writer :element_class, :locator_converter
3737

3838
def add_command(name, verb, url, &block)
3939
@extra_commands ||= {}
@@ -44,6 +44,10 @@ def add_command(name, verb, url, &block)
4444
def locator_converter
4545
@locator_converter ||= LocatorConverter.new
4646
end
47+
48+
def element_class
49+
@element_class ||= Element
50+
end
4751
end
4852

4953
#
@@ -432,7 +436,7 @@ def submit_element(element)
432436
"e.initEvent('submit', true, true);\n" \
433437
"if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n"
434438

435-
execute_script(script, Element::ELEMENT_KEY => element)
439+
execute_script(script, Bridge.element_class::ELEMENT_KEY => element)
436440
rescue Error::JavascriptError
437441
raise Error::UnsupportedOperationError, 'To submit an element, it must be nested inside a form element'
438442
end
@@ -519,7 +523,7 @@ def element_value_of_css_property(element, prop)
519523
#
520524

521525
def active_element
522-
Element.new self, element_id_from(execute(:get_active_element))
526+
Bridge.element_class.new self, element_id_from(execute(:get_active_element))
523527
end
524528

525529
alias switch_to_active_element active_element
@@ -539,7 +543,7 @@ def find_element_by(how, what, parent_ref = [])
539543
execute :find_element, {}, {using: how, value: what.to_s}
540544
end
541545

542-
Element.new self, element_id_from(id)
546+
Bridge.element_class.new self, element_id_from(id)
543547
end
544548

545549
def find_elements_by(how, what, parent_ref = [])
@@ -557,7 +561,7 @@ def find_elements_by(how, what, parent_ref = [])
557561
execute :find_elements, {}, {using: how, value: what.to_s}
558562
end
559563

560-
ids.map { |id| Element.new self, element_id_from(id) }
564+
ids.map { |id| Bridge.element_class.new self, element_id_from(id) }
561565
end
562566

563567
def shadow_root(element)
@@ -631,7 +635,7 @@ def escaper
631635
end
632636

633637
def commands(command)
634-
command_list[command]|| Bridge.extra_commands[command]
638+
command_list[command] || Bridge.extra_commands[command]
635639
end
636640

637641
def unwrap_script_result(arg)
@@ -640,7 +644,7 @@ def unwrap_script_result(arg)
640644
arg.map { |e| unwrap_script_result(e) }
641645
when Hash
642646
element_id = element_id_from(arg)
643-
return Element.new(self, element_id) if element_id
647+
return Bridge.element_class.new(self, element_id) if element_id
644648

645649
shadow_root_id = shadow_root_id_from(arg)
646650
return ShadowRoot.new self, shadow_root_id if shadow_root_id
@@ -652,7 +656,7 @@ def unwrap_script_result(arg)
652656
end
653657

654658
def element_id_from(id)
655-
id['ELEMENT'] || id[Element::ELEMENT_KEY]
659+
id['ELEMENT'] || id[Bridge.element_class::ELEMENT_KEY]
656660
end
657661

658662
def shadow_root_id_from(id)
@@ -663,7 +667,6 @@ def prepare_capabilities_payload(capabilities)
663667
capabilities = {alwaysMatch: capabilities} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
664668
{capabilities: capabilities}
665669
end
666-
667670
end # Bridge
668671
end # Remote
669672
end # WebDriver

rb/spec/unit/selenium/webdriver/remote/bridge_spec.rb

+66
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,72 @@ module Remote
141141
expect { bridge.quit }.not_to raise_error
142142
end
143143
end
144+
145+
describe 'finding elements' do
146+
let(:http) { WebDriver::Remote::Http::Default.new }
147+
let(:bridge) { described_class.new(http_client: http, url: 'http://localhost') }
148+
149+
before do
150+
allow(http).to receive(:request)
151+
.with(:post, URI('http://localhost/session'), any_args)
152+
.and_return('status' => 200, 'value' => {'sessionId' => 'foo', 'capabilities' => {}})
153+
bridge.create_session({})
154+
end
155+
156+
describe '#find_element_by' do
157+
before do
158+
allow(http).to receive(:request)
159+
.with(:post, URI('http://localhost/session/foo/element'), any_args)
160+
.and_return('status' => 200, 'value' => {Element::ELEMENT_KEY => 'bar'})
161+
end
162+
163+
it 'returns an element' do
164+
expect(bridge.find_element_by(:id, 'test', nil)).to be_an_instance_of(Element)
165+
end
166+
167+
context 'when custom element class is used' do
168+
before do
169+
stub_const('MyCustomElement', Class.new(Selenium::WebDriver::Element))
170+
described_class.element_class = MyCustomElement
171+
end
172+
173+
after do
174+
described_class.element_class = nil
175+
end
176+
177+
it 'returns a custom element' do
178+
expect(bridge.find_element_by(:id, 'test', nil)).to be_an_instance_of(MyCustomElement)
179+
end
180+
end
181+
end
182+
183+
describe '#find_elements_by' do
184+
before do
185+
allow(http).to receive(:request)
186+
.with(:post, URI('http://localhost/session/foo/elements'), any_args)
187+
.and_return('status' => 200, 'value' => [{Element::ELEMENT_KEY => 'bar'}])
188+
end
189+
190+
it 'returns an element' do
191+
expect(bridge.find_elements_by(:id, 'test', nil)).to all(be_an_instance_of(Element))
192+
end
193+
194+
context 'when custom element class is used' do
195+
before do
196+
stub_const('MyCustomElement', Class.new(Selenium::WebDriver::Element))
197+
described_class.element_class = MyCustomElement
198+
end
199+
200+
after do
201+
described_class.element_class = nil
202+
end
203+
204+
it 'returns a custom element' do
205+
expect(bridge.find_elements_by(:id, 'test', nil)).to all(be_an_instance_of(MyCustomElement))
206+
end
207+
end
208+
end
209+
end
144210
end
145211
end # Remote
146212
end # WebDriver

0 commit comments

Comments
 (0)