Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

browser-monkey

Package Overview
Dependencies
Maintainers
2
Versions
87
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

browser-monkey - npm Package Compare versions

Comparing version 3.0.0-beta.3 to 3.0.0-beta.4

8

lib/BrowserMonkeyAssertionError.ts

@@ -10,2 +10,4 @@ import { ExecutedTransform } from './ExecutedTransform'

public executedTransforms: ExecutedTransformPath
public duration: number
public retries: number

@@ -43,3 +45,7 @@ public constructor (message, {

public renderError (): string {
return `${this.description}${this.executedTransforms.transforms.length ? ` (found: ${this.executedTransforms.renderError()})`: ''}`
const stats = this.duration !== undefined && this.retries !== undefined
? ` [waited ${this.duration}ms, retried ${this.retries} times]`
: ''
return `${this.description}${stats}${this.executedTransforms.transforms.length ? ` (found: ${this.executedTransforms.renderError()})`: ''}`
}

@@ -46,0 +52,0 @@ }

7

lib/ExecutedContainingTransform.ts
import { ExecutedTransform } from './ExecutedTransform'
import inspect from 'object-inspect'
export class ExecutedContainingTransform extends ExecutedTransform {
public model: any
public failingActuals: any[]
public constructor (value: any, model: any) {
public constructor (value: any, model: any, failingActuals: any[]) {
super(value)
this.model = model
this.failingActuals = failingActuals
}
public renderError (): string {
return `containing(${this.model ? '...' + this.model.renderError() : ''}) [${this.value.length}]`
return `containing(${this.failingActuals ? inspect({expected: this.model, actual: this.failingActuals}) : inspect(this.model)}) [${this.value.length}]`
}
}
const settable =
'input:not([type]), ' +
'input[type=text], ' +
'input[type=hidden], ' +
'input[type=email], ' +

@@ -5,0 +6,0 @@ 'input[type=password], ' +

@@ -12,12 +12,12 @@ import { ExecutedTransform } from './ExecutedTransform'

import toExecutedTransform from './toExecutedTransform'
const pluralize = require('pluralize')
const extend = require('lowscore/extend')
import pluralize from 'pluralize'
import extend from 'lowscore/extend'
import retry from './retry'
const inspect = require('object-inspect')
const uniq = require('lowscore/uniq')
import inspect from 'object-inspect'
import uniq from 'lowscore/uniq'
const debug = require('debug')('browser-monkey')
const inputSelectors = require('./inputSelectors')
const object = require('lowscore/object')
const range = require('lowscore/range')
const flatten = require('lowscore/flatten')
import inputSelectors from './inputSelectors'
import object from 'lowscore/object'
import range from 'lowscore/range'
import flatten from 'lowscore/flatten'
import {match} from './match'

@@ -28,18 +28,24 @@ import * as matchers from './matchers'

type Action = (elements: any, executedTransforms: ExecutedTransform[]) => void
interface FieldType {
value?: (query: Query) => Query
interface InputDefinition {
values?: (query: Query) => Query
setter?: (query: Query, value: any) => Query
valueAsserter?: (query: Query, expected: any) => Query
valueAsserters?: (query: Query, expected: any) => Query
}
type LabelName = string | RegExp
type LabelDefinition = <Q extends Query>(query: Q, name: LabelName) => Q
type FieldDefinition = <Q extends Query>(query: Q, ...any) => Q
type Match = {
isMatch: boolean,
actual: any,
expected: any,
}
type FieldName = string | RegExp
type FieldFinderDefinition = <Q extends Query>(query: Q, name: FieldName) => Q
type FinderDefinition = <Q extends Query>(query: Q, ...any) => Q
interface Definitions {
fieldTypes: FieldType[]
button: LabelDefinition[]
label: ({name: string, definition: LabelDefinition})[]
fields: {
[key: string]: FieldDefinition
inputs: InputDefinition[]
buttons: FieldFinderDefinition[]
fields: ({name: string, definition: FieldFinderDefinition})[]
finders: {
[key: string]: FinderDefinition
}

@@ -67,3 +73,3 @@ }

definitions: {
fieldTypes: [
inputs: [
{

@@ -73,3 +79,3 @@ setter: (query, value) => {

.is('input[type=checkbox]')
.expectOneElement()
.shouldHaveElements(1)
.transform(([checkbox]) => {

@@ -87,7 +93,6 @@ if (typeof value !== 'boolean') {

},
value: (query) => {
values: (query) => {
return query
.is('input[type=checkbox]')
.expectOneElement()
.transform(([checkbox]) => {
.map((checkbox) => {
return query._dom.checked(checkbox)

@@ -101,3 +106,3 @@ })

.is('select')
.expectOneElement('expected to be select element')
.shouldHaveElements(1, 'expected to be select element')
.findCss('option')

@@ -107,3 +112,3 @@ .filter(o => {

}, `option with text or value ${JSON.stringify(value)}`)
.expectOneElement(`expected one option element with text or value ${JSON.stringify(value)}`)
.shouldHaveElements(1, `expected one option element with text or value ${JSON.stringify(value)}`)
.transform(([option]) => {

@@ -117,12 +122,13 @@ return () => {

},
valueAsserter: (query, expected) => {
valueAsserters: (query, expected) => {
return query
.is('select')
.expectOneElement('expected to be select element')
.transform(([select]) => {
.map((select) => {
return () => {
const value = select.value
if (match(expected, value).isMatch) {
return
const matchValue = match(expected, value)
if (matchValue.isMatch) {
return matchValue
}

@@ -133,18 +139,27 @@

const actual = query._dom.elementInnerText(selectedOption)
if (match(expected, actual).isMatch) {
return
const matchText = match(expected, actual)
if (matchText.isMatch) {
return matchText
} else {
this.error('expected ' + inspect(actual) + ' or ' + inspect(value) + ' to equal ' + inspect(expected), { actual, expected })
return {
isMatch: false,
actual,
expected,
}
}
}
this.error('expected ' + inspect(value) + ' to equal ' + inspect(expected), { actual: value, expected })
return {
isMatch: false,
actual: value,
expected,
}
}
})
},
value: (query) => {
values: (query) => {
return query
.is('select')
.expectOneElement('expected to be select element')
.transform(([select]) => {
.map((select) => {
const selectedOption = select.options[select.selectedIndex]

@@ -159,3 +174,3 @@ return selectedOption && query._dom.elementInnerText(selectedOption)

.is(inputSelectors.settable)
.expectOneElement()
.shouldHaveElements(1)
.transform(([element]) => {

@@ -171,4 +186,4 @@ if (typeof value !== 'string') {

},
value: (query) => {
return query.is(inputSelectors.gettable).expectOneElement().transform(([input]) => {
values: (query) => {
return query.is(inputSelectors.gettable).map((input) => {
return input.value

@@ -179,4 +194,4 @@ })

{
value: (query) => {
return query.expectOneElement().transform(([element]) => {
values: (query) => {
return query.map((element) => {
return query._dom.elementInnerText(element)

@@ -187,3 +202,3 @@ })

],
button: [
buttons: [
(query, name) => {

@@ -193,3 +208,3 @@ return query.findCss('button, input[type=button], input[type=submit], input[type=reset], a').containing(name)

],
label: [
fields: [
{

@@ -240,4 +255,4 @@ name: 'label',

],
fields: {
Label: (q, value) => q.findLabel(value),
finders: {
Field: (q, value) => q.findLabel(value),
Button: (q, value) => q.findButton(value),

@@ -282,4 +297,4 @@ Css: (q, value) => q.findCss(value),

public findButton (name: LabelName): this {
return this.concat(this._options.definitions.button.map(definition => {
public findButton (name: FieldName): this {
return this.concat(this._options.definitions.buttons.map(definition => {
return (q: Query): Query => {

@@ -292,3 +307,3 @@ return definition(q, name)

public findLabel (name: string): this {
return this.concat(this._options.definitions.label.map(({definition}) => {
return this.concat(this._options.definitions.fields.map(({definition}) => {
return (q: Query): Query => {

@@ -300,22 +315,38 @@ return definition(q, name)

public defineButtonType (definition: LabelDefinition): this {
return this.clone(q => q._options.definitions.button.push(definition))
public defineButtonFinder (name: string | FieldFinderDefinition, definition: FieldFinderDefinition): this {
if (!definition) {
definition = name as FieldFinderDefinition
name = undefined
}
return this.clone(q => q._options.definitions.buttons.push(definition))
}
public defineLabelType (name: string | LabelDefinition, definition?: LabelDefinition): this {
public undefineButtonFinder (name: string): this {
return this.clone(q => {
const index = q._options.definitions.buttons.findIndex(def => def.name === name)
if (index >= 0) {
q._options.definitions.buttons.splice(index, 1)
} else {
throw new Error(`field definition ${JSON.stringify(name)} doesn't exist`)
}
})
}
public defineFieldFinder (name: string | FieldFinderDefinition, definition?: FieldFinderDefinition): this {
if (!definition) {
definition = name as LabelDefinition
definition = name as FieldFinderDefinition
name = undefined
}
return this.clone(q => q._options.definitions.label.push({name: name as string, definition}))
return this.clone(q => q._options.definitions.fields.push({name: name as string, definition}))
}
public undefineLabelType (name: string): this {
public undefineFieldFinder (name: string): this {
return this.clone(q => {
const index = q._options.definitions.label.findIndex(def => def.name === name)
const index = q._options.definitions.fields.findIndex(def => def.name === name)
if (index >= 0) {
q._options.definitions.label.splice(index, 1)
q._options.definitions.fields.splice(index, 1)
} else {
throw new Error(`label definition ${JSON.stringify(name)} doesn't exist`)
throw new Error(`field definition ${JSON.stringify(name)} doesn't exist`)
}

@@ -506,6 +537,14 @@ })

let retries = 0
const startTime = new Date()
const promise = Promise.resolve(retry(() => {
retries++
return this.execute().value
})).catch(error => {
if (error instanceof BrowserMonkeyAssertionError) {
error.retries = retries
error.duration = new Date() - startTime
error.rewriteMessage()
if (debug.enabled) {

@@ -568,8 +607,6 @@ debug('assertion error', error.message)

public expectNoElements (message?: string): this {
public shouldHaveElements (count: number, message?: string): this {
return this.expect(elements => {
expectElements(elements)
if (elements.length !== 0) {
this.error(message || 'expected no elements, found ' + elements.length)
if (elements.length !== count) {
this.error(message || `expected ${count} ${pluralize('elements', count)}, found ` + elements.length)
}

@@ -579,8 +616,6 @@ })

public expectOneElement (message?: string): this {
public shouldExist (message?: string): this {
return this.expect(elements => {
expectElements(elements)
if (elements.length !== 1) {
this.error(message || 'expected just one element, found ' + elements.length)
if (elements.length < 1) {
this.error(message || 'expected one or more elements, found ' + elements.length)
}

@@ -590,16 +625,6 @@ })

public elementResult (): HTMLElement {
return this.expectOneElement().result()[0]
}
public elementsResult (): HTMLElement {
return this.expectSomeElements().result()
}
public expectSomeElements (message?: string): this {
public shouldNotExist (message?: string): this {
return this.expect(elements => {
expectElements(elements)
if (elements.length < 1) {
this.error(message || 'expected one or more elements, found ' + elements.length)
if (elements.length !== 0) {
this.error(message || 'expected no elements, found ' + elements.length)
}

@@ -609,14 +634,12 @@ })

public expectLength (length: number): this {
return this.expect(elements => {
expectElements(elements)
public elementResult (): HTMLElement {
return this.shouldHaveElements(1).result()[0]
}
if (elements.length !== length) {
this.error(`expected ${length} elements, found ` + elements.length)
}
})
public elementsResult (): HTMLElement {
return this.shouldExist().result()
}
public click (selector?: string): this {
return this.optionalSelector(selector).expectOneElement().action(([element]) => {
return this.optionalSelector(selector).shouldHaveElements(1).action(([element]) => {
debug('click', element)

@@ -627,3 +650,3 @@ this._dom.click(element)

public clickButton (name: LabelName): this {
public clickButton (name: FieldName): this {
return this.findButton(name).click()

@@ -634,3 +657,3 @@ }

return this.optionalSelector(selector)
.expectOneElement()
.shouldHaveElements(1)
.expect(([element]) => {

@@ -654,3 +677,3 @@ if (!element.form) {

return this.optionalSelector(selector)
.expectOneElement()
.shouldHaveElements(1)
.is(inputSelectors.settable)

@@ -704,3 +727,3 @@ .action(([element]) => {

value: (query, model): ActualExpected => {
const setter = query.setter(model).result()
const setter = query.shouldHaveElements(1).setter(model).result()
setters.push(() => setter())

@@ -714,3 +737,3 @@ return {

expectOne: (query): ActualExpected => {
query.expectOneElement().result()
query.shouldHaveElements(1).result()
return {

@@ -740,10 +763,2 @@ actual: {},

public shouldExist (): this {
return this.expectSomeElements()
}
public shouldNotExist (): this {
return this.expectNoElements()
}
public async shouldAppearAfter (action: () => void): Promise<void> {

@@ -772,3 +787,3 @@ await this.shouldNotExist()

try {
query.expectOneElement().result()
query.shouldHaveElements(1).result()
return {actual: {}, expected: {}}

@@ -789,36 +804,9 @@ } catch (e) {

value: (query, model): ActualExpected => {
let valueAsserter
const match = query.matchValue(model)
try {
valueAsserter = query.valueAsserter(model).result()
} catch (e) {
if (e instanceof BrowserMonkeyAssertionError) {
isError = true
return {
actual: e,
expected: model,
}
} else {
throw e
}
if (!match.isMatch) {
isError = true
}
try {
valueAsserter()
} catch (e) {
if (e instanceof BrowserMonkeyAssertionError) {
isError = true
return {
actual: e.actual,
expected: e.expected,
}
} else {
throw e
}
}
return {
actual: model,
expected: model,
}
return match
},

@@ -858,2 +846,5 @@

return this.transform(elements => {
if (elements.length <= index) {
this.error(`index(${index}) where there are only ${elements.length} elements`)
}
return new ExecutedSimpleTransform([elements[index]], 'index ' + index)

@@ -863,8 +854,8 @@ })

public define (name: string, fieldDefinition): this {
if (typeof fieldDefinition === 'function') {
this._options.definitions.fields[name] = fieldDefinition
} else if (typeof fieldDefinition === 'string') {
this._options.definitions.fields[name] = q => q.find(fieldDefinition)
} else if (name.constructor === Object && fieldDefinition === undefined) {
public define (name: string, finderDefinition): this {
if (typeof finderDefinition === 'function') {
this._options.definitions.finders[name] = finderDefinition
} else if (typeof finderDefinition === 'string') {
this._options.definitions.finders[name] = q => q.find(finderDefinition)
} else if (name.constructor === Object && finderDefinition === undefined) {
Object.keys(name).forEach(key => this.define(key, name[key]))

@@ -876,24 +867,36 @@ }

private setter (model): this {
return this.firstOf(this._options.definitions.fieldTypes.filter(def => def.setter).map(def => {
return query => def.setter(query, model)
private setter (value): this {
return this.firstOf(this._options.definitions.inputs.filter(def => def.setter).map(def => {
return query => def.setter(query, value)
}))
}
private valueAsserter (expected: any): this {
return this.firstOf(this._options.definitions.fieldTypes.filter(def => def.value).map(def => {
return query => def.valueAsserter
? def.valueAsserter(query, expected)
: def.value(query).transform(actual => {
return () => {
if (!match(actual, expected).isMatch) {
this.error('expected ' + inspect(actual) + ' to equal ' + inspect(expected), { actual, expected })
}
}
private valueAsserters (expected: any): this {
return this.transform(elements => {
const definitions = this._options.definitions.inputs.filter(def => def.values || def.valueAsserters)
const asserters = elements.map(element => {
const queryOfOneElement = this.resolve([element])
const firstAsserterForElement = definitions.map(def => {
const definitionAsserters = def.valueAsserters
? def.valueAsserters(queryOfOneElement, expected)
: def.values(queryOfOneElement).transform(actuals => {
return actuals.map(actual => () => {
return match(actual, expected)
})
})
return definitionAsserters.result()[0]
})
}))
return firstAsserterForElement.find(Boolean)
}).filter(Boolean)
return asserters
})
}
public defineFieldType (fieldTypeDefinition: FieldType): void {
this._options.definitions.fieldTypes.unshift(fieldTypeDefinition)
public defineInput (inputDefinition: InputDefinition): void {
this._options.definitions.inputs.unshift(inputDefinition)
}

@@ -908,10 +911,10 @@

value: (query, value): ActualExpected => {
const valueAsserter = query.valueAsserter(value).result()
valueAsserter()
value: (query, model): ActualExpected => {
const match = query.matchValue(model)
return {
actual: value,
expected: value
if (!match.isMatch) {
isError = true
}
return match
},

@@ -933,14 +936,26 @@

let lastError
let lastSuccess
let isError
const failingActuals = []
const matchingElements = []
const matchingElements = elements.filter(element => {
elements.forEach(element => {
try {
const clone = this.resolve([element])
lastSuccess = new ExecutedSimpleTransform(clone.mapModel(model, actions))
return true
isError = false
const match = clone.mapModel(model, actions)
if (isError) {
failingActuals.push(match.actual)
} else {
matchingElements.push(element)
}
} catch (e) {
if (e instanceof BrowserMonkeyAssertionError) {
lastError = new ExecutedTransformError(e)
return false
failingActuals.push({
isMatch: false,
actual: e.actual,
expected: e.expected,
})
} else {

@@ -952,10 +967,26 @@ throw e

return new ExecutedContainingTransform(matchingElements, lastSuccess ? lastSuccess : lastError)
return new ExecutedContainingTransform(matchingElements, model, matchingElements.length ? undefined : failingActuals)
})
}
public value (): this {
return this.firstOf(this._options.definitions.fieldTypes.filter(def => def.value).map(def => {
return query => def.value(query)
}))
public values (): this {
return this.transform(elements => {
const definitions = this._options.definitions.inputs.filter(def => def.values)
const values = elements.map(element => {
const queryOfOneElement = this.resolve([element])
const value = definitions.map(def => {
const values = def.values(queryOfOneElement).transform(actuals => {
return actuals
}).result()
return values
}).filter(vs => vs.length).map(vs => vs[0])[0]
return value
})
return values
})
}

@@ -965,3 +996,2 @@

const findElements = this.transform(elements => {
expectElements(elements)
return new ExecutedSimpleTransform(flatten(elements.map(element => {

@@ -981,3 +1011,3 @@ return this._dom.querySelectorAll(element, selector, this._options)

const [, name,, value] = match
const finder = this._options.definitions.fields[name]
const finder = this._options.definitions.finders[name]

@@ -1019,2 +1049,24 @@ if (value !== undefined) {

private matchValue(model: any): Match {
const valueAsserters = this.valueAsserters(model).result()
const results = valueAsserters.map(valueAsserter => valueAsserter())
const success = results.find(r => r.isMatch)
if (success) {
return success
} else {
const actual = results.length === 1
? results[0].actual
: results.length === 0
? undefined
: results.map(r => r.actual)
return {
isMatch: false,
actual,
expected: model,
}
}
}
private mapModel (model: any, actions: Actions): any {

@@ -1061,3 +1113,3 @@ const map = (query: Query, model: any): any => {

} else {
return actions.value(query.expectOneElement(), model)
return actions.value(query, model)
}

@@ -1070,8 +1122,2 @@ }

function expectElements (elements): void {
if (!isArrayOfHTMLElements(elements)) {
throw new BrowserMonkeyAssertionError('expected an array of HTML elements')
}
}
function cloneDefinitions(definitions: Definitions): Definitions {

@@ -1104,9 +1150,2 @@ const result = {}

function isArrayOfHTMLElements (elements): boolean {
return elements instanceof Array &&
elements.every(element => {
return isHTMLElement(element)
})
}
type Retry = <T>(fn: () => T, options?: {timeout?: number, interval?: number}) => Promise<T>

@@ -1113,0 +1152,0 @@

{
"name": "browser-monkey",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"description": "reliable dom testing",

@@ -24,9 +24,9 @@ "main": "dist/index.js",

"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/polyfill": "^7.2.5",
"@babel/preset-env": "^7.2.3",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.8.3",
"@babel/register": "^7.0.0",
"@types/jquery": "^3.3.31",
"@babel/core": "^7.10.4",
"@babel/polyfill": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"@babel/preset-react": "^7.10.4",
"@babel/preset-typescript": "^7.10.4",
"@babel/register": "^7.10.4",
"@types/jquery": "^3.5.0",
"@types/mocha": "^5.2.7",

@@ -33,0 +33,0 @@ "@types/react": "^16.9.19",

@@ -8,6 +8,6 @@ /* global location */

const { expect } = require('chai')
const inspect = require('object-inspect')
import Dom from '../../lib/Dom'
import {Query} from '../../lib/Query'
const object = require('lowscore/object')
import inspect from 'object-inspect'

@@ -144,8 +144,12 @@ export class DomAssembly {

public assertRejection (promise: Promise<any>, expectedMessage): Promise<void> {
public assertRejection (promise: Promise<any>, expectedMessage, {assertMetrics = false} = {}): Promise<void> {
return promise.then(() => {
throw new Error('expected rejection ' + JSON.stringify(expectedMessage))
throw new Error('expected rejection ' + inspect(expectedMessage))
}, e => {
if (e.message.indexOf(expectedMessage) === -1) {
throw new Error('expected error message ' + inspect(e.message) + ' to include ' + inspect(expectedMessage))
const message = assertMetrics
? e.message
: e.message.replace(/ \[waited \d+ms, retried \d+ times\]/, '')
if (expectedMessage instanceof RegExp ? !expectedMessage.test(message) : message.indexOf(expectedMessage) === -1) {
throw new Error('expected error message ' + inspect(message) + ' to include ' + inspect(expectedMessage))
}

@@ -152,0 +156,0 @@ })

@@ -19,3 +19,3 @@ const {DomAssembly} = require('./DomAssembly')

const element = assembly.insertHtml('<div class="a"/>')
const [found] = await browser.find('.a').expectOneElement()
const [found] = await browser.find('.a').shouldHaveElements(1)
expect(found).to.equal(element)

@@ -25,3 +25,3 @@ })

it('can eventually insert html before searching', async () => {
const promise = browser.find('.a').expectOneElement().then()
const promise = browser.find('.a').shouldHaveElements(1).then()
const element = assembly.eventuallyInsertHtml('<div class="a"/>')

@@ -33,3 +33,3 @@ const [found] = await promise

it('can eventually insert html after searching', async () => {
const found = browser.find('.a').expectOneElement().then()
const found = browser.find('.a').shouldHaveElements(1).then()
const element = assembly.eventuallyInsertHtml('<div class="a"/>')

@@ -41,4 +41,4 @@ expect((await found)[0]).to.equal(await element)

const promise = Promise.all([
browser.find('.a').expectOneElement().then(),
browser.find('.a').expectOneElement().then()
browser.find('.a').shouldHaveElements(1).then(),
browser.find('.a').shouldHaveElements(1).then()
])

@@ -45,0 +45,0 @@ const element = assembly.eventuallyInsertHtml('<div class="a"/>')

@@ -64,3 +64,3 @@ import {DomAssembly} from './assemblies/DomAssembly'

const query = browser.defineButtonType((query, name) => query.find('div.button').containing(name))
const query = browser.defineButtonFinder((query, name) => query.find('div.button').containing(name))

@@ -75,3 +75,3 @@ const elements = query.findButton('Login').result()

const query = browser.defineButtonType((query, name) => query.find('div.button').containing(name))
const query = browser.defineButtonFinder((query, name) => query.find('div.button').containing(name))

@@ -107,3 +107,3 @@ const elements = query.findButton('Login').result()

it('can click a defined button', async () => {
const query = browser.defineButtonType((query, name) => query.find('div.button').containing(name))
const query = browser.defineButtonFinder((query, name) => query.find('div.button').containing(name))
await assertCanClickButton('<div class="target button">Login</div>', () => query.click('Button("Login")'))

@@ -113,7 +113,7 @@ })

it('throws if the button cannot be found to click', async () => {
const query = browser.defineButtonType((query, name) => query.find('div.button').containing(name))
const query = browser.defineButtonFinder((query, name) => query.find('div.button').containing(name))
assembly.insertHtml('<button class="target">Login</button>')
await assembly.assertRejection(query.clickButton('Logout'), "expected just one element, found 0")
await assembly.assertRejection(query.clickButton('Logout'), "expected 1 element, found 0")
})
})
})

@@ -67,2 +67,3 @@ import {DomAssembly} from './assemblies/DomAssembly'

<div class="title">Title</div>
<div class="title">ax</div>
<div class="body">Body</div>

@@ -80,2 +81,16 @@ </div>

it('matches when it matches one of several child elements', () => {
assembly.insertHtml(`
<div class="result correct">
<div class="title">Title</div>
<div class="title">Other</div>
<div class="body">Body</div>
</div>
`)
const results = browser.find('.result').containing({'.title': 'Title'}).result()
const expected = assembly.findAll('.correct')
expect(results).to.eql(expected)
})
it("shows why it couldn't find the element", () => {

@@ -96,4 +111,4 @@ assembly.insertHtml(`

expect(() =>
browser.find('.result').containing({'.title': 'Title', '.body': 'None'}).expectOneElement().result()
).to.throw(`expected just one element, found 0 (found: path(find('.result') [3], containing(...expected just one element, found 0 (found: find('.title') [0])) [0]))`)
browser.find('.result').containing({'.title': 'Title', '.body': 'None'}).shouldHaveElements(1).result()
).to.throw(`expected 1 element, found 0 (found: path(find('.result') [3], containing({ expected: { '.title': 'Title', '.body': 'None' }, actual: [ { '.title': 'Title', '.body': undefined }, { '.title': 'Title', '.body': 'Body' }, { '.title': undefined, '.body': 'Body' } ] }) [0]))`)
})

@@ -148,6 +163,6 @@ })

browser.find('.result').containing(result => result.find('.body').shouldExist()).find('.title').expectOneElement().result()
browser.find('.result').containing(result => result.find('.body').shouldExist()).find('.title').shouldHaveElements(1).result()
expect(() =>
browser.find('.result').containing(result => result.find('.body').shouldExist()).find('.title').expectOneElement().result()
).to.throw(`expected just one element, found 0 (found: path(find('.result') [3], containing(...path(find('.body') [1])) [2], find('.title') [0]))`)
browser.find('.result').containing(result => result.find('.body').shouldExist()).find('.title').shouldHaveElements(1).result()
).to.throw(`expected 1 element, found 0 (found: path(find('.result') [3], containing(...path(find('.body') [1])) [2], find('.title') [0]))`)
})

@@ -169,6 +184,6 @@

expect(() =>
browser.find('.result').containing(result => result.find('.body').shouldExist()).find('.title').expectOneElement().result()
).to.throw(`expected just one element, found 0 (found: path(find('.result') [3], containing(...expected one or more elements, found 0 (found: find('.body') [0])) [0], find('.title') [0])`)
browser.find('.result').containing(result => result.find('.body').shouldExist()).find('.title').shouldHaveElements(1).result()
).to.throw(`expected 1 element, found 0 (found: path(find('.result') [3], containing(...expected one or more elements, found 0 (found: find('.body') [0])) [0], find('.title') [0])`)
})
})
})

@@ -32,3 +32,3 @@ import {DomAssembly} from './assemblies/DomAssembly'

query.find(label).expectNoElements().result()
query.find(label).shouldNotExist().result()
}

@@ -46,3 +46,3 @@

`,
'Label("Feature Enabled")'
'Field("Feature Enabled")'
)

@@ -60,3 +60,3 @@ })

`,
'Label("Feature Enabled")'
'Field("Feature Enabled")'
)

@@ -74,3 +74,3 @@ })

`,
'Label("Feature Enabled")'
'Field("Feature Enabled")'
)

@@ -88,3 +88,3 @@ })

`,
'Label("Feature")'
'Field("Feature")'
)

@@ -102,3 +102,3 @@ })

`,
'Label(/Feature/)'
'Field(/Feature/)'
)

@@ -115,3 +115,3 @@ })

`,
'Label("Search")'
'Field("Search")'
)

@@ -126,3 +126,3 @@ })

`,
'Label(/sea/i)'
'Field(/sea/i)'
)

@@ -137,3 +137,3 @@ })

`,
'Label("Search")'
'Field("Search")'
)

@@ -149,3 +149,3 @@ })

`,
'Label("Search")'
'Field("Search")'
)

@@ -161,3 +161,3 @@ })

`,
'Label(/sea/i)'
'Field(/sea/i)'
)

@@ -173,3 +173,3 @@ })

`,
'Label("Search")'
'Field("Search")'
)

@@ -185,3 +185,3 @@ })

`,
'Label("Search")'
'Field("Search")'
)

@@ -198,3 +198,3 @@ })

`,
'Label("Search")'
'Field("Search")'
)

@@ -209,3 +209,3 @@ })

`,
'Label(/sea/i)'
'Field(/sea/i)'
)

@@ -231,3 +231,3 @@ })

const found = browser.find('Label("Feature Enabled")').result()
const found = browser.find('Field("Feature Enabled")').result()

@@ -239,3 +239,3 @@ expect(found).to.eql(expected)

it('can define a new way of finding labels', () => {
const query = browser.defineLabelType((query, label) => query.findCss(`[data-label=${JSON.stringify(label)}]`))
const query = browser.defineFieldFinder((query, label) => query.findCss(`[data-label=${JSON.stringify(label)}]`))

@@ -247,3 +247,3 @@ assertFoundElementByLabel(

`,
'Label("Search")'
'Field("Search")'
)

@@ -253,3 +253,3 @@ })

it('can add and remove a label definition by name', async () => {
const query = browser.defineLabelType('data-label', (query, label) => query.findCss(`[data-label=${JSON.stringify(label)}]`))
const query = browser.defineFieldFinder('data-label', (query, label) => query.findCss(`[data-label=${JSON.stringify(label)}]`))

@@ -261,14 +261,14 @@ assertFoundElementByLabel(

`,
'Label("Search")'
'Field("Search")'
)
const without = query.undefineLabelType('data-label')
const without = query.undefineFieldFinder('data-label')
await without.find('Label("Search")').expectNoElements().result()
await without.find('Field("Search")').shouldNotExist().result()
})
it("throws if we try to undefine a label that doesn't exist", async () => {
expect(() => browser.undefineLabelType('data-label')).to.throw("doesn't exist")
expect(() => browser.undefineFieldFinder('data-label')).to.throw("doesn't exist")
})
})
})

@@ -19,3 +19,3 @@ import {expect} from 'chai'

it('can find an element by DOM selector', async () => {
const selectedElementPromise = browserMonkey.find('.test').expectOneElement().then()
const selectedElementPromise = browserMonkey.find('.test').shouldHaveElements(1).then()

@@ -42,3 +42,3 @@ const insertedElementPromise = assembly.eventuallyInsertHtml(

describe('expectNoElements', () => {
describe('shouldNotExist', () => {
it('passes when there are no elements found', async () => {

@@ -54,3 +54,3 @@ assembly.insertHtml(`

.find('.contact')
.expectNoElements()
.shouldNotExist()
.then()

@@ -77,3 +77,3 @@

.find('.contact')
.expectNoElements()
.shouldNotExist()
.then()

@@ -86,59 +86,59 @@

describe('expectOneElement', () => {
it('when there is one element, returns it', async () => {
const contacts = browserMonkey
.find('.contact')
.expectOneElement()
.then()
describe('shouldHaveElements', () => {
describe('when 1', () => {
it('when there is one element, returns it', async () => {
const contacts = browserMonkey
.find('.contact')
.shouldHaveElements(1)
.then()
assembly.eventuallyInsertHtml(`
<div class="contact">
<div class="name">Sally</div>
<div class="address">32 Yellow Drive</div>
</div>
`)
assembly.eventuallyInsertHtml(`
<div class="contact">
<div class="name">Sally</div>
<div class="address">32 Yellow Drive</div>
</div>
`)
expect(await contacts).to.eql([assembly.find('.contact:nth-child(1)')])
})
expect(await contacts).to.eql([assembly.find('.contact:nth-child(1)')])
})
it('when there is more than one element, throws an error', async () => {
const contacts = browserMonkey
.find('.contact')
.expectOneElement()
.then()
it('when there is more than one element, throws an error', async () => {
const contacts = browserMonkey
.find('.contact')
.shouldHaveElements(1)
.then()
assembly.eventuallyInsertHtml(`
<div class="contact">
<div class="name">Sally</div>
<div class="address">32 Yellow Drive</div>
</div>
<div class="contact">
<div class="name">Bob</div>
<div class="address">32 Red Drive</div>
</div>
`)
assembly.eventuallyInsertHtml(`
<div class="contact">
<div class="name">Sally</div>
<div class="address">32 Yellow Drive</div>
</div>
<div class="contact">
<div class="name">Bob</div>
<div class="address">32 Red Drive</div>
</div>
`)
await assembly.assertRejection(contacts, 'expected just one element, found 2')
})
await assembly.assertRejection(contacts, 'expected 1 element, found 2')
})
it('when there no elements, throws an error', async () => {
const contacts = browserMonkey
.find('.contact')
.expectOneElement()
.then()
it('when there no elements, throws an error', async () => {
const contacts = browserMonkey
.find('.contact')
.shouldHaveElements(1)
.then()
assembly.eventuallyInsertHtml(`
<div class="title"></div>
<div class="title"></div>
`)
assembly.eventuallyInsertHtml(`
<div class="title"></div>
<div class="title"></div>
`)
await assembly.assertRejection(contacts, 'expected just one element, found 0')
await assembly.assertRejection(contacts, 'expected 1 element, found 0')
})
})
})
describe('expectLength', () => {
it('asserts list of one element has one element', async () => {
it('asserts list of two elements has two elements', async () => {
const items = browserMonkey
.find('li ul')
.expectLength(2)
.shouldHaveElements(2)
.then()

@@ -156,6 +156,6 @@

it('asserts list of one element has one element', async () => {
it('fails when a list of two element is asserted to have three elements', async () => {
const items = browserMonkey
.find('li ul')
.expectLength(3)
.shouldHaveElements(3)
.then()

@@ -195,3 +195,3 @@

.find('.title')
.elementResult()).to.throw('expected just one element, found 2')
.elementResult()).to.throw('expected 1 element, found 2')
})

@@ -205,3 +205,3 @@

.find('.title')
.elementResult()).to.throw('expected just one element, found 0')
.elementResult()).to.throw('expected 1 element, found 0')
})

@@ -236,7 +236,7 @@ })

describe('expectSomeElements', () => {
describe('shouldExist', () => {
it('when there are one or more elements, selects them', async () => {
const contacts = browserMonkey
.find('.contact')
.expectSomeElements()
.shouldExist()
.then()

@@ -261,3 +261,3 @@

.find('.contact')
.expectSomeElements()
.shouldExist()
.then()

@@ -355,3 +355,3 @@

})
.expectOneElement()
.shouldHaveElements(1)
.then()

@@ -381,3 +381,3 @@

})
.expectSomeElements()
.shouldExist()
.then()

@@ -443,3 +443,3 @@

.find('.name')
.expectOneElement()
.shouldHaveElements(1)
.then()

@@ -457,3 +457,3 @@

await assembly.assertRejection(name, "expected just one element, found 0 (found: path(find('.container') [1], find('.contact') [2], find('.name') [0]))")
await assembly.assertRejection(name, "expected 1 element, found 0 (found: path(find('.container') [1], find('.contact') [2], find('.name') [0]))")
})

@@ -496,3 +496,3 @@ })

b => b.find('.b')
]).find('.child').expectSomeElements()
]).find('.child').shouldExist()

@@ -503,7 +503,19 @@ return assembly.assertRejection(promise, "expected one or more elements, found 0 (found: path(concat(find('.a') [1], find('.b') [1]) [2], find('.child') [0])")

describe('errors', () => {
it('throws error with wait duration and retry count', async () => {
assembly.insertHtml(`
<div class="a">A</div>
`)
const promise = browserMonkey.find('.b').shouldExist()
return assembly.assertRejection(promise, /expected one or more elements, found 0 \[waited \d+ms, retried 1 times\]/, {assertMetrics: true})
})
})
describe('firstOf', () => {
it('finds the first of two or more queries', async () => {
const promise = browserMonkey.firstOf([
b => b.find('.a').expectSomeElements(),
b => b.find('.b').expectSomeElements()
b => b.find('.a').shouldExist(),
b => b.find('.b').shouldExist()
]).then()

@@ -523,4 +535,4 @@

const promise = browserMonkey.find('.content').firstOf([
b => b.find('.a').expectSomeElements(),
b => b.find('.b').expectSomeElements()
b => b.find('.a').shouldExist(),
b => b.find('.b').shouldExist()
])

@@ -536,3 +548,3 @@

b => b.find('.a'),
b => b.find('.b').expectSomeElements()
b => b.find('.b').shouldExist()
])

@@ -547,4 +559,4 @@

const promise = browserMonkey.detect({
a: q => q.find('.a').expectSomeElements(),
b: q => q.find('.b').expectSomeElements()
a: q => q.find('.a').shouldExist(),
b: q => q.find('.b').shouldExist()
}).then()

@@ -566,4 +578,4 @@

const promise = browserMonkey.find('.content').detect({
a: b => b.find('.a').expectSomeElements(),
b: b => b.find('.b').expectSomeElements()
a: b => b.find('.a').shouldExist(),
b: b => b.find('.b').shouldExist()
})

@@ -579,3 +591,3 @@

a: b => b.find('.a'),
b: b => b.find('.b').expectSomeElements()
b: b => b.find('.b').shouldExist()
})

@@ -582,0 +594,0 @@

@@ -164,3 +164,3 @@ import {DomAssembly} from './assemblies/DomAssembly'

},
}), "expected just one element, found 2 (found: path(find('.address') [1], find('.street') [2]))")
}), "expected 1 element, found 2 (found: path(find('.address') [1], find('.street') [2]))")
})

@@ -278,3 +278,3 @@

'.street': streetQuery => {
streetQuery.expectOneElement().result()[0].innerText = 'hi'
streetQuery.shouldHaveElements(1).result()[0].innerText = 'hi'
}

@@ -301,3 +301,3 @@ })

})
await assembly.assertRejection(promise, "expected just one element, found 0 (found: path(find('form') [1], find('.street') [0]))")
await assembly.assertRejection(promise, "expected 1 element, found 0 (found: path(find('form') [1], find('.street') [0]))")

@@ -304,0 +304,0 @@ expect(assembly.find('.phone').value).to.equal('')

@@ -29,2 +29,29 @@ import {DomAssembly} from './assemblies/DomAssembly'

it('can assert html element when there are more than one', async () => {
assembly.insertHtml(`
<span class="address">12 Hapless Boulevard</span>
<span class="address">54 Harvard St</span>
`)
await browser.shouldContain({
'.address': '12 Hapless Boulevard',
})
})
it('fails to assert html element when there are more than one', async () => {
assembly.insertHtml(`
<span class="address">12 Boulevard Ave</span>
<span class="address">54 Harvard St</span>
`)
await assembly.assertExpectedActual(browser, {
'.address': '12 Hapless Boulevard',
}, {
'.address': [
'12 Boulevard Ave',
'54 Harvard St',
],
})
})
it('can assert text inputs', async () => {

@@ -59,3 +86,3 @@ assembly.insertHtml(`

}, {
'.address': "Error: expected just one element, found 0 (found: find('.address') [0])",
'.address': undefined,
})

@@ -192,3 +219,3 @@ })

'h1': 'Title',
'.content': "Error: expected just one element, found 0 (found: find('.content') [0])"
'.content': undefined,
})

@@ -216,3 +243,3 @@ })

'h1': 'Title',
'.content': "Error: expected just one element, found 0 (found: path(find('.result') [2], index 0 [1], find('.content') [0]))"
'.content': undefined,
},

@@ -251,3 +278,3 @@ 'The Content'

'h1': 'Title',
'.content': "Error: expected just one element, found 0 (found: find('.content') [0])"
'.content': "Error: expected 1 element, found 0 (found: find('.content') [0])"
})

@@ -254,0 +281,0 @@ })

@@ -20,4 +20,4 @@ import {expect} from 'chai'

const value = browser.find('.element').expectOneElement().value().result()
expect(value).to.equal(expectedValue)
const value = browser.find('.element').shouldHaveElements(1).values().result()
expect(value).to.eql(expectedValue)
}

@@ -27,3 +27,3 @@

it('can get value of input', () => {
assertValue('<input class="element" type="text" value="the value">', 'the value')
assertValue('<input class="element" type="text" value="the value">', ['the value'])
})

@@ -34,3 +34,3 @@ })

it('returns the innerHTML', () => {
assertValue('<div class="element">this is the inner text</div>', 'this is the inner text')
assertValue('<div class="element">this is the inner text</div>', ['this is the inner text'])
})

@@ -41,7 +41,7 @@ })

it('when checked, returns true', () => {
assertValue('<input class="element" type="checkbox" checked />', true)
assertValue('<input class="element" type="checkbox" checked />', [true])
})
it('when unchecked, returns false', () => {
assertValue('<input class="element" type="checkbox" />', false)
assertValue('<input class="element" type="checkbox" />', [false])
})

@@ -53,4 +53,4 @@

const value = browser.find('.element').expectOneElement().value().result()
expect(value).to.equal('indeterminate')
const values = browser.find('.element').shouldHaveElements(1).values().result()
expect(values).to.eql(['indeterminate'])
})

@@ -68,3 +68,3 @@ })

`,
'two'
['two']
)

@@ -71,0 +71,0 @@ })

Sorry, the diff of this file is too big to display

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