npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

selenium-query

v0.52.76

Published

jQuery API for Selenium WebDriver/JSDom

Downloads

1,423

Readme

Web Query and Manipulation Library


Build Status NPM version TypeScript

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.


Request

All cookies received from the backend will be reused for a domain.

import SQuery from 'selenium-query';
let $ = await SQuery.load(url, config?: IConfig)

Query and Manipulate

Asynchronous nature

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);

Extension methods

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();

WebDriver network monitor

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);

WebDriver network interceptor

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

Pseudo selectors

:text and improved :has selectors
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'

API

constructor(WebDriver|WebElement|Array<WebElement>|SQuery|Array<SQuery>)
let SQuery = require('selenium-query');
let $document = SQuery(driver);
let $inputs = $document.find('inputs');

Collection

length:number

Count of WebElements in a current set.

:exclamation: Due to asynchronous nature, sometimes you have to wait until the promise is resolved to get the correct length value

eq(index:number):SQuery

Get the SQuery instance with only one element at the index.

:exclamation: 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.'));
slice([start:number = 0, end:number = .length]):SQuery

Get elements range.

each(function<node:WebElement, index:number, Promise|void 0>):SQuery

Enumerate the collection. The callback function can return a promise, if an async job is performed.

map(function<node:WebElement, index:number, Promise|any>):SQuery

Map the collection into the new one. Return the value from the function or a promise which resolves then with the value.

toArray():Promise<Array<any>>

Returns a promise which resolves with an Array instance of current elements in collection

Traverse

find(selector:string):SQuery

Find element(s).

filter(selector:string):SQuery

Filter element(s) out of the current collection.

children([selector:string]):SQuery

Get, and optionally filter, children of every element in the collection.

parent():SQuery

Get parent elements of every element in the collection

closest(selector):SQuery

Find ancestor of every element in the collection

Attributes

attr(key:string | key:string, val:any | attributes:Object ):SQuery|Promise<any>

Get attribute value of the first element in the collection, or set attribute(s) to each element.

removeAttr(key:string):SQuery

Remove the attribute

prop(key:string | key:string, val:any | properties:Object):SQuery|Promise<any>

Get property value of the first element in the collection, or set property(ies) to each element.

removeProp(key:string):SQuery

Delete property

val([value:string]):SQuery

Get or set value property, like input.value

css(key:string | key:string, val:string | css:Object ):SQuery|Promise<any>

Get or set style properties

Class

hasClass(name:string):Promise<boolean>

Check if the first element has the class name.

addClass(name:string):SQuery

Add the class name(s) to every element in the collection

removeClass(name:string):SQuery

Remove the class name(s) of every element in the collection

toggleClass(name:string):SQuery

Toggle the class name(s) of every element in the collection

Manipulate

remove():SQuery

Remove the elements from the parent nodes

Dimensions

height():Promise<number>
width():Promise<number>
innerHeight():Promise<number>
innerWidth():Promise<number>
offset():Promise<object{top,left}>
position():Promise<object{top,left}>
scrollTop():Promise<number>
scrollLeft():Promise<number>

Content

html([html:string]):SQuery|Promise<string>
text([text:string]):SQuery|Promise<string>
append(html:string):SQuery
prepend(html:string):SQuery
before(html:string):SQuery
after(html:string):SQuery

Events

trigger(type:string [, data:Object]):SQuery

Trigger native or custom event.

click():SQuery
change():SQuery

Trigger change event

focus():SQuery
blur():SQuery
type(text:string):SQuery

Enter the text.

:exclamation: Meta keys are supported in {}

press(combination:string):SQuery

Press key combination. E.g.: ctrl+c, a+b+c, ctrl+alt+d, ctrl++ (control and plus keys)

sendKeys(text:string):SQuery

Call native Selenums sendKeys fn on each element

select(text:string | start:number[, end:number]):SQuery

Select an option from the select element, or if the input the selects a text or range

Misc

eval(fn:Function, ...args):Promise<any>

Evaluate function in Browser.

:exclamation: 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;
    });

Document

static load(url:string[, config:WebDriverOptions]):SQuery

Create or reuse a WebDriver, and load the page.

WebDriverOptions defaults

{
    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) {}
}

JsDom

static SQuery.jsdom.build(config: IJsdomParams):SQuery

interface IJsdomParams {
    html: string
}

Create SQuery collection with JsDom driver

static SQuery.jsdom.load(url: string, config: IJsdomLoadParams):SQuery

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
}

Cheerio

static SQuery.cheerio.build(config: ICheerioParams):SQuery

interface ICheerioParams {
    html: string
}

Create SQuery collection with Cheerio driver (Only query and manipulation methods are implemented)

static SQuery.cheerio.load(url: string, config: ICheerioLoadParams):SQuery

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
}

Network

HTTP Utils to load and submit data. Handles cache and cookies.

load SQuery.network.load(url: string, config: IHttpParams):IHttpResponse

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');

Known "features"

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.

:checkered_flag:


:copyright: MIT, Alex Kit