Path: blob/trunk/rb/spec/unit/selenium/webdriver/support/select_spec.rb
1865 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 File.expand_path('../spec_helper', __dir__)2021module Selenium22module WebDriver23module Support24describe Select do25let(:select) do26select_element = instance_double(Element, tag_name: 'select')27allow(select_element).to receive(:dom_attribute).with(:multiple)28select_element29end3031let(:multi_select) do32select_element = instance_double(Element, tag_name: 'select')33allow(select_element).to receive(:dom_attribute).with(:multiple).and_return 'multiple'34select_element35end3637it 'raises ArgumentError if passed a non-select Element' do38link = instance_double(Element, tag_name: 'a')3940expect { described_class.new link }.to raise_error(ArgumentError)41end4243it 'indicates whether a select is multiple correctly' do44selects = Array.new(4) { instance_double(Element, tag_name: 'select') }4546allow(selects[0]).to receive(:dom_attribute).with(:multiple).and_return('false')47allow(selects[1]).to receive(:dom_attribute).with(:multiple).and_return(nil)48allow(selects[2]).to receive(:dom_attribute).with(:multiple).and_return('true')49allow(selects[3]).to receive(:dom_attribute).with(:multiple).and_return('multiple')5051expect(described_class.new(selects[0])).not_to be_multiple52expect(described_class.new(selects[1])).not_to be_multiple53expect(described_class.new(selects[2])).to be_multiple54expect(described_class.new(selects[3])).to be_multiple55end5657it 'returns all options' do58options = []59allow(multi_select).to receive(:find_elements).and_return(options)6061expect(described_class.new(multi_select).options).to eql(options)62expect(multi_select).to have_received(:find_elements).with(tag_name: 'option')63end6465it 'returns all selected options' do66bad_option = instance_double(Element, selected?: false)67good_option = instance_double(Element, selected?: true)68allow(multi_select).to receive(:find_elements).and_return([bad_option, good_option])6970opts = described_class.new(multi_select).selected_options7172expect(opts.size).to eq(1)73expect(opts.first).to eq(good_option)74expect(multi_select).to have_received(:find_elements).with(tag_name: 'option')75end7677it 'returns the first selected option' do78first_option = instance_double(Element, selected?: true)79second_option = instance_double(Element, selected?: true)80allow(multi_select).to receive(:find_elements).and_return([first_option, second_option])8182option = described_class.new(multi_select).first_selected_option83expect(option).to eq(first_option)84expect(multi_select).to have_received(:find_elements).with(tag_name: 'option')85end8687it 'raises a NoSuchElementError if nothing is selected' do88option = instance_double(Element, selected?: false)89allow(multi_select).to receive(:find_elements).and_return([option])9091expect { described_class.new(multi_select).first_selected_option }.to raise_error(Error::NoSuchElementError)92end9394it 'allows options to be selected by visible text' do95option = instance_double(Element, selected?: false, enabled?: true, click: nil)96allow(multi_select).to receive(:find_elements).and_return([option])9798described_class.new(multi_select).select_by(:text, 'fish')99expect(option).to have_received(:click)100expect(multi_select).to have_received(:find_elements).with(xpath: './/option[normalize-space(.) = "fish"]')101end102103it 'allows options to be selected by index' do104first_option = instance_double(Element, selected?: true, enabled?: true, click: nil)105second_option = instance_double(Element, selected?: false, enabled?: true, click: nil)106107allow(first_option).to receive(:property).with(:index).and_return 0108allow(second_option).to receive(:property).with(:index).and_return 1109allow(multi_select).to receive(:find_elements).and_return([first_option, second_option])110111described_class.new(multi_select).select_by(:index, 1)112expect(first_option).to have_received(:property).with(:index)113expect(second_option).to have_received(:property).with(:index)114expect(multi_select).to have_received(:find_elements).with(tag_name: 'option')115expect(first_option).not_to have_received(:click)116expect(second_option).to have_received(:click).once117end118119it 'allows options to be selected by returned value' do120first_option = instance_double(Element, selected?: false, enabled?: true, click: nil)121allow(multi_select).to receive(:find_elements).and_return([first_option])122123described_class.new(multi_select).select_by(:value, 'b')124125expect(multi_select).to have_received(:find_elements).with(xpath: './/option[@value = "b"]')126expect(first_option).to have_received(:click).once127expect(multi_select).to have_received(:find_elements).with(xpath: './/option[@value = "b"]')128end129130it 'can deselect all when select supports multiple selections' do131first_option = instance_double(Element, selected?: true, click: nil)132second_option = instance_double(Element, selected?: false, click: nil)133allow(multi_select).to receive(:find_elements).and_return([first_option, second_option])134135described_class.new(multi_select).deselect_all136137expect(multi_select).to have_received(:find_elements).with(tag_name: 'option')138expect(first_option).to have_received(:click).once139expect(second_option).not_to have_received(:click)140end141142it 'can not deselect all when select does not support multiple selections' do143expect { described_class.new(select).deselect_all }.to raise_error(Error::UnsupportedOperationError)144end145146it 'can deselect options by visible text' do147first_option = instance_double(Element, selected?: true, click: nil)148second_option = instance_double(Element, selected?: false, click: nil)149allow(multi_select).to receive(:find_elements).and_return([first_option, second_option])150151described_class.new(multi_select).deselect_by(:text, 'b')152153expect(multi_select).to have_received(:find_elements).with(xpath: './/option[normalize-space(.) = "b"]')154expect(first_option).to have_received(:click).once155expect(second_option).not_to have_received(:click)156end157158it 'can deselect options by index' do159first_option = instance_double(Element, selected?: true, click: nil)160second_option = instance_double(Element, click: nil)161162allow(multi_select).to receive(:find_elements).and_return([first_option, second_option])163allow(first_option).to receive(:property).with(:index).and_return(2)164allow(second_option).to receive(:property).with(:index).and_return(1)165166described_class.new(multi_select).deselect_by(:index, 2)167168expect(first_option).to have_received(:click).once169expect(second_option).not_to have_received(:click)170expect(multi_select).to have_received(:find_elements).with(tag_name: 'option')171end172173it 'can deselect options by returned value' do174first_option = instance_double(Element, selected?: true, click: nil)175second_option = instance_double(Element, selected?: false, click: nil)176allow(multi_select).to receive(:find_elements).and_return([first_option, second_option])177178described_class.new(multi_select).deselect_by(:value, 'b')179180expect(first_option).to have_received(:click).once181expect(second_option).not_to have_received(:click)182expect(multi_select).to have_received(:find_elements).with(xpath: './/option[@value = "b"]')183end184185it 'falls back to slow lookups when "get by visible text fails" and there is a space' do186first_option = instance_double(Element, selected?: false, enabled?: true, text: 'foo bar', click: nil)187allow(select).to receive(:find_elements).and_return([], [first_option])188189described_class.new(select).select_by(:text, 'foo bar')190191expect(first_option).to have_received(:click).once192expect(select).to have_received(:find_elements).with(xpath: './/option[normalize-space(.) = "foo bar"]').once193expect(select).to have_received(:find_elements).with(xpath: './/option[contains(., "foo")]').once194end195196it 'raises NoSuchElementError if there are no selects to select' do197allow(select).to receive(:find_elements).and_return []198199select_element = described_class.new select200201expect { select_element.select_by :index, 12 }.to raise_error(Error::NoSuchElementError)202expect { select_element.select_by :value, 'not there' }.to raise_error(Error::NoSuchElementError)203expect { select_element.select_by :text, 'also not there' }.to raise_error(Error::NoSuchElementError)204end205206it 'raises NoSuchElementError if there are no selects to deselect' do207allow(multi_select).to receive(:find_elements).and_return []208209select_element = described_class.new multi_select210211expect { select_element.deselect_by :index, 12 }.to raise_error(Error::NoSuchElementError)212expect { select_element.deselect_by :value, 'not there' }.to raise_error(Error::NoSuchElementError)213expect { select_element.deselect_by :text, 'also not there' }.to raise_error(Error::NoSuchElementError)214end215216it 'raises UnsupportedOperationError if trying to deselect options in non-multiselect' do217select_element = described_class.new select218219expect { select_element.deselect_by :index, 0 }.to raise_error(Error::UnsupportedOperationError)220expect { select_element.deselect_by :value, 'not there' }.to raise_error(Error::UnsupportedOperationError)221expect { select_element.deselect_by :text, 'also not there' }.to raise_error(Error::UnsupportedOperationError)222end223end # Select224225describe Escaper do226it 'converts an unquoted string into one with quotes' do227expect(described_class.escape('abc')).to eq('"abc"')228expect(described_class.escape('abc aqewqqw')).to eq('"abc aqewqqw"')229expect(described_class.escape('')).to eq('""')230expect(described_class.escape(' ')).to eq('" "')231expect(described_class.escape(' abc ')).to eq('" abc "')232end233234it 'double quotes a string that contains a single quote' do235expect(described_class.escape("f'oo")).to eq(%("f'oo"))236end237238it 'single quotes a string that contains a double quote' do239expect(described_class.escape('f"oo')).to eq(%('f"oo'))240end241242it 'provides concatenated strings when string to escape contains both single and double quotes' do243expect(described_class.escape(%(f"o'o))).to eq(%{concat("f", '"', "o'o")})244end245246it 'provides concatenated strings when string ends with quote' do247expect(described_class.escape(%('"))).to eq(%{concat("'", '"')})248end249end250end # Support251end # WebDriver252end # Selenium253254255