@testspectra/matchers 1.1.0-rc.0 → 1.1.0-rc.1
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/contract.d.ts +61 -29
- package/dist/proto.d.ts +8 -0
- package/dist/types.d.ts +138 -38
- package/package.json +1 -1
- package/src/contract.ts +69 -28
- package/src/proto.ts +8 -0
- package/src/runtime/assertions.ts +85 -82
- package/src/runtime/element_actions.ts +12 -3
- package/src/runtime/element_proxy.ts +68 -27
- package/src/runtime/element_state.ts +6 -3
- package/src/runtime/spectra.ts +1 -0
- package/src/types.ts +144 -38
package/dist/contract.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (`WebCdpDriverBridge`, `AndroidTcpDriverBridge`) implements this interface so that the
|
|
8
8
|
* DSL layer contains zero platform branching.
|
|
9
9
|
*/
|
|
10
|
-
import type { CDPNetworkEntry, MockInterceptHandle, MockRule, ScrollOptions, SpectraBrowserBridge, SwipeOptions } from './types.js';
|
|
10
|
+
import type { CDPNetworkEntry, MockInterceptHandle, MockRule, ScopedSelector, ScrollOptions, SpectraBrowserBridge, SwipeOptions } from './types.js';
|
|
11
11
|
/**
|
|
12
12
|
* Runtime configuration injected by the Rust orchestrator via `globalThis.__TESTSPECTRA_CONFIG__`.
|
|
13
13
|
*/
|
|
@@ -39,6 +39,15 @@ export interface RuntimeWorkerConfig {
|
|
|
39
39
|
implicitWaitMs?: number;
|
|
40
40
|
timeoutMs?: number;
|
|
41
41
|
stepDelayMs?: number;
|
|
42
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.networkMonitoringEnabled` (default: true). */
|
|
43
|
+
networkMonitoringEnabled?: boolean;
|
|
44
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.monitoredDomains`. Empty/absent = capture all. */
|
|
45
|
+
monitoredDomains?: {
|
|
46
|
+
domain: string;
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
}[];
|
|
49
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.environmentVariables`. */
|
|
50
|
+
environmentVariables?: Record<string, string>;
|
|
42
51
|
}
|
|
43
52
|
/**
|
|
44
53
|
* Cross-cutting shared runtime state injected into the assembled worker script.
|
|
@@ -60,16 +69,19 @@ export interface RuntimeContext {
|
|
|
60
69
|
getImplicitWaitMs(): number;
|
|
61
70
|
getAssertionTimeoutMs(): number;
|
|
62
71
|
matchesUrlPattern(pattern: string, url: string): boolean;
|
|
72
|
+
/** Whether a captured network request/response for `url` should be recorded, per
|
|
73
|
+
* `config.networkMonitoringEnabled` / `config.monitoredDomains`. */
|
|
74
|
+
shouldRecordNetworkEntry(url: string): boolean;
|
|
63
75
|
createMockHandle(rule: MockRule): MockInterceptHandle;
|
|
64
76
|
parseMockRule(patternOrOptions?: any, maybeMethodOrHandler?: any, maybeFixture?: any, maybeOptions?: any): MockRule;
|
|
65
77
|
recordDuration?: (label: string, category: string, durationMs: number, extra?: Record<string, unknown>) => void;
|
|
66
78
|
withDuration?: <T>(label: string, category: string, fn: () => Promise<T>, extra?: Record<string, unknown>) => Promise<T>;
|
|
67
79
|
durationLogPath?: string | null;
|
|
68
|
-
createElementActions?: (selector: string, index: number | null) => Record<string, any>;
|
|
69
|
-
createElementState?: (selector: string, index: number | null) => Record<string, any>;
|
|
70
|
-
createElementAssertions?: (selector: string, index: number | null, state: Record<string, any>) => Record<string, any>;
|
|
71
|
-
createElementProxy?: (selector: string, index?: number | null) => any;
|
|
72
|
-
createCollectionProxy?: (selector: string) => any;
|
|
80
|
+
createElementActions?: (selector: string | ScopedSelector, index: number | null) => Record<string, any>;
|
|
81
|
+
createElementState?: (selector: string | ScopedSelector, index: number | null) => Record<string, any>;
|
|
82
|
+
createElementAssertions?: (selector: string | ScopedSelector, index: number | null, state: Record<string, any>) => Record<string, any>;
|
|
83
|
+
createElementProxy?: (selector: string | ScopedSelector, index?: number | null) => any;
|
|
84
|
+
createCollectionProxy?: (selector: string | ScopedSelector) => any;
|
|
73
85
|
resolveTargetProxy?: (target: any) => any;
|
|
74
86
|
buildSpectra?: () => any;
|
|
75
87
|
cdpBridgeClass?: any;
|
|
@@ -96,31 +108,51 @@ export interface PlatformDriverBridge extends SpectraBrowserBridge {
|
|
|
96
108
|
close(): Promise<void>;
|
|
97
109
|
/** Navigates to target URL (Web) or Activity / Deep Link (Android). */
|
|
98
110
|
navigate(targetUrl: string): Promise<void>;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
111
|
+
/** Navigates one step backward in browser/navigation history. */
|
|
112
|
+
back(): Promise<void>;
|
|
113
|
+
/** Navigates one step forward in browser/navigation history. */
|
|
114
|
+
forward(): Promise<void>;
|
|
115
|
+
/** Reloads / refreshes the current active page. */
|
|
116
|
+
refresh(): Promise<void>;
|
|
117
|
+
/** Sets the browser viewport dimensions (width and height in pixels). */
|
|
118
|
+
setViewport(width: number, height: number): Promise<void>;
|
|
119
|
+
/** Pauses execution for the given duration in milliseconds. */
|
|
120
|
+
pause(ms: number): Promise<void>;
|
|
121
|
+
/** Intercepts and mocks HTTP network requests matching the specified pattern or options. */
|
|
122
|
+
intercept(patternOrOptions: string | {
|
|
123
|
+
url: string;
|
|
124
|
+
method?: string;
|
|
125
|
+
response?: unknown;
|
|
126
|
+
}, method?: string, fixture?: unknown, options?: {
|
|
127
|
+
statusCode?: number;
|
|
128
|
+
headers?: Record<string, string>;
|
|
129
|
+
delayMs?: number;
|
|
130
|
+
}): Promise<MockInterceptHandle>;
|
|
131
|
+
click(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
132
|
+
doubleClick(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
133
|
+
rightClick(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
134
|
+
setValue(selector: string | ScopedSelector, value: unknown, index?: number | null): Promise<void>;
|
|
135
|
+
clearValue(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
136
|
+
select(selector: string | ScopedSelector, option: string, index?: number | null): Promise<void>;
|
|
137
|
+
hover(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
138
|
+
focus(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
139
|
+
dragDrop(sourceSelector: string | ScopedSelector, targetSelector: string, sourceIndex?: number | null): Promise<void>;
|
|
140
|
+
longPress(selector: string | ScopedSelector, duration: number, index?: number | null): Promise<void>;
|
|
141
|
+
scrollIntoView(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
142
|
+
getText(selector: string | ScopedSelector, index?: number | null): Promise<string>;
|
|
143
|
+
getValue(selector: string | ScopedSelector, index?: number | null): Promise<string>;
|
|
144
|
+
isDisplayed(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
145
|
+
isExisting(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
146
|
+
isEnabled(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
147
|
+
isSelected(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
148
|
+
isFocused(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
149
|
+
isClickable(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
150
|
+
hasClass(selector: string | ScopedSelector, className: string, index?: number | null): Promise<boolean>;
|
|
151
|
+
getAttribute(selector: string | ScopedSelector, name: string, index?: number | null): Promise<string | null>;
|
|
152
|
+
getCSSProperty(selector: string | ScopedSelector, name: string, index?: number | null): Promise<{
|
|
121
153
|
value: string;
|
|
122
154
|
}>;
|
|
123
|
-
count(selector: string): Promise<number>;
|
|
155
|
+
count(selector: string | ScopedSelector): Promise<number>;
|
|
124
156
|
pressKey(key: string | number): Promise<void>;
|
|
125
157
|
scroll(options?: ScrollOptions): Promise<void>;
|
|
126
158
|
swipe(options: SwipeOptions): Promise<void>;
|
package/dist/proto.d.ts
CHANGED
|
@@ -16,6 +16,14 @@ declare global {
|
|
|
16
16
|
* Global step library injected by TestSpectra runner.
|
|
17
17
|
*/
|
|
18
18
|
var Step: Record<string, any>;
|
|
19
|
+
/**
|
|
20
|
+
* Typed shape of `Spectra.env`. Empty by default — each `spectra.config.ts`
|
|
21
|
+
* `executionConfig.environmentVariables` key is merged in as a `readonly <KEY>: string` member
|
|
22
|
+
* by the CLI's generated `.testspectra/types/env.d.ts` (plain TypeScript interface merging, the
|
|
23
|
+
* same mechanism `@types/node` uses to let projects augment `NodeJS.ProcessEnv`).
|
|
24
|
+
*/
|
|
25
|
+
interface SpectraEnv {
|
|
26
|
+
}
|
|
19
27
|
namespace WebdriverIO {
|
|
20
28
|
interface Browser extends SpectraBrowserBridge {
|
|
21
29
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -37,6 +37,25 @@ export type Direction = 'up' | 'down' | 'left' | 'right';
|
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
export type ElementTarget = string | SingleElementProxy | Promise<SingleElementProxy>;
|
|
40
|
+
/**
|
|
41
|
+
* Internal descriptor for a selector resolved relative to a parent element, produced by
|
|
42
|
+
* `element.get()` / `element.getAll()` chaining (see `SingleElementProxy.get`). Recursive so
|
|
43
|
+
* arbitrarily deep chains (e.g. `Spectra.getAll('.card').nth(2).get('.buy-btn')`) carry their
|
|
44
|
+
* full ancestry down to the driver.
|
|
45
|
+
*
|
|
46
|
+
* Resolution differs per platform: web (CDP) nests real DOM `.querySelector()` calls against the
|
|
47
|
+
* resolved parent; Android has no ancestor/descendant API, so the parent's bounds rectangle is
|
|
48
|
+
* used to filter candidates via containment (a child is "within" the parent if its bounds sit
|
|
49
|
+
* inside the parent's).
|
|
50
|
+
*/
|
|
51
|
+
export interface ScopedSelector {
|
|
52
|
+
/** This level's own selector string (`~`/`#` shorthand or raw CSS/xpath), not the full chain. */
|
|
53
|
+
selector: string;
|
|
54
|
+
/** Positional index at this level, or null. */
|
|
55
|
+
index: number | null;
|
|
56
|
+
/** The element this selector is scoped within, or undefined for a root-level selector. */
|
|
57
|
+
parent?: ScopedSelector;
|
|
58
|
+
}
|
|
40
59
|
/**
|
|
41
60
|
* Configuration options for scroll actions.
|
|
42
61
|
*
|
|
@@ -105,6 +124,25 @@ export interface TypeOptions {
|
|
|
105
124
|
/** Whether to clear existing input value before typing new text (default: false) */
|
|
106
125
|
clearFirst?: boolean;
|
|
107
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Per-call override for how long an assertion polls before failing, mirroring Playwright's
|
|
129
|
+
* `{ timeout }` option on web-first assertions (`expect(locator).toHaveText(x, { timeout })`).
|
|
130
|
+
*
|
|
131
|
+
* Defaults to the adaptive assertion timeout (`Spectra`'s fail-fast cap, distinct from
|
|
132
|
+
* `implicitWait`) when omitted — pass this when a specific assertion is known to need longer,
|
|
133
|
+
* e.g. right after a deliberately delayed `Spectra.intercept(..., { delayMs })` mock, without
|
|
134
|
+
* raising the timeout for every other assertion in the test.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* const mock = await Spectra.intercept('/api/report', { response: { delayMs: 4000, body } });
|
|
139
|
+
* await ReportPage.statusBadge.shouldHaveText('Ready', { timeoutMs: 5000 });
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export interface AssertionOptions {
|
|
143
|
+
/** Maximum time (in milliseconds) to keep polling before the assertion fails. */
|
|
144
|
+
timeoutMs?: number;
|
|
145
|
+
}
|
|
108
146
|
/**
|
|
109
147
|
* Canonical assertion matcher keys for single element verification.
|
|
110
148
|
* Dispatched internally by semantic receiver methods (`.shouldBeVisible()`, `.shouldHaveText()`, etc.).
|
|
@@ -129,7 +167,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
129
167
|
* await LoginPage.submitButton.shouldBeVisible();
|
|
130
168
|
* ```
|
|
131
169
|
*/
|
|
132
|
-
shouldBeVisible(): TReturn;
|
|
170
|
+
shouldBeVisible(options?: AssertionOptions): TReturn;
|
|
133
171
|
/**
|
|
134
172
|
* Asserts that the target element is hidden, detached, or not displayed on the page.
|
|
135
173
|
*
|
|
@@ -138,7 +176,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
138
176
|
* await Spectra.get('.loading-spinner').shouldNotBeVisible();
|
|
139
177
|
* ```
|
|
140
178
|
*/
|
|
141
|
-
shouldNotBeVisible(): TReturn;
|
|
179
|
+
shouldNotBeVisible(options?: AssertionOptions): TReturn;
|
|
142
180
|
/**
|
|
143
181
|
* Asserts that the target element exists in the DOM.
|
|
144
182
|
*
|
|
@@ -147,7 +185,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
147
185
|
* await Spectra.get('#cookie-consent-modal').shouldExist();
|
|
148
186
|
* ```
|
|
149
187
|
*/
|
|
150
|
-
shouldExist(): TReturn;
|
|
188
|
+
shouldExist(options?: AssertionOptions): TReturn;
|
|
151
189
|
/**
|
|
152
190
|
* Asserts that the target element does not exist in the DOM.
|
|
153
191
|
*
|
|
@@ -156,7 +194,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
156
194
|
* await Spectra.get('#deleted-record-row').shouldNotExist();
|
|
157
195
|
* ```
|
|
158
196
|
*/
|
|
159
|
-
shouldNotExist(): TReturn;
|
|
197
|
+
shouldNotExist(options?: AssertionOptions): TReturn;
|
|
160
198
|
/**
|
|
161
199
|
* Asserts that the target element is visible, enabled, and clickable.
|
|
162
200
|
*
|
|
@@ -165,7 +203,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
165
203
|
* await Spectra.get('button[type="submit"]').shouldBeClickable();
|
|
166
204
|
* ```
|
|
167
205
|
*/
|
|
168
|
-
shouldBeClickable(): TReturn;
|
|
206
|
+
shouldBeClickable(options?: AssertionOptions): TReturn;
|
|
169
207
|
/**
|
|
170
208
|
* Asserts that the target element is disabled, covered, or not clickable.
|
|
171
209
|
*
|
|
@@ -174,7 +212,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
174
212
|
* await Spectra.get('button.disabled-action').shouldNotBeClickable();
|
|
175
213
|
* ```
|
|
176
214
|
*/
|
|
177
|
-
shouldNotBeClickable(): TReturn;
|
|
215
|
+
shouldNotBeClickable(options?: AssertionOptions): TReturn;
|
|
178
216
|
/**
|
|
179
217
|
* Asserts that the target form input/button is enabled (not disabled).
|
|
180
218
|
*
|
|
@@ -183,7 +221,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
183
221
|
* await Spectra.get('#username-field').shouldBeEnabled();
|
|
184
222
|
* ```
|
|
185
223
|
*/
|
|
186
|
-
shouldBeEnabled(): TReturn;
|
|
224
|
+
shouldBeEnabled(options?: AssertionOptions): TReturn;
|
|
187
225
|
/**
|
|
188
226
|
* Asserts that the target form input/button has the disabled state/attribute.
|
|
189
227
|
*
|
|
@@ -192,7 +230,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
192
230
|
* await Spectra.get('#submit-order-btn').shouldBeDisabled();
|
|
193
231
|
* ```
|
|
194
232
|
*/
|
|
195
|
-
shouldBeDisabled(): TReturn;
|
|
233
|
+
shouldBeDisabled(options?: AssertionOptions): TReturn;
|
|
196
234
|
/**
|
|
197
235
|
* Asserts that the target checkbox or radio input is checked/selected.
|
|
198
236
|
*
|
|
@@ -201,7 +239,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
201
239
|
* await Spectra.get('#terms-checkbox').shouldBeChecked();
|
|
202
240
|
* ```
|
|
203
241
|
*/
|
|
204
|
-
shouldBeChecked(): TReturn;
|
|
242
|
+
shouldBeChecked(options?: AssertionOptions): TReturn;
|
|
205
243
|
/**
|
|
206
244
|
* Asserts that the target checkbox or radio input is unchecked/deselected.
|
|
207
245
|
*
|
|
@@ -210,7 +248,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
210
248
|
* await Spectra.get('#subscribe-newsletter').shouldNotBeChecked();
|
|
211
249
|
* ```
|
|
212
250
|
*/
|
|
213
|
-
shouldNotBeChecked(): TReturn;
|
|
251
|
+
shouldNotBeChecked(options?: AssertionOptions): TReturn;
|
|
214
252
|
/**
|
|
215
253
|
* Asserts that the target element currently holds active document focus.
|
|
216
254
|
*
|
|
@@ -219,7 +257,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
219
257
|
* await Spectra.get('#search-input').shouldBeFocused();
|
|
220
258
|
* ```
|
|
221
259
|
*/
|
|
222
|
-
shouldBeFocused(): TReturn;
|
|
260
|
+
shouldBeFocused(options?: AssertionOptions): TReturn;
|
|
223
261
|
/**
|
|
224
262
|
* Asserts that the target element does not hold active document focus.
|
|
225
263
|
*
|
|
@@ -228,7 +266,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
228
266
|
* await Spectra.get('#blur-input').shouldNotBeFocused();
|
|
229
267
|
* ```
|
|
230
268
|
*/
|
|
231
|
-
shouldNotBeFocused(): TReturn;
|
|
269
|
+
shouldNotBeFocused(options?: AssertionOptions): TReturn;
|
|
232
270
|
/**
|
|
233
271
|
* Asserts that the target element's text content matches the expected string or regular expression.
|
|
234
272
|
*
|
|
@@ -239,7 +277,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
239
277
|
* await Spectra.get('.badge').shouldHaveText(/Active|Pending/);
|
|
240
278
|
* ```
|
|
241
279
|
*/
|
|
242
|
-
shouldHaveText(expected: string | RegExp): TReturn;
|
|
280
|
+
shouldHaveText(expected: string | RegExp, options?: AssertionOptions): TReturn;
|
|
243
281
|
/**
|
|
244
282
|
* Asserts that the target element's text content does not match the expected string or regular expression.
|
|
245
283
|
*
|
|
@@ -249,7 +287,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
249
287
|
* await Spectra.get('.status-label').shouldNotHaveText('Error');
|
|
250
288
|
* ```
|
|
251
289
|
*/
|
|
252
|
-
shouldNotHaveText(expected: string | RegExp): TReturn;
|
|
290
|
+
shouldNotHaveText(expected: string | RegExp, options?: AssertionOptions): TReturn;
|
|
253
291
|
/**
|
|
254
292
|
* Asserts that the target element's text content contains the specified substring.
|
|
255
293
|
*
|
|
@@ -259,7 +297,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
259
297
|
* await Spectra.get('.toast-message').shouldContainText('Successfully saved');
|
|
260
298
|
* ```
|
|
261
299
|
*/
|
|
262
|
-
shouldContainText(substring: string): TReturn;
|
|
300
|
+
shouldContainText(substring: string, options?: AssertionOptions): TReturn;
|
|
263
301
|
/**
|
|
264
302
|
* Asserts that the target element's text content does not contain the specified substring.
|
|
265
303
|
*
|
|
@@ -269,7 +307,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
269
307
|
* await Spectra.get('.log-output').shouldNotContainText('Fatal Exception');
|
|
270
308
|
* ```
|
|
271
309
|
*/
|
|
272
|
-
shouldNotContainText(substring: string): TReturn;
|
|
310
|
+
shouldNotContainText(substring: string, options?: AssertionOptions): TReturn;
|
|
273
311
|
/**
|
|
274
312
|
* Asserts that the form input or textarea element's value exactly equals the specified string.
|
|
275
313
|
*
|
|
@@ -279,7 +317,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
279
317
|
* await Spectra.get('input[name="email"]').shouldHaveValue('admin@testspectra.dev');
|
|
280
318
|
* ```
|
|
281
319
|
*/
|
|
282
|
-
shouldHaveValue(value: string): TReturn;
|
|
320
|
+
shouldHaveValue(value: string, options?: AssertionOptions): TReturn;
|
|
283
321
|
/**
|
|
284
322
|
* Asserts that the form input or textarea element's value does not equal the specified string.
|
|
285
323
|
*
|
|
@@ -289,7 +327,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
289
327
|
* await Spectra.get('input[name="role"]').shouldNotHaveValue('guest');
|
|
290
328
|
* ```
|
|
291
329
|
*/
|
|
292
|
-
shouldNotHaveValue(value: string): TReturn;
|
|
330
|
+
shouldNotHaveValue(value: string, options?: AssertionOptions): TReturn;
|
|
293
331
|
/**
|
|
294
332
|
* Asserts that the form input or textarea element's value contains the specified substring.
|
|
295
333
|
*
|
|
@@ -299,7 +337,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
299
337
|
* await Spectra.get('input[name="email"]').shouldContainValue('@testspectra.dev');
|
|
300
338
|
* ```
|
|
301
339
|
*/
|
|
302
|
-
shouldContainValue(substring: string): TReturn;
|
|
340
|
+
shouldContainValue(substring: string, options?: AssertionOptions): TReturn;
|
|
303
341
|
/**
|
|
304
342
|
* Asserts that the form input or textarea element's value does not contain the specified substring.
|
|
305
343
|
*
|
|
@@ -309,7 +347,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
309
347
|
* await Spectra.get('input[name="url"]').shouldNotContainValue('http://');
|
|
310
348
|
* ```
|
|
311
349
|
*/
|
|
312
|
-
shouldNotContainValue(substring: string): TReturn;
|
|
350
|
+
shouldNotContainValue(substring: string, options?: AssertionOptions): TReturn;
|
|
313
351
|
/**
|
|
314
352
|
* Asserts that the element has the specified attribute, and optionally that its value matches.
|
|
315
353
|
*
|
|
@@ -321,7 +359,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
321
359
|
* await Spectra.get('input.required-field').shouldHaveAttribute('required');
|
|
322
360
|
* ```
|
|
323
361
|
*/
|
|
324
|
-
shouldHaveAttribute(name: string, value?: string): TReturn;
|
|
362
|
+
shouldHaveAttribute(name: string, value?: string, options?: AssertionOptions): TReturn;
|
|
325
363
|
/**
|
|
326
364
|
* Asserts that the element does not have the specified attribute.
|
|
327
365
|
*
|
|
@@ -331,7 +369,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
331
369
|
* await Spectra.get('button#action-btn').shouldNotHaveAttribute('disabled');
|
|
332
370
|
* ```
|
|
333
371
|
*/
|
|
334
|
-
shouldNotHaveAttribute(name: string): TReturn;
|
|
372
|
+
shouldNotHaveAttribute(name: string, options?: AssertionOptions): TReturn;
|
|
335
373
|
/**
|
|
336
374
|
* Asserts that the element contains the specified CSS class name.
|
|
337
375
|
*
|
|
@@ -341,7 +379,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
341
379
|
* await Spectra.get('.nav-tab').shouldHaveClass('active');
|
|
342
380
|
* ```
|
|
343
381
|
*/
|
|
344
|
-
shouldHaveClass(className: string): TReturn;
|
|
382
|
+
shouldHaveClass(className: string, options?: AssertionOptions): TReturn;
|
|
345
383
|
/**
|
|
346
384
|
* Asserts that the element does not contain the specified CSS class name.
|
|
347
385
|
*
|
|
@@ -351,7 +389,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
351
389
|
* await Spectra.get('.modal-backdrop').shouldNotHaveClass('hidden');
|
|
352
390
|
* ```
|
|
353
391
|
*/
|
|
354
|
-
shouldNotHaveClass(className: string): TReturn;
|
|
392
|
+
shouldNotHaveClass(className: string, options?: AssertionOptions): TReturn;
|
|
355
393
|
/**
|
|
356
394
|
* Asserts that the computed CSS style property of the element equals the specified value.
|
|
357
395
|
*
|
|
@@ -362,7 +400,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
362
400
|
* await Spectra.get('.badge-success').shouldHaveCss('color', 'rgb(0, 128, 0)');
|
|
363
401
|
* ```
|
|
364
402
|
*/
|
|
365
|
-
shouldHaveCss(property: string, value: string): TReturn;
|
|
403
|
+
shouldHaveCss(property: string, value: string, options?: AssertionOptions): TReturn;
|
|
366
404
|
/**
|
|
367
405
|
* Asserts that the computed CSS style property of the element does not equal the specified value.
|
|
368
406
|
*
|
|
@@ -373,7 +411,7 @@ export interface ElementReceiverAssertions<TReturn = Promise<void>> {
|
|
|
373
411
|
* await Spectra.get('.main-content').shouldNotHaveCss('display', 'none');
|
|
374
412
|
* ```
|
|
375
413
|
*/
|
|
376
|
-
shouldNotHaveCss(property: string, value: string): TReturn;
|
|
414
|
+
shouldNotHaveCss(property: string, value: string, options?: AssertionOptions): TReturn;
|
|
377
415
|
}
|
|
378
416
|
/**
|
|
379
417
|
* Receiver-oriented collection assertion methods.
|
|
@@ -389,7 +427,7 @@ export interface CollectionReceiverAssertions<TReturn = Promise<void>> {
|
|
|
389
427
|
* await Spectra.getAll('.user-table-row').shouldHaveLength(10);
|
|
390
428
|
* ```
|
|
391
429
|
*/
|
|
392
|
-
shouldHaveLength(count: number): TReturn;
|
|
430
|
+
shouldHaveLength(count: number, options?: AssertionOptions): TReturn;
|
|
393
431
|
/**
|
|
394
432
|
* Asserts that the collection does not contain the specified number of matching elements.
|
|
395
433
|
*
|
|
@@ -399,7 +437,7 @@ export interface CollectionReceiverAssertions<TReturn = Promise<void>> {
|
|
|
399
437
|
* await Spectra.getAll('.error-item').shouldNotHaveLength(0);
|
|
400
438
|
* ```
|
|
401
439
|
*/
|
|
402
|
-
shouldNotHaveLength(count: number): TReturn;
|
|
440
|
+
shouldNotHaveLength(count: number, options?: AssertionOptions): TReturn;
|
|
403
441
|
/**
|
|
404
442
|
* Asserts that the collection contains strictly more than `min` matching elements.
|
|
405
443
|
*
|
|
@@ -409,7 +447,7 @@ export interface CollectionReceiverAssertions<TReturn = Promise<void>> {
|
|
|
409
447
|
* await Spectra.getAll('.search-result-card').shouldHaveLengthGreaterThan(0);
|
|
410
448
|
* ```
|
|
411
449
|
*/
|
|
412
|
-
shouldHaveLengthGreaterThan(min: number): TReturn;
|
|
450
|
+
shouldHaveLengthGreaterThan(min: number, options?: AssertionOptions): TReturn;
|
|
413
451
|
/**
|
|
414
452
|
* Asserts that the collection contains strictly fewer than `max` matching elements.
|
|
415
453
|
*
|
|
@@ -419,7 +457,7 @@ export interface CollectionReceiverAssertions<TReturn = Promise<void>> {
|
|
|
419
457
|
* await Spectra.getAll('.warning-banner').shouldHaveLengthLessThan(5);
|
|
420
458
|
* ```
|
|
421
459
|
*/
|
|
422
|
-
shouldHaveLengthLessThan(max: number): TReturn;
|
|
460
|
+
shouldHaveLengthLessThan(max: number, options?: AssertionOptions): TReturn;
|
|
423
461
|
/**
|
|
424
462
|
* Asserts that the collection contains zero matching elements.
|
|
425
463
|
*
|
|
@@ -428,7 +466,7 @@ export interface CollectionReceiverAssertions<TReturn = Promise<void>> {
|
|
|
428
466
|
* await Spectra.getAll('.unread-notification-badge').shouldBeEmpty();
|
|
429
467
|
* ```
|
|
430
468
|
*/
|
|
431
|
-
shouldBeEmpty(): TReturn;
|
|
469
|
+
shouldBeEmpty(options?: AssertionOptions): TReturn;
|
|
432
470
|
/**
|
|
433
471
|
* Asserts that the collection contains at least one matching element.
|
|
434
472
|
*
|
|
@@ -437,7 +475,7 @@ export interface CollectionReceiverAssertions<TReturn = Promise<void>> {
|
|
|
437
475
|
* await Spectra.getAll('.product-card').shouldNotBeEmpty();
|
|
438
476
|
* ```
|
|
439
477
|
*/
|
|
440
|
-
shouldNotBeEmpty(): TReturn;
|
|
478
|
+
shouldNotBeEmpty(options?: AssertionOptions): TReturn;
|
|
441
479
|
}
|
|
442
480
|
/**
|
|
443
481
|
* Browser-level context assertion methods.
|
|
@@ -453,7 +491,7 @@ export interface BrowserReceiverAssertions {
|
|
|
453
491
|
* await Spectra.browser.shouldHaveUrl('https://app.testspectra.dev/dashboard');
|
|
454
492
|
* ```
|
|
455
493
|
*/
|
|
456
|
-
shouldHaveUrl(expectedUrl: string): Promise<void>;
|
|
494
|
+
shouldHaveUrl(expectedUrl: string, options?: AssertionOptions): Promise<void>;
|
|
457
495
|
/**
|
|
458
496
|
* Asserts that current browser URL contains the specified substring.
|
|
459
497
|
*
|
|
@@ -463,7 +501,7 @@ export interface BrowserReceiverAssertions {
|
|
|
463
501
|
* await Spectra.browser.shouldContainUrl('/dashboard');
|
|
464
502
|
* ```
|
|
465
503
|
*/
|
|
466
|
-
shouldContainUrl(expectedSubstr: string): Promise<void>;
|
|
504
|
+
shouldContainUrl(expectedSubstr: string, options?: AssertionOptions): Promise<void>;
|
|
467
505
|
/**
|
|
468
506
|
* Asserts that current page title exactly matches the expected title.
|
|
469
507
|
*
|
|
@@ -473,7 +511,7 @@ export interface BrowserReceiverAssertions {
|
|
|
473
511
|
* await Spectra.browser.shouldHaveTitle('Dashboard - TestSpectra');
|
|
474
512
|
* ```
|
|
475
513
|
*/
|
|
476
|
-
shouldHaveTitle(expectedTitle: string): Promise<void>;
|
|
514
|
+
shouldHaveTitle(expectedTitle: string, options?: AssertionOptions): Promise<void>;
|
|
477
515
|
/**
|
|
478
516
|
* Asserts that current page title contains the specified substring.
|
|
479
517
|
*
|
|
@@ -483,7 +521,7 @@ export interface BrowserReceiverAssertions {
|
|
|
483
521
|
* await Spectra.browser.shouldContainTitle('Dashboard');
|
|
484
522
|
* ```
|
|
485
523
|
*/
|
|
486
|
-
shouldContainTitle(expectedSubstr: string): Promise<void>;
|
|
524
|
+
shouldContainTitle(expectedSubstr: string, options?: AssertionOptions): Promise<void>;
|
|
487
525
|
/**
|
|
488
526
|
* Asserts that the browser document `readyState` is 'complete' or 'interactive'.
|
|
489
527
|
*
|
|
@@ -492,7 +530,7 @@ export interface BrowserReceiverAssertions {
|
|
|
492
530
|
* await Spectra.browser.shouldBeLoaded();
|
|
493
531
|
* ```
|
|
494
532
|
*/
|
|
495
|
-
shouldBeLoaded(): Promise<void>;
|
|
533
|
+
shouldBeLoaded(options?: AssertionOptions): Promise<void>;
|
|
496
534
|
/**
|
|
497
535
|
* Asserts that no severe or unhandled JavaScript errors occurred in the browser console.
|
|
498
536
|
*
|
|
@@ -501,7 +539,7 @@ export interface BrowserReceiverAssertions {
|
|
|
501
539
|
* await Spectra.browser.shouldHaveNoConsoleErrors();
|
|
502
540
|
* ```
|
|
503
541
|
*/
|
|
504
|
-
shouldHaveNoConsoleErrors(): Promise<void>;
|
|
542
|
+
shouldHaveNoConsoleErrors(options?: AssertionOptions): Promise<void>;
|
|
505
543
|
/**
|
|
506
544
|
* Clears all browser cookies for the active domain.
|
|
507
545
|
*
|
|
@@ -511,6 +549,28 @@ export interface BrowserReceiverAssertions {
|
|
|
511
549
|
* ```
|
|
512
550
|
*/
|
|
513
551
|
clearCookies(): Promise<void>;
|
|
552
|
+
/**
|
|
553
|
+
* Applies one or more raw `Set-Cookie` header values — exactly as received from a `fetch()`
|
|
554
|
+
* response, e.g. `response.headers.getSetCookie()` — to the browser's cookie jar. Operates at
|
|
555
|
+
* the CDP `Network` domain level rather than through `document.cookie`, so `HttpOnly` cookies
|
|
556
|
+
* are fully supported (set, not just read-blocked). Useful for seeding an authenticated session
|
|
557
|
+
* by logging in via a direct API call instead of driving the real login UI — see
|
|
558
|
+
* `docs/v2/features/authentication-and-session-seeding.md`.
|
|
559
|
+
*
|
|
560
|
+
* `url` is required to resolve `Domain`/`Path`/`Secure` defaults for any `Set-Cookie` value that
|
|
561
|
+
* doesn't specify them explicitly (an omitted `Domain` defaults to the issuing request's own
|
|
562
|
+
* host, per RFC 6265) — pass the URL the response actually came from.
|
|
563
|
+
*
|
|
564
|
+
* Web only — Android has no browser/cookie-jar concept; see the docs above for the mobile
|
|
565
|
+
* equivalent (deep-link-triggered, Keystore-backed session seeding).
|
|
566
|
+
*
|
|
567
|
+
* @example
|
|
568
|
+
* ```ts
|
|
569
|
+
* const res = await fetch('https://api.example.com/auth/login', { method: 'POST', body: ... });
|
|
570
|
+
* await Spectra.browser.setCookies(res.headers.getSetCookie(), res.url);
|
|
571
|
+
* ```
|
|
572
|
+
*/
|
|
573
|
+
setCookies(setCookieHeaders: string | string[], url: string): Promise<void>;
|
|
514
574
|
/**
|
|
515
575
|
* Clears all key-value entries in browser `localStorage`.
|
|
516
576
|
*
|
|
@@ -529,6 +589,29 @@ export interface SingleElementProxy extends ElementReceiverAssertions<Promise<vo
|
|
|
529
589
|
selector: string;
|
|
530
590
|
/** Positional index when matched from a collection (or null for standalone selectors). */
|
|
531
591
|
index: number | null;
|
|
592
|
+
/**
|
|
593
|
+
* Finds `childSelector` scoped to this element's subtree, mirroring Playwright's locator
|
|
594
|
+
* chaining (`parent.locator(child)`) instead of a separate `within()`/`findWithin()` verb.
|
|
595
|
+
* Resolution is a real DOM descendant query on web; on Android (no ancestor API) it's a
|
|
596
|
+
* bounds-containment heuristic over the flat accessibility-tree dump.
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```ts
|
|
600
|
+
* const modal = Spectra.get('#modal');
|
|
601
|
+
* await modal.get('#save-btn').click();
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
get(childSelector: string, index?: number | null): SingleElementProxy;
|
|
605
|
+
/**
|
|
606
|
+
* Finds all elements matching `childSelector` scoped to this element's subtree — the
|
|
607
|
+
* collection equivalent of `get()`.
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* ```ts
|
|
611
|
+
* await Spectra.get('#modal').getAll('.list-item').shouldHaveLength(3);
|
|
612
|
+
* ```
|
|
613
|
+
*/
|
|
614
|
+
getAll(childSelector: string): CollectionProxy;
|
|
532
615
|
/**
|
|
533
616
|
* Waits until the element exists in the DOM within the specified timeout.
|
|
534
617
|
*
|
|
@@ -794,10 +877,15 @@ export interface CollectionProxy extends CollectionReceiverAssertions<Promise<vo
|
|
|
794
877
|
/**
|
|
795
878
|
* Returns a `SingleElementProxy` pointing to the matching element at the specified zero-based index.
|
|
796
879
|
*
|
|
880
|
+
* When this collection itself came from a `.getAll()` chain, `first()`/`last()`/`nth()` carry
|
|
881
|
+
* that scope forward instead of reverting to an unscoped lookup — e.g. the button below is
|
|
882
|
+
* resolved within the 3rd `.card`, not just anywhere on the page:
|
|
883
|
+
*
|
|
797
884
|
* @param index Zero-based index of the target element.
|
|
798
885
|
* @example
|
|
799
886
|
* ```ts
|
|
800
887
|
* await Spectra.getAll('.list-item').nth(2).click();
|
|
888
|
+
* await Spectra.getAll('.card').nth(2).get('.buy-btn').click();
|
|
801
889
|
* ```
|
|
802
890
|
*/
|
|
803
891
|
nth(index: number): SingleElementProxy;
|
|
@@ -1296,6 +1384,18 @@ export interface SpectraStatic {
|
|
|
1296
1384
|
* Direct access to browser context commands and page assertions.
|
|
1297
1385
|
*/
|
|
1298
1386
|
browser: SpectraBrowserBridge;
|
|
1387
|
+
/**
|
|
1388
|
+
* Typed environment variables from `spectra.config.ts`'s `executionConfig.environmentVariables`.
|
|
1389
|
+
* Each configured key is generated into `.testspectra/types/env.d.ts` as a `SpectraEnv` member
|
|
1390
|
+
* (TypeScript interface merging), so `Spectra.env.MY_KEY` resolves to `string` — never
|
|
1391
|
+
* `string | undefined` like raw `process.env.MY_KEY` would.
|
|
1392
|
+
*
|
|
1393
|
+
* @example
|
|
1394
|
+
* ```ts
|
|
1395
|
+
* const mode = Spectra.env.API_MODE;
|
|
1396
|
+
* ```
|
|
1397
|
+
*/
|
|
1398
|
+
env: SpectraEnv;
|
|
1299
1399
|
/**
|
|
1300
1400
|
* Intercepts and mocks HTTP network requests matching the specified pattern or options.
|
|
1301
1401
|
*
|
package/package.json
CHANGED