-
-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add access to Selenium Action API. (#2061)
* Add access to Selenium Action API. The Action API gives us the ability to write so much cleaner code.
- Loading branch information
1 parent
96f83d8
commit d1a4b87
Showing
6 changed files
with
187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// We disable these because they are needed for code completion | ||
/* eslint no-unused-vars: "off" */ | ||
import { Actions as SeleniumActions } from 'selenium-webdriver/lib/input.js'; | ||
/** | ||
* This class provides an abstraction layer for Selenium's action sequence functionality. | ||
* It allows for easy interaction with web elements using different locating strategies | ||
* and simulating complex user gestures like mouse movements, key presses, etc. | ||
* | ||
* @class | ||
* @hideconstructor | ||
* @see https://www.selenium.dev/documentation/webdriver/actions_api/ | ||
* @see https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html | ||
*/ | ||
export class Actions { | ||
constructor(browser) { | ||
/** | ||
* @private | ||
*/ | ||
this.driver = browser.getDriver(); | ||
/** | ||
* @private | ||
*/ | ||
this.actions = this.driver.actions({ async: true }); | ||
} | ||
|
||
/* | ||
* Clears the stored actions. You need to manually clear actions, before you start a new action. | ||
* | ||
* @returns {Promise<void>} A promise that will be resolved when the actions have been | ||
* cleared. | ||
*/ | ||
async clear() { | ||
return this.driver.actions().clear(); | ||
} | ||
|
||
/** | ||
* Retrieves the current action sequence builder. | ||
* The actions builder can be used to chain multiple browser actions. | ||
* @returns {SeleniumActions} The current Selenium Actions builder object for chaining browser actions. | ||
* @example | ||
* // Example of using the actions builder to perform a drag-and-drop operation: | ||
* const elementToDrag = await commands.action.getElementByCss('.draggable'); | ||
* const dropTarget = await commands.action.getElementByCss('.drop-target'); | ||
* await commands.action.getAction() | ||
* .dragAndDrop(elementToDrag, dropTarget) | ||
* .perform(); | ||
* | ||
*/ | ||
getActions() { | ||
return this.actions; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// We disable these because they are needed for code completion | ||
/* eslint no-unused-vars: "off" */ | ||
import { By, WebElement } from 'selenium-webdriver'; | ||
/** | ||
* This class provides a way to get hokld of Seleniums WebElements. | ||
* @class | ||
* @hideconstructor | ||
*/ | ||
export class Element { | ||
constructor(browser) { | ||
/** | ||
* @private | ||
*/ | ||
this.driver = browser.getDriver(); | ||
} | ||
|
||
/** | ||
* Finds an element by its CSS selector. | ||
* | ||
* @param {string} name - The CSS selector of the element. | ||
* @returns {Promise<WebElement>} A promise that resolves to the WebElement found. | ||
*/ | ||
async getByCss(name) { | ||
return this.driver.findElement(By.css(name)); | ||
} | ||
|
||
/** | ||
* Finds an element by its ID. | ||
* | ||
* @param {string} id - The ID of the element. | ||
* @returns {Promise<WebElement>} A promise that resolves to the WebElement found. | ||
*/ | ||
async getById(id) { | ||
return this.driver.findElement(By.id(id)); | ||
} | ||
|
||
/** | ||
* Finds an element by its XPath. | ||
* | ||
* @param {string} xpath - The XPath query of the element. | ||
* @returns {Promise<WebElement>} A promise that resolves to the WebElement found. | ||
*/ | ||
async getByXpath(xpath) { | ||
return this.driver.findElement(By.xpath(xpath)); | ||
} | ||
|
||
/** | ||
* Finds an element by its class name. | ||
* | ||
* @param {string} className - The class name of the element. | ||
* @returns {Promise<WebElement>} A promise that resolves to the WebElement found. | ||
*/ | ||
async getByClassName(className) { | ||
return this.driver.findElement(By.className(className)); | ||
} | ||
|
||
/** | ||
* Finds an element by its name attribute. | ||
* | ||
* @param {string} name - The name attribute of the element. | ||
* @returns {Promise<WebElement>} A promise that resolves to the WebElement found. | ||
*/ | ||
async getByName(name) { | ||
return this.driver.findElement(By.name(name)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import test from 'ava'; | ||
const { before, after, serial } = test; | ||
import { resolve } from 'node:path'; | ||
import { getEngine } from '../util/engine.js'; | ||
import { startServer, stopServer } from '../util/httpserver.js'; | ||
import { fileURLToPath } from 'node:url'; | ||
import path from 'node:path'; | ||
const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
|
||
const timeout = 20_000; | ||
|
||
let engine; | ||
|
||
function getPath(file) { | ||
return resolve(__dirname, '..', 'data', 'commandscripts', file); | ||
} | ||
|
||
before('Setup the HTTP server', () => { | ||
return startServer(); | ||
}); | ||
|
||
after.always('Stop the HTTP server', () => { | ||
return stopServer(); | ||
}); | ||
|
||
serial.beforeEach('Start the browser', async t => { | ||
t.timeout(timeout); | ||
engine = getEngine(); | ||
return engine.start(); | ||
}); | ||
|
||
serial('Run through the action API', async t => { | ||
const result = await engine.runMultiple([getPath('actions.cjs')], { | ||
scripts: { uri: 'document.documentURI' } | ||
}); | ||
t.deepEqual( | ||
result[0].browserScripts[0].scripts.uri, | ||
'http://127.0.0.1:3000/simple/' | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module.exports = async function (context, commands) { | ||
await commands.measure.start('http://127.0.0.1:3000/simple/'); | ||
const clickable = await commands.element.getById('clickable'); | ||
return commands.action.getActions() | ||
.move({ origin: clickable }) | ||
.pause(1000) | ||
.press() | ||
.pause(1000) | ||
.sendKeys('abc') | ||
.perform(); | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters