browser-monkey
Advanced tools
Comparing version 3.0.0-beta.7 to 3.0.0-beta.8
@@ -5,2 +5,3 @@ "use strict"; | ||
var object = require('lowscore/object'); | ||
// TODO: get rid of `any` | ||
function match(actual, expected) { | ||
@@ -7,0 +8,0 @@ if (typeof expected === 'function') { |
@@ -95,2 +95,3 @@ "use strict"; | ||
if (input === void 0) { input = document.body; } | ||
this._actionExecuted = false; | ||
this._hasExpectation = false; | ||
@@ -105,5 +106,5 @@ this._transforms = []; | ||
{ | ||
selector: 'input[type=checkbox]', | ||
setter: function (query, value) { | ||
return query | ||
.is('input[type=checkbox]') | ||
.shouldHaveElements(1) | ||
@@ -132,5 +133,5 @@ .transform(function (_a) { | ||
{ | ||
selector: 'select', | ||
setter: function (query, value) { | ||
return query | ||
.is('select') | ||
.shouldHaveElements(1, 'expected to be select element') | ||
@@ -194,5 +195,5 @@ .findCss('option') | ||
{ | ||
selector: inputSelectors_1.default.settable, | ||
setter: function (query, value) { | ||
return query | ||
.is(inputSelectors_1.default.settable) | ||
.shouldHaveElements(1) | ||
@@ -233,3 +234,3 @@ .transform(function (_a) { | ||
definition: function (query, name) { | ||
return query.find('label').containing(name).find('input'); | ||
return query.find('label').containing(name).find(query.inputSelector()); | ||
}, | ||
@@ -363,2 +364,3 @@ }, | ||
}; | ||
// TODO: try removing any | ||
Query.prototype.result = function () { | ||
@@ -424,5 +426,4 @@ return this.execute().value; | ||
var q = runQueryCreator(query, resolved); | ||
q.assertHasActionOrExpectation(); | ||
return { | ||
value: q.execute() | ||
value: q.ensureExpectation().execute() | ||
}; | ||
@@ -466,6 +467,5 @@ } | ||
var q = runQueryCreator(queryCreator, resolved); | ||
q.assertHasActionOrExpectation(); | ||
return { | ||
key: key, | ||
value: q.execute() | ||
value: q.ensureExpectation().execute() | ||
}; | ||
@@ -513,10 +513,4 @@ } | ||
}; | ||
Query.prototype.assertHasActionOrExpectation = function () { | ||
if (!this._hasExpectation && !this._action) { | ||
throw new Error('no expectations or actions in query, use .result(), or add an expectation or an action'); | ||
} | ||
}; | ||
Query.prototype.then = function (resolve, reject) { | ||
var _this = this; | ||
this.assertHasActionOrExpectation(); | ||
var retry = retryFromOptions(this._options); | ||
@@ -527,3 +521,3 @@ var retries = 0; | ||
retries++; | ||
return _this.execute().value; | ||
return _this.ensureExpectation().execute().value; | ||
})).catch(function (error) { | ||
@@ -578,5 +572,7 @@ if (error instanceof BrowserMonkeyAssertionError_1.default) { | ||
}; | ||
// TODO: why is this public? | ||
Query.prototype.input = function (value) { | ||
return this.clone(function (q) { return q._input = value; }); | ||
}; | ||
// TODO: rename `input`/`getInput` to something better | ||
Query.prototype.getInput = function () { | ||
@@ -851,5 +847,8 @@ return this._input; | ||
}; | ||
Query.prototype.inputSelector = function () { | ||
return this._options.definitions.inputs.map(function (i) { return i.selector; }).filter(Boolean).join(','); | ||
}; | ||
Query.prototype.setter = function (value) { | ||
return this.firstOf(this._options.definitions.inputs.filter(function (def) { return def.setter; }).map(function (def) { | ||
return function (query) { return def.setter(query, value); }; | ||
return function (query) { return def.setter(query.is(def.selector), value); }; | ||
})); | ||
@@ -895,9 +894,2 @@ }; | ||
}, | ||
expectOne: function (query) { | ||
query.expectOne().execute(); | ||
return { | ||
actual: {}, | ||
expected: {}, | ||
}; | ||
}, | ||
function: function (query, fn) { | ||
@@ -1078,2 +1070,8 @@ _this.runModelFunction(fn, query); | ||
}; | ||
Query.prototype.ensureExpectation = function () { | ||
if (!this._hasExpectation && !this._action) { | ||
return this.shouldExist(); | ||
} | ||
return this; | ||
}; | ||
return Query; | ||
@@ -1095,14 +1093,4 @@ }()); | ||
function isIframe(element) { | ||
return isHTMLElement(element, 'HTMLIFrameElement'); | ||
return element.contentWindow !== undefined; | ||
} | ||
function isHTMLElement(element, subclass) { | ||
if (subclass === void 0) { subclass = 'HTMLElement'; } | ||
if (element.ownerDocument && element.ownerDocument.defaultView) { | ||
// an element inside an iframe | ||
return element instanceof element.ownerDocument.defaultView[subclass]; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
function retryFromOptions(options) { | ||
@@ -1128,2 +1116,3 @@ if (options && options.retry) { | ||
} | ||
// TODO: try getting rid of any | ||
function spliceModelArrayFromActual(model, query, actions) { | ||
@@ -1151,2 +1140,3 @@ var length = query.result().length; | ||
} | ||
// TODO: try getting rid of any | ||
function arrayAssign(a, b) { | ||
@@ -1153,0 +1143,0 @@ return a.map(function (itemA, index) { |
const object = require('lowscore/object') | ||
// TODO: get rid of `any` | ||
export function match (actual: any, expected: any): {isMatch: boolean, actual: any, expected: any} { | ||
@@ -4,0 +5,0 @@ if (typeof expected === 'function') { |
import {match} from './match' | ||
import BrowserMonkeyAssertionError from './BrowserMonkeyAssertionError' | ||
import { Query } from './Query' | ||
export function elementAttributes (expected): (Query) => void { | ||
export function elementAttributes (expected): (query: Query) => void { | ||
return query => { | ||
@@ -6,0 +7,0 @@ const element = query.elementResult() |
259
lib/Query.ts
@@ -25,5 +25,6 @@ import { ExecutedTransform } from './ExecutedTransform' | ||
type Transform = (elements: any, executedTransforms: ExecutedTransform[]) => any | ||
type Action = (elements: any, executedTransforms: ExecutedTransform[]) => void | ||
type Transform = (elements: Array<HTMLElement>, executedTransforms: ExecutedTransform[]) => any | ||
type Action = (elements: Array<HTMLElement>, executedTransforms: ExecutedTransform[]) => void | ||
interface InputDefinition { | ||
selector?: string, | ||
values?: (query: Query) => Query | ||
@@ -41,5 +42,9 @@ setter?: (query: Query, value: any) => Query | ||
type FieldName = string | RegExp | ||
type FieldFinderDefinition = <Q extends Query>(query: Q, name: FieldName) => Q | ||
type FinderDefinition = <Q extends Query>(query: Q, ...any) => Q | ||
type FieldFinderDefinition = (query: Query, name: FieldName) => Query | ||
type FinderDefinition = (query: Query, ...any) => Query | ||
type LiteralModel = string | RegExp | boolean | ||
type FunctionModel = (query: Query) => void | ||
type Model = LiteralModel | FunctionModel | { [key: string]: Model } | Model[] | ||
interface Definitions { | ||
@@ -59,10 +64,9 @@ inputs: InputDefinition[] | ||
private _options: Options | ||
private _input: any | ||
private _actionExecuted: any | ||
private _input: [HTMLElement] | ||
private _actionExecuted = false | ||
private _action: Action | ||
private _hasExpectation: boolean | ||
private _hasExpectation = false | ||
private _dom: Dom | ||
public constructor (input: HTMLElement = document.body) { | ||
this._hasExpectation = false | ||
this._transforms = [] | ||
@@ -76,5 +80,5 @@ this._options = { | ||
{ | ||
setter: (query, value) => { | ||
selector: 'input[type=checkbox]', | ||
setter: (query: Query, value) => { | ||
return query | ||
.is('input[type=checkbox]') | ||
.shouldHaveElements(1) | ||
@@ -86,3 +90,3 @@ .transform(([checkbox]) => { | ||
return () => { | ||
if (query._dom.checked(checkbox) !== value) { | ||
if (query._dom.checked(checkbox as HTMLInputElement) !== value) { | ||
debug('checkbox', checkbox, value) | ||
@@ -94,6 +98,6 @@ query._dom.click(checkbox) | ||
}, | ||
values: (query) => { | ||
values: (query: Query) => { | ||
return query | ||
.is('input[type=checkbox]') | ||
.map((checkbox) => { | ||
.map((checkbox: HTMLInputElement) => { | ||
return query._dom.checked(checkbox) | ||
@@ -104,8 +108,8 @@ }) | ||
{ | ||
setter: (query, value) => { | ||
selector: 'select', | ||
setter: (query: Query, value) => { | ||
return query | ||
.is('select') | ||
.shouldHaveElements(1, 'expected to be select element') | ||
.findCss('option') | ||
.filter(o => { | ||
.filter((o: HTMLInputElement) => { | ||
return match(o.value, value).isMatch || match(query._dom.elementInnerText(o), value).isMatch | ||
@@ -118,10 +122,10 @@ }, `option with text or value ${JSON.stringify(value)}`) | ||
debug('select', selectElement) | ||
query._dom.selectOption(selectElement, option) | ||
query._dom.selectOption(selectElement as HTMLSelectElement, option as HTMLOptionElement) | ||
} | ||
}) | ||
}, | ||
valueAsserters: (query, expected) => { | ||
valueAsserters: (query: Query, expected) => { | ||
return query | ||
.is('select') | ||
.map((select) => { | ||
.map((select: HTMLSelectElement) => { | ||
return () => { | ||
@@ -160,6 +164,6 @@ const value = select.value | ||
}, | ||
values: (query) => { | ||
values: (query: Query) => { | ||
return query | ||
.is('select') | ||
.map((select) => { | ||
.map((select: HTMLSelectElement) => { | ||
const selectedOption = select.options[select.selectedIndex] | ||
@@ -171,5 +175,5 @@ return selectedOption && query._dom.elementInnerText(selectedOption) | ||
{ | ||
setter: (query, value) => { | ||
selector: inputSelectors.settable, | ||
setter: (query: Query, value) => { | ||
return query | ||
.is(inputSelectors.settable) | ||
.shouldHaveElements(1) | ||
@@ -182,8 +186,8 @@ .transform(([element]) => { | ||
debug('set', element, value) | ||
query._dom.enterText(element, value, {incremental: false}) | ||
query._dom.enterText(element as HTMLInputElement, value, {incremental: false}) | ||
} | ||
}) | ||
}, | ||
values: (query) => { | ||
return query.is(inputSelectors.gettable).map((input) => { | ||
values: (query: Query) => { | ||
return query.is(inputSelectors.gettable).map((input: HTMLInputElement) => { | ||
return input.value | ||
@@ -194,3 +198,3 @@ }) | ||
{ | ||
values: (query) => { | ||
values: (query: Query) => { | ||
return query.map((element) => { | ||
@@ -203,3 +207,3 @@ return query._dom.elementInnerText(element) | ||
buttons: [ | ||
(query, name) => { | ||
(query: Query, name) => { | ||
return query.findCss('button, input[type=button], input[type=submit], input[type=reset], a').containing(name) | ||
@@ -211,4 +215,4 @@ }, | ||
name: 'label', | ||
definition: (query, name) => { | ||
return query.find('label').containing(name).find('input') | ||
definition: (query: Query, name) => { | ||
return query.find('label').containing(name).find(query.inputSelector()) | ||
}, | ||
@@ -218,3 +222,3 @@ }, | ||
name: 'label-for', | ||
definition: (query, name) => { | ||
definition: (query: Query, name) => { | ||
return query.find('label[for]').containing(name).map(label => { | ||
@@ -228,3 +232,3 @@ const id = label.getAttribute('for') | ||
name: 'aria-label', | ||
definition: (query, name) => { | ||
definition: (query: Query, name) => { | ||
return query.find('[aria-label]').filter(element => { | ||
@@ -238,3 +242,3 @@ const label = element.getAttribute('aria-label') | ||
name: 'aria-labelledby', | ||
definition: (query, name) => { | ||
definition: (query: Query, name) => { | ||
return query.find('[aria-labelledby]').filter(element => { | ||
@@ -251,3 +255,3 @@ const id = element.getAttribute('aria-labelledby') | ||
name: 'placeholder', | ||
definition: (query, name) => { | ||
definition: (query: Query, name) => { | ||
return query.find(inputSelectors.gettable).containing(matchers.elementAttributes({ | ||
@@ -260,5 +264,5 @@ placeholder: name, | ||
finders: { | ||
Field: (q, value) => q.findLabel(value), | ||
Button: (q, value) => q.findButton(value), | ||
Css: (q, value) => q.findCss(value), | ||
Field: (q: Query, value) => q.findLabel(value), | ||
Button: (q: Query, value) => q.findButton(value), | ||
Css: (q: Query, value) => q.findCss(value), | ||
}, | ||
@@ -276,7 +280,7 @@ } | ||
public transform (transform: Transform): this { | ||
public transform (transform: Transform): Query { | ||
return this.clone(clone => clone._transforms.push(transform)) | ||
} | ||
public expect (expectation: (any) => void): this { | ||
public expect <E extends HTMLElement>(expectation: (elements: E[]) => void): Query { | ||
const expectQuery = this.transform(function (value) { | ||
@@ -292,3 +296,3 @@ expectation.call(this, value) | ||
public action (action: Action): any { | ||
public action (action: Action): Query { | ||
if (this._action) { | ||
@@ -303,3 +307,3 @@ throw new Error('can only have one action') | ||
public findButton (name: FieldName): this { | ||
public findButton (name: FieldName): Query { | ||
return this.concat(this._options.definitions.buttons.map(definition => { | ||
@@ -312,3 +316,3 @@ return (q: Query): Query => { | ||
public findLabel (name: string): this { | ||
public findLabel (name: string): Query { | ||
return this.concat(this._options.definitions.fields.map(({definition}) => { | ||
@@ -321,3 +325,3 @@ return (q: Query): Query => { | ||
public defineButtonFinder (name: string | FieldFinderDefinition, definition: FieldFinderDefinition): this { | ||
public defineButtonFinder (name: string | FieldFinderDefinition, definition?: FieldFinderDefinition): Query { | ||
if (!definition) { | ||
@@ -331,3 +335,3 @@ definition = name as FieldFinderDefinition | ||
public undefineButtonFinder (name: string): this { | ||
public undefineButtonFinder (name: string): Query { | ||
return this.clone(q => { | ||
@@ -343,3 +347,3 @@ const index = q._options.definitions.buttons.findIndex(def => def.name === name) | ||
public defineFieldFinder (name: string | FieldFinderDefinition, definition?: FieldFinderDefinition): this { | ||
public defineFieldFinder (name: string | FieldFinderDefinition, definition?: FieldFinderDefinition): Query { | ||
if (!definition) { | ||
@@ -353,3 +357,3 @@ definition = name as FieldFinderDefinition | ||
public undefineFieldFinder (name: string): this { | ||
public undefineFieldFinder (name: string): Query { | ||
return this.clone(q => { | ||
@@ -365,2 +369,3 @@ const index = q._options.definitions.fields.findIndex(def => def.name === name) | ||
// TODO: try removing any | ||
public result (): any { | ||
@@ -370,3 +375,3 @@ return this.execute().value | ||
public resolve (input: any): this { | ||
public resolve (input: any): Query { | ||
const resolved = this.clone() | ||
@@ -378,3 +383,3 @@ resolved._input = input | ||
public map (map: (a: any) => any, description?: string): this { | ||
private map <E extends HTMLElement>(map: (e: E) => any, description?: string): Query { | ||
return this.transform((elements) => { | ||
@@ -385,3 +390,3 @@ return new ExecutedSimpleTransform(elements.map(map), description) | ||
public filter (filter: (a: any) => boolean, description?: string): this { | ||
public filter <E extends HTMLElement>(filter: (e: E) => boolean, description?: string): Query { | ||
return this.transform((elements) => { | ||
@@ -392,3 +397,3 @@ return new ExecutedSimpleTransform(elements.filter(filter), description) | ||
public concat (queryCreators: ((q: Query) => Query)[]): this { | ||
public concat (queryCreators: ((q: Query) => Query)[]): Query { | ||
return this.transform((elements) => { | ||
@@ -404,3 +409,3 @@ const resolved = this.resolve(elements) | ||
public error (message: string, {expected = undefined, actual = undefined} = {}): void { | ||
private error (message: string, {expected = undefined, actual = undefined} = {}): void { | ||
throw new BrowserMonkeyAssertionError(message, { expected, actual }) | ||
@@ -433,3 +438,3 @@ } | ||
public firstOf (queryCreators: ((q: Query) => Query)[]): this { | ||
public firstOf (queryCreators: ((q: Query) => Query)[]): Query { | ||
const transformed = this.transform((elements) => { | ||
@@ -441,5 +446,5 @@ const resolved = this.resolve(elements) | ||
const q = runQueryCreator(query, resolved) | ||
q.assertHasActionOrExpectation() | ||
return { | ||
value: q.execute() | ||
value: q.ensureExpectation().execute() | ||
} | ||
@@ -479,3 +484,3 @@ } catch (e) { | ||
public detect (queryCreators: {[key: string]: (q: Query) => Query}): this { | ||
public detect (queryCreators: {[key: string]: (q: Query) => Query}): Query { | ||
const transformed = this.transform((elements) => { | ||
@@ -489,6 +494,6 @@ const resolved = this.resolve(elements) | ||
const q = runQueryCreator(queryCreator, resolved) | ||
q.assertHasActionOrExpectation() | ||
return { | ||
key, | ||
value: q.execute() | ||
value: q.ensureExpectation().execute() | ||
} | ||
@@ -537,19 +542,11 @@ } catch (e) { | ||
public options (options: Options): any { | ||
public options (options: Options): Query { | ||
return this.clone(q => extend(q._options, options)) | ||
} | ||
public getOptions (): any { | ||
public getOptions (): Options { | ||
return this._options | ||
} | ||
private assertHasActionOrExpectation (): void { | ||
if (!this._hasExpectation && !this._action) { | ||
throw new Error('no expectations or actions in query, use .result(), or add an expectation or an action') | ||
} | ||
} | ||
public then (resolve?: (r) => any, reject?: (e) => any): Promise<any> { | ||
this.assertHasActionOrExpectation() | ||
const retry = retryFromOptions(this._options) | ||
@@ -562,3 +559,3 @@ | ||
retries++ | ||
return this.execute().value | ||
return this.ensureExpectation().execute().value | ||
})).catch(error => { | ||
@@ -600,3 +597,3 @@ if (error instanceof BrowserMonkeyAssertionError) { | ||
public clone (modifier?: (clone: this) => void): this { | ||
private clone (modifier?: (clone: Query) => void): Query { | ||
const clone = new (this.constructor as any)() | ||
@@ -610,7 +607,9 @@ clone.copyQueryFields(this) | ||
public input (value): this { | ||
// TODO: why is this public? | ||
public input (value): Query { | ||
return this.clone(q => q._input = value) | ||
} | ||
public getInput (): this { | ||
// TODO: rename `input`/`getInput` to something better | ||
public getInput (): [HTMLElement] { | ||
return this._input | ||
@@ -629,3 +628,3 @@ } | ||
public shouldHaveElements (count: number, message?: string): this { | ||
public shouldHaveElements (count: number, message?: string): Query { | ||
return this.expect(elements => { | ||
@@ -638,3 +637,3 @@ if (elements.length !== count) { | ||
public shouldExist (message?: string): this { | ||
public shouldExist (message?: string): Query { | ||
return this.expect(elements => { | ||
@@ -647,3 +646,3 @@ if (elements.length < 1) { | ||
public shouldNotExist (message?: string): this { | ||
public shouldNotExist (message?: string): Query { | ||
return this.expect(elements => { | ||
@@ -664,3 +663,3 @@ if (elements.length !== 0) { | ||
public click (selector?: string): this { | ||
public click (selector?: string): Query { | ||
return this.optionalSelector(selector).shouldHaveElements(1).action(([element]) => { | ||
@@ -672,11 +671,11 @@ debug('click', element) | ||
public clickButton (name: FieldName): this { | ||
public clickButton (name: FieldName): Query { | ||
return this.findButton(name).click() | ||
} | ||
public submit (selector?: string): this { | ||
public submit (selector?: string): Query { | ||
return this.optionalSelector(selector) | ||
.shouldHaveElements(1) | ||
.expect(([element]) => { | ||
if (!element.form) { | ||
if (!(element as HTMLInputElement).form) { | ||
throw new BrowserMonkeyAssertionError('expected element to be inside a form for submit') | ||
@@ -687,7 +686,7 @@ } | ||
debug('submit', element) | ||
this._dom.submit(element) | ||
this._dom.submit(element as HTMLInputElement) | ||
}) | ||
} | ||
public enterText (selector: string, text?: string): this { | ||
public enterText (selector: string, text?: string | string[]): Query { | ||
if (text === undefined) { | ||
@@ -703,7 +702,7 @@ text = selector | ||
debug('enterText', element, text) | ||
this._dom.enterText(element, text) | ||
this._dom.enterText(element as HTMLInputElement, text) | ||
}) | ||
} | ||
public scope (element: HTMLElement): this { | ||
public scope (element: HTMLElement): Query { | ||
return this.input([element]) | ||
@@ -716,3 +715,3 @@ } | ||
public iframe (selector?: string): this { | ||
public iframe (selector?: string): Query { | ||
return this.optionalSelector(selector).transform(elements => { | ||
@@ -733,10 +732,10 @@ return new ExecutedSimpleTransform(elements.map(element => { | ||
public enabled (): this { | ||
public enabled (): Query { | ||
return this.filter(element => { | ||
const tagName = element.tagName | ||
return !((tagName === 'BUTTON' || tagName === 'INPUT') && element.disabled) | ||
return !((tagName === 'BUTTON' || tagName === 'INPUT') && (element as HTMLInputElement).disabled) | ||
}, 'enabled') | ||
} | ||
public set (model: any): this { | ||
public set (model: Model): Query { | ||
return this.action(elements => { | ||
@@ -746,7 +745,7 @@ const setters = [] | ||
const actions = { | ||
arrayLengthError: (query, actualLength, expectedLength): void => { | ||
arrayLengthError: (query: Query, actualLength, expectedLength): void => { | ||
query.error('expected ' + expectedLength + ' ' + pluralize('elements', expectedLength) + ', found ' + actualLength) | ||
}, | ||
value: (query, model): ActualExpected => { | ||
value: (query: Query, model): ActualExpected => { | ||
const setter = query.shouldHaveElements(1).setter(model).result() | ||
@@ -760,3 +759,3 @@ setters.push(() => setter()) | ||
expectOne: (query): ActualExpected => { | ||
expectOne: (query: Query): ActualExpected => { | ||
query.shouldHaveElements(1).result() | ||
@@ -769,3 +768,3 @@ return { | ||
function: (query, model): ActualExpected => { | ||
function: (query: Query, model): ActualExpected => { | ||
setters.push(() => this.runModelFunction(model, query)) | ||
@@ -800,3 +799,3 @@ return { | ||
public shouldContain (model): this { | ||
public shouldContain (model: Model): Query { | ||
return this.expect(elements => { | ||
@@ -810,3 +809,3 @@ let isError = false | ||
expectOne: (query): ActualExpected => { | ||
expectOne: (query: Query): ActualExpected => { | ||
try { | ||
@@ -828,3 +827,3 @@ query.shouldHaveElements(1).result() | ||
value: (query, model): ActualExpected => { | ||
value: (query: Query, model): ActualExpected => { | ||
const match = query.matchValue(model) | ||
@@ -839,3 +838,3 @@ | ||
function: (query, model): ActualExpected => { | ||
function: (query: Query, model): ActualExpected => { | ||
try { | ||
@@ -870,3 +869,3 @@ this.runModelFunction(model, query) | ||
public index (index: number): this { | ||
public index (index: number): Query { | ||
return this.transform(elements => { | ||
@@ -880,7 +879,7 @@ if (elements.length <= index) { | ||
public define (name: string, finderDefinition): this { | ||
public define (name: string | Object, finderDefinition?: FinderDefinition | string): this { | ||
if (typeof finderDefinition === 'function') { | ||
this._options.definitions.finders[name] = finderDefinition | ||
this._options.definitions.finders[name as string] = finderDefinition | ||
} else if (typeof finderDefinition === 'string') { | ||
this._options.definitions.finders[name] = q => q.find(finderDefinition) | ||
this._options.definitions.finders[name as string] = q => q.find(finderDefinition) | ||
} else if (name.constructor === Object && finderDefinition === undefined) { | ||
@@ -893,9 +892,13 @@ Object.keys(name).forEach(key => this.define(key, name[key])) | ||
private setter (value): this { | ||
private inputSelector (): string { | ||
return this._options.definitions.inputs.map(i => i.selector).filter(Boolean).join(',') | ||
} | ||
private setter (value): Query { | ||
return this.firstOf(this._options.definitions.inputs.filter(def => def.setter).map(def => { | ||
return query => def.setter(query, value) | ||
return query => def.setter(query.is(def.selector), value) | ||
})) | ||
} | ||
private valueAsserters (expected: any): this { | ||
private valueAsserters (expected: any): Query { | ||
return this.transform(elements => { | ||
@@ -930,10 +933,10 @@ const definitions = this._options.definitions.inputs.filter(def => def.values || def.valueAsserters) | ||
public containing (model: any): this { | ||
public containing (model: Model): Query { | ||
return this.transform(elements => { | ||
const actions = { | ||
arrayLengthError: (query, actualLength, expectedLength): void => { | ||
arrayLengthError: (query: Query, actualLength, expectedLength): void => { | ||
query.error('expected ' + expectedLength + ' ' + pluralize('elements', expectedLength) + ', found ' + actualLength) | ||
}, | ||
value: (query, model): ActualExpected => { | ||
value: (query: Query, model): ActualExpected => { | ||
const match = query.matchValue(model) | ||
@@ -948,11 +951,3 @@ | ||
expectOne: (query): ActualExpected => { | ||
query.expectOne().execute() | ||
return { | ||
actual: {}, | ||
expected: {}, | ||
} | ||
}, | ||
function: (query, fn): ActualExpected => { | ||
function: (query: Query, fn): ActualExpected => { | ||
this.runModelFunction(fn, query) | ||
@@ -997,3 +992,3 @@ return {actual: fn, expected: fn} | ||
public values (): this { | ||
public values (): Query { | ||
return this.transform(elements => { | ||
@@ -1020,3 +1015,3 @@ const definitions = this._options.definitions.inputs.filter(def => def.values) | ||
public findCss (selector: string): this { | ||
public findCss (selector: string): Query { | ||
const findElements = this.transform(elements => { | ||
@@ -1031,3 +1026,3 @@ return new ExecutedSimpleTransform(flatten(elements.map(element => { | ||
public find (selector: string): this { | ||
public find (selector: string): Query { | ||
// name(arg1, arg2, ...) | ||
@@ -1056,3 +1051,3 @@ const match = /^\s*([$a-z_][0-9a-z_$]*)\s*(\((.*)\)\s*)?$/i.exec(selector) | ||
public is (selector: string): this { | ||
public is (selector: string): Query { | ||
return this.filter(element => { | ||
@@ -1063,3 +1058,3 @@ return this._dom.elementMatches(element, selector) | ||
private runModelFunction(fn: (Query) => any, query: Query): ExecutedTransform | undefined { | ||
private runModelFunction(fn: (query: Query) => any, query: Query): ExecutedTransform | undefined { | ||
const result = fn(query) | ||
@@ -1073,3 +1068,3 @@ if (result instanceof Query) { | ||
private optionalSelector (selector?: string): this { | ||
private optionalSelector (selector?: string): Query { | ||
return selector ? this.find(selector) : this | ||
@@ -1100,3 +1095,3 @@ } | ||
private mapModel (model: any, actions: Actions): any { | ||
private mapModel (model: Model, actions: Actions): any { | ||
const map = (query: Query, model: any): any => { | ||
@@ -1148,2 +1143,9 @@ if (model === missing) { | ||
} | ||
private ensureExpectation(): Query { | ||
if (!this._hasExpectation && !this._action) { | ||
return this.shouldExist() | ||
} | ||
return this | ||
} | ||
} | ||
@@ -1165,15 +1167,6 @@ | ||
function isIframe (element): boolean { | ||
return isHTMLElement(element, 'HTMLIFrameElement') | ||
function isIframe (element: HTMLElement): element is HTMLIFrameElement { | ||
return (element as HTMLIFrameElement).contentWindow !== undefined | ||
} | ||
function isHTMLElement (element, subclass = 'HTMLElement'): boolean { | ||
if (element.ownerDocument && element.ownerDocument.defaultView) { | ||
// an element inside an iframe | ||
return element instanceof element.ownerDocument.defaultView[subclass] | ||
} else { | ||
return false | ||
} | ||
} | ||
type Retry = <T>(fn: () => T, options?: {timeout?: number, interval?: number}) => Promise<T> | ||
@@ -1209,5 +1202,6 @@ | ||
value (q: Query, model: any): ActualExpected | ||
expectOne (q: Query): ActualExpected | ||
expectOne? (q: Query): ActualExpected | ||
} | ||
// TODO: try getting rid of any | ||
function spliceModelArrayFromActual (model, query: Query, actions: Actions): any[] { | ||
@@ -1235,2 +1229,3 @@ const length = query.result().length | ||
// TODO: try getting rid of any | ||
function arrayAssign (a: any[], b: any[]): any[] { | ||
@@ -1237,0 +1232,0 @@ return a.map((itemA, index) => { |
{ | ||
"name": "browser-monkey", | ||
"version": "3.0.0-beta.7", | ||
"version": "3.0.0-beta.8", | ||
"description": "reliable dom testing", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -97,2 +97,6 @@ /* global location */ | ||
public emptyHtml (): void { | ||
this._div.innerHTML = '' | ||
} | ||
public eventuallyDoNothing (): void { | ||
@@ -99,0 +103,0 @@ this.eventually(() => { /* do nothing */ }) |
@@ -0,1 +1,2 @@ | ||
import { Query } from '../lib/Query' | ||
import {DomAssembly} from './assemblies/DomAssembly' | ||
@@ -5,3 +6,3 @@ | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -32,12 +33,2 @@ beforeEach(() => { | ||
}) | ||
it('allows timeout and interval parameters to be used', async () => { | ||
assembly.insertHtml('<div class="removing"></div>') | ||
const promise = browser.find('.removing').shouldNotExist({ timeout: 500, interval: 100 }).then() | ||
assembly.eventuallyDeleteHtml('.removing') | ||
await promise | ||
}) | ||
}) | ||
@@ -65,3 +56,3 @@ | ||
it('eventually finds an element containing text', async () => { | ||
const promise = browser.find('.element', { text: 'some t' }).shouldExist().then() | ||
const promise = browser.find('.element').shouldExist().then() | ||
assembly.eventuallyInsertHtml('<div class="element"><div>some text</div></div>') | ||
@@ -68,0 +59,0 @@ await promise |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {expect} from 'chai' | ||
import {Query} from '../lib/Query' | ||
describe('buttons', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -8,0 +9,0 @@ beforeEach(function () { |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {expect} from 'chai' | ||
import {elementAttributes} from '../lib/matchers' | ||
import {Query} from '../lib/Query' | ||
describe('containing', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -32,2 +33,15 @@ beforeEach(function () { | ||
it('filters elements with text that match RegExp', () => { | ||
assembly.insertHtml(` | ||
<span class="found">car</span> | ||
<span class="found">car</span> | ||
<span>horse</span> | ||
<span class="found">cart</span> | ||
`) | ||
const transports = browser.find('span').containing(/car/).result() | ||
const cars = assembly.findAll('.found') | ||
expect(transports).to.eql(cars) | ||
}) | ||
it('filters input elements that have the exact text', () => { | ||
@@ -34,0 +48,0 @@ assembly.insertHtml(` |
@@ -1,7 +0,8 @@ | ||
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {expect} from 'chai' | ||
import { expect } from 'chai' | ||
import { DomAssembly } from './assemblies/DomAssembly' | ||
import {Query} from '../lib/Query' | ||
describe('define', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -35,2 +36,15 @@ beforeEach(function () { | ||
it('finds defined field', async function() { | ||
assembly.insertHtml(` | ||
<div class="flash-success">Success!</div> | ||
<div class="flash-alert">Fail!</div> | ||
`) | ||
browser.define('Flash', (q, flashType) => q.find(`.flash-${flashType}`)) | ||
await browser.shouldContain({ | ||
'Flash("success")': 'Success!', | ||
'Flash("alert")': /Fail/, | ||
}) | ||
}) | ||
describe('definition not found', () => { | ||
@@ -37,0 +51,0 @@ it('with arguments: throws an error if the definition is not found', () => { |
import {expect} from 'chai' | ||
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {Query} from '../lib/Query' | ||
describe('enterText', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -8,0 +9,0 @@ beforeEach(function () { |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import retry from '../lib/retry' | ||
import {expect} from 'chai' | ||
import {Query} from '../lib/Query' | ||
describe('events', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -9,0 +10,0 @@ beforeEach(function () { |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {expect} from 'chai' | ||
import { Query } from '../lib/Query' | ||
describe('find', () => { | ||
let assembly | ||
let browser | ||
let assembly: DomAssembly | ||
let browser: Query | ||
@@ -18,2 +19,3 @@ beforeEach(function () { | ||
function assertFound (html, query): void { | ||
assembly.emptyHtml() | ||
assembly.insertHtml(html) | ||
@@ -26,2 +28,20 @@ | ||
it('resolves with found elements', async function() { | ||
const [selectedElements, insertedElement] = await Promise.all([ | ||
browser.find('.test').then(), | ||
assembly.eventuallyInsertHtml( | ||
`<div class="test"></div>` | ||
) | ||
]) | ||
expect(selectedElements).to.eql([insertedElement]) | ||
}) | ||
it('throws if nothing found', async function() { | ||
await assembly.assertRejection( | ||
browser.find('.stuff').then(), | ||
"expected one or more elements, found 0 (found: find('.stuff') [0])" | ||
) | ||
}) | ||
it('finds all elements that match', () => { | ||
@@ -53,6 +73,40 @@ assertFound( | ||
`, | ||
browser.find('.outer').find('.inner') | ||
browser.find('.outer').find('.inner'), | ||
) | ||
}) | ||
it('queries are immutable', () => { | ||
const outerQuery = browser.find('.outer') | ||
assertFound( | ||
` | ||
<div> | ||
<div class="outer"> | ||
<div class="expected inner"></div> | ||
<div class="anotherInner"></div> | ||
</div> | ||
</div> | ||
<div> | ||
<div class="inner"></div> | ||
</div> | ||
`, | ||
outerQuery.find('.inner'), | ||
) | ||
assertFound( | ||
` | ||
<div> | ||
<div class="outer"> | ||
<div class="expected anotherInner"></div> | ||
<div class="inner"></div> | ||
</div> | ||
</div> | ||
<div> | ||
<div class="inner"></div> | ||
</div> | ||
`, | ||
outerQuery.find('.anotherInner'), | ||
) | ||
}) | ||
it('returns an emtpy array if nothing matched', () => { | ||
@@ -59,0 +113,0 @@ assembly.insertHtml( |
@@ -5,6 +5,7 @@ import retry from '../lib/retry' | ||
const {expect} = require('chai') | ||
import {Query} from '../lib/Query' | ||
describe('hyperdom integration', function () { | ||
let assembly | ||
let browserMonkey | ||
let browserMonkey: Query | ||
@@ -11,0 +12,0 @@ beforeEach(() => { |
@@ -7,7 +7,7 @@ import {expect} from 'chai' | ||
let assembly: DomAssembly | ||
let browserMonkey: Query | ||
let browser: Query | ||
beforeEach(() => { | ||
assembly = new DomAssembly() | ||
browserMonkey = assembly.browserMonkey() | ||
browser = assembly.browserMonkey() | ||
}) | ||
@@ -20,3 +20,3 @@ | ||
it('can find an element by DOM selector', async () => { | ||
const selectedElementPromise = browserMonkey.find('.test').shouldHaveElements(1).then() | ||
const selectedElementPromise = browser.find('.test').shouldHaveElements(1).then() | ||
@@ -35,7 +35,7 @@ const insertedElementPromise = assembly.eventuallyInsertHtml( | ||
it('returns a new Browser Monkey object without modifying the current one', () => { | ||
expect(browserMonkey.options({timeout: 400}).getOptions().timeout).to.equal(400) | ||
expect(browser.options({timeout: 400}).getOptions().timeout).to.equal(400) | ||
}) | ||
it('overrides previously set option', () => { | ||
expect(browserMonkey.options({timeout: 400}).options({timeout: 4000}).getOptions().timeout).to.equal(4000) | ||
expect(browser.options({timeout: 400}).options({timeout: 4000}).getOptions().timeout).to.equal(4000) | ||
}) | ||
@@ -53,3 +53,3 @@ }) | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
@@ -76,3 +76,3 @@ .shouldNotExist() | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
@@ -90,3 +90,3 @@ .shouldNotExist() | ||
it('when there is one element, returns it', async () => { | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
@@ -107,3 +107,3 @@ .shouldHaveElements(1) | ||
it('when there is more than one element, throws an error', async () => { | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
@@ -128,3 +128,3 @@ .shouldHaveElements(1) | ||
it('when there no elements, throws an error', async () => { | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
@@ -144,3 +144,3 @@ .shouldHaveElements(1) | ||
it('asserts list of two elements has two elements', async () => { | ||
const items = browserMonkey | ||
const items = browser | ||
.find('li ul') | ||
@@ -161,3 +161,3 @@ .shouldHaveElements(2) | ||
it('fails when a list of two element is asserted to have three elements', async () => { | ||
const items = browserMonkey | ||
const items = browser | ||
.find('li ul') | ||
@@ -184,3 +184,3 @@ .shouldHaveElements(3) | ||
const actual = browserMonkey | ||
const actual = browser | ||
.find('.title') | ||
@@ -198,3 +198,3 @@ .elementResult() | ||
expect(() => browserMonkey | ||
expect(() => browser | ||
.find('.title') | ||
@@ -208,3 +208,3 @@ .elementResult()).to.throw('expected 1 element, found 2') | ||
expect(() => browserMonkey | ||
expect(() => browser | ||
.find('.title') | ||
@@ -224,3 +224,3 @@ .elementResult()).to.throw('expected 1 element, found 0') | ||
const actual = browserMonkey | ||
const actual = browser | ||
.find('.title') | ||
@@ -236,3 +236,3 @@ .elementsResult() | ||
expect(() => browserMonkey | ||
expect(() => browser | ||
.find('.title') | ||
@@ -245,3 +245,3 @@ .elementsResult()).to.throw('expected one or more elements, found 0') | ||
it('when there are one or more elements, selects them', async () => { | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
@@ -266,3 +266,3 @@ .shouldExist() | ||
it('when there no elements, throws an error', async () => { | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
@@ -283,3 +283,3 @@ .shouldExist() | ||
it('input sets the input used in transform', async () => { | ||
const query = browserMonkey | ||
const query = browser | ||
.input('a') | ||
@@ -294,3 +294,3 @@ .transform(x => `input: ${x}`) | ||
it('when scope is one element, sets the input to an array of one', () => { | ||
const query = browserMonkey | ||
const query = browser | ||
.scope(document.body) | ||
@@ -310,3 +310,3 @@ | ||
it('waits for the input to eventually pass the assertion', async () => { | ||
const hello = browserMonkey | ||
const hello = browser | ||
.expect(elements => { | ||
@@ -325,3 +325,3 @@ expect(elements.some(element => element.innerText.includes('hello'))).to.equal(true) | ||
it('eventually throws the last error if it never passes', async () => { | ||
const hello = browserMonkey | ||
const hello = browser | ||
.expect(elements => { | ||
@@ -342,3 +342,3 @@ expect(elements.some(element => element.innerText.includes('hello')), 'expected to see hello').to.equal(true) | ||
it('can map all the elements', async () => { | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.name') | ||
@@ -362,6 +362,6 @@ .transform(names => { | ||
it('can filter elements', async () => { | ||
const contacts = browserMonkey | ||
const contacts = browser | ||
.find('.contact') | ||
.filter(contact => { | ||
return contact.querySelector('.name').innerText === 'Sally' | ||
return (contact.querySelector('.name') as HTMLElement).innerText === 'Sally' | ||
}) | ||
@@ -386,26 +386,27 @@ .shouldHaveElements(1) | ||
describe('map', () => { | ||
it('can map elements', async () => { | ||
const contacts = browserMonkey | ||
.find('.contact') | ||
.map(contact => { | ||
return contact.querySelector('.name') | ||
}) | ||
.shouldExist() | ||
.then() | ||
// `map` has been moved to private | ||
// describe('map', () => { | ||
// it('can map elements', async () => { | ||
// const contacts = browser | ||
// .find('.contact') | ||
// .map(contact => { | ||
// return contact.querySelector('.name') | ||
// }) | ||
// .shouldExist() | ||
// .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> | ||
// `) | ||
expect(await contacts).to.eql(assembly.findAll('.name')) | ||
}) | ||
}) | ||
// expect(await contacts).to.eql(assembly.findAll('.name')) | ||
// }) | ||
// }) | ||
@@ -420,3 +421,3 @@ describe('actions', () => { | ||
const action = browserMonkey.find('div').action(function () { | ||
const action = browser.find('div').action(function () { | ||
actionExecuted++ | ||
@@ -440,3 +441,3 @@ }) | ||
let givenElements | ||
const action = browserMonkey.find('div').action(function (els) { | ||
const action = browser.find('div').action(function (els) { | ||
givenElements = els | ||
@@ -453,3 +454,3 @@ }) | ||
it('shows what it was able to map', async () => { | ||
const name = browserMonkey | ||
const name = browser | ||
.find('.container') | ||
@@ -487,5 +488,6 @@ .find('.contact') | ||
const elementsFound = browserMonkey.concat([ | ||
b => b.find('.a'), | ||
b => b.find('.b') | ||
const elementsFound = browser.concat([ | ||
q => q.find('.a'), | ||
q => q.find('.b'), | ||
q => q.find('.x'), | ||
]).result() | ||
@@ -507,3 +509,3 @@ | ||
const promise = browserMonkey.concat([ | ||
const promise = browser.concat([ | ||
b => b.find('.a'), | ||
@@ -523,3 +525,3 @@ b => b.find('.b') | ||
const promise = browserMonkey.find('.b').shouldExist() | ||
const promise = browser.find('.b').shouldExist() | ||
@@ -532,3 +534,3 @@ return assembly.assertRejection(promise, /expected one or more elements, found 0 \[waited \d+ms, retried 1 times\]/, {assertMetrics: true}) | ||
it('finds the first of two or more queries', async () => { | ||
const promise = browserMonkey.firstOf([ | ||
const promise = browser.firstOf([ | ||
b => b.find('.a').shouldExist(), | ||
@@ -549,5 +551,5 @@ b => b.find('.b').shouldExist() | ||
const promise = browserMonkey.find('.content').firstOf([ | ||
b => b.find('.a').shouldExist(), | ||
b => b.find('.b').shouldExist() | ||
const promise = browser.find('.content').firstOf([ | ||
b => b.find('.a'), | ||
b => b.find('.b') | ||
]) | ||
@@ -557,13 +559,2 @@ | ||
}) | ||
it('throws if one of the queries does not have an assertion or action', async () => { | ||
assembly.insertHtml('<div class="content">content<div class="c"/>C</div>') | ||
const promise = browserMonkey.find('.content').firstOf([ | ||
b => b.find('.a'), | ||
b => b.find('.b').shouldExist() | ||
]) | ||
await assembly.assertRejection(promise, 'no expectations or actions in query') | ||
}) | ||
}) | ||
@@ -573,5 +564,5 @@ | ||
it('finds the first of two or more queries', async () => { | ||
const promise = browserMonkey.detect({ | ||
a: q => q.find('.a').shouldExist(), | ||
b: q => q.find('.b').shouldExist() | ||
const promise = browser.detect({ | ||
a: q => q.find('.a'), | ||
b: q => q.find('.b') | ||
}).then() | ||
@@ -592,3 +583,3 @@ | ||
const promise = browserMonkey.find('.content').detect({ | ||
const promise = browser.find('.content').detect({ | ||
a: b => b.find('.a').shouldExist(), | ||
@@ -600,14 +591,3 @@ b: b => b.find('.b').shouldExist() | ||
}) | ||
it('throws if one of the queries does not have an assertion or action', async () => { | ||
assembly.insertHtml('<div class="content">content<div class="c"/>C</div>') | ||
const promise = browserMonkey.find('.content').detect({ | ||
a: b => b.find('.a'), | ||
b: b => b.find('.b').shouldExist() | ||
}) | ||
await assembly.assertRejection(promise, 'no expectations or actions in query') | ||
}) | ||
}) | ||
}) |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {expect} from 'chai' | ||
import {Query} from '../lib/Query' | ||
describe('set', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -8,0 +9,0 @@ beforeEach(function () { |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {Query} from '../lib/Query' | ||
describe('buttons', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -7,0 +8,0 @@ beforeEach(function () { |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import BrowserMonkeyAssertionError from '../lib/BrowserMonkeyAssertionError' | ||
import {elementAttributes} from '../lib/matchers' | ||
import {Query} from '../lib/Query' | ||
describe('shouldContain', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -9,0 +10,0 @@ beforeEach(function () { |
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {expect} from 'chai' | ||
import {Query} from '../lib/Query' | ||
describe('submit', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -8,0 +9,0 @@ beforeEach(function () { |
import {expect} from 'chai' | ||
import {DomAssembly} from './assemblies/DomAssembly' | ||
import {Query} from '../lib/Query' | ||
describe('value', function () { | ||
let assembly | ||
let browser | ||
let browser: Query | ||
@@ -8,0 +9,0 @@ beforeEach(function () { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
360222
7538
1