@testspectra/matchers 1.0.41 → 1.0.42

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 CHANGED
@@ -1,3 +1,23 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * # @testspectra/matchers
4
+ *
5
+ * Cross-platform action commands, fluent runners, and callable assertion matchers for TestSpectra.
6
+ *
7
+ * ## Features:
8
+ * - **`Spectra`**: Unified automation API (`Spectra.get()`, `Spectra.getAll()`, `Spectra.click()`, `Spectra.type()`, etc.)
9
+ * - **`SingleElementRunner`**: Fluent interaction & assertion runner for single element targets
10
+ * - **`MultiElementRunner`**: Fluent assertion & traversal runner for multi-element collections
11
+ * - **Callable Matchers**: Ambient prototypes for WebdriverIO Element & Browser (`.shouldBeVisible()`, `.shouldHaveText()`, etc.)
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { Spectra } from "@testspectra/matchers";
16
+ *
17
+ * await Spectra.get("#login-btn").click().should("not.be.visible");
18
+ * await Spectra.getAll(".list-item").should("have.length.greaterThan", 0);
19
+ * ```
20
+ */
1
21
  export * from "./types.js";
2
22
  export * from "./matchers.js";
3
23
  export * from "./runner/single.js";
package/dist/index.js CHANGED
@@ -1,3 +1,23 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * # @testspectra/matchers
4
+ *
5
+ * Cross-platform action commands, fluent runners, and callable assertion matchers for TestSpectra.
6
+ *
7
+ * ## Features:
8
+ * - **`Spectra`**: Unified automation API (`Spectra.get()`, `Spectra.getAll()`, `Spectra.click()`, `Spectra.type()`, etc.)
9
+ * - **`SingleElementRunner`**: Fluent interaction & assertion runner for single element targets
10
+ * - **`MultiElementRunner`**: Fluent assertion & traversal runner for multi-element collections
11
+ * - **Callable Matchers**: Ambient prototypes for WebdriverIO Element & Browser (`.shouldBeVisible()`, `.shouldHaveText()`, etc.)
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { Spectra } from "@testspectra/matchers";
16
+ *
17
+ * await Spectra.get("#login-btn").click().should("not.be.visible");
18
+ * await Spectra.getAll(".list-item").should("have.length.greaterThan", 0);
19
+ * ```
20
+ */
1
21
  export * from "./types.js";
2
22
  export * from "./matchers.js";
3
23
  export * from "./runner/single.js";
@@ -2,13 +2,24 @@ import { SingleElementMatcher, MultiElementMatcher, ElementTarget } from "./type
2
2
  /**
3
3
  * Resolves an ElementTarget (selector string, WebdriverIO.Element, or ChainablePromiseElement)
4
4
  * to an actionable WebdriverIO.Element.
5
+ *
6
+ * @param target - Selector string or element instance.
7
+ * @returns Resolved WebdriverIO.Element instance.
5
8
  */
6
9
  export declare function resolveElement(target: ElementTarget): Promise<WebdriverIO.Element>;
7
10
  /**
8
11
  * Executes a single element matcher against the WebdriverIO browser / element context.
12
+ *
13
+ * @param target - Optional element target (not required for browser-level assertions).
14
+ * @param matcher - Single element matcher string.
15
+ * @param args - Arguments passed to the matcher.
9
16
  */
10
17
  export declare function executeSingleMatcher(target: ElementTarget | undefined, matcher: SingleElementMatcher, args: any[]): Promise<void>;
11
18
  /**
12
19
  * Executes a multi-element collection matcher against WebdriverIO $$.
20
+ *
21
+ * @param selector - CSS/XPath selector for the collection.
22
+ * @param matcher - Multi-element matcher string.
23
+ * @param args - Expected values or count limits.
13
24
  */
14
25
  export declare function executeMultiMatcher(selector: string, matcher: MultiElementMatcher, args: any[]): Promise<void>;
package/dist/matchers.js CHANGED
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Resolves an ElementTarget (selector string, WebdriverIO.Element, or ChainablePromiseElement)
3
3
  * to an actionable WebdriverIO.Element.
4
+ *
5
+ * @param target - Selector string or element instance.
6
+ * @returns Resolved WebdriverIO.Element instance.
4
7
  */
