expect-webdriverio 5.4.3 → 5.6.0

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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # expect-webdriverio [![Test](https://github.com/webdriverio/expect-webdriverio/actions/workflows/test.yml/badge.svg)](https://github.com/webdriverio/expect-webdriverio/actions/workflows/test.yml)
2
2
 
3
3
 
4
- ###### [API](docs/API.md) | [TypeScript / JS Autocomplete](/docs/Types.md) | [Examples](docs/Examples.md) | [Extending Matchers](/docs/Extend.md)
4
+ ###### [API](docs/API.md) | [TypeScript / JS Autocomplete](docs/Types.md) | [Examples](docs/Examples.md) | [Extending Matchers](docs/CustomMatchers.md)
5
5
 
6
6
  > [WebdriverIO](https://webdriver.io/) Assertion library inspired by [expect](https://www.npmjs.com/package/expect)
7
7
 
@@ -0,0 +1,22 @@
1
+ /// <reference types="./types/expect-webdriverio.d.ts"/>
2
+
3
+ /**
4
+ * Overrides the default wdio `expect` for Jasmine case specifically since the `expect` is now completely asynchronous which is not the case under Jest or standalone.
5
+ */
6
+ declare namespace ExpectWebdriverIO {
7
+ interface Expect extends ExpectWebdriverIO.AsymmetricMatchers, ExpectLibInverse<ExpectWebdriverIO.InverseAsymmetricMatchers>, WdioExpect {
8
+ /**
9
+ * The `expect` function is used every time you want to test a value.
10
+ * You will rarely call `expect` by itself.
11
+ *
12
+ * expect function declaration contains two generics:
13
+ * - T: the type of the actual value, e.g. any type, not just WebdriverIO.Browser or WebdriverIO.Element
14
+ * - R: the type of the return value, e.g. Promise<void> or void
15
+ *
16
+ * Note: The function must stay here in the namespace to overwrite correctly the expect function from the expect library.
17
+ *
18
+ * @param actual The value to apply matchers against.
19
+ */
20
+ <T = unknown>(actual: T): ExpectWebdriverIO.MatchersAndInverse<Promise<void>, T>
21
+ }
22
+ }
package/jasmine.d.ts CHANGED
@@ -1,6 +1,27 @@
1
1
  /// <reference types="./types/expect-webdriverio.d.ts"/>
2
2
 
3
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
+ */
4
13
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
- interface AsyncMatchers<T, U> extends ExpectWebdriverIO.Matchers<Promise<void>, T> {}
6
- }
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
+ }
package/jest.d.ts CHANGED
@@ -1,5 +1,37 @@
1
1
  /// <reference types="./types/expect-webdriverio.d.ts"/>
2
2
 
3
+ /**
4
+ * Augment the Jest namespace to include the matchers from expect-webdriverio.
5
+ * When Jest Library is used, it specifies `expect-webdriverio/jest` for this file in the tsconfig.json's types.
6
+ */
7
+
3
8
  declare namespace jest {
4
- interface Matchers<R, T> extends ExpectWebdriverIO.Matchers<R, T> { }
5
- }
9
+
10
+ interface Matchers<R extends void | Promise<void>, T> extends ExpectWebdriverIO.Matchers<R, T> {
11
+
12
+ /**
13
+ * Below are overloaded Jest's matchers not part of `expect` but of `jest-snapshot`.
14
+ * @see https://github.com/jestjs/jest/blob/73dbef5d2d3195a1e55fb254c54cce70d3036252/packages/jest-snapshot/src/types.ts#L37
15
+ *
16
+ * Note: We need to define them below so that they are correctly typed overloaded.
17
+ * Else even when extending `WdioJestOverloadedMatchers` we have typing errors.
18
+ */
19
+
20
+ /**
21
+ * snapshot matcher
22
+ * @param label optional snapshot label
23
+ */
24
+ toMatchSnapshot(label?: string): T extends WdioPromiseLike ? Promise<void> : void;
25
+
26
+ /**
27
+ * inline snapshot matcher
28
+ * @param snapshot snapshot string (autogenerated if not specified)
29
+ * @param label optional snapshot label
30
+ */
31
+ toMatchInlineSnapshot(snapshot?: string, label?: string): T extends WdioPromiseLike ? Promise<void> : void;
32
+ }
33
+
34
+ interface Expect extends ExpectWebdriverIO.Expect {}
35
+
36
+ interface InverseAsymmetricMatchers extends ExpectWebdriverIO.AsymmetricMatchers {}
37
+ }
@@ -53,7 +53,7 @@ export async function toHaveAttribute(received, attribute, value, options = DEFA
53
53
  expectedValue: [attribute, value],
54
54
  options,
55
55
  });
