@testspectra/matchers 1.0.41 → 1.0.43
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/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/matchers.d.ts +11 -0
- package/dist/matchers.js +11 -0
- package/dist/proto.d.ts +242 -0
- package/dist/runner/collection.d.ts +76 -0
- package/dist/runner/collection.js +76 -0
- package/dist/runner/single.d.ts +131 -4
- package/dist/runner/single.js +104 -0
- package/dist/spectra.d.ts +194 -4
- package/dist/spectra.js +194 -4
- package/dist/types.d.ts +101 -2
- package/dist/types.js +0 -4
- package/package.json +1 -1
- package/src/index.ts +22 -0
- package/src/matchers.ts +11 -0
- package/src/proto.ts +275 -0
- package/src/runner/collection.ts +80 -0
- package/src/runner/single.ts +137 -2
- package/src/spectra.ts +195 -4
- package/src/types.ts +102 -3
package/src/proto.ts
CHANGED
|
@@ -4,48 +4,323 @@ import { resolveElement } from "./matchers.js";
|
|
|
4
4
|
declare global {
|
|
5
5
|
namespace WebdriverIO {
|
|
6
6
|
interface Element {
|
|
7
|
+
/**
|
|
8
|
+
* Asserts that the element is displayed on the screen and visible to the user.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* await LoginPage.submitButton.shouldBeVisible();
|
|
13
|
+
* ```
|
|
14
|
+
* @returns The element instance for chaining.
|
|
15
|
+
*/
|
|
7
16
|
shouldBeVisible(): Promise<Element>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Asserts that the element is NOT displayed or is hidden from view.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* await LoginPage.errorMessage.shouldNotBeVisible();
|
|
24
|
+
* ```
|
|
25
|
+
* @returns The element instance for chaining.
|
|
26
|
+
*/
|
|
8
27
|
shouldNotBeVisible(): Promise<Element>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Asserts that the element exists in the DOM/UI hierarchy.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* await LoginPage.rememberMeCheckbox.shouldExist();
|
|
35
|
+
* ```
|
|
36
|
+
* @returns The element instance for chaining.
|
|
37
|
+
*/
|
|
9
38
|
shouldExist(): Promise<Element>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Asserts that the element does NOT exist in the DOM/UI hierarchy.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* await LoginPage.loadingSpinner.shouldNotExist();
|
|
46
|
+
* ```
|
|
47
|
+
* @returns The element instance for chaining.
|
|
48
|
+
*/
|
|
10
49
|
shouldNotExist(): Promise<Element>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Asserts that the element is enabled for interaction.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* await LoginPage.loginButton.shouldBeEnabled();
|
|
57
|
+
* ```
|
|
58
|
+
* @returns The element instance for chaining.
|
|
59
|
+
*/
|
|
11
60
|
shouldBeEnabled(): Promise<Element>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Asserts that the element is disabled (cannot be interacted with).
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* await LoginPage.disabledSubmit.shouldBeDisabled();
|
|
68
|
+
* ```
|
|
69
|
+
* @returns The element instance for chaining.
|
|
70
|
+
*/
|
|
12
71
|
shouldBeDisabled(): Promise<Element>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Asserts that the form element (radio button, checkbox, option) is selected.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* await SettingsPage.darkModeRadio.shouldBeSelected();
|
|
79
|
+
* ```
|
|
80
|
+
* @returns The element instance for chaining.
|
|
81
|
+
*/
|
|
13
82
|
shouldBeSelected(): Promise<Element>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Asserts that the checkbox or radio element is checked.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* await SettingsPage.termsCheckbox.shouldBeChecked();
|
|
90
|
+
* ```
|
|
91
|
+
* @returns The element instance for chaining.
|
|
92
|
+
*/
|
|
14
93
|
shouldBeChecked(): Promise<Element>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Asserts that the input element has the exact given value.
|
|
97
|
+
*
|
|
98
|
+
* @param expectedValue - The exact expected value.
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* await LoginPage.usernameInput.shouldHaveValue("admin@test.com");
|
|
102
|
+
* ```
|
|
103
|
+
* @returns The element instance for chaining.
|
|
104
|
+
*/
|
|
15
105
|
shouldHaveValue(expectedValue: string): Promise<Element>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Asserts that the input element's value contains the given substring.
|
|
109
|
+
*
|
|
110
|
+
* @param expectedValue - Substring expected to be present in the value.
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* await LoginPage.tokenInput.shouldContainValue("JWT_");
|
|
114
|
+
* ```
|
|
115
|
+
* @returns The element instance for chaining.
|
|
116
|
+
*/
|
|
16
117
|
shouldContainValue(expectedValue: string): Promise<Element>;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Asserts that the element's text content matches the exact expected text.
|
|
121
|
+
*
|
|
122
|
+
* @param expectedText - The exact expected text content.
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* await LoginPage.headerTitle.shouldHaveText("Welcome to TestSpectra");
|
|
126
|
+
* ```
|
|
127
|
+
* @returns The element instance for chaining.
|
|
128
|
+
*/
|
|
17
129
|
shouldHaveText(expectedText: string): Promise<Element>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Asserts that the element's text content contains the expected substring.
|
|
133
|
+
*
|
|
134
|
+
* @param expectedText - Substring expected to be within the element text.
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* await LoginPage.welcomeBanner.shouldContainText("Welcome");
|
|
138
|
+
* ```
|
|
139
|
+
* @returns The element instance for chaining.
|
|
140
|
+
*/
|
|
18
141
|
shouldContainText(expectedText: string): Promise<Element>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Asserts that the element has the specified CSS class.
|
|
145
|
+
*
|
|
146
|
+
* @param className - Expected CSS class name.
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts
|
|
149
|
+
* await NavigationBar.homeTab.shouldHaveClass("is-active");
|
|
150
|
+
* ```
|
|
151
|
+
* @returns The element instance for chaining.
|
|
152
|
+
*/
|
|
19
153
|
shouldHaveClass(className: string): Promise<Element>;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Asserts that the element has the specified attribute, optionally checking its exact value.
|
|
157
|
+
*
|
|
158
|
+
* @param attributeName - Name of the attribute (e.g. `aria-label`, `disabled`, `href`).
|
|
159
|
+
* @param expectedValue - Optional expected value of the attribute.
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* await NavigationBar.logoLink.shouldHaveAttribute("href", "/dashboard");
|
|
163
|
+
* await NavigationBar.cartButton.shouldHaveAttribute("aria-expanded");
|
|
164
|
+
* ```
|
|
165
|
+
* @returns The element instance for chaining.
|
|
166
|
+
*/
|
|
20
167
|
shouldHaveAttribute(attributeName: string, expectedValue?: string): Promise<Element>;
|
|
21
168
|
}
|
|
22
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Optional settings for HTTP network interception responses.
|
|
172
|
+
*/
|
|
173
|
+
export interface InterceptFixtureOptions {
|
|
174
|
+
/** HTTP status code to return in the mocked response (default: 200) */
|
|
175
|
+
statusCode?: number;
|
|
176
|
+
/** Custom HTTP response headers */
|
|
177
|
+
headers?: Record<string, string>;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Structured mock payload object with optional status code and headers.
|
|
182
|
+
*/
|
|
183
|
+
export interface InterceptFixtureObject<TData = unknown> {
|
|
184
|
+
/** HTTP status code */
|
|
185
|
+
statusCode?: number;
|
|
186
|
+
/** Response body payload */
|
|
187
|
+
body: TData;
|
|
188
|
+
/** Custom HTTP response headers */
|
|
189
|
+
headers?: Record<string, string>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Input payload for API mocking: JSON object, string, or structured fixture object.
|
|
194
|
+
*/
|
|
195
|
+
export type InterceptInput<TData = unknown> =
|
|
196
|
+
| InterceptFixtureObject<TData>
|
|
197
|
+
| TData
|
|
198
|
+
| string;
|
|
199
|
+
|
|
200
|
+
interface Mock {
|
|
201
|
+
/**
|
|
202
|
+
* Dynamically set or change the fixture response for this mock instance.
|
|
203
|
+
* Supports fixture file paths, structured `{ statusCode, body, headers }` objects, or raw data.
|
|
204
|
+
*
|
|
205
|
+
* @param fixture - Data payload or Fixture reference.
|
|
206
|
+
* @param options - Optional status code and header overrides.
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* const mock = await browser.intercept("/api/user", "GET");
|
|
210
|
+
* await mock.respondWith({ name: "Admin", role: "superadmin" });
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
respondWith<TData = unknown>(
|
|
214
|
+
fixture: InterceptInput<TData>,
|
|
215
|
+
options?: InterceptFixtureOptions
|
|
216
|
+
): Promise<void>;
|
|
217
|
+
}
|
|
218
|
+
|
|
23
219
|
interface Browser {
|
|
220
|
+
/**
|
|
221
|
+
* Intercepts and mocks network API requests matching the specified endpoint.
|
|
222
|
+
* Supports automatic base URL resolution and TestSpectra JSON Fixtures.
|
|
223
|
+
*
|
|
224
|
+
* @param path - URL path or route to intercept (e.g. `"/api/users"` or `"https://api.example.com/v1/*"`).
|
|
225
|
+
* @param method - HTTP request method (`"GET"`, `"POST"`, `"PUT"`, `"DELETE"`, `"PATCH"`).
|
|
226
|
+
* @param fixture - Optional initial response payload or Fixture object.
|
|
227
|
+
* @param options - Optional status code and header configuration.
|
|
228
|
+
* @example
|
|
229
|
+
* ```ts
|
|
230
|
+
* // Intercept with JSON Fixture
|
|
231
|
+
* await browser.intercept("/api/status", "GET", Fixture.userData);
|
|
232
|
+
*
|
|
233
|
+
* // Intercept with custom payload & status code
|
|
234
|
+
* await browser.intercept("/api/auth/login", "POST", { token: "xyz" }, { statusCode: 200 });
|
|
235
|
+
* ```
|
|
236
|
+
* @returns `Mock` instance allowing dynamic response modification.
|
|
237
|
+
*/
|
|
238
|
+
intercept<TData = unknown>(
|
|
239
|
+
path: string,
|
|
240
|
+
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH",
|
|
241
|
+
fixture?: InterceptInput<TData>,
|
|
242
|
+
options?: InterceptFixtureOptions
|
|
243
|
+
): Promise<Mock>;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Asserts that the current browser page URL exactly matches the expected URL.
|
|
247
|
+
*
|
|
248
|
+
* @param expectedUrl - The exact URL expected.
|
|
249
|
+
* @example
|
|
250
|
+
* ```ts
|
|
251
|
+
* await browser.shouldHaveUrl("https://app.example.com/dashboard");
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
24
254
|
shouldHaveUrl(expectedUrl: string): Promise<void>;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Asserts that the current browser page URL contains the given substring.
|
|
258
|
+
*
|
|
259
|
+
* @param expectedUrl - Substring expected in the current URL.
|
|
260
|
+
* @example
|
|
261
|
+
* ```ts
|
|
262
|
+
* await browser.shouldContainUrl("/dashboard");
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
25
265
|
shouldContainUrl(expectedUrl: string): Promise<void>;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Asserts that the current browser page title matches the expected title.
|
|
269
|
+
*
|
|
270
|
+
* @param expectedTitle - The exact title expected.
|
|
271
|
+
* @example
|
|
272
|
+
* ```ts
|
|
273
|
+
* await browser.shouldHaveTitle("Dashboard - TestSpectra");
|
|
274
|
+
* ```
|
|
275
|
+
*/
|
|
26
276
|
shouldHaveTitle(expectedTitle: string): Promise<void>;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Asserts that the current browser page title contains the expected substring.
|
|
280
|
+
*
|
|
281
|
+
* @param expectedTitle - Substring expected in the title.
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* await browser.shouldContainTitle("Dashboard");
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
27
287
|
shouldContainTitle(expectedTitle: string): Promise<void>;
|
|
28
288
|
}
|
|
29
289
|
}
|
|
30
290
|
|
|
31
291
|
interface Promise<T> {
|
|
292
|
+
/** Asserts that the element promise resolves to a visible element. */
|
|
32
293
|
shouldBeVisible(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
294
|
+
/** Asserts that the element promise resolves to a hidden/non-visible element. */
|
|
33
295
|
shouldNotBeVisible(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
296
|
+
/** Asserts that the element promise resolves to an existing element in the DOM. */
|
|
34
297
|
shouldExist(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
298
|
+
/** Asserts that the element promise resolves to an element that does not exist in the DOM. */
|
|
35
299
|
shouldNotExist(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
300
|
+
/** Asserts that the element promise resolves to an enabled element. */
|
|
36
301
|
shouldBeEnabled(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
302
|
+
/** Asserts that the element promise resolves to a disabled element. */
|
|
37
303
|
shouldBeDisabled(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
304
|
+
/** Asserts that the element promise resolves to a selected element. */
|
|
38
305
|
shouldBeSelected(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
306
|
+
/** Asserts that the element promise resolves to a checked checkbox or radio. */
|
|
39
307
|
shouldBeChecked(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
|
|
308
|
+
/** Asserts that the element promise resolves to an element with the exact value. */
|
|
40
309
|
shouldHaveValue(this: Promise<WebdriverIO.Element>, expectedValue: string): Promise<WebdriverIO.Element>;
|
|
310
|
+
/** Asserts that the element promise resolves to an element whose value contains the substring. */
|
|
41
311
|
shouldContainValue(this: Promise<WebdriverIO.Element>, expectedValue: string): Promise<WebdriverIO.Element>;
|
|
312
|
+
/** Asserts that the element promise resolves to an element with the exact text content. */
|
|
42
313
|
shouldHaveText(this: Promise<WebdriverIO.Element>, expectedText: string): Promise<WebdriverIO.Element>;
|
|
314
|
+
/** Asserts that the element promise resolves to an element whose text contains the substring. */
|
|
43
315
|
shouldContainText(this: Promise<WebdriverIO.Element>, expectedText: string): Promise<WebdriverIO.Element>;
|
|
316
|
+
/** Asserts that the element promise resolves to an element having the CSS class. */
|
|
44
317
|
shouldHaveClass(this: Promise<WebdriverIO.Element>, className: string): Promise<WebdriverIO.Element>;
|
|
318
|
+
/** Asserts that the element promise resolves to an element having the attribute. */
|
|
45
319
|
shouldHaveAttribute(this: Promise<WebdriverIO.Element>, attributeName: string, expectedValue?: string): Promise<WebdriverIO.Element>;
|
|
46
320
|
}
|
|
47
321
|
}
|
|
48
322
|
|
|
323
|
+
|
|
49
324
|
/**
|
|
50
325
|
* Install direct callable assertion methods onto WebdriverIO browser/element and Promise prototypes.
|
|
51
326
|
*/
|
package/src/runner/collection.ts
CHANGED
|
@@ -2,11 +2,35 @@ import { MultiElementMatcher } from "../types.js";
|
|
|
2
2
|
import { executeMultiMatcher } from "../matchers.js";
|
|
3
3
|
import { SingleElementRunner } from "./single.js";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Representation of a queued assertion against an element collection.
|
|
7
|
+
*/
|
|
5
8
|
type CollectionAssertion = {
|
|
6
9
|
matcher: MultiElementMatcher;
|
|
7
10
|
args: any[];
|
|
8
11
|
};
|
|
9
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Fluent assertion, filtering, and iteration runner for multi-element collections.
|
|
15
|
+
*
|
|
16
|
+
* Implements `PromiseLike<void>`, allowing assertions across matching elements,
|
|
17
|
+
* array index access (`.eq()`, `.first()`, `.last()`), and sequential iteration (`.each()`).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* // Assert collection size
|
|
22
|
+
* await Spectra.getAll(".cart-item").should("have.length", 3);
|
|
23
|
+
*
|
|
24
|
+
* // Target specific element from collection
|
|
25
|
+
* await Spectra.getAll(".todo-item").first().click();
|
|
26
|
+
* await Spectra.getAll(".todo-item").eq(2).should("have.text", "Buy Milk");
|
|
27
|
+
*
|
|
28
|
+
* // Iteration
|
|
29
|
+
* await Spectra.getAll(".nav-link").each(async (link, i) => {
|
|
30
|
+
* await link.should("be.visible");
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
10
34
|
export class MultiElementRunner implements PromiseLike<void> {
|
|
11
35
|
private _selector: string;
|
|
12
36
|
private _assertions: CollectionAssertion[] = [];
|
|
@@ -17,6 +41,18 @@ export class MultiElementRunner implements PromiseLike<void> {
|
|
|
17
41
|
|
|
18
42
|
// --- Collection Assertions ---
|
|
19
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Queues an assertion matcher against the multi-element collection.
|
|
46
|
+
*
|
|
47
|
+
* @param matcher - Multi-element matcher string (e.g. `'have.length'`, `'be.empty'`).
|
|
48
|
+
* @param args - Expected values or limits for the matcher.
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* await Spectra.getAll(".product-card").should("have.length.greaterThan", 0);
|
|
52
|
+
* await Spectra.getAll(".error-badge").should("be.empty");
|
|
53
|
+
* ```
|
|
54
|
+
* @returns Current collection runner instance for chaining.
|
|
55
|
+
*/
|
|
20
56
|
should(matcher: MultiElementMatcher, ...args: any[]): this {
|
|
21
57
|
this._assertions.push({ matcher, args });
|
|
22
58
|
return this;
|
|
@@ -24,15 +60,43 @@ export class MultiElementRunner implements PromiseLike<void> {
|
|
|
24
60
|
|
|
25
61
|
// --- Item Navigation ---
|
|
26
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Returns a `SingleElementRunner` targeting the element at the specified 0-based index.
|
|
65
|
+
*
|
|
66
|
+
* @param index - 0-based index of the element within the matched collection.
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* await Spectra.getAll("li.menu-item").eq(1).click();
|
|
70
|
+
* ```
|
|
71
|
+
* @returns `SingleElementRunner` for the indexed element.
|
|
72
|
+
*/
|
|
27
73
|
eq(index: number): SingleElementRunner {
|
|
28
74
|
const indexedSelector = `(${this._selector})[${index + 1}]`;
|
|
29
75
|
return new SingleElementRunner(indexedSelector);
|
|
30
76
|
}
|
|
31
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Returns a `SingleElementRunner` targeting the first element in the collection (`index = 0`).
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* await Spectra.getAll(".result-item").first().click();
|
|
84
|
+
* ```
|
|
85
|
+
* @returns `SingleElementRunner` for the first element.
|
|
86
|
+
*/
|
|
32
87
|
first(): SingleElementRunner {
|
|
33
88
|
return this.eq(0);
|
|
34
89
|
}
|
|
35
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Returns a `SingleElementRunner` targeting the last element in the collection.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* await Spectra.getAll(".step-indicator").last().should("have.class", "current");
|
|
97
|
+
* ```
|
|
98
|
+
* @returns `SingleElementRunner` for the last element.
|
|
99
|
+
*/
|
|
36
100
|
last(): SingleElementRunner {
|
|
37
101
|
const indexedSelector = `(${this._selector})[last()]`;
|
|
38
102
|
return new SingleElementRunner(indexedSelector);
|
|
@@ -40,6 +104,17 @@ export class MultiElementRunner implements PromiseLike<void> {
|
|
|
40
104
|
|
|
41
105
|
// --- Iteration Callback ---
|
|
42
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Iterates asynchronously through every matched element in the collection sequentially.
|
|
109
|
+
*
|
|
110
|
+
* @param callback - Async function called for each element with `(runner, index)`.
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* await Spectra.getAll(".checkbox").each(async (item, index) => {
|
|
114
|
+
* await item.should("be.visible");
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
43
118
|
async each(
|
|
44
119
|
callback: (el: SingleElementRunner, index: number) => Promise<void>
|
|
45
120
|
): Promise<void> {
|
|
@@ -53,6 +128,10 @@ export class MultiElementRunner implements PromiseLike<void> {
|
|
|
53
128
|
|
|
54
129
|
// --- Execution when awaited ---
|
|
55
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Standard Promise `then` implementation.
|
|
133
|
+
* Executes all queued collection assertions sequentially when awaited.
|
|
134
|
+
*/
|
|
56
135
|
async then<TResult1 = void, TResult2 = never>(
|
|
57
136
|
onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null,
|
|
58
137
|
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
|
@@ -71,3 +150,4 @@ export class MultiElementRunner implements PromiseLike<void> {
|
|
|
71
150
|
}
|
|
72
151
|
}
|
|
73
152
|
}
|
|
153
|
+
|
package/src/runner/single.ts
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
|
-
import { SingleElementMatcher, ElementTarget } from "../types.js";
|
|
1
|
+
import { SingleElementMatcher, ElementTarget, TypeOptions } from "../types.js";
|
|
2
2
|
import { executeSingleMatcher, resolveElement } from "../matchers.js";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Representation of a queued assertion against an element or page.
|
|
6
|
+
*/
|
|
4
7
|
type AssertionItem = {
|
|
5
8
|
target?: ElementTarget;
|
|
6
9
|
matcher: SingleElementMatcher;
|
|
7
10
|
args: any[];
|
|
8
11
|
};
|
|
9
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Fluent interaction and assertion runner for a single element or browser context.
|
|
15
|
+
*
|
|
16
|
+
* Implements `PromiseLike<void>`, allowing it to be awaited directly or chained with
|
|
17
|
+
* multiple actions and `.should(...)` assertions.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* // Direct action + chained assertion
|
|
22
|
+
* await Spectra.get("#submit-btn")
|
|
23
|
+
* .click()
|
|
24
|
+
* .should("not.be.visible");
|
|
25
|
+
*
|
|
26
|
+
* // Query + multiple assertions
|
|
27
|
+
* await Spectra.get(LoginPage.usernameInput)
|
|
28
|
+
* .should("be.visible")
|
|
29
|
+
* .should("be.enabled")
|
|
30
|
+
* .should("have.value", "admin");
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
10
33
|
export class SingleElementRunner implements PromiseLike<void> {
|
|
11
34
|
private _target: ElementTarget | undefined;
|
|
12
35
|
private _action: (() => Promise<any>) | null = null;
|
|
@@ -19,6 +42,15 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
19
42
|
|
|
20
43
|
// --- Chained Actions on current target ---
|
|
21
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Clicks on the target element.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* await Spectra.get("#login-btn").click();
|
|
51
|
+
* ```
|
|
52
|
+
* @returns Current runner instance for method chaining.
|
|
53
|
+
*/
|
|
22
54
|
click(): this {
|
|
23
55
|
const target = this.requireTarget("click");
|
|
24
56
|
this._action = async () => {
|
|
@@ -28,6 +60,15 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
28
60
|
return this;
|
|
29
61
|
}
|
|
30
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Double-clicks on the target element.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* await Spectra.get(".file-row").doubleClick();
|
|
69
|
+
* ```
|
|
70
|
+
* @returns Current runner instance for method chaining.
|
|
71
|
+
*/
|
|
31
72
|
doubleClick(): this {
|
|
32
73
|
const target = this.requireTarget("doubleClick");
|
|
33
74
|
this._action = async () => {
|
|
@@ -37,6 +78,16 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
37
78
|
return this;
|
|
38
79
|
}
|
|
39
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Performs a long-press touch or hold gesture on the target element.
|
|
83
|
+
*
|
|
84
|
+
* @param durationMs - Duration in milliseconds to hold (default: 1000).
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* await Spectra.get("#context-menu-trigger").longPress(1500);
|
|
88
|
+
* ```
|
|
89
|
+
* @returns Current runner instance for method chaining.
|
|
90
|
+
*/
|
|
40
91
|
longPress(durationMs = 1000): this {
|
|
41
92
|
const target = this.requireTarget("longPress");
|
|
42
93
|
this._action = async () => {
|
|
@@ -53,7 +104,18 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
53
104
|
return this;
|
|
54
105
|
}
|
|
55
106
|
|
|
56
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Types string value into the target input element.
|
|
109
|
+
*
|
|
110
|
+
* @param value - Text string to type into the element.
|
|
111
|
+
* @param options - Optional typing options (e.g. `clearFirst: true`).
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* await Spectra.get("#search-input").type("iPhone 15", { clearFirst: true });
|
|
115
|
+
* ```
|
|
116
|
+
* @returns Current runner instance for method chaining.
|
|
117
|
+
*/
|
|
118
|
+
type(value: string, options?: TypeOptions): this {
|
|
57
119
|
const target = this.requireTarget("type");
|
|
58
120
|
this._action = async () => {
|
|
59
121
|
const el = await resolveElement(target);
|
|
@@ -65,6 +127,15 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
65
127
|
return this;
|
|
66
128
|
}
|
|
67
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Clears the current value of the target input element.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* await Spectra.get("#search-input").clear();
|
|
136
|
+
* ```
|
|
137
|
+
* @returns Current runner instance for method chaining.
|
|
138
|
+
*/
|
|
68
139
|
clear(): this {
|
|
69
140
|
const target = this.requireTarget("clear");
|
|
70
141
|
this._action = async () => {
|
|
@@ -74,6 +145,16 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
74
145
|
return this;
|
|
75
146
|
}
|
|
76
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Selects an option from a `<select>` dropdown by its visible text.
|
|
150
|
+
*
|
|
151
|
+
* @param value - Visible text of the option to select.
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* await Spectra.get("#country-select").select("United States");
|
|
155
|
+
* ```
|
|
156
|
+
* @returns Current runner instance for method chaining.
|
|
157
|
+
*/
|
|
77
158
|
select(value: string): this {
|
|
78
159
|
const target = this.requireTarget("select");
|
|
79
160
|
this._action = async () => {
|
|
@@ -83,6 +164,15 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
83
164
|
return this;
|
|
84
165
|
}
|
|
85
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Moves the mouse cursor over the target element (hover).
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```ts
|
|
172
|
+
* await Spectra.get("#dropdown-menu-trigger").hover();
|
|
173
|
+
* ```
|
|
174
|
+
* @returns Current runner instance for method chaining.
|
|
175
|
+
*/
|
|
86
176
|
hover(): this {
|
|
87
177
|
const target = this.requireTarget("hover");
|
|
88
178
|
this._action = async () => {
|
|
@@ -92,6 +182,16 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
92
182
|
return this;
|
|
93
183
|
}
|
|
94
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Waits for the target element to become displayed in the DOM.
|
|
187
|
+
*
|
|
188
|
+
* @param timeoutMs - Maximum duration in milliseconds to wait (default: 10000).
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* await Spectra.get("#modal-dialog").waitForElement(5000);
|
|
192
|
+
* ```
|
|
193
|
+
* @returns Current runner instance for method chaining.
|
|
194
|
+
*/
|
|
95
195
|
waitForElement(timeoutMs = 10000): this {
|
|
96
196
|
const target = this.requireTarget("waitForElement");
|
|
97
197
|
this._action = async () => {
|
|
@@ -103,8 +203,35 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
103
203
|
|
|
104
204
|
// --- Fluent Assertion Matchers ---
|
|
105
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Queues an assertion matcher against the current target element or page.
|
|
208
|
+
*
|
|
209
|
+
* @param matcher - Single element matcher string (e.g. `'be.visible'`, `'have.text'`).
|
|
210
|
+
* @param args - Additional parameters for the matcher (e.g. expected text or value).
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* await Spectra.get("#status-badge").should("be.visible");
|
|
214
|
+
* await Spectra.get("#username").should("have.value", "alice");
|
|
215
|
+
* await Spectra.get("#banner").should("have.class", "alert-success");
|
|
216
|
+
* ```
|
|
217
|
+
* @returns Current runner instance for method chaining.
|
|
218
|
+
*/
|
|
106
219
|
should(matcher: SingleElementMatcher, ...args: any[]): this;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Queues an assertion matcher targeting a specific element.
|
|
223
|
+
*
|
|
224
|
+
* @param target - Custom element target for this specific assertion.
|
|
225
|
+
* @param matcher - Single element matcher string.
|
|
226
|
+
* @param args - Additional parameters for the matcher.
|
|
227
|
+
* @example
|
|
228
|
+
* ```ts
|
|
229
|
+
* await Spectra.should(LoginPage.submitBtn, "be.enabled");
|
|
230
|
+
* ```
|
|
231
|
+
* @returns Current runner instance for method chaining.
|
|
232
|
+
*/
|
|
107
233
|
should(target: ElementTarget, matcher: SingleElementMatcher, ...args: any[]): this;
|
|
234
|
+
|
|
108
235
|
should(a: ElementTarget | SingleElementMatcher, b?: any, ...rest: any[]): this {
|
|
109
236
|
const isFirstArgMatcher =
|
|
110
237
|
typeof a === "string" &&
|
|
@@ -136,6 +263,10 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
136
263
|
|
|
137
264
|
// --- Execution when awaited ---
|
|
138
265
|
|
|
266
|
+
/**
|
|
267
|
+
* Standard Promise `then` implementation.
|
|
268
|
+
* Executes queued action first (if any), followed sequentially by all queued assertions.
|
|
269
|
+
*/
|
|
139
270
|
async then<TResult1 = void, TResult2 = never>(
|
|
140
271
|
onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null,
|
|
141
272
|
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
|
@@ -157,6 +288,9 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
157
288
|
}
|
|
158
289
|
}
|
|
159
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Helper that throws an error if an action is called without a defined target.
|
|
293
|
+
*/
|
|
160
294
|
private requireTarget(actionName: string): ElementTarget {
|
|
161
295
|
if (!this._target) {
|
|
162
296
|
throw new Error(`Cannot execute '${actionName}' without specifying an element target.`);
|
|
@@ -164,3 +298,4 @@ export class SingleElementRunner implements PromiseLike<void> {
|
|
|
164
298
|
return this._target;
|
|
165
299
|
}
|
|
166
300
|
}
|
|
301
|
+
|