selenium
This commit is contained in:
466
node_modules/selenium-webdriver/lib/select.js
generated
vendored
Normal file
466
node_modules/selenium-webdriver/lib/select.js
generated
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
// Licensed to the Software Freedom Conservancy (SFC) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The SFC licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
/*
|
||||
* Licensed to the Software Freedom Conservancy (SFC) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The SFC licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const { By, escapeCss } = require('./by')
|
||||
const error = require('./error')
|
||||
|
||||
/**
|
||||
* ISelect interface makes a protocol for all kind of select elements (standard html and custom
|
||||
* model)
|
||||
*
|
||||
* @interface
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
class ISelect {
|
||||
/**
|
||||
* @return {!Promise<boolean>} Whether this select element supports selecting multiple options at the same time? This
|
||||
* is done by checking the value of the "multiple" attribute.
|
||||
*/
|
||||
isMultiple() {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* @return {!Promise<!Array<!WebElement>>} All options belonging to this select tag
|
||||
*/
|
||||
getOptions() {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* @return {!Promise<!Array<!WebElement>>} All selected options belonging to this select tag
|
||||
*/
|
||||
getAllSelectedOptions() {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* @return {!Promise<!WebElement>} The first selected option in this select tag (or the currently selected option in a
|
||||
* normal select)
|
||||
*/
|
||||
getFirstSelectedOption() {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* Select all options that display text matching the argument. That is, when given "Bar" this
|
||||
* would select an option like:
|
||||
*
|
||||
* <option value="foo">Bar</option>
|
||||
*
|
||||
* @param {string} text The visible text to match against
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
selectByVisibleText(text) {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* Select all options that have a value matching the argument. That is, when given "foo" this
|
||||
* would select an option like:
|
||||
*
|
||||
* <option value="foo">Bar</option>
|
||||
*
|
||||
* @param {string} value The value to match against
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
selectByValue(value) {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* Select the option at the given index. This is done by examining the "index" attribute of an
|
||||
* element, and not merely by counting.
|
||||
*
|
||||
* @param {Number} index The option at this index will be selected
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
selectByIndex(index) {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* Clear all selected entries. This is only valid when the SELECT supports multiple selections.
|
||||
*
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
deselectAll() {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* Deselect all options that display text matching the argument. That is, when given "Bar" this
|
||||
* would deselect an option like:
|
||||
*
|
||||
* <option value="foo">Bar</option>
|
||||
*
|
||||
* @param {string} text The visible text to match against
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
deselectByVisibleText(text) {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* Deselect all options that have a value matching the argument. That is, when given "foo" this
|
||||
* would deselect an option like:
|
||||
*
|
||||
* @param {string} value The value to match against
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
deselectByValue(value) {} // eslint-disable-line
|
||||
|
||||
/**
|
||||
* Deselect the option at the given index. This is done by examining the "index" attribute of an
|
||||
* element, and not merely by counting.
|
||||
*
|
||||
* @param {Number} index The option at this index will be deselected
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
deselectByIndex(index) {} // eslint-disable-line
|
||||
}
|
||||
|
||||
/**
|
||||
* @implements ISelect
|
||||
*/
|
||||
class Select {
|
||||
/**
|
||||
* Create an Select Element
|
||||
* @param {WebElement} element Select WebElement.
|
||||
*/
|
||||
constructor(element) {
|
||||
this.element = element
|
||||
|
||||
this.element.getAttribute('tagName').then(function (tagName) {
|
||||
if (tagName.toLowerCase() !== 'select') {
|
||||
throw new Error(`Select only works on <select> elements`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Select option with specified index.
|
||||
*
|
||||
* <example>
|
||||
<select id="selectbox">
|
||||
<option value="1">Option 1</option>
|
||||
<option value="2">Option 2</option>
|
||||
<option value="3">Option 3</option>
|
||||
</select>
|
||||
const selectBox = await driver.findElement(By.id("selectbox"));
|
||||
await selectObject.selectByIndex(1);
|
||||
* </example>
|
||||
*
|
||||
* @param index
|
||||
*/
|
||||
async selectByIndex(index) {
|
||||
if (index < 0) {
|
||||
throw new Error('Index needs to be 0 or any other positive number')
|
||||
}
|
||||
|
||||
let options = await this.element.findElements(By.tagName('option'))
|
||||
|
||||
if (options.length === 0) {
|
||||
throw new Error("Select element doesn't contain any option element")
|
||||
}
|
||||
|
||||
if (options.length - 1 < index) {
|
||||
throw new Error(
|
||||
`Option with index "${index}" not found. Select element only contains ${
|
||||
options.length - 1
|
||||
} option elements`
|
||||
)
|
||||
}
|
||||
|
||||
for (let option of options) {
|
||||
if ((await option.getAttribute('index')) === index.toString()) {
|
||||
await this.setSelected(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Select option by specific value.
|
||||
*
|
||||
* <example>
|
||||
<select id="selectbox">
|
||||
<option value="1">Option 1</option>
|
||||
<option value="2">Option 2</option>
|
||||
<option value="3">Option 3</option>
|
||||
</select>
|
||||
const selectBox = await driver.findElement(By.id("selectbox"));
|
||||
await selectObject.selectByVisibleText("Option 2");
|
||||
* </example>
|
||||
*
|
||||
*
|
||||
* @param {string} value value of option element to be selected
|
||||
*/
|
||||
async selectByValue(value) {
|
||||
let matched = false
|
||||
let isMulti = await this.isMultiple()
|
||||
|
||||
let options = await this.element.findElements({
|
||||
css: 'option[value =' + escapeCss(value) + ']',
|
||||
})
|
||||
|
||||
for (let option of options) {
|
||||
await this.setSelected(option)
|
||||
|
||||
if (!isMulti) {
|
||||
return
|
||||
}
|
||||
matched = true
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
throw new Error(`Cannot locate option with value: ${value}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Select option with displayed text matching the argument.
|
||||
*
|
||||
* <example>
|
||||
<select id="selectbox">
|
||||
<option value="1">Option 1</option>
|
||||
<option value="2">Option 2</option>
|
||||
<option value="3">Option 3</option>
|
||||
</select>
|
||||
const selectBox = await driver.findElement(By.id("selectbox"));
|
||||
await selectObject.selectByVisibleText("Option 2");
|
||||
* </example>
|
||||
*
|
||||
* @param {String|Number} text text of option element to get selected
|
||||
*
|
||||
*/
|
||||
async selectByVisibleText(text) {
|
||||
text = typeof text === 'number' ? text.toString() : text
|
||||
|
||||
const normalized = text
|
||||
.trim() // strip leading and trailing white-space characters
|
||||
.replace(/\s+/, ' ') // replace sequences of whitespace characters by a single space
|
||||
|
||||
/**
|
||||
* find option element using xpath
|
||||
*/
|
||||
const formatted = /"/.test(normalized)
|
||||
? 'concat("' + normalized.split('"').join('", \'"\', "') + '")'
|
||||
: `"${normalized}"`
|
||||
const dotFormat = `[. = ${formatted}]`
|
||||
const spaceFormat = `[normalize-space(text()) = ${formatted}]`
|
||||
|
||||
const selections = [
|
||||
`./option${dotFormat}`,
|
||||
`./option${spaceFormat}`,
|
||||
`./optgroup/option${dotFormat}`,
|
||||
`./optgroup/option${spaceFormat}`,
|
||||
]
|
||||
|
||||
const optionElement = await this.element.findElement({
|
||||
xpath: selections.join('|'),
|
||||
})
|
||||
await this.setSelected(optionElement)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all options belonging to this select tag
|
||||
* @returns {!Promise<!Array<!WebElement>>}
|
||||
*/
|
||||
async getOptions() {
|
||||
return await this.element.findElements({ tagName: 'option' })
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value if the select tag is multiple
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async isMultiple() {
|
||||
return (await this.element.getAttribute('multiple')) !== null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all selected options belonging to this select tag
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getAllSelectedOptions() {
|
||||
const opts = await this.getOptions()
|
||||
const results = []
|
||||
for (let options of opts) {
|
||||
if (await options.isSelected()) {
|
||||
results.push(options)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first Selected Option
|
||||
* @returns {Promise<Element>}
|
||||
*/
|
||||
async getFirstSelectedOption() {
|
||||
return (await this.getAllSelectedOptions())[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Deselects all selected options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async deselectAll() {
|
||||
if (!this.isMultiple()) {
|
||||
throw new Error('You may only deselect all options of a multi-select')
|
||||
}
|
||||
|
||||
const options = await this.getOptions()
|
||||
|
||||
for (let option of options) {
|
||||
if (await option.isSelected()) {
|
||||
await option.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string|Number}text text of option to deselect
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async deselectByVisibleText(text) {
|
||||
if (!(await this.isMultiple())) {
|
||||
throw new Error('You may only deselect options of a multi-select')
|
||||
}
|
||||
|
||||
/**
|
||||
* convert value into string
|
||||
*/
|
||||
text = typeof text === 'number' ? text.toString() : text
|
||||
|
||||
const normalized = text
|
||||
.trim() // strip leading and trailing white-space characters
|
||||
.replace(/\s+/, ' ') // replace sequences of whitespace characters by a single space
|
||||
|
||||
/**
|
||||
* find option element using xpath
|
||||
*/
|
||||
const formatted = /"/.test(normalized)
|
||||
? 'concat("' + normalized.split('"').join('", \'"\', "') + '")'
|
||||
: `"${normalized}"`
|
||||
const dotFormat = `[. = ${formatted}]`
|
||||
const spaceFormat = `[normalize-space(text()) = ${formatted}]`
|
||||
|
||||
const selections = [
|
||||
`./option${dotFormat}`,
|
||||
`./option${spaceFormat}`,
|
||||
`./optgroup/option${dotFormat}`,
|
||||
`./optgroup/option${spaceFormat}`,
|
||||
]
|
||||
|
||||
const optionElement = await this.element.findElement({
|
||||
xpath: selections.join('|'),
|
||||
})
|
||||
if (await optionElement.isSelected()) {
|
||||
await optionElement.click()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Number} index index of option element to deselect
|
||||
* Deselect the option at the given index.
|
||||
* This is done by examining the "index"
|
||||
* attribute of an element, and not merely by counting.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async deselectByIndex(index) {
|
||||
if (!(await this.isMultiple())) {
|
||||
throw new Error('You may only deselect options of a multi-select')
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
throw new Error('Index needs to be 0 or any other positive number')
|
||||
}
|
||||
|
||||
let options = await this.element.findElements(By.tagName('option'))
|
||||
|
||||
if (options.length === 0) {
|
||||
throw new Error("Select element doesn't contain any option element")
|
||||
}
|
||||
|
||||
if (options.length - 1 < index) {
|
||||
throw new Error(
|
||||
`Option with index "${index}" not found. Select element only contains ${
|
||||
options.length - 1
|
||||
} option elements`
|
||||
)
|
||||
}
|
||||
|
||||
for (let option of options) {
|
||||
if ((await option.getAttribute('index')) === index.toString()) {
|
||||
if (await option.isSelected()) {
|
||||
await option.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} value value of an option to deselect
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async deselectByValue(value) {
|
||||
if (!(await this.isMultiple())) {
|
||||
throw new Error('You may only deselect options of a multi-select')
|
||||
}
|
||||
|
||||
let matched = false
|
||||
|
||||
let options = await this.element.findElements({
|
||||
css: 'option[value =' + escapeCss(value) + ']',
|
||||
})
|
||||
|
||||
for (let option of options) {
|
||||
if (await option.isSelected()) {
|
||||
await option.click()
|
||||
}
|
||||
matched = true
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
throw new Error(`Cannot locate option with value: ${value}`)
|
||||
}
|
||||
}
|
||||
|
||||
async setSelected(option) {
|
||||
if (!(await option.isSelected())) {
|
||||
if (!(await option.isEnabled())) {
|
||||
throw new error.UnsupportedOperationError(
|
||||
`You may not select a disabled option`
|
||||
)
|
||||
}
|
||||
await option.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Select }
|
||||
Reference in New Issue
Block a user