Path: blob/trunk/rb/spec/integration/selenium/webdriver/driver_spec.rb
4041 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 Driver, exclusive: {bidi: false, reason: 'Not yet implemented with BiDi'} do24after { reset_driver! if GlobalTestEnv.rbe? && GlobalTestEnv.browser == :chrome }2526it_behaves_like 'driver that can be started concurrently', exclude: [27{browser: %i[safari safari_preview]},28{browser: :firefox, reason: 'https://github.com/SeleniumHQ/selenium/issues/15451'},29{driver: :remote, rbe: true, reason: 'Cannot start 2+ drivers at once.'}30]3132it 'creates default capabilities', exclude: {browser: %i[safari safari_preview]} do33reset_driver! do |driver|34caps = driver.capabilities35expect(caps.proxy).to be_nil36expect(caps.browser_version).to match(/^\d\d\d?\./)37expect(caps.platform_name).not_to be_nil3839expect(caps.accept_insecure_certs).to eq(caps.browser_name == 'firefox')40expect(caps.page_load_strategy).to eq 'normal'41expect(caps.implicit_timeout).to be_zero42expect(caps.page_load_timeout).to eq 30000043expect(caps.script_timeout).to eq 3000044end45end4647it 'gets driver status' do48status = driver.status49expect(status).to include('ready', 'message')50end5152it 'gets the page title' do53driver.navigate.to url_for('xhtmlTest.html')54expect(driver.title).to eq('XHTML Test Page')55end5657it 'gets the page source' do58driver.navigate.to url_for('xhtmlTest.html')59expect(driver.page_source).to match(%r{<title>XHTML Test Page</title>}i)60end6162it 'refreshes the page' do63driver.navigate.to url_for('javascriptPage.html')64short_wait { driver.find_element(id: 'updatediv') }.click65expect(driver.find_element(id: 'dynamo').text).to eq('Fish and chips!')66driver.navigate.refresh67wait_for_element(id: 'dynamo')68expect(driver.find_element(id: 'dynamo').text).to eq("What's for dinner?")69end7071describe 'one element' do72it 'finds by id' do73driver.navigate.to url_for('xhtmlTest.html')74element = driver.find_element(id: 'id1')75expect(element).to be_a(WebDriver::Element)76expect(element.text).to eq('Foo')77end7879it 'finds by field name' do80driver.navigate.to url_for('formPage.html')81expect(driver.find_element(name: 'x').attribute('value')).to eq('name')82end8384it 'finds by class name' do85driver.navigate.to url_for('xhtmlTest.html')86expect(driver.find_element(class: 'header').text).to eq('XHTML Might Be The Future')87end8889it 'finds by link text' do90driver.navigate.to url_for('xhtmlTest.html')91expect(driver.find_element(link: 'Foo').text).to eq('Foo')92end9394it 'finds by xpath' do95driver.navigate.to url_for('xhtmlTest.html')96expect(driver.find_element(xpath: '//h1').text).to eq('XHTML Might Be The Future')97end9899it 'finds by css selector' do100driver.navigate.to url_for('xhtmlTest.html')101expect(driver.find_element(css: 'div.content').attribute('class')).to eq('content')102end103104it 'finds by tag name' do105driver.navigate.to url_for('xhtmlTest.html')106expect(driver.find_element(tag_name: 'div').attribute('class')).to eq('navigation')107end108109it 'finds above another' do110driver.navigate.to url_for('relative_locators.html')111112above = driver.find_element(relative: {tag_name: 'td', above: {id: 'center'}})113expect(above.attribute('id')).to eq('top')114end115116it 'finds child element' do117driver.navigate.to url_for('nestedElements.html')118119element = driver.find_element(name: 'form2')120child = element.find_element(name: 'selectomatic')121122expect(child.attribute('id')).to eq('2')123end124125it 'finds child element by tag name' do126driver.navigate.to url_for('nestedElements.html')127128element = driver.find_element(name: 'form2')129child = element.find_element(tag_name: 'select')130131expect(child.attribute('id')).to eq('2')132end133134it 'finds elements with the shortcut syntax' do135driver.navigate.to url_for('xhtmlTest.html')136137expect(driver[:id1]).to be_a(WebDriver::Element)138expect(driver[xpath: '//h1']).to be_a(WebDriver::Element)139end140141it 'raises if element not found' do142driver.navigate.to url_for('xhtmlTest.html')143expect {144driver.find_element(id: 'not-there')145}.to raise_error(Error::NoSuchElementError, /errors#nosuchelementexception/)146end147148it 'raises if invalid locator',149exclude: {browser: %i[safari safari_preview], reason: 'Safari TimeoutError'} do150driver.navigate.to url_for('xhtmlTest.html')151expect {152driver.find_element(xpath: '*?//-')153}.to raise_error(Error::InvalidSelectorError, /errors#invalidselectorexception/)154end155end156157describe 'many elements' do158it 'finds by class name' do159driver.navigate.to url_for('xhtmlTest.html')160expect(driver.find_elements(class: 'nameC').size).to eq(2)161end162163it 'finds by css selector' do164driver.navigate.to url_for('xhtmlTest.html')165expect(driver.find_elements(css: 'p').size).to be_positive166end167168it 'finds above element' do169driver.navigate.to url_for('relative_locators.html')170171lowest = driver.find_element(id: 'below')172above = driver.find_elements(relative: {tag_name: 'p', above: lowest})173expect(above.map { |e| e.attribute('id') }).to eq(%w[mid above])174end175176it 'finds above another' do177driver.navigate.to url_for('relative_locators.html')178179above = driver.find_elements(relative: {css: 'td', above: {id: 'center'}})180expect(above.map { |e| e.attribute('id') }).to eq(%w[top topLeft topRight])181end182183it 'finds below element' do184driver.navigate.to url_for('relative_locators.html')185186midpoint = driver.find_element(id: 'mid')187above = driver.find_elements(relative: {id: 'below', below: midpoint})188expect(above.map { |e| e.attribute('id') }).to eq(['below'])189end190191it 'finds near another within default distance' do192driver.navigate.to url_for('relative_locators.html')193194near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'right'}})195expect(near.map { |e| e.attribute('id') }).to eq(%w[topRight bottomRight center top bottom])196end197198it 'finds near another within custom distance', except: {browser: %i[safari safari_preview]} do199driver.navigate.to url_for('relative_locators.html')200201near = driver.find_elements(relative: {tag_name: 'td', near: {id: 'right', distance: 100}})202expect(near.map { |e| e.attribute('id') }).to eq(%w[topRight bottomRight center top bottom])203end204205it 'finds to the left of another' do206driver.navigate.to url_for('relative_locators.html')207208left = driver.find_elements(relative: {tag_name: 'td', left: {id: 'center'}})209expect(left.map { |e| e.attribute('id') }).to eq(%w[left topLeft bottomLeft])210end211212it 'finds to the right of another' do213driver.navigate.to url_for('relative_locators.html')214215right = driver.find_elements(relative: {tag_name: 'td', right: {id: 'center'}})216expect(right.map { |e| e.attribute('id') }).to eq(%w[right topRight bottomRight])217end218219it 'finds by combined relative locators' do220driver.navigate.to url_for('relative_locators.html')221222found = driver.find_elements(relative: {tag_name: 'td', right: {id: 'top'}, above: {id: 'center'}})223expect(found.map { |e| e.attribute('id') }).to eq(['topRight'])224end225226it 'finds all by empty relative locator' do227driver.navigate.to url_for('relative_locators.html')228229expected = driver.find_elements(tag_name: 'p')230actual = driver.find_elements(relative: {tag_name: 'p'})231expect(actual).to eq(expected)232end233234it 'finds children by field name' do235driver.navigate.to url_for('nestedElements.html')236element = driver.find_element(name: 'form2')237children = element.find_elements(name: 'selectomatic')238expect(children.size).to eq(2)239end240end241242describe '#execute_script' do243it 'returns strings' do244driver.navigate.to url_for('xhtmlTest.html')245expect(driver.execute_script('return document.title;')).to eq('XHTML Test Page')246end247248it 'returns numbers' do249driver.navigate.to url_for('xhtmlTest.html')250expect(driver.execute_script('return document.title.length;')).to eq(15)251end252253it 'returns elements' do254driver.navigate.to url_for('xhtmlTest.html')255element = driver.execute_script("return document.getElementById('id1');")256expect(element).to be_a(WebDriver::Element)257expect(element.text).to eq('Foo')258end259260it 'unwraps elements in deep objects' do261driver.navigate.to url_for('xhtmlTest.html')262result = driver.execute_script(<<~SCRIPT)263var e1 = document.getElementById('id1');264var body = document.body;265266return {267elements: {'body' : body, other: [e1] }268};269SCRIPT270271expect(result).to be_a(Hash)272expect(result['elements']['body']).to be_a(WebDriver::Element)273expect(result['elements']['other'].first).to be_a(WebDriver::Element)274end275276it 'returns booleans' do277driver.navigate.to url_for('xhtmlTest.html')278expect(driver.execute_script('return true;')).to be(true)279end280281it 'raises if the script is bad' do282driver.navigate.to url_for('xhtmlTest.html')283expect {284driver.execute_script('return squiggle();')285}.to raise_error(Selenium::WebDriver::Error::JavascriptError)286end287288it 'returns arrays' do289driver.navigate.to url_for('xhtmlTest.html')290expect(driver.execute_script('return ["zero", "one", "two"];')).to eq(%w[zero one two])291end292293it 'is able to call functions on the page' do294driver.navigate.to url_for('javascriptPage.html')295driver.execute_script("displayMessage('I like cheese');")296expect(driver.find_element(id: 'result').text.strip).to eq('I like cheese')297end298299it 'is able to pass string arguments' do300driver.navigate.to url_for('javascriptPage.html')301expect(driver.execute_script("return arguments[0] == 'fish' ? 'fish' : 'not fish';", 'fish')).to eq('fish')302end303304it 'is able to pass boolean arguments' do305driver.navigate.to url_for('javascriptPage.html')306expect(driver.execute_script('return arguments[0] == true;', true)).to be(true)307end308309it 'is able to pass numeric arguments' do310driver.navigate.to url_for('javascriptPage.html')311expect(driver.execute_script('return arguments[0] == 1 ? 1 : 0;', 1)).to eq(1)312end313314it 'is able to pass null arguments' do315driver.navigate.to url_for('javascriptPage.html')316expect(driver.execute_script('return arguments[0];', nil)).to be_nil317end318319it 'is able to pass array arguments' do320driver.navigate.to url_for('javascriptPage.html')321expect(driver.execute_script('return arguments[0];', [1, '2', 3])).to eq([1, '2', 3])322end323324it 'is able to pass element arguments' do325driver.navigate.to url_for('javascriptPage.html')326button = driver.find_element(id: 'plainButton')327js = "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble'];"328expect(driver.execute_script(js, button))329.to eq('plainButton')330end331332it 'is able to pass in multiple arguments' do333driver.navigate.to url_for('javascriptPage.html')334expect(driver.execute_script('return arguments[0] + arguments[1];', 'one', 'two')).to eq('onetwo')335end336end337338describe 'execute async script' do339before do340driver.manage.timeouts.script = 1341driver.navigate.to url_for('ajaxy_page.html')342end343344it 'is able to return arrays of primitives from async scripts' do345result = driver.execute_async_script "arguments[arguments.length - 1]([null, 123, 'abc', true, false]);"346expect(result).to eq([nil, 123, 'abc', true, false])347end348349it 'is able to pass multiple arguments to async scripts' do350result = driver.execute_async_script 'arguments[arguments.length - 1](arguments[0] + arguments[1]);', 1, 2351expect(result).to eq(3)352end353354# Safari raises TimeoutError instead355it 'times out if the callback is not invoked', except: {browser: %i[safari safari_preview]} do356expect {357# Script is expected to be async and explicitly callback, so this should timeout.358driver.execute_async_script 'return 1 + 2;'359}.to raise_error(Selenium::WebDriver::Error::ScriptTimeoutError)360end361end362end363end # WebDriver364end # Selenium365366367