5
8
  export async function resolveElement(target) {
6
9
  if (typeof target === "string") {
@@ -12,6 +15,10 @@ export async function resolveElement(target) {
12
15
  }
13
16
  /**
14
17
  * Executes a single element matcher against the WebdriverIO browser / element context.
18
+ *
19
+ * @param target - Optional element target (not required for browser-level assertions).
20
+ * @param matcher - Single element matcher string.
21
+ * @param args - Arguments passed to the matcher.
15
22
  */
16
23
  export async function executeSingleMatcher(target, matcher, args) {
17
24
  const isBrowserLevel = matcher === "have.url" ||
@@ -92,6 +99,10 @@ export async function executeSingleMatcher(target, matcher, args) {
92
99
  }
93
100
  /**
94
101
  * Executes a multi-element collection matcher against WebdriverIO $$.
102
+ *
103
+ * @param selector - CSS/XPath selector for the collection.
104
+ * @param matcher - Multi-element matcher string.
105
+ * @param args - Expected values or count limits.
95
106
  */
96
107
  export async function executeMultiMatcher(selector, matcher, args) {
97
108
  const elements = await $$(selector);
package/dist/proto.d.ts CHANGED
@@ -1,42 +1,284 @@
1
1
  declare global {
2
2
  namespace WebdriverIO {
3
3
  interface Element {
4
+ /**
5
+ * Asserts that the element is displayed on the screen and visible to the user.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * await LoginPage.submitButton.shouldBeVisible();
10
+ * ```
11
+ * @returns The element instance for chaining.
12
+ */
4
13
  shouldBeVisible(): Promise<Element>;
14
+ /**
15
+ * Asserts that the element is NOT displayed or is hidden from view.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * await LoginPage.errorMessage.shouldNotBeVisible();
20
+ * ```
21
+ * @returns The element instance for chaining.
22
+ */
5
23
  shouldNotBeVisible(): Promise<Element>;
24
+ /**
25
+ * Asserts that the element exists in the DOM/UI hierarchy.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * await LoginPage.rememberMeCheckbox.shouldExist();
30
+ * ```
31
+ * @returns The element instance for chaining.
32
+ */
6
33
  shouldExist(): Promise<Element>;
34
+ /**
35
+ * Asserts that the element does NOT exist in the DOM/UI hierarchy.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * await LoginPage.loadingSpinner.shouldNotExist();
40
+ * ```
41
+ * @returns The element instance for chaining.
42
+ */
7
43
  shouldNotExist(): Promise<Element>;
44
+ /**
45
+ * Asserts that the element is enabled for interaction.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * await LoginPage.loginButton.shouldBeEnabled();
50
+ * ```
51
+ * @returns The element instance for chaining.
52
+ */
8
53
  shouldBeEnabled(): Promise<Element>;
54
+ /**
55
+ * Asserts that the element is disabled (cannot be interacted with).
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * await LoginPage.disabledSubmit.shouldBeDisabled();
60
+ * ```
61
+ * @returns The element instance for chaining.
62
+ */
9
63
  shouldBeDisabled(): Promise<Element>;
64
+ /**
65
+ * Asserts that the form element (radio button, checkbox, option) is selected.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * await SettingsPage.darkModeRadio.shouldBeSelected();
70
+ * ```
71
+ * @returns The element instance for chaining.
72
+ */
10
73
  shouldBeSelected(): Promise<Element>;
74
+ /**
75
+ * Asserts that the checkbox or radio element is checked.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * await SettingsPage.termsCheckbox.shouldBeChecked();
80
+ * ```
81
+ * @returns The element instance for chaining.
82
+ */
11
83
  shouldBeChecked(): Promise<Element>;
84
+ /**
85
+ * Asserts that the input element has the exact given value.
86
+ *
87
+ * @param expectedValue - The exact expected value.
88
+ * @example
89
+ * ```ts
90
+ * await LoginPage.usernameInput.shouldHaveValue("admin@test.com");
91
+ * ```
92
+ * @returns The element instance for chaining.
93
+ */
12
94
  shouldHaveValue(expectedValue: string): Promise<Element>;
95
+ /**
96
+ * Asserts that the input element's value contains the given substring.
97
+ *
98
+ * @param expectedValue - Substring expected to be present in the value.
99
+ * @example
100
+ * ```ts
101
+ * await LoginPage.tokenInput.shouldContainValue("JWT_");
102
+ * ```
103
+ * @returns The element instance for chaining.
104
+ */
13
105
  shouldContainValue(expectedValue: string): Promise<Element>;
106
+ /**
107
+ * Asserts that the element's text content matches the exact expected text.
108
+ *
109
+ * @param expectedText - The exact expected text content.
110
+ * @example
111
+ * ```ts
112
+ * await LoginPage.headerTitle.shouldHaveText("Welcome to TestSpectra");
113
+ * ```
114
+ * @returns The element instance for chaining.
115
+ */
14
116
  shouldHaveText(expectedText: string): Promise<Element>;
117
+ /**
118
+ * Asserts that the element's text content contains the expected substring.
119
+ *
120
+ * @param expectedText - Substring expected to be within the element text.
121
+ * @example
122
+ * ```ts
123
+ * await LoginPage.welcomeBanner.shouldContainText("Welcome");
124
+ * ```
125
+ * @returns The element instance for chaining.
126
+ */
15
127
  shouldContainText(expectedText: string): Promise<Element>;
128
+ /**
129
+ * Asserts that the element has the specified CSS class.
130
+ *
131
+ * @param className - Expected CSS class name.
132
+ * @example
133
+ * ```ts
134
+ * await NavigationBar.homeTab.shouldHaveClass("is-active");
135
+ * ```
136
+ * @returns The element instance for chaining.
137
+ */
16
138
  shouldHaveClass(className: string): Promise<Element>;
139
+ /**
140
+ * Asserts that the element has the specified attribute, optionally checking its exact value.
141
+ *
142
+ * @param attributeName - Name of the attribute (e.g. `aria-label`, `disabled`, `href`).
143
+ * @param expectedValue - Optional expected value of the attribute.
144
+ * @example
145
+ * ```ts
146
+ * await NavigationBar.logoLink.shouldHaveAttribute("href", "/dashboard");
147
+ * await NavigationBar.cartButton.shouldHaveAttribute("aria-expanded");
148
+ * ```
149
+ * @returns The element instance for chaining.
150
+ */
17
151
  shouldHaveAttribute(attributeName: string, expectedValue?: string): Promise<Element>;
18
152
  }
153
+ /**
154
+ * Optional settings for HTTP network interception responses.
155
+ */
156
+ interface InterceptFixtureOptions {
157
+ /** HTTP status code to return in the mocked response (default: 200) */
158
+ statusCode?: number;
159
+ /** Custom HTTP response headers */
160
+ headers?: Record<string, string>;
161
+ }
162
+ /**
163
+ * Structured mock payload object with optional status code and headers.
164
+ */
165
+ interface InterceptFixtureObject<TData = unknown> {
166
+ /** HTTP status code */
167
+ statusCode?: number;
168
+ /** Response body payload */
169
+ body: TData;
170
+ /** Custom HTTP response headers */
171
+ headers?: Record<string, string>;
172
+ }
173
+ /**
174
+ * Input payload for API mocking: JSON object, string, or structured fixture object.
175
+ */
176
+ type InterceptInput<TData = unknown> = InterceptFixtureObject<TData> | TData | string;
177
+ interface Mock {
178
+ /**
179
+ * Dynamically set or change the fixture response for this mock instance.
180
+ * Supports fixture file paths, structured `{ statusCode, body, headers }` objects, or raw data.
181
+ *
182
+ * @param fixture - Data payload or Fixture reference.
183
+ * @param options - Optional status code and header overrides.
184
+ * @example
185
+ * ```ts
186
+ * const mock = await browser.intercept("/api/user", "GET");
187
+ * await mock.respondWith({ name: "Admin", role: "superadmin" });
188
+ * ```
189
+ */
190
+ respondWith<TData = unknown>(fixture: InterceptInput<TData>, options?: InterceptFixtureOptions): Promise<void>;
191
+ }
19
192
  interface Browser {
193
+ /**
194
+ * Intercepts and mocks network API requests matching the specified endpoint.
195
+ * Supports automatic base URL resolution and TestSpectra JSON Fixtures.
196
+ *
197
+ * @param path - URL path or route to intercept (e.g. `"/api/users"` or `"https://api.example.com/v1/*"`).
198
+ * @param method - HTTP request method (`"GET"`, `"POST"`, `"PUT"`, `"DELETE"`, `"PATCH"`).
199
+ * @param fixture - Optional initial response payload or Fixture object.
200
+ * @param options - Optional status code and header configuration.
201
+ * @example
202
+ * ```ts
203
+ * // Intercept with JSON Fixture
204
+ * await browser.intercept("/api/status", "GET", Fixture.userData);
205
+ *
206
+ * // Intercept with custom payload & status code
207
+ * await browser.intercept("/api/auth/login", "POST", { token: "xyz" }, { statusCode: 200 });
208
+ * ```
209
+ * @returns `Mock` instance allowing dynamic response modification.
210
+ */
211
+ intercept<TData = unknown>(path: string, method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH", fixture?: InterceptInput<TData>, options?: InterceptFixtureOptions): Promise<Mock>;
212
+ /**
213
+ * Asserts that the current browser page URL exactly matches the expected URL.
214
+ *
215
+ * @param expectedUrl - The exact URL expected.
216
+ * @example
217
+ * ```ts
218
+ * await browser.shouldHaveUrl("https://app.example.com/dashboard");
219
+ * ```
220
+ */
20
221
  shouldHaveUrl(expectedUrl: string): Promise<void>;
222
+ /**
223
+ * Asserts that the current browser page URL contains the given substring.
224
+ *
225
+ * @param expectedUrl - Substring expected in the current URL.
226
+ * @example
227
+ * ```ts
228
+ * await browser.shouldContainUrl("/dashboard");
229
+ * ```
230
+ */
21
231
  shouldContainUrl(expectedUrl: string): Promise<void>;
232
+ /**
233
+ * Asserts that the current browser page title matches the expected title.
234
+ *
235
+ * @param expectedTitle - The exact title expected.
236
+ * @example
237
+ * ```ts
238
+ * await browser.shouldHaveTitle("Dashboard - TestSpectra");
239
+ * ```
240
+ */
22
241
  shouldHaveTitle(expectedTitle: string): Promise<void>;
242
+ /**
243
+ * Asserts that the current browser page title contains the expected substring.
244
+ *
245
+ * @param expectedTitle - Substring expected in the title.
246
+ * @example
247
+ * ```ts
248
+ * await browser.shouldContainTitle("Dashboard");
249
+ * ```
250
+ */
23
251
  shouldContainTitle(expectedTitle: string): Promise<void>;
24
252
  }
25
253
  }
26
254
  interface Promise<T> {
255
+ /** Asserts that the element promise resolves to a visible element. */
27
256
  shouldBeVisible(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
257
+ /** Asserts that the element promise resolves to a hidden/non-visible element. */
28
258
  shouldNotBeVisible(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
259
+ /** Asserts that the element promise resolves to an existing element in the DOM. */
29
260
  shouldExist(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
261
+ /** Asserts that the element promise resolves to an element that does not exist in the DOM. */
30
262
  shouldNotExist(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
263
+ /** Asserts that the element promise resolves to an enabled element. */
31
264
  shouldBeEnabled(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
265
+ /** Asserts that the element promise resolves to a disabled element. */
32
266
  shouldBeDisabled(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
267
+ /** Asserts that the element promise resolves to a selected element. */
33
268
  shouldBeSelected(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
269
+ /** Asserts that the element promise resolves to a checked checkbox or radio. */
34
270
  shouldBeChecked(this: Promise<WebdriverIO.Element>): Promise<WebdriverIO.Element>;
271
+ /** Asserts that the element promise resolves to an element with the exact value. */
35
272
  shouldHaveValue(this: Promise<WebdriverIO.Element>, expectedValue: string): Promise<WebdriverIO.Element>;
273
+ /** Asserts that the element promise resolves to an element whose value contains the substring. */
36
274
  shouldContainValue(this: Promise<WebdriverIO.Element>, expectedValue: string): Promise<WebdriverIO.Element>;
275
+ /** Asserts that the element promise resolves to an element with the exact text content. */
37
276
  shouldHaveText(this: Promise<WebdriverIO.Element>, expectedText: string): Promise<WebdriverIO.Element>;
277
+ /** Asserts that the element promise resolves to an element whose text contains the substring. */
38
278
  shouldContainText(this: Promise<WebdriverIO.Element>, expectedText: string): Promise<WebdriverIO.Element>;
279
+ /** Asserts that the element promise resolves to an element having the CSS class. */
39
280
  shouldHaveClass(this: Promise<WebdriverIO.Element>, className: string): Promise<WebdriverIO.Element>;
281
+ /** Asserts that the element promise resolves to an element having the attribute. */
40
282
  shouldHaveAttribute(this: Promise<WebdriverIO.Element>, attributeName: string, expectedValue?: string): Promise<WebdriverIO.Element>;
41
283
  }
42
284
  }
@@ -1,13 +1,89 @@
1
1
  import { MultiElementMatcher } from "../types.js";
2
2
  import { SingleElementRunner } from "./single.js";
3
+ /**
4
+ * Fluent assertion, filtering, and iteration runner for multi-element collections.
5
+ *
6
+ * Implements `PromiseLike<void>`, allowing assertions across matching elements,
7
+ * array index access (`.eq()`, `.first()`, `.last()`), and sequential iteration (`.each()`).
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // Assert collection size
12
+ * await Spectra.getAll(".cart-item").should("have.length", 3);
13
+ *
14
+ * // Target specific element from collection
15
+ * await Spectra.getAll(".todo-item").first().click();
16
+ * await Spectra.getAll(".todo-item").eq(2).should("have.text", "Buy Milk");
17
+ *
18
+ * // Iteration
19
+ * await Spectra.getAll(".nav-link").each(async (link, i) => {
20
+ * await link.should("be.visible");
21
+ * });
22
+ * ```
23
+ */
3
24
  export declare class MultiElementRunner implements PromiseLike<void> {
4
25
  private _selector;
5
26
  private _assertions;
6
27
  constructor(selector: string);
28
+ /**
29
+ * Queues an assertion matcher against the multi-element collection.
30
+ *
31
+ * @param matcher - Multi-element matcher string (e.g. `'have.length'`, `'be.empty'`).
32
+ * @param args - Expected values or limits for the matcher.
33
+ * @example
34
+ * ```ts
35
+ * await Spectra.getAll(".product-card").should("have.length.greaterThan", 0);
36
+ * await Spectra.getAll(".error-badge").should("be.empty");
37
+ * ```
38
+ * @returns Current collection runner instance for chaining.
39
+ */
7
40
  should(matcher: MultiElementMatcher, ...args: any[]): this;
41
+ /**
42
+ * Returns a `SingleElementRunner` targeting the element at the specified 0-based index.
43
+ *
44
+ * @param index - 0-based index of the element within the matched collection.
45
+ * @example
46
+ * ```ts
47
+ * await Spectra.getAll("li.menu-item").eq(1).click();
48
+ * ```
49
+ * @returns `SingleElementRunner` for the indexed element.
50
+ */
8
51
  eq(index: number): SingleElementRunner;
52
+ /**
53
+ * Returns a `SingleElementRunner` targeting the first element in the collection (`index = 0`).
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * await Spectra.getAll(".result-item").first().click();
58
+ * ```
59
+ * @returns `SingleElementRunner` for the first element.
60
+ */
9
61
  first(): SingleElementRunner;
62
+ /**
63
+ * Returns a `SingleElementRunner` targeting the last element in the collection.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * await Spectra.getAll(".step-indicator").last().should("have.class", "current");
68
+ * ```
69
+ * @returns `SingleElementRunner` for the last element.
70
+ */
10
71
  last(): SingleElementRunner;
72
+ /**
73
+ * Iterates asynchronously through every matched element in the collection sequentially.
74
+ *
75
+ * @param callback - Async function called for each element with `(runner, index)`.
76
+ * @example
77
+ * ```ts
78
+ * await Spectra.getAll(".checkbox").each(async (item, index) => {
79
+ * await item.should("be.visible");
80
+ * });
81
+ * ```
82
+ */
11
83
  each(callback: (el: SingleElementRunner, index: number) => Promise<void>): Promise<void>;
84
+ /**
85
+ * Standard Promise `then` implementation.
86
+ * Executes all queued collection assertions sequentially when awaited.
87
+ */
12
88
  then<TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
13
89
  }
@@ -1,5 +1,26 @@
1
1
  import { executeMultiMatcher } from "../matchers.js";
2
2
  import { SingleElementRunner } from "./single.js";
3
+ /**
4
+ * Fluent assertion, filtering, and iteration runner for multi-element collections.
5
+ *
6
+ * Implements `PromiseLike<void>`, allowing assertions across matching elements,
7
+ * array index access (`.eq()`, `.first()`, `.last()`), and sequential iteration (`.each()`).
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // Assert collection size
12
+ * await Spectra.getAll(".cart-item").should("have.length", 3);
13
+ *
14
+ * // Target specific element from collection
15
+ * await Spectra.getAll(".todo-item").first().click();
16
+ * await Spectra.getAll(".todo-item").eq(2).should("have.text", "Buy Milk");
17
+ *
18
+ * // Iteration
19
+ * await Spectra.getAll(".nav-link").each(async (link, i) => {
20
+ * await link.should("be.visible");
21
+ * });
22
+ * ```
23
+ */
3
24
  export class MultiElementRunner {
4
25
  _selector;
5
26
  _assertions = [];
@@ -7,23 +28,74 @@ export class MultiElementRunner {
7
28
  this._selector = selector;
8
29
  }
9
30
  // --- Collection Assertions ---
31
+ /**
32
+ * Queues an assertion matcher against the multi-element collection.
33
+ *
34
+ * @param matcher - Multi-element matcher string (e.g. `'have.length'`, `'be.empty'`).
35
+ * @param args - Expected values or limits for the matcher.
36
+ * @example
37
+ * ```ts
38
+ * await Spectra.getAll(".product-card").should("have.length.greaterThan", 0);
39
+ * await Spectra.getAll(".error-badge").should("be.empty");
40
+ * ```
41
+ * @returns Current collection runner instance for chaining.
42
+ */
10
43
  should(matcher, ...args) {
11
44
  this._assertions.push({ matcher, args });
12
45
  return this;
13
46
  }
14
47
  // --- Item Navigation ---
48
+ /**
49
+ * Returns a `SingleElementRunner` targeting the element at the specified 0-based index.
50
+ *
51
+ * @param index - 0-based index of the element within the matched collection.
52
+ * @example
53
+ * ```ts
54
+ * await Spectra.getAll("li.menu-item").eq(1).click();
55
+ * ```
56
+ * @returns `SingleElementRunner` for the indexed element.
57
+ */
15
58
  eq(index) {
16
59
  const indexedSelector = `(${this._selector})[${index + 1}]`;
17
60
  return new SingleElementRunner(indexedSelector);
18
61
  }
62
+ /**
63
+ * Returns a `SingleElementRunner` targeting the first element in the collection (`index = 0`).
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * await Spectra.getAll(".result-item").first().click();
68
+ * ```
69
+ * @returns `SingleElementRunner` for the first element.
70
+ */
19
71
  first() {
20
72
  return this.eq(0);
21
73
  }
74
+ /**
75
+ * Returns a `SingleElementRunner` targeting the last element in the collection.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * await Spectra.getAll(".step-indicator").last().should("have.class", "current");
80
+ * ```
81
+ * @returns `SingleElementRunner` for the last element.
82
+ */
22
83
  last() {
23
84
  const indexedSelector = `(${this._selector})[last()]`;
24
85
  return new SingleElementRunner(indexedSelector);
25
86
  }
26
87
  // --- Iteration Callback ---
88
+ /**
89
+ * Iterates asynchronously through every matched element in the collection sequentially.
90
+ *
91
+ * @param callback - Async function called for each element with `(runner, index)`.
92
+ * @example
93
+ * ```ts
94
+ * await Spectra.getAll(".checkbox").each(async (item, index) => {
95
+ * await item.should("be.visible");
96
+ * });
97
+ * ```
98
+ */
27
99
  async each(callback) {
28
100
  const elements = await $$(this._selector);
29
101
  const count = await elements.length;
@@ -33,6 +105,10 @@ export class MultiElementRunner {
33
105
  }
34
106
  }
35
107
  // --- Execution when awaited ---
108
+ /**
109
+ * Standard Promise `then` implementation.
110
+ * Executes all queued collection assertions sequentially when awaited.
111
+ */
36
112
  async then(onfulfilled, onrejected) {
37
113
  try {
38
114
  for (const assert of this._assertions) {