jQuery-alike API for Selenium WebDriver, JSDom and Cheerio
Single API to query web-pages or html blocks with supported providers: Selenium WebDriver
, JSDom
, Cheerio
, Plain-HTTP
.
Use for tests, crawlers and automations.
All cookies received from the backend will be reused for a domain.
import SQuery from 'selenium-query';
let $ = await SQuery.load(url, config?: IConfig)
As the WebDriver methods are async, Selenium Query
instance implements Promise
and you can chain the function calls or use async/await
. A very basic example
import $ from 'selenium-query';
$(driver)
.find('.foo')
.filter('input')
.attr('placeholder', 'Baz')
.val()
.then(value => console.log(value));
// or via await
let value = await $(driver).find('input.foo').val();
console.log(value);
As with jQuery you can define an extension method and call it in your tests
import $ from 'selenium-query';
$.fn.doBaz = function(){
return this.each(el => {
// do some usefull things with WebElement/JsDomElement/CherioElement
});
};
$(driver)
.find('input')
.doBaz();
Allows to get and to listen for events emitted by the browser
import { BrowserNetworkMonitor } from 'selenium-query';
let monitor = await BrowserNetworkMonitor.start(driver);
monitor
.on('requestWillBeSent', req => console.log(req))
.on('responseReceived', req => console.log(req))
.on('loadingFinished', req => console.log(req));
// ... e.g. after the a page is loaded
let { request, response } = monitor.getRequest(/index.html/);
console.log(request.headers, response.headers);
// get the response body
let { base64Encoded, body } = monitor.getResponseBody(mainPageRequest);
Allows to send custom responses for requests back to the browser
import { BrowserNetworkInterceptor } from 'selenium-query';
let interceptor = await BrowserNetworkInterceptor.start(driver);
interceptor.register({
match: /index.html/,
response: {
status: 200,
headers: {
'Content-Type': 'text/html'
},
body: '<!DOCTYPE html> <h1>Changed</h1>'
}
});
// ... load index.html, and the modified content should be loaded
let html = `
<ul>
<li name='x'>Foo <span id='foo'></span></li>
<li name='y'>Bar <span id='bar'></span></li>
</ul>
`;
SQuery.pseudo.isBar = async ($el, innerQuery) => {
let $children = await $el.find('#bar');
return $children.length > 0;
};
let value1 = await $.find('li:text(Bar)').attr('name');
let value2 = await $.find('li:has(span#id)').attr('name');
let value3 = await $.find('li:isBar()').attr('name');
// value1 === value2 === value3 === 'y'
let SQuery = require('selenium-query');
let $document = SQuery(driver);
let $inputs = $document.find('inputs');
Count of WebElements in a current set.
❗ Due to asynchronous nature, sometimes you have to wait until the promise is resolved to get the correct
length
value
Get the SQuery instance with only one element at the index.
❗ Once again, wait until the promise is resolved, or chain the manipulations
await $(driver)
.find('button')
.eq(0)
.css('background-color', 'red')
// instead of an equivalent
let buttons = await $(driver).find('button')
let firstButton = await buttons.eq(0);
await firstButton.css('background-color', 'red');
console.log('The color has been changed.'));
Get elements range.
Enumerate the collection. The callback function can return a promise, if an async job is performed.
Map the collection into the new one. Return the value from the function or a promise which resolves then with the value.
Returns a promise which resolves with an Array instance of current elements in collection
Find element(s).
Filter element(s) out of the current collection.
Get, and optionally filter, children of every element in the collection.
Get parent elements of every element in the collection
Find ancestor of every element in the collection
Get attribute value of the first element in the collection, or set attribute(s) to each element.
Remove the attribute
Get property value of the first element in the collection, or set property(ies) to each element.
Delete property
Get or set value
property, like input.value
Get or set style properties
Check if the first element has the class name.
Add the class name(s) to every element in the collection
Remove the class name(s) of every element in the collection
Toggle the class name(s) of every element in the collection
Remove the elements from the parent nodes
Trigger native or custom event.
Trigger change
event
Enter the text.
❗ Meta keys are supported in
{}
Press key combination. E.g.: ctrl+c
, a+b+c
, ctrl+alt+d
, ctrl++
(control
and plus
keys)
Call native Selenums sendKeys
fn on each element
Select an option from the select
element, or if the input
the selects a text or range
Evaluate function in Browser.
❗ The first argument is the first element in the set
let result = await $(driver)
.find('button')
.eval((el: HTMLButton) => {
// browser context
// do smth. with the Element and return a value
return el.tagName;
});
Create or reuse a WebDriver, and load the page.
{
name: 'Chrome',
args: ['no-sandbox'],
binaryPath: null,
// For better control and to change the behaviour of how the options are created and applied,
// you can define next functions
applyOptions: function(builder, options) {},
setOptions (builder, options) {},
setArguments (options) {},
setBinaryPath (options) {},
setLogging (options) {}
}
interface IJsdomParams {
html: string
}
Create SQuery collection with JsDom driver
interface IJsdomLoadParams {
headers?: {[name: string] : string }
method?
query?: {[name: string] : string }
payload?
cookies?: string | string[]
cache?: {
folder?: string
maxAge?: number
}
cacheQueryIgnore?: string[]
/** Webdriver will load this url, or requested url, to set the cookies first */
cookieOrigin?: string
}
interface ICheerioParams {
html: string
}
Create SQuery collection with Cheerio driver (Only query and manipulation methods are implemented)
interface ICheerioLoadParams {
headers?: {[name: string] : string }
method?
query?: {[name: string] : string }
payload?
cookies?: string | string[]
cache?: {
folder?: string
maxAge?: number
}
cacheQueryIgnore?: string[]
/** Webdriver will load this url, or requested url, to set the cookies first */
cookieOrigin?: string
}
HTTP Utils to load and submit data. Handles cache and cookies.
interface IHttpParams {
headers?: {[name: string] : string }
method?: 'post' | 'get' | 'delete' | 'patch' | 'head' | string
query?: {[name: string] : string }
body?: string | Buffer
cookies?: {[name: string] : string } | string[] | string
cookiesDefault?: {[name: string] : string } | string[] | string
cache?: boolean | {
folder?: string
maxAge?: number
compress?: boolean
//-ensureCacheAllowed? (resp): boolean
}
cacheQueryIgnore?: string[]
retryCount?: number
retryTimeout?: number
follow?: number
httpsProxy?: string
ignoreSSLErrors?: boolean
}
interface IHttpResponse {
status: number
message?: string
headers: {[name: string] : string }
url: string
body: any
}
Example
$
.load('http://google.com')
.find('input')
.css('background-color', 'red');
This version of ChromeDriver only supports Chrome version XYZ
Means the installed version of the Chromedriver is not compatible with Chrome itself. Usually it doesn't required one-to-one version, means you can use v97 of the chrome driver, with Chrome v98.
All platforms: Download the required Chromedriver from https://chromedriver.chromium.org/downloads
Windows: choco upgrade chromedriver
Stale element not found
When creating HTML DOM Elements in Chrome, make sure they are attached to the DOM
before returning them to the nodejs
process.
🏁
©️ MIT, Alex Kit