Path: blob/trunk/rb/spec/integration/selenium/webdriver/element_spec.rb
4012 views
# frozen_string_literal: true12# Licensed to the Software Freedom Conservancy (SFC) under one3# or more contributor license agreements. See the NOTICE file4# distributed with this work for additional information5# regarding copyright ownership. The SFC licenses this file6# to you under the Apache License, Version 2.0 (the7# "License"); you may not use this file except in compliance8# with the License. You may obtain a copy of the License at9#10# http://www.apache.org/licenses/LICENSE-2.011#12# Unless required by applicable law or agreed to in writing,13# software distributed under the License is distributed on an14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY15# KIND, either express or implied. See the License for the16# specific language governing permissions and limitations17# under the License.1819require_relative 'spec_helper'2021module Selenium22module WebDriver23describe Element, exclusive: {bidi: false, reason: 'Not yet implemented with BiDi'} do24it 'clicks' do25open_file 'formPage.html'26element = wait_for_element(id: 'imageButton')27expect { element.click }.not_to raise_error28reset_driver!(time: 1) if %i[safari safari_preview].include? GlobalTestEnv.browser29end3031# Safari returns "click intercepted" error instead of "element click intercepted"32it 'raises if different element receives click', except: {browser: %i[safari safari_preview]} do33open_file 'click_tests/overlapping_elements.html'34element = wait_for_element(id: 'contents', timeout: 10)35expect { element.click }.to raise_error(Error::ElementClickInterceptedError)36end3738# Safari returns "click intercepted" error instead of "element click intercepted"39it 'raises if element is partially covered', except: {browser: %i[safari safari_preview]} do40open_file 'click_tests/overlapping_elements.html'41element = wait_for_element(id: 'other_contents')42expect { element.click }.to raise_error(Error::ElementClickInterceptedError)43end4445it 'raises if element stale' do46open_file 'formPage.html'47button = wait_for_element(id: 'imageButton')48driver.navigate.refresh4950expect { button.click }.to raise_exception(Error::StaleElementReferenceError,51/errors#staleelementreferenceexception/)5253reset_driver!(time: 1) if %i[safari safari_preview].include? GlobalTestEnv.browser54end5556describe '#submit' do57it 'valid submit button' do58open_file 'formPage.html'59wait_for_element(id: 'submitButton').submit6061wait_for_url('resultPage.html')62expect(driver.title).to eq('We Arrive Here')63end6465it 'any input element in form' do66open_file 'formPage.html'67wait_for_element(id: 'checky').submit6869wait_for_url('resultPage.html')70expect(driver.title).to eq('We Arrive Here')71end7273it 'any element in form' do74open_file 'formPage.html'75wait_for_element(css: 'form > p').submit7677wait_for_url('resultPage.html')78expect(driver.title).to eq('We Arrive Here')79end8081it 'button with id submit' do82open_file 'formPage.html'83wait_for_element(id: 'submit').submit8485wait_for_url('resultPage.html')86expect(driver.title).to eq('We Arrive Here')87end8889it 'button with name submit' do90open_file 'formPage.html'91wait_for_element(name: 'submit').submit9293wait_for_url('resultPage.html')94expect(driver.title).to eq('We Arrive Here')95end9697it 'errors with button outside form' do98open_file 'formPage.html'99element = wait_for_element(name: 'SearchableText')100expect { element.submit }.to raise_error(Error::UnsupportedOperationError)101end102end103104it 'sends empty keys' do105open_file 'formPage.html'106element = wait_for_element(id: 'working')107element.send_keys108expect(element.text).to be_empty109end110111it 'sends string keys' do112open_file 'formPage.html'113wait_for_element(id: 'working')114expect { driver.find_element(id: 'working').send_keys('foo', 'bar') }.not_to raise_error115end116117it 'sends key presses' do118open_file 'javascriptPage.html'119key_reporter = wait_for_element(id: 'keyReporter')120121key_reporter.send_keys('Tet', :arrow_left, 's')122expect(key_reporter.attribute('value')).to eq('Test')123end124125# https://github.com/mozilla/geckodriver/issues/245126it 'sends key presses chords', except: {browser: %i[firefox safari safari_preview]} do127open_file 'javascriptPage.html'128key_reporter = wait_for_element(id: 'keyReporter')129130key_reporter.send_keys([:shift, 'h'], 'ello')131expect(key_reporter.attribute('value')).to eq('Hello')132end133134it 'handles file uploads' do135open_file 'formPage.html'136137element = wait_for_element(id: 'upload')138expect(element.attribute('value')).to be_empty139140path = WebDriver::Platform.windows? ? WebDriver::Platform.windows_path(__FILE__) : __FILE__141142element.send_keys path143144expect(element.attribute('value')).to include(File.basename(path))145end146147describe 'properties and attributes' do148before { open_file 'formPage.html' }149150context 'when string type' do151let(:element) { wait_for_element(id: 'checky') }152let(:prop_or_attr) { 'type' }153154it '#dom_attribute returns attribute value' do155expect(element.dom_attribute(prop_or_attr)).to eq 'checkbox'156end157158it '#property returns property value' do159expect(element.property(prop_or_attr)).to eq 'checkbox'160end161162it '#attribute returns value' do163expect(element.attribute(prop_or_attr)).to eq 'checkbox'164end165end166167context 'when numeric type' do168let(:element) { wait_for_element(id: 'withText') }169let(:prop_or_attr) { 'rows' }170171it '#dom_attribute String' do172expect(element.dom_attribute(prop_or_attr)).to eq '5'173end174175it '#property returns Number' do176expect(element.property(prop_or_attr)).to eq 5177end178179it '#attribute returns String' do180expect(element.attribute(prop_or_attr)).to eq '5'181end182end183184context 'with boolean type of true' do185let(:element) { wait_for_element(id: 'checkedchecky') }186let(:prop_or_attr) { 'checked' }187188it '#dom_attribute returns String', except: {browser: :safari} do189expect(element.dom_attribute(prop_or_attr)).to eq 'true'190end191192it '#property returns true' do193expect(element.property(prop_or_attr)).to be true194end195196it '#attribute returns String' do197expect(element.attribute(prop_or_attr)).to eq 'true'198end199200it '#dom_attribute does not update after click', except: {browser: :safari} do201element.click202expect(element.dom_attribute(prop_or_attr)).to eq 'true'203end204205it '#property updates to false after click' do206element.click207expect(element.property(prop_or_attr)).to be false208end209210it '#attribute updates to nil after click' do211element.click212expect(element.attribute(prop_or_attr)).to be_nil213end214end215216context 'with boolean type of false' do217let(:element) { wait_for_element(id: 'checky') }218let(:prop_or_attr) { 'checked' }219220it '#dom_attribute returns nil' do221expect(element.dom_attribute(prop_or_attr)).to be_nil222end223224it '#property returns false' do225expect(element.property(prop_or_attr)).to be false226end227228it '#attribute returns nil' do229expect(element.attribute(prop_or_attr)).to be_nil230end231232it '#dom_attribute does not update after click' do233element.click234expect(element.dom_attribute(prop_or_attr)).to be_nil235end236237it '#property updates to true after click' do238element.click239expect(element.property(prop_or_attr)).to be true240end241242it '#attribute updates to String after click' do243element.click244expect(element.attribute(prop_or_attr)).to eq 'true'245end246end247248context 'when property exists but attribute does not' do249let(:element) { wait_for_element(id: 'withText') }250let(:prop_or_attr) { 'value' }251252it '#dom_attribute returns nil' do253expect(element.dom_attribute(prop_or_attr)).to be_nil254end255256it '#property returns default property' do257expect(element.property(prop_or_attr)).to eq 'Example text'258end259260it '#attribute returns default property' do261expect(element.attribute(prop_or_attr)).to eq 'Example text'262end263264it '#property returns updated property' do265element.clear266expect(element.property(prop_or_attr)).to be_empty267end268269it '#attribute returns updated property' do270element.clear271expect(element.attribute(prop_or_attr)).to be_empty272end273end274275context 'when attribute exists but property does not' do276let(:element) { wait_for_element(id: 'vsearchGadget') }277let(:prop_or_attr) { 'accesskey' }278279it '#dom_attribute returns attribute' do280expect(element.dom_attribute(prop_or_attr)).to eq '4'281end282283it '#property returns nil' do284expect(element.property(prop_or_attr)).to be_nil285end286287it '#attribute returns attribute' do288expect(element.attribute(prop_or_attr)).to eq '4'289end290end291292context 'when neither attribute nor property exists' do293let(:element) { wait_for_element(id: 'checky') }294let(:prop_or_attr) { 'nonexistent' }295296it '#dom_attribute returns nil' do297expect(element.dom_attribute(prop_or_attr)).to be_nil298end299300it '#property returns nil' do301expect(element.property(prop_or_attr)).to be_nil302end303304it '#attribute returns nil' do305expect(element.attribute(prop_or_attr)).to be_nil306end307end308309describe 'style' do310before { open_file 'clickEventPage.html' }311312let(:element) { wait_for_element(id: 'result') }313let(:prop_or_attr) { 'style' }314315it '#dom_attribute attribute with no formatting' do316expect(element.dom_attribute(prop_or_attr)).to eq 'width:300;height:60'317end318319# TODO: This might not be correct behavior320it '#property returns object',321except: [{browser: :firefox,322reason: 'https://github.com/mozilla/geckodriver/issues/1846'},323{browser: :safari}] do324expect(element.property(prop_or_attr)).to eq %w[width height]325end326327it '#attribute returns attribute with formatting' do328expect(element.attribute(prop_or_attr)).to eq 'width: 300px; height: 60px;'329end330end331332describe 'incorrect casing' do333let(:element) { wait_for_element(id: 'checky') }334let(:prop_or_attr) { 'nAme' }335336it '#dom_attribute returns correctly cased attribute' do337expect(element.dom_attribute(prop_or_attr)).to eq 'checky'338end339340it '#property returns nil' do341expect(element.property(prop_or_attr)).to be_nil342end343344it '#attribute returns correctly cased attribute' do345expect(element.attribute(prop_or_attr)).to eq 'checky'346end347end348349describe 'property attribute case difference with attribute casing' do350let(:element) { wait_for_element(name: 'readonly') }351let(:prop_or_attr) { 'readonly' }352353it '#dom_attribute returns a String', except: {browser: :safari} do354expect(element.dom_attribute(prop_or_attr)).to eq 'true'355end356357it '#property returns nil' do358expect(element.property(prop_or_attr)).to be_nil359end360361it '#attribute returns a String' do362expect(element.attribute(prop_or_attr)).to eq 'true'363end364end365366describe 'property attribute case difference with property casing' do367let(:element) { wait_for_element(name: 'readonly') }368let(:prop_or_attr) { 'readOnly' }369370it '#dom_attribute returns a String',371except: [{browser: :firefox,372reason: 'https://github.com/mozilla/geckodriver/issues/1850'},373{browser: :safari}] do374expect(element.dom_attribute(prop_or_attr)).to eq 'true'375end376377it '#property returns property as true' do378expect(element.property(prop_or_attr)).to be true379end380381it '#attribute returns property as String' do382expect(element.attribute(prop_or_attr)).to eq 'true'383end384end385386describe 'property attribute name difference with attribute naming' do387let(:element) { wait_for_element(id: 'wallace') }388let(:prop_or_attr) { 'class' }389390it '#dom_attribute returns attribute value' do391expect(element.dom_attribute(prop_or_attr)).to eq 'gromit'392end393394it '#property returns nil' do395expect(element.property(prop_or_attr)).to be_nil396end397398it '#attribute returns attribute value' do399expect(element.attribute(prop_or_attr)).to eq 'gromit'400end401end402403describe 'property attribute name difference with property naming' do404let(:element) { wait_for_element(id: 'wallace') }405let(:prop_or_attr) { 'className' }406407it '#dom_attribute returns nil' do408expect(element.dom_attribute(prop_or_attr)).to be_nil409end410411it '#property returns property value' do412expect(element.property(prop_or_attr)).to eq 'gromit'413end414415it '#attribute returns property value' do416expect(element.attribute(prop_or_attr)).to eq 'gromit'417end418end419420describe 'property attribute value difference' do421let(:element) { wait_for_element(tag_name: 'form') }422let(:prop_or_attr) { 'action' }423424it '#dom_attribute returns attribute value' do425expect(element.dom_attribute(prop_or_attr)).to eq 'resultPage.html'426end427428it '#property returns property value' do429expect(element.property(prop_or_attr)).to match(%r{http://(.+)/resultPage\.html})430end431432it '#attribute returns property value' do433expect(element.attribute(prop_or_attr)).to match(%r{http://(.+)/resultPage\.html})434end435end436end437438it 'returns ARIA role' do439driver.navigate.to 'data:text/html,' \440"<div role='heading' aria-level='1'>Level 1 Header</div>" \441'<h1>Level 1 Header</h1>' \442"<h2 role='alert'>Level 2 Header</h2>"443expect(driver.find_element(tag_name: 'div').aria_role).to eq('heading')444expect(driver.find_element(tag_name: 'h1').aria_role).to eq('heading')445expect(driver.find_element(tag_name: 'h2').aria_role).to eq('alert')446end447448it 'returns accessible name' do449driver.navigate.to 'data:text/html,<h1>Level 1 Header</h1>'450expect(driver.find_element(tag_name: 'h1').accessible_name).to eq('Level 1 Header')451end452453it 'clears' do454open_file 'formPage.html'455element = wait_for_element(id: 'withText')456expect { element.clear }.not_to raise_error457end458459it 'gets and set selected' do460open_file 'formPage.html'461462cheese = wait_for_element(id: 'cheese')463peas = wait_for_element(id: 'peas')464465cheese.click466467expect(cheese).to be_selected468expect(peas).not_to be_selected469470peas.click471472expect(peas).to be_selected473expect(cheese).not_to be_selected474end475476it 'gets enabled' do477open_file 'formPage.html'478element = wait_for_element(id: 'notWorking')479expect(element).not_to be_enabled480end481482it 'gets text' do483open_file 'xhtmlTest.html'484element = wait_for_element(class: 'header')485expect(element.text).to eq('XHTML Might Be The Future')486end487488it 'gets displayed' do489open_file 'xhtmlTest.html'490element = wait_for_element(class: 'header')491expect(element).to be_displayed492end493494describe 'size and location' do495it 'gets current location' do496open_file 'xhtmlTest.html'497loc = wait_for_element(class: 'header').location498499expect(loc.x).to be >= 1500expect(loc.y).to be >= 1501end502503it 'gets location once scrolled into view' do504open_file 'javascriptPage.html'505loc = wait_for_element(id: 'keyUp').location_once_scrolled_into_view506507expect(loc.x).to be >= 1508expect(loc.y).to be >= 0 # can be 0 if scrolled to the top509end510511it 'gets size' do512open_file 'xhtmlTest.html'513size = wait_for_element(class: 'header').size514515expect(size.width).to be_positive516expect(size.height).to be_positive517end518519it 'gets rect' do520open_file 'xhtmlTest.html'521rect = wait_for_element(class: 'header').rect522523expect(rect.x).to be_positive524expect(rect.y).to be_positive525expect(rect.width).to be_positive526expect(rect.height).to be_positive527end528end529530# IE - https://github.com/SeleniumHQ/selenium/pull/4043531it 'drags and drop', except: {browser: :ie} do532open_file 'dragAndDropTest.html'533534img1 = wait_for_element(id: 'test1')535img2 = wait_for_element(id: 'test2')536537driver.action.drag_and_drop_by(img1, 100, 100)538.drag_and_drop(img2, img1)539.perform540541expect(img1.location).to eq(img2.location)542end543544it 'gets css property' do545open_file 'javascriptPage.html'546element = wait_for_element(id: 'green-parent')547548style1 = element.css_value('background-color')549style2 = element.style('background-color') # backwards compatibility550551acceptable = ['rgb(0, 128, 0)', '#008000', 'rgba(0,128,0,1)', 'rgba(0, 128, 0, 1)']552expect(acceptable).to include(style1, style2)553end554555it 'knows when two elements are equal' do556open_file 'simpleTest.html'557558body = wait_for_element(tag_name: 'body')559xbody = wait_for_element(xpath: '//body')560jsbody = driver.execute_script('return document.getElementsByTagName("body")[0]')561562expect(body).to eq(xbody)563expect(body).to eq(jsbody)564expect(body).to eql(xbody)565expect(body).to eql(jsbody)566end567568it 'knows when element arrays are equal' do569open_file 'simpleTest.html'570571tags = driver.find_elements(tag_name: 'div')572jstags = driver.execute_script('return document.getElementsByTagName("div")')573574expect(tags).to eq(jstags)575end576577it 'knows when two elements are not equal' do578open_file 'simpleTest.html'579580elements = driver.find_elements(tag_name: 'p')581p1 = elements.fetch(0)582p2 = elements.fetch(1)583584expect(p1).not_to eq(p2)585expect(p1).not_to eql(p2)586end587588it 'returns the same #hash for equal elements when found by Driver#find_element' do589open_file 'simpleTest.html'590591body = driver.find_element(tag_name: 'body')592xbody = driver.find_element(xpath: '//body')593594expect(body.hash).to eq(xbody.hash)595end596597it 'returns the same #hash for equal elements when found by Driver#find_elements' do598open_file 'simpleTest.html'599600body = driver.find_elements(tag_name: 'body').fetch(0)601xbody = driver.find_elements(xpath: '//body').fetch(0)602603expect(body.hash).to eq(xbody.hash)604end605end606end # WebDriver607end # Selenium608609610