@testspectra/matchers 1.1.0 → 1.1.8-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/__tests__/matcher-contracts.test.d.ts +1 -0
- package/dist/__tests__/matcher-contracts.test.js +498 -0
- package/dist/contract.d.ts +173 -0
- package/dist/contract.js +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/matchers.d.ts +10 -3
- package/dist/matchers.js +576 -135
- package/dist/proto.d.ts +8 -0
- package/dist/reporter.js +13 -1
- package/dist/runner/collection.js +32 -6
- package/dist/runner/single.d.ts +2 -2
- package/dist/runner/single.js +24 -7
- package/dist/semantic.d.ts +11 -0
- package/dist/semantic.js +141 -0
- package/dist/types.d.ts +246 -115
- package/package.json +11 -10
- package/src/contract.ts +223 -0
- package/src/index.ts +1 -0
- package/src/proto.ts +8 -0
- package/src/runtime/assertions.ts +453 -0
- package/src/runtime/element_actions.ts +178 -0
- package/src/runtime/element_proxy.ts +200 -0
- package/src/runtime/element_state.ts +94 -0
- package/src/runtime/spectra.ts +110 -0
- package/src/types.ts +251 -124
- package/tsconfig.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testspectra/matchers",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8-rc.1",
|
|
4
4
|
"description": "Canonical TypeScript contracts and ambient type definitions for TestSpectra",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,15 +11,16 @@
|
|
|
11
11
|
"default": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
"@types/node": "^20.14.0",
|
|
16
|
-
"typescript": "^5.6.3"
|
|
17
|
-
},
|
|
18
|
-
"type": "module",
|
|
19
|
-
"license": "SEE LICENSE IN LICENSE.md",
|
|
20
14
|
"scripts": {
|
|
21
15
|
"build": "tsc",
|
|
22
16
|
"watch": "tsc -w",
|
|
23
|
-
"typecheck": "tsc --noEmit"
|
|
24
|
-
|
|
25
|
-
}
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "catalog:",
|
|
22
|
+
"typescript": "catalog:"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"license": "SEE LICENSE IN LICENSE.md"
|
|
26
|
+
}
|
package/src/contract.ts
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* # PlatformDriverBridge Contract
|
|
4
|
+
*
|
|
5
|
+
* The unified abstract driver contract consumed by `@testspectra/matchers` element proxies,
|
|
6
|
+
* fluent matchers, and the `Spectra` automation object. Every platform-specific driver
|
|
7
|
+
* (`WebCdpDriverBridge`, `AndroidTcpDriverBridge`) implements this interface so that the
|
|
8
|
+
* DSL layer contains zero platform branching.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
CDPNetworkEntry,
|
|
13
|
+
MockInterceptHandle,
|
|
14
|
+
MockRule,
|
|
15
|
+
ScopedSelector,
|
|
16
|
+
ScrollOptions,
|
|
17
|
+
SpectraBrowserBridge,
|
|
18
|
+
SwipeOptions,
|
|
19
|
+
} from './types.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Runtime configuration injected by the Rust orchestrator via `globalThis.__TESTSPECTRA_CONFIG__`.
|
|
23
|
+
*/
|
|
24
|
+
export interface RuntimeWorkerConfig {
|
|
25
|
+
workerId?: number;
|
|
26
|
+
rootDir: string;
|
|
27
|
+
testFilePath?: string;
|
|
28
|
+
testFiles?: Array<{ id: string; title: string; filePath: string; suite: string }>;
|
|
29
|
+
activePlatform: string;
|
|
30
|
+
configuredBaseUrl: string;
|
|
31
|
+
cdpWsUrl: string;
|
|
32
|
+
driverServerUrl: string;
|
|
33
|
+
manifest?: Record<string, any>;
|
|
34
|
+
/** Target app package (Android). Paired with androidSerial/adbPath for on-demand adb actions. */
|
|
35
|
+
appPackage?: string;
|
|
36
|
+
/** Target adb device serial for this worker (Android only). */
|
|
37
|
+
androidSerial?: string;
|
|
38
|
+
/** Resolved `adb` binary path (Android only), paired with androidSerial above. */
|
|
39
|
+
adbPath?: string;
|
|
40
|
+
/** Host port this worker's own MobileMockProxyServer should listen on (Android only) — derived
|
|
41
|
+
* per-device the same way androidSerial/the driver-server port already are, so each device in
|
|
42
|
+
* a multi-device run gets its own proxy instead of every worker racing for one shared port. */
|
|
43
|
+
mockProxyPort?: number;
|
|
44
|
+
implicitWaitMs?: number;
|
|
45
|
+
timeoutMs?: number;
|
|
46
|
+
stepDelayMs?: number;
|
|
47
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.networkMonitoringEnabled` (default: true). */
|
|
48
|
+
networkMonitoringEnabled?: boolean;
|
|
49
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.monitoredDomains`. Empty/absent = capture all. */
|
|
50
|
+
monitoredDomains?: { domain: string; enabled: boolean }[];
|
|
51
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.environmentVariables`. */
|
|
52
|
+
environmentVariables?: Record<string, string>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Cross-cutting shared runtime state injected into the assembled worker script.
|
|
57
|
+
*
|
|
58
|
+
* The worker runtime is emitted as a single self-contained TypeScript module (concatenated
|
|
59
|
+
* by the Rust orchestrator). This object is created once in the harness prelude and mutated
|
|
60
|
+
* in place (`activeDriver` is bound after the platform bridge is instantiated), so fragments
|
|
61
|
+
* access it lazily at call-time through `globalThis.__TS_RUNTIME__`.
|
|
62
|
+
*/
|
|
63
|
+
export interface RuntimeContext {
|
|
64
|
+
config: RuntimeWorkerConfig;
|
|
65
|
+
activeDriver: PlatformDriverBridge | null;
|
|
66
|
+
mobileMockRules: MockRule[];
|
|
67
|
+
lastFocusedSelector: string | null;
|
|
68
|
+
currentTargetItem?: any;
|
|
69
|
+
|
|
70
|
+
emitEvent(tag: string, payload: string): void;
|
|
71
|
+
trackStep<T>(
|
|
72
|
+
category: 'action' | 'assertion' | 'browser',
|
|
73
|
+
payloadObj: Record<string, any>,
|
|
74
|
+
fn: () => Promise<T>,
|
|
75
|
+
): Promise<T>;
|
|
76
|
+
pollCondition(fn: () => Promise<boolean> | boolean, timeoutMs?: number, intervalMs?: number): Promise<boolean>;
|
|
77
|
+
getImplicitWaitMs(): number;
|
|
78
|
+
getAssertionTimeoutMs(): number;
|
|
79
|
+
matchesUrlPattern(pattern: string, url: string): boolean;
|
|
80
|
+
/** Whether a captured network request/response for `url` should be recorded, per
|
|
81
|
+
* `config.networkMonitoringEnabled` / `config.monitoredDomains`. */
|
|
82
|
+
shouldRecordNetworkEntry(url: string): boolean;
|
|
83
|
+
createMockHandle(rule: MockRule): MockInterceptHandle;
|
|
84
|
+
parseMockRule(patternOrOptions?: any, maybeMethodOrHandler?: any, maybeFixture?: any, maybeOptions?: any): MockRule;
|
|
85
|
+
|
|
86
|
+
// Opt-in duration logging (see core/orchestrator/src/worker/prelude.ts). Present at runtime only
|
|
87
|
+
// when TESTSPECTRA_DURATION_LOG is set; the wrappers are pass-through no-ops otherwise.
|
|
88
|
+
recordDuration?: (label: string, category: string, durationMs: number, extra?: Record<string, unknown>) => void;
|
|
89
|
+
withDuration?: <T>(
|
|
90
|
+
label: string,
|
|
91
|
+
category: string,
|
|
92
|
+
fn: () => Promise<T>,
|
|
93
|
+
extra?: Record<string, unknown>,
|
|
94
|
+
) => Promise<T>;
|
|
95
|
+
durationLogPath?: string | null;
|
|
96
|
+
|
|
97
|
+
// Matchers runtime factories — registered onto the context by the `tools/matchers` fragments
|
|
98
|
+
// at load time, then consumed by sibling fragments (concatenated single-scope assembly).
|
|
99
|
+
createElementActions?: (selector: string | ScopedSelector, index: number | null) => Record<string, any>;
|
|
100
|
+
createElementState?: (selector: string | ScopedSelector, index: number | null) => Record<string, any>;
|
|
101
|
+
createElementAssertions?: (
|
|
102
|
+
selector: string | ScopedSelector,
|
|
103
|
+
index: number | null,
|
|
104
|
+
state: Record<string, any>,
|
|
105
|
+
) => Record<string, any>;
|
|
106
|
+
createElementProxy?: (selector: string | ScopedSelector, index?: number | null) => any;
|
|
107
|
+
createCollectionProxy?: (selector: string | ScopedSelector) => any;
|
|
108
|
+
resolveTargetProxy?: (target: any) => any;
|
|
109
|
+
buildSpectra?: () => any;
|
|
110
|
+
|
|
111
|
+
// Platform driver classes — registered by the driver bridge fragments at load time.
|
|
112
|
+
cdpBridgeClass?: any;
|
|
113
|
+
androidBridgeClass?: any;
|
|
114
|
+
mobileMockProxyClass?: any;
|
|
115
|
+
mobileMockProxy?: any;
|
|
116
|
+
|
|
117
|
+
// BDD harness lifecycle hooks & entrypoints — `bdd_runner.ts` owns the hook slots and
|
|
118
|
+
// `runSuite`; `auto_import.ts` owns `bootstrapEnvironment`. Routed through this shared context
|
|
119
|
+
// (rather than plain module-scoped bindings) because the harness fragments are concatenated
|
|
120
|
+
// into one script by the Rust orchestrator but remain separate ES modules for unit testing.
|
|
121
|
+
beforeHook?: (() => Promise<void> | void) | null;
|
|
122
|
+
afterHook?: (() => Promise<void> | void) | null;
|
|
123
|
+
beforeEachHook?: (() => Promise<void> | void) | null;
|
|
124
|
+
afterEachHook?: (() => Promise<void> | void) | null;
|
|
125
|
+
bootstrapEnvironment?: () => Promise<void>;
|
|
126
|
+
runSuite?: () => Promise<void>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The unified platform driver contract. It extends the browser surface documented in
|
|
131
|
+
* `SpectraBrowserBridge` (navigation, script execution, network interception, browser-level
|
|
132
|
+
* assertions) with the element interaction and state-inspection methods needed by the DSL,
|
|
133
|
+
* so the `tools/matchers` layer never branches on `activePlatform`.
|
|
134
|
+
*/
|
|
135
|
+
export interface PlatformDriverBridge extends SpectraBrowserBridge {
|
|
136
|
+
/** Establishes connection to the underlying runtime endpoint (WebSocket / TCP Socket). */
|
|
137
|
+
connect(): Promise<void>;
|
|
138
|
+
|
|
139
|
+
/** Cleans up open connections, servers, and listeners. */
|
|
140
|
+
close(): Promise<void>;
|
|
141
|
+
|
|
142
|
+
/** Navigates to target URL (Web) or Activity / Deep Link (Android). */
|
|
143
|
+
navigate(targetUrl: string): Promise<void>;
|
|
144
|
+
|
|
145
|
+
/** Navigates one step backward in browser/navigation history. */
|
|
146
|
+
back(): Promise<void>;
|
|
147
|
+
|
|
148
|
+
/** Navigates one step forward in browser/navigation history. */
|
|
149
|
+
forward(): Promise<void>;
|
|
150
|
+
|
|
151
|
+
/** Reloads / refreshes the current active page. */
|
|
152
|
+
refresh(): Promise<void>;
|
|
153
|
+
|
|
154
|
+
/** Sets the browser viewport dimensions (width and height in pixels). */
|
|
155
|
+
setViewport(width: number, height: number): Promise<void>;
|
|
156
|
+
|
|
157
|
+
/** Pauses execution for the given duration in milliseconds. */
|
|
158
|
+
pause(ms: number): Promise<void>;
|
|
159
|
+
|
|
160
|
+
/** Intercepts and mocks HTTP network requests matching the specified pattern or options. */
|
|
161
|
+
intercept(
|
|
162
|
+
patternOrOptions: string | { url: string; method?: string; response?: unknown },
|
|
163
|
+
method?: string,
|
|
164
|
+
fixture?: unknown,
|
|
165
|
+
options?: { statusCode?: number; headers?: Record<string, string>; delayMs?: number },
|
|
166
|
+
): Promise<MockInterceptHandle>;
|
|
167
|
+
|
|
168
|
+
// --- Element Actions ---
|
|
169
|
+
// `selector` accepts a `ScopedSelector` when resolved via `element.get()`/`.getAll()` chaining
|
|
170
|
+
// (see tools/matchers/src/types.ts); when it is one, its own `.index` is authoritative and the
|
|
171
|
+
// separate `index` argument below is unused. `dragDrop`'s destination stays `string`-only —
|
|
172
|
+
// scoping it is out of scope (see the plan's non-goals).
|
|
173
|
+
click(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
174
|
+
doubleClick(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
175
|
+
rightClick(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
176
|
+
setValue(selector: string | ScopedSelector, value: unknown, index?: number | null): Promise<void>;
|
|
177
|
+
clearValue(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
178
|
+
select(selector: string | ScopedSelector, option: string, index?: number | null): Promise<void>;
|
|
179
|
+
hover(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
180
|
+
focus(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
181
|
+
dragDrop(sourceSelector: string | ScopedSelector, targetSelector: string, sourceIndex?: number | null): Promise<void>;
|
|
182
|
+
longPress(selector: string | ScopedSelector, duration: number, index?: number | null): Promise<void>;
|
|
183
|
+
scrollIntoView(selector: string | ScopedSelector, index?: number | null): Promise<void>;
|
|
184
|
+
|
|
185
|
+
// --- Element State Inspection ---
|
|
186
|
+
getText(selector: string | ScopedSelector, index?: number | null): Promise<string>;
|
|
187
|
+
getValue(selector: string | ScopedSelector, index?: number | null): Promise<string>;
|
|
188
|
+
isDisplayed(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
189
|
+
isExisting(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
190
|
+
isEnabled(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
191
|
+
isSelected(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
192
|
+
isFocused(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
193
|
+
isClickable(selector: string | ScopedSelector, index?: number | null): Promise<boolean>;
|
|
194
|
+
hasClass(selector: string | ScopedSelector, className: string, index?: number | null): Promise<boolean>;
|
|
195
|
+
getAttribute(selector: string | ScopedSelector, name: string, index?: number | null): Promise<string | null>;
|
|
196
|
+
getCSSProperty(selector: string | ScopedSelector, name: string, index?: number | null): Promise<{ value: string }>;
|
|
197
|
+
count(selector: string | ScopedSelector): Promise<number>;
|
|
198
|
+
|
|
199
|
+
// --- Gestures & Keys ---
|
|
200
|
+
pressKey(key: string | number): Promise<void>;
|
|
201
|
+
scroll(options?: ScrollOptions): Promise<void>;
|
|
202
|
+
swipe(options: SwipeOptions): Promise<void>;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Grants an Android runtime permission on demand (e.g. right after confirming an in-app
|
|
206
|
+
* rationale dialog), via `adb shell pm grant` on the host. No-op on platforms without an
|
|
207
|
+
* OS-level runtime permission model (e.g. web).
|
|
208
|
+
*/
|
|
209
|
+
grantPermission(name: string): Promise<void>;
|
|
210
|
+
|
|
211
|
+
/** Clears all active network interception rules. */
|
|
212
|
+
clearMocks(): void;
|
|
213
|
+
|
|
214
|
+
// --- State accessed by the harness & tests ---
|
|
215
|
+
mockRules: MockRule[];
|
|
216
|
+
consoleErrors: string[];
|
|
217
|
+
recordedNetwork: CDPNetworkEntry[];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
declare global {
|
|
221
|
+
// eslint-disable-next-line no-var
|
|
222
|
+
var __TS_RUNTIME__: RuntimeContext;
|
|
223
|
+
}
|
package/src/index.ts
CHANGED
package/src/proto.ts
CHANGED
|
@@ -21,6 +21,14 @@ declare global {
|
|
|
21
21
|
*/
|
|
22
22
|
var Step: Record<string, any>;
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Typed shape of `Spectra.env`. Empty by default — each `spectra.config.ts`
|
|
26
|
+
* `executionConfig.environmentVariables` key is merged in as a `readonly <KEY>: string` member
|
|
27
|
+
* by the CLI's generated `.testspectra/types/env.d.ts` (plain TypeScript interface merging, the
|
|
28
|
+
* same mechanism `@types/node` uses to let projects augment `NodeJS.ProcessEnv`).
|
|
29
|
+
*/
|
|
30
|
+
interface SpectraEnv {}
|
|
31
|
+
|
|
24
32
|
namespace WebdriverIO {
|
|
25
33
|
interface Browser extends SpectraBrowserBridge {}
|
|
26
34
|
}
|