Skip to content

Commit

Permalink
Add usage to README and default timeout to API
Browse files Browse the repository at this point in the history
  • Loading branch information
gidztech committed Feb 27, 2018
0 parents commit b10b131
Show file tree
Hide file tree
Showing 9 changed files with 679 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea/
node_modules/
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Gideon Pyzer / Huddle

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
183 changes: 183 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# puppeteer-extensions
This library exposes a number of convenience functions to extend Puppeteer's API, in order to make writing tests easier.
The idea is that many of these functions (or similar ones) will eventually make their way into Puppeteer's own API, but
this allows us to experiment with new ways of improving UI testing.

## Usage
- `page` Puppeteer page instance
- `timeout` [Optional] Timeout for waits in milliseconds (default: 5000 ms)

```javascript
const extensions = require('puppeteer-extensions')(page);
```

```javascript
(async() {
const listItem = '.todo-list li';
...
await page.extensions.waitForNthSelectorAttributeValue(listItem, 1, 'class', 'completed');
})();

```


## API
The API is split into categories to better organise the extension functions. This currently includes:

- [Waits](#waits)
- [Retrieval](#retrieval)
- [Miscellaneous](#miscellaneous)


**resetRequests()**

Resets the requests cache used by the `waits` API. This should be called when you are going to navigate to another page,
in order to track the new requests correctly.

## Waits
**waitForResource(resource, timeout=defaultTimeout)**
- `resource` \<string> The URL of the resource (or a substring of it)
- `timeout` \<number> Timeout for the check

Wait for a resource request to be responded to


**waitForLoadedWebFontCountToBe(count, timeout=defaultTimeout)**
- `count` \<number> The number of web fonts to expect
- `timeout` \<number> Timeout for the check

Wait for a specific number of web fonts to be loaded and ready on the page


**waitForFunction(fn, options, ...args)**
- `fn` \<function> The function to execute on the page
- `options` \<object> Optional waiting parameters
- `args` \<...args> Arguments to be passed into the function

Wait for function to execute on the page (see [waitForFunction](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitforfunctionpagefunction-options-args))


**waitForSelector(selector, timeout=defaultTimeout)**
- `selector` \<string> The selector for the element on the page
- `timeout` \<number> Timeout for the check

Wait for element with a given selector to exist on the page (see [waitForSelector](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitforselectorselector-options))


**waitUntilExistsAndVisible(selector)**
- `selector` \<string> The selector for the element on the page

Wait until an element exists on the page and is visible (i.e. not transparent) (see [waitForSelector](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitforselectorselector-options))


**waitWhileExistsAndVisible(selector)**
- `selector` \<string> The selector for the element on the page

Wait while an element still exists on the page and is visible (i.e. not transparent) (see [waitForSelector](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitforselectorselector-options))


**waitUntilSelectorHasVisibleContent(selector)**
- `selector` \<string> The selector for the element on the page

Wait until the selector has visible content (i.e. the element takes up some width and height on the page) (i.e. not transparent)


**waitWhileSelectorHasVisibleContent(selector)**
- `selector` \<string> The selector for the element on the page

Wait while the selector has visible content (i.e. the element takes up some width and height on the page) (i.e. not transparent)


**waitForNthSelectorAttribute(selector, nth, attributeName)**
- `selector` \<string> The selector for the element on the page
- `nth` \<number> The nth element found by the selector
- `attributeName` \<string> The attribute name to look for

Wait for the nth element found from the selector has a particular attribute


**waitForSelectorAttribute(selector, attributeName)**
- `selector` \<string> The selector for the element on the page
- `attributeName` \<string> The attribute name to look for

Wait for the element found from the selector has a particular attribute


**waitForNthSelectorAttributeValue(selector, nth, attributeName, attributeValue)**
- `selector` \<string> The selector for the element on the page
- `nth` \<number> The nth element found by the selector
- `attributeName` \<string> The attribute name to look for
- `attributeValue` \<string> The attribute value to match the attributeName

Wait for the nth element found from the selector has a particular attribute value pair


**waitForSelectorAttributeValue(selector, attributeName, attributeValue)**
- `selector` \<string> The selector for the element on the page
- `attributeName` \<string> The attribute name to look for
- `attributeValue` \<string> The attribute value to match the attributeName

Wait for the element found from the selector has a particular attribute value pair


**waitForElementCount(selector, expectedCount)**
- `selector` \<string> The selector for the element on the page
- `expectedCount` \<number> The number of elements to expect

Wait for the element count to be a particular value


**waitForUrl(regex)**
- `regex` \<RegExp> The regular expression to match the URL on

Wait for the current window location to match a particular regular expression


**waitFor(milliseconds)**
- `milliseconds` \<number> The number of milliseconds to wait for

Wait for a given number of milliseconds


## Retrieval

**getValue(selector)**
- `selector` \<string> The selector for the element to get the value for
- **returns** \<string> The value property value for the element

Get the value property value for a particular element


**getText(selector)**
- `selector` \<string> The selector for the element to get the text for
- **returns** \<string> The text property value for the element

Get the text property value for a particular element


**getPropertyValue(selector, property)**
- `selector` \<string> The selector for the element to get the property value for
- `property` \<string> The property to look for
- **returns** \<string> The property value for the element

Get the value of a particular property for a particular element


**isElementFocused(selector)**
- `selector` \<string> The selector of the element to check for focus state
- **returns** \<boolean> Whether the element is focused or not

Check if element is focused

## Miscellaneous

**turnOffAnimations()**

Turn off CSS animations on the page to help avoid flaky visual comparisons


**evaluate(fn, ...args)**
- `fn` \<function> The function to execute on the page
- `args` \<...args> Arguments to be passed into the function

Runs a function on the page
43 changes: 43 additions & 0 deletions api/miscellaneous.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
*
* This file represents the miscellaneous API. It exposes functions that don't fit under a particular category.
*
**/

const serializeFunctionWithArgs = require('../external/serialization-utils');

module.exports = puppeteerPage => ({
/**
* Turn off CSS animations on the page to help avoid flaky visual comparisons
*/
async turnOffAnimations () {
return puppeteerPage.evaluate(() => {
function disableAnimations() {
const {jQuery} = window;
if (jQuery) {
jQuery.fx.off = true;
}

const css = document.createElement('style');
css.type = 'text/css';
css.innerHTML = '* { -webkit-transition: none !important; transition: none !important; -webkit-animation: none !important; animation: none !important; }';
document.body.appendChild( css );
}

if (document.readyState !== 'loading') {
disableAnimations();
} else {
window.addEventListener('load', disableAnimations, false);
}
})
},
/**
* Run a function on the page
* @param {function} fn - The function to execute on the page
* @param {...args} args - Arguments to be passed into the function
*/
async evaluate(fn, ...args) {
const fnStr = serializeFunctionWithArgs(fn, ...args);
return puppeteerPage.evaluate(fnStr);
},
});
55 changes: 55 additions & 0 deletions api/retrieval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
*
* This file represents the retrieval API. It exposes convenience functions for getting properties/values/state from the UI.
*
**/

module.exports = puppeteerPage => ({
/**
* Get the value property value for a particular element
* @param {string} selector - The selector for the element to get the value for
* @returns {string} value - The value property value for the element
*/
async getValue(selector) {
return puppeteerPage.evaluate(selector => {
return document.querySelector(selector).value;
}, selector);
},
/**
* Get the text property value for a particular element
* @param {string} selector - The selector for the element to get the text for
* @returns {string} value - The text property value for the element
*/
async getText(selector) {
return puppeteerPage.evaluate(selector => {
return document.querySelector(selector).textContent;
}, selector);
},
/**
* Get the value of a particular property for a particular element
* @param {string} selector - The selector for the element to get the property value for
* @param {string} property - The property to look for
* @returns {string} value - The property value for the element
*/
async getPropertyValue(selector, property) {
try {
return puppeteerPage.evaluate((selector, property) => {
const element = document.querySelector(selector);
return element[property];
}, selector, property);
} catch(e) {
throw Error(`Unable able to get ${property} from ${selector}.`, e);
}
},
/**
* Check if element is focused
* @param {string} selector - The selector of the element to check for focus state
* @returns {boolean} Whether the element is focused or not
*/
async isElementFocused (selector) {
return puppeteerPage.evaluate(selector => {
const element = document.querySelector(selector);
return element === document.activeElement;
}, selector);
},
});
Loading

0 comments on commit b10b131

Please sign in to comment.