New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

expect-puppeteer

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

expect-puppeteer - npm Package Compare versions

Comparing version 2.0.1 to 2.1.0

lib/matchers/notToMatchElement.js

86

lib/index.js
'use strict';
var _toMatch = require('./matchers/toMatch');
var _utils = require('./utils');
var _toMatch2 = _interopRequireDefault(_toMatch);
var _notToMatch = require('./matchers/notToMatch');
var _notToMatch2 = _interopRequireDefault(_notToMatch);
var _notToMatchElement = require('./matchers/notToMatchElement');
var _notToMatchElement2 = _interopRequireDefault(_notToMatchElement);
var _toClick = require('./matchers/toClick');

@@ -11,10 +17,6 @@

var _toSelect = require('./matchers/toSelect');
var _toDisplayDialog = require('./matchers/toDisplayDialog');
var _toSelect2 = _interopRequireDefault(_toSelect);
var _toDisplayDialog2 = _interopRequireDefault(_toDisplayDialog);
var _toUploadFile = require('./matchers/toUploadFile');
var _toUploadFile2 = _interopRequireDefault(_toUploadFile);
var _toFill = require('./matchers/toFill');

@@ -28,23 +30,47 @@

var _toDisplayDialog = require('./matchers/toDisplayDialog');
var _toMatch = require('./matchers/toMatch');
var _toDisplayDialog2 = _interopRequireDefault(_toDisplayDialog);
var _toMatch2 = _interopRequireDefault(_toMatch);
var _notToMatch = require('./matchers/notToMatch');
var _toMatchElement = require('./matchers/toMatchElement');
var _notToMatch2 = _interopRequireDefault(_notToMatch);
var _toMatchElement2 = _interopRequireDefault(_toMatchElement);
var _toSelect = require('./matchers/toSelect');
var _toSelect2 = _interopRequireDefault(_toSelect);
var _toUploadFile = require('./matchers/toUploadFile');
var _toUploadFile2 = _interopRequireDefault(_toUploadFile);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-use-before-define, no-restricted-syntax, no-await-in-loop */
const matchers = {
const pageMatchers = {
toClick: _toClick2.default,
toDisplayDialog: _toDisplayDialog2.default,
toFill: _toFill2.default,
toFillForm: _toFillForm2.default,
toMatch: _toMatch2.default,
toClick: _toClick2.default,
toMatchElement: _toMatchElement2.default,
toSelect: _toSelect2.default,
toUploadFile: _toUploadFile2.default,
not: {
toMatch: _notToMatch2.default,
toMatchElement: _notToMatchElement2.default
}
}; /* eslint-disable no-use-before-define, no-restricted-syntax, no-await-in-loop */
const elementHandleMatchers = {
toClick: _toClick2.default,
toFill: _toFill2.default,
toFillForm: _toFillForm2.default,
toDisplayDialog: _toDisplayDialog2.default,
toMatch: _toMatch2.default,
toMatchElement: _toMatchElement2.default,
toSelect: _toSelect2.default,
toUploadFile: _toUploadFile2.default,
not: {
toMatch: _notToMatch2.default
toMatch: _notToMatch2.default,
toMatchElement: _notToMatchElement2.default
}

@@ -68,3 +94,3 @@ };

function expectPage(page) {
function internalExpect(type, matchers) {
const expectation = {

@@ -76,7 +102,7 @@ not: {}

if (key === 'not') return;
expectation[key] = createMatcher(matchers[key], page);
expectation[key] = createMatcher(matchers[key], type);
});
Object.keys(matchers.not).forEach(key => {
expectation.not[key] = createMatcher(matchers.not[key], page);
expectation.not[key] = createMatcher(matchers.not[key], type);
});

@@ -87,9 +113,19 @@

function expectPuppeteer(actual) {
const type = (0, _utils.getPuppeteerType)(actual);
switch (type) {
case 'Page':
return internalExpect(actual, pageMatchers);
case 'ElementHandle':
return internalExpect(actual, elementHandleMatchers);
default:
throw new Error(`${actual} is not supported`);
}
}
if (typeof global.expect !== 'undefined') {
const isPuppeteerPage = object => Boolean(object && object.$ && object.$$ && object.close && object.click);
const originalExpect = global.expect;
global.expect = (actual, ...args) => {
if (isPuppeteerPage(actual)) {
return expectPage(actual);
}
const type = (0, _utils.getPuppeteerType)(actual);
if (type) return expectPuppeteer(actual);
return originalExpect(actual, ...args);

@@ -102,2 +138,2 @@ };

module.exports = expectPage;
module.exports = expectPuppeteer;

@@ -1,7 +0,17 @@

"use strict";
'use strict';
exports.__esModule = true;
async function notToMatch(page, matcher, options = { timeout: 500 }) {
var _utils = require('../utils');
async function notToMatch(instance, matcher, options) {
options = (0, _utils.defaultOptions)(options);
const { page, handle } = await (0, _utils.getContext)(instance, () => document.body);
try {
await page.waitForFunction(`document.body && document.body.textContent.match(new RegExp('${matcher}')) === null`, options);
await page.waitForFunction((handle, matcher) => {
if (!handle) return false;
return handle.textContent.match(new RegExp(matcher)) === null;
}, options, handle, matcher);
} catch (error) {

@@ -8,0 +18,0 @@ throw new Error(`Text found "${matcher}"`);

'use strict';
exports.__esModule = true;
async function toClick(page, selector, { text } = {}) {
await page.$$eval(selector, (elements, selector, text) => {
const element = text !== undefined ? [...elements].find(({ textContent }) => textContent.match(text)) : elements[0];
if (!element) {
throw new Error(`Element ${selector} ${text !== undefined ? `(text: "${text}")` : ''} not found`);
}
var _toMatchElement = require('./toMatchElement');
element.click();
}, selector, text);
var _toMatchElement2 = _interopRequireDefault(_toMatchElement);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function toClick(instance, selector, options) {
const element = await (0, _toMatchElement2.default)(instance, selector, options);
await element.click(options);
}
exports.default = toClick;

@@ -1,15 +0,17 @@

"use strict";
'use strict';
exports.__esModule = true;
async function toFill(page, selector, value, options = { timeout: 500 }) {
try {
await page.waitFor(selector, options);
} catch (error) {
throw new Error(`Unable to find "${selector}" field`);
}
await page.click(selector, { clickCount: 3 });
await page.keyboard.type(value);
var _toMatchElement = require('./toMatchElement');
var _toMatchElement2 = _interopRequireDefault(_toMatchElement);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function toFill(instance, selector, value, options) {
const element = await (0, _toMatchElement2.default)(instance, selector, options);
await element.click({ clickCount: 3 });
await element.type(value);
}
exports.default = toFill;

@@ -5,2 +5,4 @@ 'use strict';

var _utils = require('../utils');
var _toFill = require('./toFill');

@@ -10,14 +12,16 @@

var _toMatchElement = require('./toMatchElement');
var _toMatchElement2 = _interopRequireDefault(_toMatchElement);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-restricted-syntax, no-await-in-loop */
async function toFillForm(page, formSelector, values, options = { timeout: 500 }) {
try {
await page.waitFor(formSelector, options);
} catch (error) {
throw new Error(`Unable to find "${formSelector}" form`);
}
async function toFillForm(instance, selector, values, options) {
options = (0, _utils.defaultOptions)(options);
const form = await (0, _toMatchElement2.default)(instance, selector, options);
for (const name of Object.keys(values)) {
await (0, _toFill2.default)(page, `${formSelector} [name="${name}"]`, values[name], options);
await (0, _toFill2.default)(form, `[name="${name}"]`, values[name], options);
}

@@ -24,0 +28,0 @@ }

@@ -1,7 +0,17 @@

"use strict";
'use strict';
exports.__esModule = true;
async function toMatch(page, matcher, options = { timeout: 500 }) {
var _utils = require('../utils');
async function toMatch(instance, matcher, options) {
options = (0, _utils.defaultOptions)(options);
const { page, handle } = await (0, _utils.getContext)(instance, () => document.body);
try {
await page.waitForFunction(`document.body && document.body.textContent.match(new RegExp('${matcher}')) !== null`, options);
await page.waitForFunction((handle, matcher) => {
if (!handle) return false;
return handle.textContent.match(new RegExp(matcher)) !== null;
}, options, handle, matcher);
} catch (error) {

@@ -8,0 +18,0 @@ throw new Error(`Text not found "${matcher}"`);

@@ -1,15 +0,74 @@

"use strict";
'use strict';
exports.__esModule = true;
async function toSelect(page, selector, valueOrText) {
const foundValue = await page.$$eval(`${selector} option`, (options, valueOrText, selector) => {
const option = options.find(option => option.value === valueOrText || option.textContent === valueOrText);
if (!option) {
throw new Error(`Option not found "${selector}" ("${valueOrText}")`);
var _toMatchElement = require('./toMatchElement');
var _toMatchElement2 = _interopRequireDefault(_toMatchElement);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function select(page, element, value) {
return page.evaluate((element, value) => {
if (element.nodeName.toLowerCase() !== 'select') throw new Error('Element is not a <select> element.');
const options = Array.from(element.options);
element.value = undefined;
for (const option of options) {
option.selected = value === option.value;
if (option.selected && !element.multiple) break;
}
return option.value;
}, valueOrText, selector);
await page.select(selector, foundValue);
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
return options.filter(option => option.selected).map(option => option.value);
}, element, value);
} /* eslint-disable no-restricted-syntax */
async function toSelect(instance, selector, valueOrText, options) {
const element = await (0, _toMatchElement2.default)(instance, selector, options);
const optionElements = await element.$$('option');
const optionsAttributes = await Promise.all(optionElements.map(async option => {
const textContentProperty = await option.getProperty('textContent');
const valueProperty = await option.getProperty('value');
return {
value: await valueProperty.jsonValue(),
textContent: await textContentProperty.jsonValue()
};
}));
const option = optionsAttributes.find(({ value, textContent }) => value === valueOrText || textContent === valueOrText);
if (!option) {
throw new Error(`Option not found "${selector}" ("${valueOrText}")`);
}
await select(page, element, option.value);
// await page.select(selector, foundValue)
// console.log(select.select)
// select.select()
// const foundValue = await select.$$eval(
// `${selector} option`,
// (options, valueOrText, selector) => {
// const option = options.find(
// option =>
// option.value === valueOrText || option.textContent === valueOrText,
// )
// if (!option) {
// throw new Error(`Option not found "${selector}" ("${valueOrText}")`)
// }
// return option.value
// },
// valueOrText,
// selector,
// )
//
// await page.select(selector, foundValue)
}
exports.default = toSelect;

@@ -1,16 +0,17 @@

"use strict";
'use strict';
exports.__esModule = true;
async function toUploadFile(page, selector, file, options = { timeout: 500 }) {
let input;
try {
input = await page.waitFor(selector, options);
} catch (error) {
throw new Error(`Unable to find "${selector}" field`);
}
var _toMatchElement = require('./toMatchElement');
await input.uploadFile(file);
var _toMatchElement2 = _interopRequireDefault(_toMatchElement);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function toUploadFile(instance, selector, file, options) {
const input = await (0, _toMatchElement2.default)(instance, selector, options);
const files = Array.isArray(file) ? file : [file];
await input.uploadFile(...files);
}
exports.default = toUploadFile;
{
"name": "expect-puppeteer",
"description": "Assertion toolkit for Puppeteer.",
"version": "2.0.1",
"version": "2.1.0",
"main": "lib/index.js",

@@ -6,0 +6,0 @@ "repository": "https://github.com/smooth-code/jest-puppeteer/tree/master/packages/puppeteer-expect",

@@ -38,2 +38,8 @@ # expect-puppeteer

## Why do I need it
Writing integration test is very hard especially in Single Page Application. Data are loaded asynchronously and it is difficult to know exactly when it will be displayed in the page.
Puppeteer API is great, all this methods are built with it but it is low level and not designed to test an application. This API is designed for integration testing and will wait element before running each action.
## API

@@ -45,15 +51,21 @@

* [toClick](#expectpagetoclickselector-options)
* [toDisplayDialog](#expectpagetodisplaydialogblock)
* [toFill](#expectpagetofillselector-value-options)
* [toFillForm](#expectpagetofillformselector-values-options)
* [toMatch](#expectpagetomatchtext)
* [toSelect](#expectpagetoselectselector-valueortext)
* [toUploadFile](#expectpagetouploadfileselector-filepath)
* [toClick](#toClick)
* [toDisplayDialog](#toDisplayDialog)
* [toFill](#toFill)
* [toFillForm](#toFillForm)
* [toMatch](#toMatch)
* [toMatchElement](#toMatchElement)
* [toSelect](#toSelect)
* [toUploadFile](#toUploadFile)
### expect(page).toClick(selector[, options])
### <a name="toClick"></a>expect(instance).toClick(selector[, options])
* `instance` <[Page]|[ElementHandle]> Context
* `selector` <[string]> A [selector] to click on
* `options` <[Object]> Optional parameters
* text <[string]> A text to match
* `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
* `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
* `mutation` - to execute `pageFunction` on every DOM mutation.
* `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`.
* `text` <[string]> A text or a RegExp to match in element `textContent`.

@@ -64,4 +76,5 @@ ```js

### expect(page).toDisplayDialog(block)
### <a name="toDisplayDialog"></a>expect(page).toDisplayDialog(block)
* `page` <[Page]> Context
* `block` <[function]> A [function] that should trigger a dialog

@@ -75,7 +88,11 @@

### expect(page).toFill(selector, value[, options])
### <a name="toFill"></a>expect(instance).toFill(selector, value[, options])
* `instance` <[Page]|[ElementHandle]> Context
* `selector` <[string]> A [selector] to match field
* `value` <[string]> Value to fill
* `options` <[Object]> Optional parameters
* `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
* `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
* `mutation` - to execute `pageFunction` on every DOM mutation.
* `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`.

@@ -87,7 +104,11 @@

### expect(page).toFillForm(selector, values[, options])
### <a name="toFillForm"></a>expect(instance).toFillForm(selector, values[, options])
* `instance` <[Page]|[ElementHandle]> Context
* `selector` <[string]> A [selector] to match form
* `values` <[Object]> Values to fill
* `options` <[Object]> Optional parameters
* `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
* `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
* `mutation` - to execute `pageFunction` on every DOM mutation.
* `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`.

@@ -102,16 +123,47 @@

### expect(page).toMatch(text)
### <a name="toMatch"></a>expect(instance).toMatch(matcher[, options])
* `text` <[string]> A text to match in page
* `instance` <[Page]|[ElementHandle]> Context
* `matcher` <[string]> A text or a RegExp to match in page
* `options` <[Object]> Optional parameters
* `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
* `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
* `mutation` - to execute `pageFunction` on every DOM mutation.
* `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`.
```js
// Matching using text
await expect(page).toMatch('Lorem ipsum')
// Matching using RegExp
await expect(page).toMatch('lo.*')
```
### expect(page).toSelect(selector, valueOrText)
### <a name="toMatchElement"></a>expect(instance).toMatchElement(selector[, options])
* `instance` <[Page]|[ElementHandle]> Context
* `selector` <[string]> A [selector] to match element
* `options` <[Object]> Optional parameters
* `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
* `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
* `mutation` - to execute `pageFunction` on every DOM mutation.
* `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`.
* `text` <[string]> A text or a RegExp to match in element `textContent`.
```js
// Select a row containing a text
const row = await expect(page).toMatchElement('tr', { text: 'My row' })
// Click on the third column link
await expect(row).toClick('td:nth-child(2) a')
```
### <a name="toSelect"></a>expect(instance).toSelect(selector, valueOrText[, options])
* `instance` <[Page]|[ElementHandle]> Context
* `selector` <[string]> A [selector] to match select [element]
* `valueOrText` <[string]> Value or text matching option
* `options` <[Object]> Optional parameters
* `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
* `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
* `mutation` - to execute `pageFunction` on every DOM mutation.
* `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`.

@@ -122,6 +174,12 @@ ```js

### expect(page).toUploadFile(selector, filePath)
### <a name="toUploadFile"></a>expect(instance).toUploadFile(selector, filePath[, options])
* `instance` <[Page]|[ElementHandle]> Context
* `selector` <[string]> A [selector] to match input [element]
* `filePath` <[string]> A file path
* `options` <[Object]> Optional parameters
* `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
* `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
* `mutation` - to execute `pageFunction` on every DOM mutation.
* `timeout` <[number]> maximum time to wait for in milliseconds. Defaults to `500`.

@@ -158,1 +216,3 @@ ```js

[selector]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors 'selector'
[page]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-page 'Page'
[element-handle]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-elementhandle 'ElementHandle'
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc