Path: blob/trunk/rb/spec/integration/selenium/webdriver/element_spec.rb
1864 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' do25driver.navigate.to url_for('formPage.html')26expect { driver.find_element(id: 'imageButton').click }.not_to raise_error27reset_driver!(time: 1) if %i[safari safari_preview].include? GlobalTestEnv.browser28end2930# Safari returns "click intercepted" error instead of "element click intercepted"31it 'raises if different element receives click', except: {browser: %i[safari safari_preview]} do32driver.navigate.to url_for('click_tests/overlapping_elements.html')33expect { driver.find_element(id: 'contents').click }.to raise_error(Error::ElementClickInterceptedError)34end3536# Safari returns "click intercepted" error instead of "element click intercepted"37it 'raises if element is partially covered', except: {browser: %i[safari safari_preview]} do38driver.navigate.to url_for('click_tests/overlapping_elements.html')39expect { driver.find_element(id: 'other_contents').click }.to raise_error(Error::ElementClickInterceptedError)40end4142it 'raises if element stale' do43driver.navigate.to url_for('formPage.html')44button = driver.find_element(id: 'imageButton')45driver.navigate.refresh4647expect { button.click }.to raise_exception(Error::StaleElementReferenceError,48/errors#stale-element-reference-exception/)4950reset_driver!(time: 1) if %i[safari safari_preview].include? GlobalTestEnv.browser51end5253describe '#submit' do54it 'valid submit button' do55driver.navigate.to url_for('formPage.html')56driver.find_element(id: 'submitButton').submit5758sleep 0.559expect(driver.title).to eq('We Arrive Here')60end6162it 'any input element in form' do63driver.navigate.to url_for('formPage.html')64driver.find_element(id: 'checky').submit6566sleep 0.567expect(driver.title).to eq('We Arrive Here')68end6970it 'any element in form' do71driver.navigate.to url_for('formPage.html')72driver.find_element(css: 'form > p').submit7374sleep 0.575expect(driver.title).to eq('We Arrive Here')76end7778it 'button with id submit' do79driver.navigate.to url_for('formPage.html')80driver.find_element(id: 'submit').submit8182sleep 0.583expect(driver.title).to eq('We Arrive Here')84end8586it 'button with name submit' do87driver.navigate.to url_for('formPage.html')88driver.find_element(name: 'submit').submit8990sleep 0.591expect(driver.title).to eq('We Arrive Here')92end9394it 'errors with button outside form' do95driver.navigate.to url_for('formPage.html')96expect { driver.find_element(name: 'SearchableText').submit }.to raise_error(Error::UnsupportedOperationError)97end98end99100it 'sends empty keys' do101driver.navigate.to url_for('formPage.html')102element = wait_for_element(id: 'working')103element.send_keys104expect(element.text).to be_empty105end106107it 'sends string keys' do108driver.navigate.to url_for('formPage.html')109wait_for_element(id: 'working')110expect { driver.find_element(id: 'working').send_keys('foo', 'bar') }.not_to raise_error111end112113it 'sends key presses' do114driver.navigate.to url_for('javascriptPage.html')115key_reporter = driver.find_element(id: 'keyReporter')116117key_reporter.send_keys('Tet', :arrow_left, 's')118expect(key_reporter.attribute('value')).to eq('Test')119end120121# https://github.com/mozilla/geckodriver/issues/245122it 'sends key presses chords', except: {browser: %i[firefox safari safari_preview]} do123driver.navigate.to url_for('javascriptPage.html')124key_reporter = driver.find_element(id: 'keyReporter')125126key_reporter.send_keys([:shift, 'h'], 'ello')127expect(key_reporter.attribute('value')).to eq('Hello')128end129130it 'handles file uploads' do131driver.navigate.to url_for('formPage.html')132133element = driver.find_element(id: 'upload')134expect(element.attribute('value')).to be_empty135136path = WebDriver::Platform.windows? ? WebDriver::Platform.windows_path(__FILE__) : __FILE__137138element.send_keys path139140expect(element.attribute('value')).to include(File.basename(path))141end142143describe 'properties and attributes' do144before { driver.navigate.to url_for('formPage.html') }145146context 'when string type' do147let(:element) { driver.find_element(id: 'checky') }148let(:prop_or_attr) { 'type' }149150it '#dom_attribute returns attribute value' do151expect(element.dom_attribute(prop_or_attr)).to eq 'checkbox'152end153154it '#property returns property value' do155expect(element.property(prop_or_attr)).to eq 'checkbox'156end157158it '#attribute returns value' do159expect(element.attribute(prop_or_attr)).to eq 'checkbox'160end161end162163context 'when numeric type' do164let(:element) { driver.find_element(id: 'withText') }165let(:prop_or_attr) { 'rows' }166167it '#dom_attribute String' do168expect(element.dom_attribute(prop_or_attr)).to eq '5'169end170171it '#property returns Number' do172expect(element.property(prop_or_attr)).to eq 5173end174175it '#attribute returns String' do176expect(element.attribute(prop_or_attr)).to eq '5'177end178end179180context 'with boolean type of true' do181let(:element) { driver.find_element(id: 'checkedchecky') }182let(:prop_or_attr) { 'checked' }183184it '#dom_attribute returns String', except: {browser: :safari} do185expect(element.dom_attribute(prop_or_attr)).to eq 'true'186end187188it '#property returns true' do189expect(element.property(prop_or_attr)).to be true190end191192it '#attribute returns String' do193expect(element.attribute(prop_or_attr)).to eq 'true'194end195196it '#dom_attribute does not update after click', except: {browser: :safari} do197element.click198expect(element.dom_attribute(prop_or_attr)).to eq 'true'199end200201it '#property updates to false after click' do202element.click203expect(element.property(prop_or_attr)).to be false204end205206it '#attribute updates to nil after click' do207element.click208expect(element.attribute(prop_or_attr)).to be_nil209end210end211212context 'with boolean type of false' do213let(:element) { driver.find_element(id: 'checky') }214let(:prop_or_attr) { 'checked' }215216it '#dom_attribute returns nil' do217expect(element.dom_attribute(prop_or_attr)).to be_nil218end219220it '#property returns false' do221expect(element.property(prop_or_attr)).to be false222end223224it '#attribute returns nil' do225expect(element.attribute(prop_or_attr)).to be_nil226end227228it '#dom_attribute does not update after click' do229element.click230expect(element.dom_attribute(prop_or_attr)).to be_nil231end232233it '#property updates to true after click' do234element.click235expect(element.property(prop_or_attr)).to be true236end237238it '#attribute updates to String after click' do239element.click240expect(element.attribute(prop_or_attr)).to eq 'true'241end242end243244context 'when property exists but attribute does not' do245let(:element) { driver.find_element(id: 'withText') }246let(:prop_or_attr) { 'value' }247248it '#dom_attribute returns nil' do249expect(element.dom_attribute(prop_or_attr)).to be_nil250end251252it '#property returns default property' do253expect(element.property(prop_or_attr)).to eq 'Example text'254end255256it '#attribute returns default property' do257expect(element.attribute(prop_or_attr)).to eq 'Example text'258end259260it '#property returns updated property' do261element.clear262expect(element.property(prop_or_attr)).to be_empty263end264265it '#attribute returns updated property' do266element.clear267expect(element.attribute(prop_or_attr)).to be_empty268end269end270271context 'when attribute exists but property does not' do272let(:element) { driver.find_element(id: 'vsearchGadget') }273let(:prop_or_attr) { 'accesskey' }274275it '#dom_attribute returns attribute' do276expect(element.dom_attribute(prop_or_attr)).to eq '4'277end278279it '#property returns nil' do280expect(element.property(prop_or_attr)).to be_nil281end282283it '#attribute returns attribute' do284expect(element.attribute(prop_or_attr)).to eq '4'285end286end287288context 'when neither attribute nor property exists' do289let(:element) { driver.find_element(id: 'checky') }290let(:prop_or_attr) { 'nonexistent' }291292it '#dom_attribute returns nil' do293expect(element.dom_attribute(prop_or_attr)).to be_nil294end295296it '#property returns nil' do297expect(element.property(prop_or_attr)).to be_nil298end299300it '#attribute returns nil' do301expect(element.attribute(prop_or_attr)).to be_nil302end303end304305describe 'style' do306before { driver.navigate.to url_for('clickEventPage.html') }307308let(:element) { driver.find_element(id: 'result') }309let(:prop_or_attr) { 'style' }310311it '#dom_attribute attribute with no formatting' do312expect(element.dom_attribute(prop_or_attr)).to eq 'width:300;height:60'313end314315# TODO: This might not be correct behavior316it '#property returns object',317except: [{browser: :firefox,318reason: 'https://github.com/mozilla/geckodriver/issues/1846'},319{browser: :safari}] do320expect(element.property(prop_or_attr)).to eq %w[width height]321end322323it '#attribute returns attribute with formatting' do324expect(element.attribute(prop_or_attr)).to eq 'width: 300px; height: 60px;'325end326end327328describe 'incorrect casing' do329let(:element) { driver.find_element(id: 'checky') }330let(:prop_or_attr) { 'nAme' }331332it '#dom_attribute returns correctly cased attribute' do333expect(element.dom_attribute(prop_or_attr)).to eq 'checky'334end335336it '#property returns nil' do337expect(element.property(prop_or_attr)).to be_nil338end339340it '#attribute returns correctly cased attribute' do341expect(element.attribute(prop_or_attr)).to eq 'checky'342end343end344345describe 'property attribute case difference with attribute casing' do346let(:element) { driver.find_element(name: 'readonly') }347let(:prop_or_attr) { 'readonly' }348349it '#dom_attribute returns a String', except: {browser: :safari} do350expect(element.dom_attribute(prop_or_attr)).to eq 'true'351end352353it '#property returns nil' do354expect(element.property(prop_or_attr)).to be_nil355end356357it '#attribute returns a String' do358expect(element.attribute(prop_or_attr)).to eq 'true'359end360end361362describe 'property attribute case difference with property casing' do363let(:element) { driver.find_element(name: 'readonly') }364let(:prop_or_attr) { 'readOnly' }365366it '#dom_attribute returns a String',367except: [{browser: :firefox,368reason: 'https://github.com/mozilla/geckodriver/issues/1850'},369{browser: :safari}] do370expect(element.dom_attribute(prop_or_attr)).to eq 'true'371end372373it '#property returns property as true' do374expect(element.property(prop_or_attr)).to be true375end376377it '#attribute returns property as String' do378expect(element.attribute(prop_or_attr)).to eq 'true'379end380end381382describe 'property attribute name difference with attribute naming' do383let(:element) { driver.find_element(id: 'wallace') }384let(:prop_or_attr) { 'class' }385386it '#dom_attribute returns attribute value' do387expect(element.dom_attribute(prop_or_attr)).to eq 'gromit'388end389390it '#property returns nil' do391expect(element.property(prop_or_attr)).to be_nil392end393394it '#attribute returns attribute value' do395expect(element.attribute(prop_or_attr)).to eq 'gromit'396end397end398399describe 'property attribute name difference with property naming' do400let(:element) { driver.find_element(id: 'wallace') }401let(:prop_or_attr) { 'className' }402403it '#dom_attribute returns nil' do404expect(element.dom_attribute(prop_or_attr)).to be_nil405end406407it '#property returns property value' do408expect(element.property(prop_or_attr)).to eq 'gromit'409end410411it '#attribute returns property value' do412expect(element.attribute(prop_or_attr)).to eq 'gromit'413end414end415416describe 'property attribute value difference' do417let(:element) { driver.find_element(tag_name: 'form') }418let(:prop_or_attr) { 'action' }419420it '#dom_attribute returns attribute value' do421expect(element.dom_attribute(prop_or_attr)).to eq 'resultPage.html'422end423424it '#property returns property value' do425expect(element.property(prop_or_attr)).to match(%r{http://(.+)/resultPage\.html})426end427428it '#attribute returns property value' do429expect(element.attribute(prop_or_attr)).to match(%r{http://(.+)/resultPage\.html})430end431end432end433434it 'returns ARIA role' do435driver.navigate.to 'data:text/html,' \436"<div role='heading' aria-level='1'>Level 1 Header</div>" \437'<h1>Level 1 Header</h1>' \438"<h2 role='alert'>Level 2 Header</h2>"439expect(driver.find_element(tag_name: 'div').aria_role).to eq('heading')440expect(driver.find_element(tag_name: 'h1').aria_role).to eq('heading')441expect(driver.find_element(tag_name: 'h2').aria_role).to eq('alert')442end443444it 'returns accessible name' do445driver.navigate.to 'data:text/html,<h1>Level 1 Header</h1>'446expect(driver.find_element(tag_name: 'h1').accessible_name).to eq('Level 1 Header')447end448449it 'clears' do450driver.navigate.to url_for('formPage.html')451expect { driver.find_element(id: 'withText').clear }.not_to raise_error452end453454it 'gets and set selected' do455driver.navigate.to url_for('formPage.html')456457cheese = driver.find_element(id: 'cheese')458peas = driver.find_element(id: 'peas')459460cheese.click461462expect(cheese).to be_selected463expect(peas).not_to be_selected464465peas.click466467expect(peas).to be_selected468expect(cheese).not_to be_selected469end470471it 'gets enabled' do472driver.navigate.to url_for('formPage.html')473expect(driver.find_element(id: 'notWorking')).not_to be_enabled474end475476it 'gets text' do477driver.navigate.to url_for('xhtmlTest.html')478expect(driver.find_element(class: 'header').text).to eq('XHTML Might Be The Future')479end480481it 'gets displayed' do482driver.navigate.to url_for('xhtmlTest.html')483expect(driver.find_element(class: 'header')).to be_displayed484end485486describe 'size and location' do487it 'gets current location' do488driver.navigate.to url_for('xhtmlTest.html')489loc = driver.find_element(class: 'header').location490491expect(loc.x).to be >= 1492expect(loc.y).to be >= 1493end494495it 'gets location once scrolled into view' do496driver.navigate.to url_for('javascriptPage.html')497loc = driver.find_element(id: 'keyUp').location_once_scrolled_into_view498499expect(loc.x).to be >= 1500expect(loc.y).to be >= 0 # can be 0 if scrolled to the top501end502503it 'gets size' do504driver.navigate.to url_for('xhtmlTest.html')505size = driver.find_element(class: 'header').size506507expect(size.width).to be_positive508expect(size.height).to be_positive509end510511it 'gets rect' do512driver.navigate.to url_for('xhtmlTest.html')513rect = driver.find_element(class: 'header').rect514515expect(rect.x).to be_positive516expect(rect.y).to be_positive517expect(rect.width).to be_positive518expect(rect.height).to be_positive519end520end521522# IE - https://github.com/SeleniumHQ/selenium/pull/4043523it 'drags and drop', except: {browser: :ie} do524driver.navigate.to url_for('dragAndDropTest.html')525526img1 = driver.find_element(id: 'test1')527img2 = driver.find_element(id: 'test2')528529driver.action.drag_and_drop_by(img1, 100, 100)530.drag_and_drop(img2, img1)531.perform532533expect(img1.location).to eq(img2.location)534end535536it 'gets css property' do537driver.navigate.to url_for('javascriptPage.html')538element = driver.find_element(id: 'green-parent')539540style1 = element.css_value('background-color')541style2 = element.style('background-color') # backwards compatibility542543acceptable = ['rgb(0, 128, 0)', '#008000', 'rgba(0,128,0,1)', 'rgba(0, 128, 0, 1)']544expect(acceptable).to include(style1, style2)545end546547it 'knows when two elements are equal' do548driver.navigate.to url_for('simpleTest.html')549550body = driver.find_element(tag_name: 'body')551xbody = driver.find_element(xpath: '//body')552jsbody = driver.execute_script('return document.getElementsByTagName("body")[0]')553554expect(body).to eq(xbody)555expect(body).to eq(jsbody)556expect(body).to eql(xbody)557expect(body).to eql(jsbody)558end559560it 'knows when element arrays are equal' do561driver.navigate.to url_for('simpleTest.html')562563tags = driver.find_elements(tag_name: 'div')564jstags = driver.execute_script('return document.getElementsByTagName("div")')565566expect(tags).to eq(jstags)567end568569it 'knows when two elements are not equal' do570driver.navigate.to url_for('simpleTest.html')571572elements = driver.find_elements(tag_name: 'p')573p1 = elements.fetch(0)574p2 = elements.fetch(1)575576expect(p1).not_to eq(p2)577expect(p1).not_to eql(p2)578end579580it 'returns the same #hash for equal elements when found by Driver#find_element' do581driver.navigate.to url_for('simpleTest.html')582583body = driver.find_element(tag_name: 'body')584xbody = driver.find_element(xpath: '//body')585586expect(body.hash).to eq(xbody.hash)587end588589it 'returns the same #hash for equal elements when found by Driver#find_elements' do590driver.navigate.to url_for('simpleTest.html')591592body = driver.find_elements(tag_name: 'body').fetch(0)593xbody = driver.find_elements(xpath: '//body').fetch(0)594595expect(body.hash).to eq(xbody.hash)596end597end598end # WebDriver599end # Selenium600601602