56
- const result = typeof value !== 'undefined'
56
+ const result = value !== undefined
57
57
  ? await toHaveAttributeAndValue.call(this, received, attribute, value, options)
58
58
  : await toHaveAttributeFn.call(this, received, attribute);
59
59
  await options.afterAssertion?.({
@@ -1,12 +1,12 @@
1
1
  import { DEFAULT_OPTIONS } from '../../constants.js';
2
- import { compareText, compareTextWithArray, enhanceError, executeCommand, isAsymmeyricMatcher, waitUntil, wrapExpectedWithArray } from '../../utils.js';
2
+ import { compareText, compareTextWithArray, enhanceError, executeCommand, isAsymmetricMatcher, waitUntil, wrapExpectedWithArray } from '../../utils.js';
3
3
  import { toHaveAttributeAndValue } from './toHaveAttribute.js';
4
4
  async function condition(el, attribute, value, options) {
5
5
  const actualClass = await el.getAttribute(attribute);
6
6
  if (typeof actualClass !== 'string') {
7
7
  return { result: false };
8
8
  }
9
- if (isAsymmeyricMatcher(value)) {
9
+ if (isAsymmetricMatcher(value)) {
10
10
  return compareText(actualClass, value, options);
11
11
  }
12
12
  const classes = actualClass.split(' ');
@@ -45,7 +45,7 @@ export async function toBeRequestedWith(received, expectedValue = {}, options =
45
45
  return result;
46
46
  }
47
47
  const methodMatcher = (method, expected) => {
48
- if (typeof expected === 'undefined') {
48
+ if (expected === undefined) {
49
49
  return true;
50
50
  }
51
51
  if (!Array.isArray(expected)) {
@@ -61,7 +61,7 @@ const methodMatcher = (method, expected) => {
61
61
  .includes(method);
62
62
  };
63
63
  const statusCodeMatcher = (statusCode, expected) => {
64
- if (typeof expected === 'undefined') {
64
+ if (expected === undefined) {
65
65
  return true;
66
66
  }
67
67
  if (!Array.isArray(expected)) {
@@ -70,7 +70,7 @@ const statusCodeMatcher = (statusCode, expected) => {
70
70
  return expected.includes(statusCode);
71
71
  };
72
72
  const urlMatcher = (url, expected) => {
73
- if (typeof expected === 'undefined') {
73
+ if (expected === undefined) {
74
74
  return true;
75
75
  }
76
76
  if (typeof expected === 'function') {
@@ -79,7 +79,7 @@ const urlMatcher = (url, expected) => {
79
79
  return equals(url, expected);
80
80
  };
81
81
  const headersMatcher = (headers, expected) => {
82
- if (typeof expected === 'undefined' ||
82
+ if (expected === undefined ||
83
83
  typeof expected === 'object' && Object.keys(expected).length === 0) {
84
84
  return true;
85
85
  }
@@ -98,7 +98,7 @@ const isMatcher = (filter) => {
98
98
  typeof proto.asymmetricMatch === 'function');
99
99
  };
100
100
  const minifyRequestMock = (requestMock, requestedWith) => {
101
- if (typeof requestMock === 'undefined') {
101
+ if (requestMock === undefined) {
102
102
  return requestMock;
103
103
  }
104
104
  const r = {
@@ -123,7 +123,7 @@ const minifyRequestedWith = (r) => {
123
123
  return result;
124
124
  };
125
125
  const requestedWithParamToString = (param, transformFn) => {
126
- if (typeof param === 'undefined') {
126
+ if (param === undefined) {
127
127
  return;
128
128
  }
129
129
  if (typeof param === 'function') {
@@ -175,7 +175,7 @@ const shortenString = (str, limit = STR_LIMIT) => {
175
175
  };
176
176
  const deleteUndefinedValues = (obj, baseline = obj) => {
177
177
  Object.keys(obj).forEach((k) => {
178
- if (typeof baseline[k] === 'undefined') {
178
+ if (baseline[k] === undefined) {
179
179
  delete obj[k];
180
180
  }
181
181
  });
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { expect } from 'expect';
3
3
  import { stripSnapshotIndentation } from '@vitest/snapshot';
4
- import { SnapshotService } from '../snapshot.js';
4
+ import { SnapshotService } from '../snapshot';
5
5
  function returnSnapshotError(snapshotError) {
6
6
  try {
7
7
  expect(snapshotError.actual).toBe(snapshotError.expected);
package/lib/snapshot.js CHANGED
@@ -1,43 +1,29 @@
1
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
- if (kind === "m") throw new TypeError("Private method is not writable");
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
- };
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var _WebdriverIOSnapshotEnvironment_resolveSnapshotPath, _SnapshotService_instances, _SnapshotService_currentFilePath, _SnapshotService_currentTestName, _SnapshotService_options, _SnapshotService_snapshotResults, _SnapshotService_snapshotClient, _SnapshotService_isEqual;
13
1
  import { expect } from '@wdio/globals';
14
2
  import { SnapshotClient } from '@vitest/snapshot';
15
3
  import { NodeSnapshotEnvironment } from '@vitest/snapshot/environment';
16
4
  let service;
17
5
  class WebdriverIOSnapshotEnvironment extends NodeSnapshotEnvironment {
6
+ #resolveSnapshotPath;
18
7
  constructor(resolveSnapshotPath) {
19
8
  super({});
20
- _WebdriverIOSnapshotEnvironment_resolveSnapshotPath.set(this, void 0);
21
- __classPrivateFieldSet(this, _WebdriverIOSnapshotEnvironment_resolveSnapshotPath, resolveSnapshotPath, "f");
9
+ this.#resolveSnapshotPath = resolveSnapshotPath;
22
10
  }
23
11
  async resolvePath(filepath) {
24
- if (__classPrivateFieldGet(this, _WebdriverIOSnapshotEnvironment_resolveSnapshotPath, "f")) {
25
- return __classPrivateFieldGet(this, _WebdriverIOSnapshotEnvironment_resolveSnapshotPath, "f").call(this, filepath, '.snap');
12
+ if (this.#resolveSnapshotPath) {
13
+ return this.#resolveSnapshotPath(filepath, '.snap');
26
14
  }
27
15
  return super.resolvePath(filepath);
28
16
  }
29
17
  }
30
- _WebdriverIOSnapshotEnvironment_resolveSnapshotPath = new WeakMap();
31
18
  export class SnapshotService {
19
+ #currentFilePath;
20
+ #currentTestName;
21
+ #options;
22
+ #snapshotResults = [];
23
+ #snapshotClient = new SnapshotClient({
24
+ isEqual: this.#isEqual.bind(this),
25
+ });
32
26
  constructor(options) {
33
- _SnapshotService_instances.add(this);
34
- _SnapshotService_currentFilePath.set(this, void 0);
35
- _SnapshotService_currentTestName.set(this, void 0);
36
- _SnapshotService_options.set(this, void 0);
37
- _SnapshotService_snapshotResults.set(this, []);
38
- _SnapshotService_snapshotClient.set(this, new SnapshotClient({
39
- isEqual: __classPrivateFieldGet(this, _SnapshotService_instances, "m", _SnapshotService_isEqual).bind(this),
40
- }));
41
27
  const updateSnapshot = (Boolean(process.env.CI) && !options?.updateState)
42
28
  ? 'none'
43
29
  : options?.updateState
@@ -48,45 +34,54 @@ export class SnapshotService {
48
34
  escapeString: false,
49
35
  ...options.snapshotFormat
50
36
  } : undefined;
51
- __classPrivateFieldSet(this, _SnapshotService_options, {
37
+ this.#options = {
52
38
  updateSnapshot,
53
39
  snapshotEnvironment: new WebdriverIOSnapshotEnvironment(options?.resolveSnapshotPath),
54
40
  ...(snapshotFormatConfig && { snapshotFormat: snapshotFormatConfig })
55
- }, "f");
41
+ };
56
42
  }
57
43
  get currentFilePath() {
58
- return __classPrivateFieldGet(this, _SnapshotService_currentFilePath, "f");
44
+ return this.#currentFilePath;
59
45
  }
60
46
  get currentTestName() {
61
- return __classPrivateFieldGet(this, _SnapshotService_currentTestName, "f");
47
+ return this.#currentTestName;
62
48
  }
63
49
  get client() {
64
- return __classPrivateFieldGet(this, _SnapshotService_snapshotClient, "f");
50
+ return this.#snapshotClient;
65
51
  }
66
52
  get results() {
67
- return __classPrivateFieldGet(this, _SnapshotService_snapshotResults, "f");
53
+ return this.#snapshotResults;
68
54
  }
69
55
  async beforeTest(test) {
70
- __classPrivateFieldSet(this, _SnapshotService_currentFilePath, test.file, "f");
71
- __classPrivateFieldSet(this, _SnapshotService_currentTestName, `${test.parent} > ${test.title}`, "f");
72
- await __classPrivateFieldGet(this, _SnapshotService_snapshotClient, "f").setup(test.file, __classPrivateFieldGet(this, _SnapshotService_options, "f"));
56
+ this.#currentFilePath = test.file;
57
+ this.#currentTestName = `${test.parent} > ${test.title}`;
58
+ await this.#snapshotClient.setup(test.file, this.#options);
73
59
  }
74
60
  async beforeStep(step, scenario) {
75
61
  const file = scenario.uri;
76
62
  const testName = `${scenario.name} > ${step.text}`;
77
- __classPrivateFieldSet(this, _SnapshotService_currentFilePath, file, "f");
78
- __classPrivateFieldSet(this, _SnapshotService_currentTestName, testName, "f");
79
- await __classPrivateFieldGet(this, _SnapshotService_snapshotClient, "f").setup(file, __classPrivateFieldGet(this, _SnapshotService_options, "f"));
63
+ this.#currentFilePath = file;
64
+ this.#currentTestName = testName;
65
+ await this.#snapshotClient.setup(file, this.#options);
80
66
  }
81
67
  async after() {
82
- if (!__classPrivateFieldGet(this, _SnapshotService_currentFilePath, "f")) {
68
+ if (!this.#currentFilePath) {
83
69
  return;
84
70
  }
85
- const result = await __classPrivateFieldGet(this, _SnapshotService_snapshotClient, "f").finish(__classPrivateFieldGet(this, _SnapshotService_currentFilePath, "f"));
71
+ const result = await this.#snapshotClient.finish(this.#currentFilePath);
86
72
  if (!result) {
87
73
  return;
88
74
  }
89
- __classPrivateFieldGet(this, _SnapshotService_snapshotResults, "f").push(result);
75
+ this.#snapshotResults.push(result);
76
+ }
77
+ #isEqual(received, expected) {
78
+ try {
79
+ expect(received).toBe(expected);
80
+ return true;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
90
85
  }
91
86
  static initiate(options) {
92
87
  if (!service) {
@@ -95,12 +90,3 @@ export class SnapshotService {
95
90
  return service;
96
91
  }
97
92
  }
98
- _SnapshotService_currentFilePath = new WeakMap(), _SnapshotService_currentTestName = new WeakMap(), _SnapshotService_options = new WeakMap(), _SnapshotService_snapshotResults = new WeakMap(), _SnapshotService_snapshotClient = new WeakMap(), _SnapshotService_instances = new WeakSet(), _SnapshotService_isEqual = function _SnapshotService_isEqual(received, expected) {
99
- try {
100
- expect(received).toBe(expected);
101
- return true;
102
- }
103
- catch {
104
- return false;
105
- }
106
- };
package/lib/softAssert.js CHANGED
@@ -1,8 +1,8 @@
1
1
  export class SoftAssertService {
2
- constructor() {
3
- this.failureMap = new Map();
4
- this.currentTest = null;
5
- }
2
+ static instance;
3
+ failureMap = new Map();
4
+ currentTest = null;
5
+ constructor() { }
6
6
  static getInstance() {
7
7
  if (!SoftAssertService.instance) {
8
8
  SoftAssertService.instance = new SoftAssertService();
@@ -1,5 +1,7 @@
1
1
  import { SoftAssertService } from './softAssert.js';
2
2
  export class SoftAssertionService {
3
+ softAssertService;
4
+ options;
3
5
  constructor(serviceOptions) {
4
6
  this.softAssertService = SoftAssertService.getInstance();
5
7
  this.options = {
@@ -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.8.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/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
@@ -7,10 +7,9 @@ import { enhanceError, enhanceErrorBe, numberError } from './util/formatMessage.
7
7
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8
8
  const asymmetricMatcher = typeof Symbol === 'function' && Symbol.for
9
9
  ? Symbol.for('jest.asymmetricMatcher')
10
- : 1267621;
11
- export function isAsymmeyricMatcher(expected) {
10
+ : 0x13_57_a5;
11
+ export function isAsymmetricMatcher(expected) {
12
12
  return (typeof expected === 'object' &&
13
- typeof expected === 'object' &&
14
13
  expected &&
15
14
  '$$typeof' in expected &&
16
15
  'asymmetricMatch' in expected &&
@@ -18,7 +17,7 @@ export function isAsymmeyricMatcher(expected) {
18
17
  Boolean(expected.asymmetricMatch));
19
18
  }
20
19
  function isStringContainingMatcher(expected) {
21
- return isAsymmeyricMatcher(expected) && ['StringContaining', 'StringNotContaining'].includes(expected.toString());
20
+ return isAsymmetricMatcher(expected) && ['StringContaining', 'StringNotContaining'].includes(expected.toString());
22
21
  }
23
22
  const waitUntil = async (condition, isNot = false, { wait = DEFAULT_OPTIONS.wait, interval = DEFAULT_OPTIONS.interval } = {}) => {
24
23
  if (wait === 0) {
@@ -31,7 +30,6 @@ const waitUntil = async (condition, isNot = false, { wait = DEFAULT_OPTIONS.wait
31
30
  if (Date.now() - start > wait) {
32
31
  throw new Error('timeout');
33
32
  }
34
- error = undefined;
35
33
  try {
36
34
  const result = isNot !== (await condition());
37
35
  error = undefined;
@@ -110,7 +108,7 @@ export const compareText = (actual, expected, { ignoreCase = false, trim = true,
110
108
  : expect.not.stringContaining(expected.sample?.toString().toLowerCase()));
111
109
  }
112
110
  }
113
- if (isAsymmeyricMatcher(expected)) {
111
+ if (isAsymmetricMatcher(expected)) {
114
112
  const result = expected.asymmetricMatch(actual);
115
113
  return {
116
114
  value: actual,
@@ -183,7 +181,7 @@ export const compareTextWithArray = (actual, expectedArray, { ignoreCase = false
183
181
  if (expected instanceof RegExp) {
184
182
  return !!actual.match(expected);
185
183
  }
186
- if (isAsymmeyricMatcher(expected)) {
184
+ if (isAsymmetricMatcher(expected)) {
187
185
  return expected.asymmetricMatch(actual);
188
186
  }
189
187
  if (containing) {
@@ -217,12 +215,12 @@ export const compareObject = (actual, expected) => {
217
215
  result: deepEql(actual, expected),
218
216
  };
219
217
  };
220
- export const compareStyle = async (actualEl, style, { ignoreCase = true, trim = false }) => {
218
+ export const compareStyle = async (actualEl, style, { ignoreCase = false, trim = true, containing = false, atStart = false, atEnd = false, atIndex, replace, }) => {
221
219
  let result = true;
222
220
  const actual = {};
223
221
  for (const key in style) {
224
222
  const css = await actualEl.getCSSProperty(key);
225
- let actualVal = css.value;
223
+ let actualVal = String(css.value || '');
226
224
  let expectedVal = style[key];
227
225
  if (trim) {
228
226
  actualVal = actualVal.trim();
@@ -232,8 +230,31 @@ export const compareStyle = async (actualEl, style, { ignoreCase = true, trim =
232
230
  actualVal = actualVal.toLowerCase();
233
231
  expectedVal = expectedVal.toLowerCase();
234
232
  }
235
- result = result && actualVal === expectedVal;
236
- actual[key] = css.value;
233
+ if (containing) {
234
+ result = actualVal.includes(expectedVal);
235
+ actual[key] = actualVal;
236
+ }
237
+ else if (atStart) {
238
+ result = actualVal.startsWith(expectedVal);
239
+ actual[key] = actualVal;
240
+ }
241
+ else if (atEnd) {
242
+ result = actualVal.endsWith(expectedVal);
243
+ actual[key] = actualVal;
244
+ }
245
+ else if (atIndex) {
246
+ result = actualVal.substring(atIndex, actualVal.length).startsWith(expectedVal);
247
+ actual[key] = actualVal;
248
+ }
249
+ else if (replace) {
250
+ const replacedActual = replaceActual(replace, actualVal);
251
+ result = replacedActual === expectedVal;
252
+ actual[key] = replacedActual;
253
+ }
254
+ else {
255
+ result = result && actualVal === expectedVal;
256
+ actual[key] = css.value;
257
+ }
237
258
  }
238
259
  return {
239
260
  value: actual,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expect-webdriverio",
3
- "version": "5.4.3",
3
+ "version": "5.6.0",
4
4
  "author": "Mykola Grybyk <mykola.grybyk@gmail.com>",
5
5
  "description": "WebdriverIO Assertion Library",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  "exports": {
24
24
  ".": [
25
25
  {
26
- "types": "./types/standalone.d.ts",
26
+ "types": "./types/expect-webdriverio.d.ts",
27
27
  "import": "./lib/index.js"
28
28
  },
29
29
  "./lib/index.js"
@@ -33,54 +33,64 @@
33
33
  "types": "./jest.d.ts"
34
34
  }
35
35
  ],
36
- "./types": "./types/jest-global.d.ts"
36
+ "./jasmine": [
37
+ {
38
+ "types": "./jasmine.d.ts"
39
+ }
40
+ ],
41
+ "./types": "./types/expect-global.d.ts",
42
+ "./expect-global": "./types/expect-global.d.ts"
37
43
  },
38
- "types": "./types/standalone.d.ts",
44
+ "types": "./types/expect-webdriverio.d.ts",
39
45
  "typeScriptVersion": "3.8.3",
40
46
  "engines": {
41
- "node": ">=18 || >=20 || >=22"
47
+ "node": ">=20"
42
48
  },
43
49
  "scripts": {
44
50
  "build": "run-s clean compile",
45
51
  "clean": "run-p clean:*",
46
52
  "clean:build": "rimraf ./lib",
47
- "clean:tests": "rimraf test-types/**/node_modules && rimraf test-types/**/dist",
48
53
  "compile": "tsc --build tsconfig.build.json",
49
- "tsc:root-types": "tsc jasmine.d.ts jest.d.ts",
54
+ "tsc:root-types": "node types-checks-filter-out-node_modules.js",
50
55
  "test": "run-s test:*",
51
56
  "test:tsc": "tsc --project tsconfig.json --noEmit",
52
57
  "test:lint": "eslint .",
53
58
  "test:unit": "vitest --run",
54
- "test:types": "node test-types/copy && npm run ts && npm run clean:tests && npm run tsc:root-types",
55
- "ts": "run-s ts:*",
56
- "ts:default": "cd test-types/default && tsc -p ./tsconfig.json --incremental",
57
- "ts:jest": "cd test-types/jest && tsc -p ./tsconfig.json --incremental",
58
- "ts:jasmine": "cd test-types/jasmine && tsc -p ./tsconfig.json --incremental",
59
+ "test:types": "npm run ts && npm run tsc:root-types",
60
+ "ts": "run-s ts:* ts:*:*",
61
+ "ts:jest:@jest/global": "cd test-types/jest-@jest_global && tsc --project ./tsconfig.json",
62
+ "ts:jest:@types-jest": "cd test-types/jest-@types_jest && tsc --project ./tsconfig.json",
63
+ "ts:mocha": "cd test-types/mocha && tsc --project ./tsconfig.json",
64
+ "ts:jasmine": "cd test-types/jasmine && tsc --project ./tsconfig.json",
65
+ "ts:jasmine-async": "cd test-types/jasmine-async && tsc --project ./tsconfig.json",
59
66
  "watch": "npm run compile -- --watch",
60
67
  "prepare": "husky install"
61
68
  },
62
69
  "dependencies": {
63
- "@vitest/snapshot": "^3.2.4",
70
+ "@vitest/snapshot": "^4.0.16",
64
71
  "deep-eql": "^5.0.2",
65
- "expect": "^30.0.0",
66
- "jest-matcher-utils": "^30.0.0"
72
+ "expect": "^30.2.0",
73
+ "jest-matcher-utils": "^30.2.0"
67
74
  },
68
75
  "devDependencies": {
69
76
  "@types/debug": "^4.1.12",
77
+ "@types/jasmine": "^5.1.8",
70
78
  "@types/jest": "^30.0.0",
71
- "@types/node": "^24.0.3",
72
- "@vitest/coverage-v8": "^3.2.4",
73
- "@wdio/eslint": "^0.1.1",
74
- "@wdio/types": "^9.15.0",
75
- "eslint": "^9.29.0",
79
+ "@types/node": "^24.10.1",
80
+ "@types/mocha": "^10.0.10",
81
+ "@jest/globals": "^30.2.0",
82
+ "@vitest/coverage-v8": "^4.0.16",
83
+ "@wdio/eslint": "^0.1.2",
84
+ "@wdio/types": "^9.20.0",
85
+ "eslint": "^9.39.2",
76
86
  "husky": "^9.1.7",
77
87
  "npm-run-all2": "^8.0.4",
78
- "release-it": "^19.0.3",
79
- "rimraf": "^6.0.1",
88
+ "release-it": "^19.1.0",
89
+ "rimraf": "^6.1.2",
80
90
  "shelljs": "^0.10.0",
81
- "typescript": "^5.8.3",
82
- "vitest": "^3.2.4",
83
- "webdriverio": "^9.15.0"
91
+ "typescript": "^5.9.3",
92
+ "vitest": "^4.0.16",
93
+ "webdriverio": "^9.21.0"
84
94
  },
85
95
  "peerDependencies": {
86
96
  "@wdio/globals": "^9.0.0",
@@ -0,0 +1,15 @@
1
+ /// <reference types="./expect-webdriverio.d.ts"/>
2
+
3
+ /**
4
+ * Global declaration file for WebdriverIO's Expect library to force the expect.
5
+ * Required when used in standalone mode (mocha) or to override the one of Jasmine
6
+ */
7
+
8
+ //// @ts-expect-error: IDE might flags this one but just does be concerned by it. This way the `tsc:root-types` can pass!
9
+ declare const expect: ExpectWebdriverIO.Expect
10
+
11
+ declare namespace NodeJS {
12
+ interface Global {
13
+ expect: ExpectWebdriverIO.Expect
14
+ }
15
+ }