1 | # Query and Manipulation Library
|
2 |
|
3 | [![Build Status](https://travis-ci.org/tenbits/selenium-query.png?branch=master)](https://travis-ci.org/tenbits/selenium-query)
|
4 | [![NPM version](https://badge.fury.io/js/selenium-query.svg)](http://badge.fury.io/js/selenium-query)
|
5 | [![TypeScript](https://badges.frapsoft.com/typescript/code/typescript.svg?v=101)](https://github.com/ellerbrock/typescript-badges/)
|
6 |
|
7 | #### jQuery-alike API for [Selenium WebDriver](https://seleniumhq.github.io/selenium/docs/api/javascript/index.html), [JSDom](https://github.com/jsdom/jsdom) and [Cheerio](https://github.com/cheeriojs/cheerio)
|
8 |
|
9 |
|
10 | Single API to query web-pages or html blocks with supported providers: `Selenium WebDriver`, `JSDom`, `Cheerio` _(`puppeteer` on roadmap)_.
|
11 |
|
12 | > Use for tests or crawlers.
|
13 |
|
14 | ---
|
15 |
|
16 | ### Asynchronous nature
|
17 |
|
18 | 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
|
19 |
|
20 | ```javascript
|
21 | let $ = require('selenium-query');
|
22 | $(driver)
|
23 | .find('.foo')
|
24 | .filter('input')
|
25 | .attr('placeholder', 'Baz')
|
26 | .val()
|
27 | .then(value => console.log(value));
|
28 |
|
29 | // or via await
|
30 | let value = await $(driver).find('input.foo').val();
|
31 | console.log(value);
|
32 | ```
|
33 |
|
34 | ### Extension methods
|
35 |
|
36 | As with jQuery you can define an extension method and call it in your tests
|
37 |
|
38 | ```javascript
|
39 | let $ = require('selenium-query');
|
40 | $.fn.doBaz = function(){
|
41 | return this.each(el => {
|
42 | // do some usefull things with WebElement/JsDomElement/CherioElement
|
43 | });
|
44 | };
|
45 | $(driver)
|
46 | .find('input')
|
47 | .doBaz();
|
48 | ```
|
49 |
|
50 | ## API
|
51 |
|
52 | ##### ☰
|
53 | - [`constructor`](#constructor)
|
54 | - [Collection](#collection)
|
55 | - [`length`](#length)
|
56 | - [`eq`](#eq)
|
57 | - [`slice`](#slice)
|
58 | - [`each`](#each)
|
59 | - [`map`](#map)
|
60 | - [`toArray`](#toArray)
|
61 | - [Traverse](#traverse)
|
62 | - [`find`](#find)
|
63 | - [`filter`](#filter)
|
64 | - [`children`](#children)
|
65 | - [`parent`](#parent)
|
66 | - [`closest`](#closest)
|
67 | - [Attributes](#attributes)
|
68 | - [`attr`](#attr)
|
69 | - [`removeAttr`](#removeAttr)
|
70 | - [`prop`](#prop)
|
71 | - [`removeProp`](#removeProp)
|
72 | - [`val`](#val)
|
73 | - [`css`](#css)
|
74 | - [Class](#class)
|
75 | - [`hasClass`](#hasClass)
|
76 | - [`addClass`](#addClass)
|
77 | - [`removeClass`](#removeAttr)
|
78 | - [`toggleClass`](#toggleClass)
|
79 | - [Manipulate](#manipulate)
|
80 | - [`remove`](#remove)
|
81 | - [Dimension and Position](#dimensions)
|
82 | - [`height`](#height)
|
83 | - [`width`](#width)
|
84 | - [`innerHeight`](#innerHeight)
|
85 | - [`innerWidth`](#innerWidth)
|
86 | - [`offset`](#offset)
|
87 | - [`position`](#position)
|
88 | - [`scrollTop`](#scrollTop)
|
89 | - [`scrollLeft`](#scrollLeft)
|
90 | - [Content](#content)
|
91 | - [`html`](#html)
|
92 | - [`text`](#text)
|
93 | - [`append`](#append)
|
94 | - [`prepend`](#prepend)
|
95 | - [`before`](#before)
|
96 | - [`after`](#after)
|
97 | - [Events](#events)
|
98 | - [`trigger`](#trigger)
|
99 | - [`click`](#click)
|
100 | - [`change`](#change)
|
101 | - [`focus`](#focus)
|
102 | - [`blur`](#blur)
|
103 | - :sparkles: [`type`](#type)
|
104 | - :sparkles: [`press`](#press)
|
105 | - :sparkles: [`sendKeys`](#sendKeys)
|
106 | - :sparkles: [`select`](#select)
|
107 |
|
108 | - [Misc](#misc)
|
109 | - [`eval`](#eval)
|
110 |
|
111 | - [Document](#document)
|
112 | - [`load`](#load)
|
113 | - [`getDriver`](#getDriver)
|
114 | - [`setDriver`](#setDriver)
|
115 |
|
116 | - :zap: [JsDom](#jsdom)
|
117 | - [`build`](#jsdom-build)
|
118 | - [`load`](#jsdom-load)
|
119 |
|
120 | - :zap: [Cheerio](#cheerio)
|
121 | - [`build`](#cheerio-build)
|
122 | - [`load`](#cheerio-load)
|
123 |
|
124 |
|
125 | ##### `constructor(WebDriver|WebElement|Array<WebElement>|SQuery|Array<SQuery>)` <a name='constructor'></a>
|
126 |
|
127 | - [WebDriver](https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html)
|
128 | - [WebElement](https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebElement.html)
|
129 |
|
130 | ```javascript
|
131 | let SQuery = require('selenium-query');
|
132 | let $document = SQuery(driver);
|
133 | let $inputs = $document.find('inputs');
|
134 | ```
|
135 |
|
136 | ## Collection
|
137 |
|
138 | ##### `length:number` <a name='length'></a>
|
139 | Count of WebElements in a current set.
|
140 | > :exclamation: Due to asynchronous nature, sometimes you have to wait until the promise is resolved to get the correct `length` value
|
141 |
|
142 | ##### `eq(index:number):SQuery` <a name='eq'></a>
|
143 | Get the SQuery instance with only one element at the index.
|
144 | > :exclamation: Once again, wait until the promise is resolved, or **chain** the manipulations
|
145 | ```javascript
|
146 | $(driver)
|
147 | .find('button')
|
148 | .eq(0)
|
149 | .css('background-color', 'red')
|
150 | .done(() => console.log('The color has been changed.'))
|
151 | // instead of an equivalent
|
152 | $(driver)
|
153 | .find('button')
|
154 | .done(buttons => {
|
155 | buttons
|
156 | .eq(0)
|
157 | .done(firstButton => {
|
158 | firstButton
|
159 | .css('background-color', 'red')
|
160 | .done(() => console.log('The color has been changed.'))
|
161 | })
|
162 | });
|
163 | ```
|
164 |
|
165 | ##### `slice([start:number = 0, end:number = .length]):SQuery` <a name='slice'></a>
|
166 | Get elements range.
|
167 |
|
168 | ##### `each(function<node:WebElement, index:number, Promise|void 0>):SQuery` <a name='each'></a>
|
169 | Enumerate the collection. The callback function can return a promise, if an async job is performed.
|
170 |
|
171 | ##### `map(function<node:WebElement, index:number, Promise|any>):SQuery` <a name='map'></a>
|
172 | Map the collection into the new one. Return the value from the function or a promise which resolves then with the value.
|
173 |
|
174 | ##### `toArray():Promise<Array<any>>` <a name='toarray'></a>
|
175 | Returns a promise which resolves with an Array instance of current elements in collection
|
176 |
|
177 |
|
178 | ## Traverse
|
179 |
|
180 | ##### `find(selector:string):SQuery` <a name='find'></a>
|
181 | Find element(s).
|
182 |
|
183 | ##### `filter(selector:string):SQuery` <a name='filter'></a>
|
184 | Filter element(s) out of the current collection.
|
185 |
|
186 | ##### `children([selector:string]):SQuery` <a name='children'></a>
|
187 | Get, and optionally filter, children of every element in the collection.
|
188 |
|
189 | ##### `parent():SQuery` <a name='parent'></a>
|
190 | Get parent elements of every element in the collection
|
191 |
|
192 | ##### `closest(selector):SQuery` <a name='closest'></a>
|
193 | Find ancestor of every element in the collection
|
194 |
|
195 |
|
196 | ## Attributes
|
197 |
|
198 | ##### `attr(key:string | key:string, val:any | attributes:Object ):SQuery|Promise<any>` <a name='attr'></a>
|
199 | Get attribute value of the first element in the collection, or set attribute(s) to each element.
|
200 |
|
201 | ##### `removeAttr(key:string):SQuery` <a name='removeAttr'></a>
|
202 | Remove the attribute
|
203 |
|
204 | ##### `prop(key:string | key:string, val:any | properties:Object):SQuery|Promise<any>` <a name='prop'></a>
|
205 | Get property value of the first element in the collection, or set property(ies) to each element.
|
206 |
|
207 | ##### `removeProp(key:string):SQuery` <a name='removeProp'></a>
|
208 | Delete property
|
209 |
|
210 | ##### `val([value:string]):SQuery` <a name='val'></a>
|
211 | Get or set `value` property, like `input.value`
|
212 |
|
213 | ##### `css(key:string | key:string, val:string | css:Object ):SQuery|Promise<any>` <a name='css'></a>
|
214 | Get or set style properties
|
215 |
|
216 | ## Class
|
217 |
|
218 | ##### `hasClass(name:string):Promise<boolean>` <a name='hasClass'></a>
|
219 | Check if the first element has the class name.
|
220 |
|
221 | ##### `addClass(name:string):SQuery` <a name='addClass'></a>
|
222 | Add the class name(s) to every element in the collection
|
223 |
|
224 | ##### `removeClass(name:string):SQuery` <a name='removeClass'></a>
|
225 | Remove the class name(s) of every element in the collection
|
226 |
|
227 | ##### `toggleClass(name:string):SQuery` <a name='toggleClass'></a>
|
228 | Toggle the class name(s) of every element in the collection
|
229 |
|
230 | ## Manipulate
|
231 |
|
232 | ##### `remove():SQuery` <a name='remove'></a>
|
233 | Remove the elements from the parent nodes
|
234 |
|
235 | ## Dimensions
|
236 |
|
237 | ##### `height():Promise<number>` <a name='height'></a>
|
238 | ##### `width():Promise<number>` <a name='width'></a>
|
239 | ##### `innerHeight():Promise<number>` <a name='innerHeight'></a>
|
240 | ##### `innerWidth():Promise<number>` <a name='innerWidth'></a>
|
241 | ##### `offset():Promise<object{top,left}>` <a name='offset'></a>
|
242 | ##### `position():Promise<object{top,left}>` <a name='position'></a>
|
243 | ##### `scrollTop():Promise<number>` <a name='scrollTop'></a>
|
244 | ##### `scrollLeft():Promise<number>` <a name='scrollLeft'></a>
|
245 |
|
246 | ## Content
|
247 |
|
248 | ##### `html([html:string]):SQuery|Promise<string>` <a name='html'></a>
|
249 | ##### `text([text:string]):SQuery|Promise<string>` <a name='text'></a>
|
250 |
|
251 | ##### `append(html:string):SQuery` <a name='append'></a>
|
252 | ##### `prepend(html:string):SQuery` <a name='prepend'></a>
|
253 | ##### `before(html:string):SQuery` <a name='before'></a>
|
254 | ##### `after(html:string):SQuery` <a name='after'></a>
|
255 |
|
256 | ## Events
|
257 |
|
258 | ##### `trigger(type:string [, data:Object]):SQuery` <a name='trigger'></a>
|
259 | Trigger native or custom event.
|
260 |
|
261 | ##### `click():SQuery` <a name='click'></a>
|
262 | ##### `change():SQuery` <a name='change'></a>
|
263 | Trigger `change` event
|
264 | ##### `focus():SQuery` <a name='click'></a>
|
265 | ##### `blur():SQuery` <a name='click'></a>
|
266 |
|
267 | ##### `type(text:string):SQuery` <a name='type'></a>
|
268 | Enter the text.
|
269 | > :exclamation: Meta keys are supported in `{}`
|
270 |
|
271 | ##### `press(combination:string):SQuery` <a name='press'></a>
|
272 | Press key combination. E.g.: `ctrl+c`, `a+b+c`, `ctrl+alt+d`, `ctrl++` _(`control` and `plus` keys)_
|
273 |
|
274 | ##### `sendKeys(text:string):SQuery` <a name='sendKeys'></a>
|
275 | Call native Selenums `sendKeys` fn on each element
|
276 |
|
277 | ##### `select(text:string | start:number[, end:number]):SQuery` <a name='select'></a>
|
278 | Select an option from the `select` element, or if the `input` the selects a text or range
|
279 |
|
280 |
|
281 | ## Misc
|
282 |
|
283 | ##### `eval(fn:Function, ...args):Promise<any>` <a name='eval'></a>
|
284 | Evaluate function in Browser.
|
285 | > :exclamation: The first argument is the first element in the set
|
286 | ```javascript
|
287 | $(driver)
|
288 | .find('button')
|
289 | .eval(function(el){
|
290 | // browser context
|
291 | // do smth. with the Element and return a value
|
292 | });
|
293 | ```
|
294 |
|
295 |
|
296 | ## Document
|
297 |
|
298 | #### `static` `load(url:string[, config:WebDriverOptions]):SQuery` <a name='load'></a>
|
299 | Create or reuse a WebDriver, and load the page.
|
300 |
|
301 | #### `WebDriverOptions` defaults
|
302 | ```javascript
|
303 | {
|
304 | name: 'Chrome',
|
305 | args: ['no-sandbox'],
|
306 | binaryPath: null,
|
307 |
|
308 | // For better control and to change the behaviour of how the options are created and applied,
|
309 | // you can define next functions
|
310 | applyOptions: function(builder, options) {},
|
311 | setOptions (builder, options) {},
|
312 | setArguments (options) {},
|
313 | setBinaryPath (options) {},
|
314 | setLogging (options) {}
|
315 | }
|
316 | ```
|
317 |
|
318 | ## JsDom
|
319 |
|
320 | #### `static` `SQuery.jsdom.build(config: IJsdomParams):SQuery` <a name='jsdom-build'></a>
|
321 |
|
322 | ```typescript
|
323 | interface IJsdomParams {
|
324 | html: string
|
325 | }
|
326 | ```
|
327 |
|
328 | Create SQuery collection with JsDom driver
|
329 |
|
330 | #### `static` `SQuery.jsdom.load(url: string, config: IJsdomLoadParams):SQuery` <a name='jsdom-load'></a>
|
331 |
|
332 | ```typescript
|
333 | interface IJsdomLoadParams {
|
334 | headers?: {[name: string] : string }
|
335 | method?
|
336 | query?: {[name: string] : string }
|
337 | payload?
|
338 | cookies?: string | string[]
|
339 | cache?: {
|
340 | folder?: string
|
341 | maxAge?: number
|
342 | }
|
343 | cacheQueryIgnore?: string[]
|
344 | /** Webdriver will load this url, or requested url, to set the cookies first */
|
345 | cookieOrigin?: string
|
346 | }
|
347 | ```
|
348 |
|
349 |
|
350 |
|
351 | ## Cheerio
|
352 |
|
353 | #### `static` `SQuery.cheerio.build(config: ICheerioParams):SQuery` <a name='cheerio-build'></a>
|
354 |
|
355 | ```typescript
|
356 | interface ICheerioParams {
|
357 | html: string
|
358 | }
|
359 | ```
|
360 |
|
361 | Create SQuery collection with Cheerio driver (_Only query and manipulation methods are implemented_)
|
362 |
|
363 | #### `static` `SQuery.cheerio.load(url: string, config: ICheerioLoadParams):SQuery` <a name='cheerio-load'></a>
|
364 |
|
365 | ```typescript
|
366 | interface ICheerioLoadParams {
|
367 | headers?: {[name: string] : string }
|
368 | method?
|
369 | query?: {[name: string] : string }
|
370 | payload?
|
371 | cookies?: string | string[]
|
372 | cache?: {
|
373 | folder?: string
|
374 | maxAge?: number
|
375 | }
|
376 | cacheQueryIgnore?: string[]
|
377 | /** Webdriver will load this url, or requested url, to set the cookies first */
|
378 | cookieOrigin?: string
|
379 | }
|
380 | ```
|
381 |
|
382 |
|
383 | **Example**
|
384 | ```javascript
|
385 | $
|
386 | .load('http://google.com')
|
387 | .find('input')
|
388 | .css('background-color', 'red');
|
389 | ```
|
390 |
|
391 |
|
392 | :checkered_flag:
|
393 |
|
394 | ---
|
395 |
|
396 | :copyright: MIT, Alex Kit
|