expect-webdriverio 5.6.4 → 5.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/jasmine-wdio-expect-async.d.ts +31 -4
- package/lib/constants.js +11 -0
- package/lib/index.js +7 -5
- package/lib/matchers/browser/toHaveClipboardText.js +2 -1
- package/lib/matchers/browser/toHaveLocalStorageItem.js +36 -0
- package/lib/matchers/browser/toHaveTitle.js +2 -1
- package/lib/matchers/browser/toHaveUrl.js +2 -1
- package/lib/matchers/element/toBeDisplayed.js +3 -10
- package/lib/matchers/element/toHaveAttribute.js +8 -6
- package/lib/matchers/element/toHaveChildren.js +2 -1
- package/lib/matchers/element/toHaveClass.js +2 -1
- package/lib/matchers/element/toHaveComputedLabel.js +2 -1
- package/lib/matchers/element/toHaveComputedRole.js +2 -1
- package/lib/matchers/element/toHaveElementProperty.js +3 -2
- package/lib/matchers/element/toHaveHTML.js +2 -1
- package/lib/matchers/element/toHaveHeight.js +2 -1
- package/lib/matchers/element/toHaveSize.js +2 -1
- package/lib/matchers/element/toHaveStyle.js +2 -1
- package/lib/matchers/element/toHaveText.js +2 -1
- package/lib/matchers/element/toHaveWidth.js +2 -1
- package/lib/matchers/elements/toBeElementsArrayOfSize.js +2 -1
- package/lib/matchers/mock/toBeRequestedTimes.js +2 -1
- package/lib/matchers/mock/toBeRequestedWith.js +3 -2
- package/lib/matchers.js +1 -0
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/utils.js +31 -19
- package/package.json +13 -3
- package/types/expect-webdriverio.d.ts +11 -1
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
/// <reference types="./types/expect-webdriverio.d.ts"/>
|
|
2
2
|
|
|
3
|
+
declare namespace jasmine {
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Async matchers for Jasmine to allow the typing of `expectAsync` with WebDriverIO matchers.
|
|
7
|
+
* T is the type of the actual value
|
|
8
|
+
* U is the type of the expected value
|
|
9
|
+
* Both T,U must stay named as they are to override the default `AsyncMatchers` type from Jasmine.
|
|
10
|
+
*
|
|
11
|
+
* We force Matchers to return a `Promise<void>` since Jasmine's `expectAsync` expects a promise in all cases (different from Jest)
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
|
+
interface AsyncMatchers<T, U> extends Omit<ExpectWebdriverIO.Matchers<Promise<void>, T>, 'toMatchSnapshot' | 'toMatchInlineSnapshot'> {
|
|
15
|
+
/**
|
|
16
|
+
* snapshot matcher
|
|
17
|
+
* @param label optional snapshot label
|
|
18
|
+
*/
|
|
19
|
+
toMatchSnapshot(label?: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* inline snapshot matcher
|
|
22
|
+
* @param snapshot snapshot string (autogenerated if not specified)
|
|
23
|
+
* @param label optional snapshot label
|
|
24
|
+
*/
|
|
25
|
+
toMatchInlineSnapshot(snapshot?: string, label?: string): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
3
29
|
/**
|
|
4
|
-
* Overrides the default
|
|
30
|
+
* Overrides the default WDIO expect specifically for Jasmine, since `expectAsync` is forced into `expect`, making all matchers fully asynchronous. This is not the case under Jest or Mocha.
|
|
31
|
+
* Using `jasmine.AsyncMatchers` pull on WdioMatchers above but also allow to using Jasmine's built-in matchers and also `withContext` matcher.
|
|
5
32
|
*/
|
|
6
33
|
declare namespace ExpectWebdriverIO {
|
|
7
|
-
interface Expect
|
|
34
|
+
interface Expect {
|
|
8
35
|
/**
|
|
9
36
|
* The `expect` function is used every time you want to test a value.
|
|
10
37
|
* You will rarely call `expect` by itself.
|
|
@@ -17,6 +44,6 @@ declare namespace ExpectWebdriverIO {
|
|
|
17
44
|
*
|
|
18
45
|
* @param actual The value to apply matchers against.
|
|
19
46
|
*/
|
|
20
|
-
<T = unknown>(actual: T):
|
|
47
|
+
<T = unknown>(actual: T): jasmine.AsyncMatchers<T, void>
|
|
21
48
|
}
|
|
22
|
-
}
|
|
49
|
+
}
|
package/lib/constants.js
CHANGED
|
@@ -4,3 +4,14 @@ export const DEFAULT_OPTIONS = {
|
|
|
4
4
|
beforeAssertion: async () => { },
|
|
5
5
|
afterAssertion: async () => { },
|
|
6
6
|
};
|
|
7
|
+
export const DEFAULT_OPTIONS_TO_BE_DISPLAYED = {
|
|
8
|
+
...DEFAULT_OPTIONS,
|
|
9
|
+
withinViewport: false,
|
|
10
|
+
contentVisibilityAuto: true,
|
|
11
|
+
opacityProperty: true,
|
|
12
|
+
visibilityProperty: true
|
|
13
|
+
};
|
|
14
|
+
export const defaultOptionsList = [
|
|
15
|
+
DEFAULT_OPTIONS,
|
|
16
|
+
DEFAULT_OPTIONS_TO_BE_DISPLAYED
|
|
17
|
+
];
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { expect as expectLib } from 'expect';
|
|
2
2
|
import * as wdioMatchers from './matchers.js';
|
|
3
|
-
import { DEFAULT_OPTIONS } from './constants.js';
|
|
3
|
+
import { DEFAULT_OPTIONS, defaultOptionsList } from './constants.js';
|
|
4
4
|
import createSoftExpect from './softExpect.js';
|
|
5
5
|
import { SoftAssertService } from './softAssert.js';
|
|
6
6
|
export const matchers = new Map();
|
|
@@ -34,11 +34,13 @@ Object.defineProperty(expectWithSoft, 'clearSoftFailures', {
|
|
|
34
34
|
});
|
|
35
35
|
export const expect = expectWithSoft;
|
|
36
36
|
export const getConfig = () => DEFAULT_OPTIONS;
|
|
37
|
-
export const setDefaultOptions = (options
|
|
37
|
+
export const setDefaultOptions = (options) => {
|
|
38
38
|
Object.entries(options).forEach(([key, value]) => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
defaultOptionsList.forEach((option) => {
|
|
40
|
+
if (key in option) {
|
|
41
|
+
option[key] = value;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
42
44
|
});
|
|
43
45
|
};
|
|
44
46
|
export const setOptions = setDefaultOptions;
|
|
@@ -3,6 +3,7 @@ import { waitUntil, enhanceError, compareText } from '../../utils.js';
|
|
|
3
3
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
4
4
|
const log = logger('expect-webdriverio');
|
|
5
5
|
export async function toHaveClipboardText(browser, expectedValue, options = DEFAULT_OPTIONS) {
|
|
6
|
+
const isNot = this.isNot;
|
|
6
7
|
const { expectation = 'clipboard text', verb = 'have' } = this;
|
|
7
8
|
await options.beforeAssertion?.({
|
|
8
9
|
matcherName: 'toHaveClipboardText',
|
|
@@ -15,7 +16,7 @@ export async function toHaveClipboardText(browser, expectedValue, options = DEFA
|
|
|
15
16
|
.catch((err) => log.warn(`Couldn't set clipboard permissions: ${err}`));
|
|
16
17
|
actual = await browser.execute(() => window.navigator.clipboard.readText());
|
|
17
18
|
return compareText(actual, expectedValue, options).result;
|
|
18
|
-
}, options);
|
|
19
|
+
}, isNot, options);
|
|
19
20
|
const message = enhanceError('browser', expectedValue, actual, this, verb, expectation, '', options);
|
|
20
21
|
const result = {
|
|
21
22
|
pass,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { waitUntil, enhanceError, compareText } from '../../utils.js';
|
|
2
|
+
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
3
|
+
export async function toHaveLocalStorageItem(browser, key, expectedValue, options = DEFAULT_OPTIONS) {
|
|
4
|
+
const isNot = this.isNot;
|
|
5
|
+
const { expectation = 'localStorage item', verb = 'have' } = this;
|
|
6
|
+
await options.beforeAssertion?.({
|
|
7
|
+
matcherName: 'toHaveLocalStorageItem',
|
|
8
|
+
expectedValue: expectedValue ? [key, expectedValue] : key,
|
|
9
|
+
options,
|
|
10
|
+
});
|
|
11
|
+
let actual;
|
|
12
|
+
const pass = await waitUntil(async () => {
|
|
13
|
+
actual = await browser.execute((storageKey) => {
|
|
14
|
+
return localStorage.getItem(storageKey);
|
|
15
|
+
}, key);
|
|
16
|
+
if (expectedValue === undefined) {
|
|
17
|
+
return actual !== null;
|
|
18
|
+
}
|
|
19
|
+
if (actual === null) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return compareText(actual, expectedValue, options).result;
|
|
23
|
+
}, isNot, options);
|
|
24
|
+
const message = enhanceError('browser', expectedValue !== undefined ? expectedValue : `localStorage item "${key}"`, actual, this, verb, expectation, key, options);
|
|
25
|
+
const result = {
|
|
26
|
+
pass,
|
|
27
|
+
message: () => message
|
|
28
|
+
};
|
|
29
|
+
await options.afterAssertion?.({
|
|
30
|
+
matcherName: 'toHaveLocalStorageItem',
|
|
31
|
+
expectedValue: expectedValue ? [key, expectedValue] : key,
|
|
32
|
+
options,
|
|
33
|
+
result
|
|
34
|
+
});
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { waitUntil, enhanceError, compareText } from '../../utils.js';
|
|
2
2
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
3
3
|
export async function toHaveTitle(browser, expectedValue, options = DEFAULT_OPTIONS) {
|
|
4
|
+
const isNot = this.isNot;
|
|
4
5
|
const { expectation = 'title', verb = 'have' } = this;
|
|
5
6
|
await options.beforeAssertion?.({
|
|
6
7
|
matcherName: 'toHaveTitle',
|
|
@@ -11,7 +12,7 @@ export async function toHaveTitle(browser, expectedValue, options = DEFAULT_OPTI
|
|
|
11
12
|
const pass = await waitUntil(async () => {
|
|
12
13
|
actual = await browser.getTitle();
|
|
13
14
|
return compareText(actual, expectedValue, options).result;
|
|
14
|
-
}, options);
|
|
15
|
+
}, isNot, options);
|
|
15
16
|
const message = enhanceError('window', expectedValue, actual, this, verb, expectation, '', options);
|
|
16
17
|
const result = {
|
|
17
18
|
pass,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { waitUntil, enhanceError, compareText } from '../../utils.js';
|
|
2
2
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
3
3
|
export async function toHaveUrl(browser, expectedValue, options = DEFAULT_OPTIONS) {
|
|
4
|
+
const isNot = this.isNot;
|
|
4
5
|
const { expectation = 'url', verb = 'have' } = this;
|
|
5
6
|
await options.beforeAssertion?.({
|
|
6
7
|
matcherName: 'toHaveUrl',
|
|
@@ -11,7 +12,7 @@ export async function toHaveUrl(browser, expectedValue, options = DEFAULT_OPTION
|
|
|
11
12
|
const pass = await waitUntil(async () => {
|
|
12
13
|
actual = await browser.getUrl();
|
|
13
14
|
return compareText(actual, expectedValue, options).result;
|
|
14
|
-
}, options);
|
|
15
|
+
}, isNot, options);
|
|
15
16
|
const message = enhanceError('window', expectedValue, actual, this, verb, expectation, '', options);
|
|
16
17
|
const result = {
|
|
17
18
|
pass,
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { executeCommandBe } from '../../utils.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
...DEFAULT_OPTIONS,
|
|
5
|
-
withinViewport: false,
|
|
6
|
-
contentVisibilityAuto: true,
|
|
7
|
-
opacityProperty: true,
|
|
8
|
-
visibilityProperty: true
|
|
9
|
-
};
|
|
10
|
-
export async function toBeDisplayed(received, options = DEFAULT_OPTIONS_DISPLAYED) {
|
|
2
|
+
import { DEFAULT_OPTIONS_TO_BE_DISPLAYED } from '../../constants.js';
|
|
3
|
+
export async function toBeDisplayed(received, options = DEFAULT_OPTIONS_TO_BE_DISPLAYED) {
|
|
11
4
|
this.expectation = this.expectation || 'displayed';
|
|
12
5
|
await options.beforeAssertion?.({
|
|
13
6
|
matcherName: 'toBeDisplayed',
|
|
14
7
|
options,
|
|
15
8
|
});
|
|
16
|
-
const { withinViewport, contentVisibilityAuto, opacityProperty, visibilityProperty, ...commandOptions } = { ...
|
|
9
|
+
const { withinViewport, contentVisibilityAuto, opacityProperty, visibilityProperty, ...commandOptions } = { ...DEFAULT_OPTIONS_TO_BE_DISPLAYED, ...options };
|
|
17
10
|
const result = await executeCommandBe.call(this, received, el => el?.isDisplayed({
|
|
18
11
|
withinViewport,
|
|
19
12
|
contentVisibilityAuto,
|
|
@@ -15,6 +15,7 @@ async function conditionAttrAndValue(el, attribute, value, options) {
|
|
|
15
15
|
return compareText(attr, value, options);
|
|
16
16
|
}
|
|
17
17
|
export async function toHaveAttributeAndValue(received, attribute, value, options = DEFAULT_OPTIONS) {
|
|
18
|
+
const isNot = this.isNot;
|
|
18
19
|
const { expectation = 'attribute', verb = 'have' } = this;
|
|
19
20
|
let el = await received?.getElement();
|
|
20
21
|
let attr;
|
|
@@ -23,7 +24,7 @@ export async function toHaveAttributeAndValue(received, attribute, value, option
|
|
|
23
24
|
el = result.el;
|
|
24
25
|
attr = result.values;
|
|
25
26
|
return result.success;
|
|
26
|
-
}, options);
|
|
27
|
+
}, isNot, options);
|
|
27
28
|
const expected = wrapExpectedWithArray(el, attr, value);
|
|
28
29
|
const message = enhanceError(el, expected, attr, this, verb, expectation, attribute, options);
|
|
29
30
|
return {
|
|
@@ -31,15 +32,16 @@ export async function toHaveAttributeAndValue(received, attribute, value, option
|
|
|
31
32
|
message: () => message
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
|
-
async function toHaveAttributeFn(received, attribute
|
|
35
|
-
const
|
|
35
|
+
async function toHaveAttributeFn(received, attribute) {
|
|
36
|
+
const isNot = this.isNot;
|
|
37
|
+
const { expectation = 'attribute', verb = 'have' } = this;
|
|
36
38
|
let el = await received?.getElement();
|
|
37
39
|
const pass = await waitUntil(async () => {
|
|
38
40
|
const result = await executeCommand.call(this, el, conditionAttr, {}, [attribute]);
|
|
39
41
|
el = result.el;
|
|
40
42
|
return result.success;
|
|
41
|
-
},
|
|
42
|
-
const message = enhanceError(el, !isNot, pass, this, verb, expectation, attribute,
|
|
43
|
+
}, isNot, {});
|
|
44
|
+
const message = enhanceError(el, !isNot, pass, this, verb, expectation, attribute, {});
|
|
43
45
|
return {
|
|
44
46
|
pass,
|
|
45
47
|
message: () => message
|
|
@@ -53,7 +55,7 @@ export async function toHaveAttribute(received, attribute, value, options = DEFA
|
|
|
53
55
|
});
|
|
54
56
|
const result = value !== undefined
|
|
55
57
|
? await toHaveAttributeAndValue.call(this, received, attribute, value, options)
|
|
56
|
-
: await toHaveAttributeFn.call(this, received, attribute
|
|
58
|
+
: await toHaveAttributeFn.call(this, received, attribute);
|
|
57
59
|
await options.afterAssertion?.({
|
|
58
60
|
matcherName: 'toHaveAttribute',
|
|
59
61
|
expectedValue: [attribute, value],
|
|
@@ -16,6 +16,7 @@ async function condition(el, options) {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
export async function toHaveChildren(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
19
|
+
const isNot = this.isNot;
|
|
19
20
|
const { expectation = 'children', verb = 'have' } = this;
|
|
20
21
|
await options.beforeAssertion?.({
|
|
21
22
|
matcherName: 'toHaveChildren',
|
|
@@ -32,7 +33,7 @@ export async function toHaveChildren(received, expectedValue, options = DEFAULT_
|
|
|
32
33
|
el = result.el;
|
|
33
34
|
children = result.values;
|
|
34
35
|
return result.success;
|
|
35
|
-
}, { ...numberOptions, ...options });
|
|
36
|
+
}, isNot, { ...numberOptions, ...options });
|
|
36
37
|
const error = numberError(numberOptions);
|
|
37
38
|
const expectedArray = wrapExpectedWithArray(el, children, error);
|
|
38
39
|
const message = enhanceError(el, expectedArray, children, this, verb, expectation, '', numberOptions);
|
|
@@ -24,6 +24,7 @@ export function toHaveClass(...args) {
|
|
|
24
24
|
return toHaveElementClass.call(this || {}, ...args);
|
|
25
25
|
}
|
|
26
26
|
export async function toHaveElementClass(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
27
|
+
const isNot = this.isNot;
|
|
27
28
|
const { expectation = 'class', verb = 'have' } = this;
|
|
28
29
|
await options.beforeAssertion?.({
|
|
29
30
|
matcherName: 'toHaveElementClass',
|
|
@@ -38,7 +39,7 @@ export async function toHaveElementClass(received, expectedValue, options = DEFA
|
|
|
38
39
|
el = result.el;
|
|
39
40
|
attr = result.values;
|
|
40
41
|
return result.success;
|
|
41
|
-
}, options);
|
|
42
|
+
}, isNot, options);
|
|
42
43
|
const message = enhanceError(el, wrapExpectedWithArray(el, attr, expectedValue), attr, this, verb, expectation, '', options);
|
|
43
44
|
const result = {
|
|
44
45
|
pass,
|
|
@@ -8,6 +8,7 @@ async function condition(el, label, options) {
|
|
|
8
8
|
return compareText(actualLabel, label, options);
|
|
9
9
|
}
|
|
10
10
|
export async function toHaveComputedLabel(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
11
|
+
const isNot = this.isNot;
|
|
11
12
|
const { expectation = 'computed label', verb = 'have' } = this;
|
|
12
13
|
await options.beforeAssertion?.({
|
|
13
14
|
matcherName: 'toHaveComputedLabel',
|
|
@@ -21,7 +22,7 @@ export async function toHaveComputedLabel(received, expectedValue, options = DEF
|
|
|
21
22
|
el = result.el;
|
|
22
23
|
actualLabel = result.values;
|
|
23
24
|
return result.success;
|
|
24
|
-
}, options);
|
|
25
|
+
}, isNot, options);
|
|
25
26
|
const message = enhanceError(el, wrapExpectedWithArray(el, actualLabel, expectedValue), actualLabel, this, verb, expectation, '', options);
|
|
26
27
|
const result = {
|
|
27
28
|
pass,
|
|
@@ -8,6 +8,7 @@ async function condition(el, role, options) {
|
|
|
8
8
|
return compareText(actualRole, role, options);
|
|
9
9
|
}
|
|
10
10
|
export async function toHaveComputedRole(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
11
|
+
const isNot = this.isNot;
|
|
11
12
|
const { expectation = 'computed role', verb = 'have' } = this;
|
|
12
13
|
await options.beforeAssertion?.({
|
|
13
14
|
matcherName: 'toHaveComputedRole',
|
|
@@ -21,7 +22,7 @@ export async function toHaveComputedRole(received, expectedValue, options = DEFA
|
|
|
21
22
|
el = result.el;
|
|
22
23
|
actualRole = result.values;
|
|
23
24
|
return result.success;
|
|
24
|
-
}, options);
|
|
25
|
+
}, isNot, options);
|
|
25
26
|
const message = enhanceError(el, wrapExpectedWithArray(el, actualRole, expectedValue), actualRole, this, verb, expectation, '', options);
|
|
26
27
|
const result = {
|
|
27
28
|
pass,
|
|
@@ -16,7 +16,8 @@ async function condition(el, property, value, options = DEFAULT_OPTIONS) {
|
|
|
16
16
|
return compareText(prop, value, options);
|
|
17
17
|
}
|
|
18
18
|
export async function toHaveElementProperty(received, property, value, options = DEFAULT_OPTIONS) {
|
|
19
|
-
const
|
|
19
|
+
const isNot = this.isNot;
|
|
20
|
+
const { expectation = 'property', verb = 'have' } = this;
|
|
20
21
|
await options.beforeAssertion?.({
|
|
21
22
|
matcherName: 'toHaveElementProperty',
|
|
22
23
|
expectedValue: [property, value],
|
|
@@ -29,7 +30,7 @@ export async function toHaveElementProperty(received, property, value, options =
|
|
|
29
30
|
el = result.el;
|
|
30
31
|
prop = result.values;
|
|
31
32
|
return result.success;
|
|
32
|
-
}, options);
|
|
33
|
+
}, isNot, options);
|
|
33
34
|
let message;
|
|
34
35
|
if (value === undefined) {
|
|
35
36
|
message = enhanceError(el, !isNot, pass, this, verb, expectation, property, options);
|
|
@@ -8,6 +8,7 @@ async function condition(el, html, options) {
|
|
|
8
8
|
return compareText(actualHTML, html, options);
|
|
9
9
|
}
|
|
10
10
|
export async function toHaveHTML(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
11
|
+
const isNot = this.isNot;
|
|
11
12
|
const { expectation = 'HTML', verb = 'have' } = this;
|
|
12
13
|
await options.beforeAssertion?.({
|
|
13
14
|
matcherName: 'toHaveHTML',
|
|
@@ -25,7 +26,7 @@ export async function toHaveHTML(received, expectedValue, options = DEFAULT_OPTI
|
|
|
25
26
|
el = result.el;
|
|
26
27
|
actualHTML = result.values;
|
|
27
28
|
return result.success;
|
|
28
|
-
}, options);
|
|
29
|
+
}, isNot, options);
|
|
29
30
|
const message = enhanceError(el, wrapExpectedWithArray(el, actualHTML, expectedValue), actualHTML, this, verb, expectation, '', options);
|
|
30
31
|
const result = {
|
|
31
32
|
pass,
|
|
@@ -8,6 +8,7 @@ async function condition(el, height, options) {
|
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
export async function toHaveHeight(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
11
|
+
const isNot = this.isNot;
|
|
11
12
|
const { expectation = 'height', verb = 'have' } = this;
|
|
12
13
|
await options.beforeAssertion?.({
|
|
13
14
|
matcherName: 'toHaveHeight',
|
|
@@ -31,7 +32,7 @@ export async function toHaveHeight(received, expectedValue, options = DEFAULT_OP
|
|
|
31
32
|
el = result.el;
|
|
32
33
|
actualHeight = result.values;
|
|
33
34
|
return result.success;
|
|
34
|
-
}, { ...numberOptions, ...options });
|
|
35
|
+
}, isNot, { ...numberOptions, ...options });
|
|
35
36
|
const error = numberError(numberOptions);
|
|
36
37
|
const message = enhanceError(el, error, actualHeight, this, verb, expectation, '', options);
|
|
37
38
|
const result = {
|
|
@@ -5,6 +5,7 @@ async function condition(el, size) {
|
|
|
5
5
|
return compareObject(actualSize, size);
|
|
6
6
|
}
|
|
7
7
|
export async function toHaveSize(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
8
|
+
const isNot = this.isNot;
|
|
8
9
|
const { expectation = 'size', verb = 'have' } = this;
|
|
9
10
|
await options.beforeAssertion?.({
|
|
10
11
|
matcherName: 'toHaveSize',
|
|
@@ -18,7 +19,7 @@ export async function toHaveSize(received, expectedValue, options = DEFAULT_OPTI
|
|
|
18
19
|
el = result.el;
|
|
19
20
|
actualSize = result.values;
|
|
20
21
|
return result.success;
|
|
21
|
-
}, options);
|
|
22
|
+
}, isNot, options);
|
|
22
23
|
const message = enhanceError(el, wrapExpectedWithArray(el, actualSize, expectedValue), actualSize, this, verb, expectation, '', options);
|
|
23
24
|
const result = {
|
|
24
25
|
pass,
|
|
@@ -4,6 +4,7 @@ async function condition(el, style, options) {
|
|
|
4
4
|
return compareStyle(el, style, options);
|
|
5
5
|
}
|
|
6
6
|
export async function toHaveStyle(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
7
|
+
const isNot = this.isNot;
|
|
7
8
|
const { expectation = 'style', verb = 'have' } = this;
|
|
8
9
|
await options.beforeAssertion?.({
|
|
9
10
|
matcherName: 'toHaveStyle',
|
|
@@ -17,7 +18,7 @@ export async function toHaveStyle(received, expectedValue, options = DEFAULT_OPT
|
|
|
17
18
|
el = result.el;
|
|
18
19
|
actualStyle = result.values;
|
|
19
20
|
return result.success;
|
|
20
|
-
}, options);
|
|
21
|
+
}, isNot, options);
|
|
21
22
|
const message = enhanceError(el, wrapExpectedWithArray(el, actualStyle, expectedValue), actualStyle, this, verb, expectation, '', options);
|
|
22
23
|
const result = {
|
|
23
24
|
pass,
|
|
@@ -28,6 +28,7 @@ async function condition(el, text, options) {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
export async function toHaveText(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
31
|
+
const isNot = this.isNot;
|
|
31
32
|
const { expectation = 'text', verb = 'have' } = this;
|
|
32
33
|
await options.beforeAssertion?.({
|
|
33
34
|
matcherName: 'toHaveText',
|
|
@@ -45,7 +46,7 @@ export async function toHaveText(received, expectedValue, options = DEFAULT_OPTI
|
|
|
45
46
|
el = result.el;
|
|
46
47
|
actualText = result.values;
|
|
47
48
|
return result.success;
|
|
48
|
-
}, options);
|
|
49
|
+
}, isNot, options);
|
|
49
50
|
const message = enhanceError(el, wrapExpectedWithArray(el, actualText, expectedValue), actualText, this, verb, expectation, '', options);
|
|
50
51
|
const result = {
|
|
51
52
|
pass,
|
|
@@ -8,6 +8,7 @@ async function condition(el, width, options) {
|
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
export async function toHaveWidth(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
11
|
+
const isNot = this.isNot;
|
|
11
12
|
const { expectation = 'width', verb = 'have' } = this;
|
|
12
13
|
await options.beforeAssertion?.({
|
|
13
14
|
matcherName: 'toHaveWidth',
|
|
@@ -31,7 +32,7 @@ export async function toHaveWidth(received, expectedValue, options = DEFAULT_OPT
|
|
|
31
32
|
el = result.el;
|
|
32
33
|
actualWidth = result.values;
|
|
33
34
|
return result.success;
|
|
34
|
-
}, { ...numberOptions, ...options });
|
|
35
|
+
}, isNot, { ...numberOptions, ...options });
|
|
35
36
|
const error = numberError(numberOptions);
|
|
36
37
|
const message = enhanceError(el, error, actualWidth, this, verb, expectation, '', options);
|
|
37
38
|
const result = {
|
|
@@ -2,6 +2,7 @@ import { waitUntil, enhanceError, compareNumbers, numberError } from '../../util
|
|
|
2
2
|
import { refetchElements } from '../../util/refetchElements.js';
|
|
3
3
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
4
4
|
export async function toBeElementsArrayOfSize(received, expectedValue, options = DEFAULT_OPTIONS) {
|
|
5
|
+
const isNot = this.isNot;
|
|
5
6
|
const { expectation = 'elements array of size', verb = 'be' } = this;
|
|
6
7
|
await options.beforeAssertion?.({
|
|
7
8
|
matcherName: 'toBeElementsArrayOfSize',
|
|
@@ -27,7 +28,7 @@ export async function toBeElementsArrayOfSize(received, expectedValue, options =
|
|
|
27
28
|
}
|
|
28
29
|
elements = await refetchElements(elements, numberOptions.wait, true);
|
|
29
30
|
return false;
|
|
30
|
-
}, { ...numberOptions, ...options });
|
|
31
|
+
}, isNot, { ...numberOptions, ...options });
|
|
31
32
|
if (Array.isArray(received) && pass) {
|
|
32
33
|
for (let index = originalLength; index < elements.length; index++) {
|
|
33
34
|
received.push(elements[index]);
|
|
@@ -2,6 +2,7 @@ import { waitUntil, enhanceError, compareNumbers } from '../../utils.js';
|
|
|
2
2
|
import { numberError } from '../../util/formatMessage.js';
|
|
3
3
|
import { DEFAULT_OPTIONS } from '../../constants.js';
|
|
4
4
|
export async function toBeRequestedTimes(received, expectedValue = {}, options = DEFAULT_OPTIONS) {
|
|
5
|
+
const isNot = this.isNot || false;
|
|
5
6
|
const { expectation = `called${typeof expectedValue === 'number' ? ' ' + expectedValue : ''} time${expectedValue !== 1 ? 's' : ''}`, verb = 'be' } = this;
|
|
6
7
|
await options.beforeAssertion?.({
|
|
7
8
|
matcherName: 'toBeRequestedTimes',
|
|
@@ -15,7 +16,7 @@ export async function toBeRequestedTimes(received, expectedValue = {}, options =
|
|
|
15
16
|
const pass = await waitUntil(async () => {
|
|
16
17
|
actual = received.calls.length;
|
|
17
18
|
return compareNumbers(actual, numberOptions);
|
|
18
|
-
}, { ...numberOptions, ...options });
|
|
19
|
+
}, isNot, { ...numberOptions, ...options });
|
|
19
20
|
const error = numberError(numberOptions);
|
|
20
21
|
const message = enhanceError('mock', error, actual, this, verb, expectation, '', numberOptions);
|
|
21
22
|
const result = {
|
|
@@ -10,7 +10,8 @@ function reduceHeaders(headers) {
|
|
|
10
10
|
}, {});
|
|
11
11
|
}
|
|
12
12
|
export async function toBeRequestedWith(received, expectedValue = {}, options = DEFAULT_OPTIONS) {
|
|
13
|
-
const
|
|
13
|
+
const isNot = this.isNot || false;
|
|
14
|
+
const { expectation = 'called with', verb = 'be' } = this;
|
|
14
15
|
await options.beforeAssertion?.({
|
|
15
16
|
matcherName: 'toBeRequestedWith',
|
|
16
17
|
expectedValue,
|
|
@@ -29,7 +30,7 @@ export async function toBeRequestedWith(received, expectedValue = {}, options =
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
return false;
|
|
32
|
-
}, { ...options, wait: isNot ? 0 : options.wait });
|
|
33
|
+
}, isNot, { ...options, wait: isNot ? 0 : options.wait });
|
|
33
34
|
const message = enhanceError('mock', minifyRequestedWith(expectedValue), minifyRequestMock(actual, expectedValue) || 'was not called', this, verb, expectation, '', options);
|
|
34
35
|
const result = {
|
|
35
36
|
pass,
|
package/lib/matchers.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './matchers/browser/toHaveClipboardText.js';
|
|
2
|
+
export * from './matchers/browser/toHaveLocalStorageItem.js';
|
|
2
3
|
export * from './matchers/browser/toHaveTitle.js';
|
|
3
4
|
export * from './matchers/browser/toHaveUrl.js';
|
|
4
5
|
export * from './matchers/element/toBeClickable.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/constants.ts","../src/index.ts","../src/jasmineUtils.ts","../src/matchers.ts","../src/snapshot.ts","../src/softAssert.ts","../src/softAssertService.ts","../src/softExpect.ts","../src/types.ts","../src/utils.ts","../src/matchers/snapshot.ts","../src/matchers/browser/toHaveClipboardText.ts","../src/matchers/browser/toHaveTitle.ts","../src/matchers/browser/toHaveUrl.ts","../src/matchers/element/toBeClickable.ts","../src/matchers/element/toBeDisabled.ts","../src/matchers/element/toBeDisplayed.ts","../src/matchers/element/toBeDisplayedInViewport.ts","../src/matchers/element/toBeEnabled.ts","../src/matchers/element/toBeExisting.ts","../src/matchers/element/toBeFocused.ts","../src/matchers/element/toBeSelected.ts","../src/matchers/element/toHaveAttribute.ts","../src/matchers/element/toHaveChildren.ts","../src/matchers/element/toHaveClass.ts","../src/matchers/element/toHaveComputedLabel.ts","../src/matchers/element/toHaveComputedRole.ts","../src/matchers/element/toHaveElementProperty.ts","../src/matchers/element/toHaveHTML.ts","../src/matchers/element/toHaveHeight.ts","../src/matchers/element/toHaveHref.ts","../src/matchers/element/toHaveId.ts","../src/matchers/element/toHaveSize.ts","../src/matchers/element/toHaveStyle.ts","../src/matchers/element/toHaveText.ts","../src/matchers/element/toHaveValue.ts","../src/matchers/element/toHaveWidth.ts","../src/matchers/elements/toBeElementsArrayOfSize.ts","../src/matchers/mock/toBeRequested.ts","../src/matchers/mock/toBeRequestedTimes.ts","../src/matchers/mock/toBeRequestedWith.ts","../src/util/elementsUtil.ts","../src/util/executeCommand.ts","../src/util/formatMessage.ts","../src/util/refetchElements.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["../src/constants.ts","../src/index.ts","../src/jasmineUtils.ts","../src/matchers.ts","../src/snapshot.ts","../src/softAssert.ts","../src/softAssertService.ts","../src/softExpect.ts","../src/types.ts","../src/utils.ts","../src/matchers/snapshot.ts","../src/matchers/browser/toHaveClipboardText.ts","../src/matchers/browser/toHaveLocalStorageItem.ts","../src/matchers/browser/toHaveTitle.ts","../src/matchers/browser/toHaveUrl.ts","../src/matchers/element/toBeClickable.ts","../src/matchers/element/toBeDisabled.ts","../src/matchers/element/toBeDisplayed.ts","../src/matchers/element/toBeDisplayedInViewport.ts","../src/matchers/element/toBeEnabled.ts","../src/matchers/element/toBeExisting.ts","../src/matchers/element/toBeFocused.ts","../src/matchers/element/toBeSelected.ts","../src/matchers/element/toHaveAttribute.ts","../src/matchers/element/toHaveChildren.ts","../src/matchers/element/toHaveClass.ts","../src/matchers/element/toHaveComputedLabel.ts","../src/matchers/element/toHaveComputedRole.ts","../src/matchers/element/toHaveElementProperty.ts","../src/matchers/element/toHaveHTML.ts","../src/matchers/element/toHaveHeight.ts","../src/matchers/element/toHaveHref.ts","../src/matchers/element/toHaveId.ts","../src/matchers/element/toHaveSize.ts","../src/matchers/element/toHaveStyle.ts","../src/matchers/element/toHaveText.ts","../src/matchers/element/toHaveValue.ts","../src/matchers/element/toHaveWidth.ts","../src/matchers/elements/toBeElementsArrayOfSize.ts","../src/matchers/mock/toBeRequested.ts","../src/matchers/mock/toBeRequestedTimes.ts","../src/matchers/mock/toBeRequestedWith.ts","../src/util/elementsUtil.ts","../src/util/executeCommand.ts","../src/util/formatMessage.ts","../src/util/refetchElements.ts"],"version":"5.9.3"}
|
package/lib/utils.js
CHANGED
|
@@ -19,38 +19,50 @@ export function isAsymmetricMatcher(expected) {
|
|
|
19
19
|
function isStringContainingMatcher(expected) {
|
|
20
20
|
return isAsymmetricMatcher(expected) && ['StringContaining', 'StringNotContaining'].includes(expected.toString());
|
|
21
21
|
}
|
|
22
|
-
const waitUntil = async (condition, { wait = DEFAULT_OPTIONS.wait, interval = DEFAULT_OPTIONS.interval } = {}) => {
|
|
23
|
-
|
|
22
|
+
const waitUntil = async (condition, isNot = false, { wait = DEFAULT_OPTIONS.wait, interval = DEFAULT_OPTIONS.interval } = {}) => {
|
|
23
|
+
if (wait === 0) {
|
|
24
|
+
return await condition();
|
|
25
|
+
}
|
|
24
26
|
let error;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
try {
|
|
28
|
+
const start = Date.now();
|
|
29
|
+
while (true) {
|
|
30
|
+
if (Date.now() - start > wait) {
|
|
31
|
+
throw new Error('timeout');
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const result = isNot !== (await condition());
|
|
35
|
+
error = undefined;
|
|
36
|
+
if (result) {
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
await sleep(interval);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
error = err;
|
|
43
|
+
await sleep(interval);
|
|
32
44
|
}
|
|
33
45
|
}
|
|
34
|
-
|
|
35
|
-
error
|
|
46
|
+
if (error) {
|
|
47
|
+
throw error;
|
|
36
48
|
}
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
return !isNot;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
if (error) {
|
|
53
|
+
throw error;
|
|
39
54
|
}
|
|
40
|
-
|
|
41
|
-
if (error) {
|
|
42
|
-
throw error;
|
|
55
|
+
return isNot;
|
|
43
56
|
}
|
|
44
|
-
return result;
|
|
45
57
|
};
|
|
46
58
|
async function executeCommandBe(received, command, options) {
|
|
47
|
-
const { expectation, verb = 'be' } = this;
|
|
59
|
+
const { isNot, expectation, verb = 'be' } = this;
|
|
48
60
|
let el = await received?.getElement();
|
|
49
61
|
const pass = await waitUntil(async () => {
|
|
50
62
|
const result = await executeCommand.call(this, el, async (element) => ({ result: await command(element) }), options);
|
|
51
63
|
el = result.el;
|
|
52
64
|
return result.success;
|
|
53
|
-
}, options);
|
|
65
|
+
}, isNot, options);
|
|
54
66
|
const message = enhanceErrorBe(el, pass, this, verb, expectation, options);
|
|
55
67
|
return {
|
|
56
68
|
pass,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expect-webdriverio",
|
|
3
|
-
"version": "5.6.
|
|
3
|
+
"version": "5.6.6",
|
|
4
4
|
"author": "Mykola Grybyk <mykola.grybyk@gmail.com>",
|
|
5
5
|
"description": "WebdriverIO Assertion Library",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,6 +38,11 @@
|
|
|
38
38
|
"types": "./jasmine.d.ts"
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
|
+
"./jasmine-wdio-expect-async": [
|
|
42
|
+
{
|
|
43
|
+
"types": "./jasmine-wdio-expect-async.d.ts"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
41
46
|
"./types": "./types/expect-global.d.ts",
|
|
42
47
|
"./expect-global": "./types/expect-global.d.ts"
|
|
43
48
|
},
|
|
@@ -50,7 +55,9 @@
|
|
|
50
55
|
"build": "run-s clean compile",
|
|
51
56
|
"clean": "run-p clean:*",
|
|
52
57
|
"clean:build": "rimraf ./lib",
|
|
53
|
-
"compile": "
|
|
58
|
+
"compile": "run-s compile:*",
|
|
59
|
+
"compile:lib": "tsc --build tsconfig.build.json",
|
|
60
|
+
"compile:check": "if [ ! -f lib/index.js ] || [ $(find lib -type f | wc -l) -le 30 ]; then echo 'File structure under lib is broken'; exit 1; fi",
|
|
54
61
|
"tsc:root-types": "node types-checks-filter-out-node_modules.js",
|
|
55
62
|
"test": "run-s test:*",
|
|
56
63
|
"test:tsc": "tsc --project tsconfig.json --noEmit --rootDir .",
|
|
@@ -65,7 +72,10 @@
|
|
|
65
72
|
"ts:jasmine-async": "cd test-types/jasmine-async && tsc --project ./tsconfig.json",
|
|
66
73
|
"checks:all": "npm run build && npm run compile && npm run tsc:root-types && npm run test && npm run ts",
|
|
67
74
|
"watch": "npm run compile -- --watch",
|
|
68
|
-
"prepare": "husky install"
|
|
75
|
+
"prepare": "husky install",
|
|
76
|
+
"playgrounds:setup": "for dir in playgrounds/*/; do cd \"$dir\" && npm install && cd ../..; done",
|
|
77
|
+
"playgrounds:checks:all": "for dir in playgrounds/*/; do cd \"$dir\" && npm run checks:all && cd ../..; done",
|
|
78
|
+
"playgrounds:snapshots:update": "cd playgrounds/mocha && npm run snapshots:update && cd ../jest && npm run snapshots:update && cd ../.."
|
|
69
79
|
},
|
|
70
80
|
"dependencies": {
|
|
71
81
|
"@vitest/snapshot": "^4.0.16",
|
|
@@ -89,6 +89,15 @@ interface WdioBrowserMatchers<_R, ActualT>{
|
|
|
89
89
|
* `WebdriverIO.Browser` -> `execute`
|
|
90
90
|
*/
|
|
91
91
|
toHaveClipboardText: FnWhenBrowser<ActualT, (clipboardText: string | RegExp | ExpectWebdriverIO.PartialMatcher<string>, options?: ExpectWebdriverIO.StringOptions) => Promise<void>>
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* `WebdriverIO.Browser` -> `execute`
|
|
95
|
+
*/
|
|
96
|
+
toHaveLocalStorageItem: FnWhenBrowser<ActualT, (
|
|
97
|
+
key: string,
|
|
98
|
+
expectedValue?: string | RegExp | ExpectWebdriverIO.PartialMatcher<string>,
|
|
99
|
+
options?: ExpectWebdriverIO.StringOptions
|
|
100
|
+
) => Promise<void>>
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
/**
|
|
@@ -311,7 +320,7 @@ interface WdioElementOrArrayMatchers<_R, ActualT = unknown> {
|
|
|
311
320
|
*/
|
|
312
321
|
toHaveHTML: FnWhenElementOrArrayLike<ActualT, (
|
|
313
322
|
html: string | RegExp | ExpectWebdriverIO.PartialMatcher<string> | Array<string | RegExp>,
|
|
314
|
-
options?: ExpectWebdriverIO.
|
|
323
|
+
options?: ExpectWebdriverIO.HTMLOptions
|
|
315
324
|
) => Promise<void>>
|
|
316
325
|
|
|
317
326
|
/**
|
|
@@ -728,6 +737,7 @@ declare namespace ExpectWebdriverIO {
|
|
|
728
737
|
* `true` to check if the element is invisible due to the value of its visibility property. `true` by default.
|
|
729
738
|
* @default true
|
|
730
739
|
*/
|
|
740
|
+
|
|
731
741
|
visibilityProperty?: boolean
|
|
732
742
|
}
|
|
733
743
|
|