@testspectra/matchers 1.1.11-rc.5 → 1.1.13
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 +5 -42
- 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 +1 -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 +34 -1
- package/dist/worker_config.d.ts +97 -0
- package/dist/worker_config.js +17 -0
- package/package.json +1 -1
- package/src/contract.ts +5 -36
- package/src/index.ts +1 -0
- package/src/proto.ts +2 -0
- package/src/types.ts +37 -0
- package/src/worker_config.ts +102 -0
- package/testspectra-matchers-1.1.13.tgz +0 -0
- package/tsconfig.json +1 -1
- package/src/runtime/assertions.ts +0 -454
- package/src/runtime/element_actions.ts +0 -169
- package/src/runtime/element_proxy.ts +0 -199
- package/src/runtime/element_state.ts +0 -94
- package/src/runtime/spectra.ts +0 -110
- package/testspectra-matchers-1.1.11-rc.5.tgz +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared worker-runtime configuration contract.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth for the shape of `globalThis.__TESTSPECTRA_CONFIG__`, the
|
|
5
|
+
* runtime config object every host injects before the shared DSL is exercised:
|
|
6
|
+
*
|
|
7
|
+
* - E2E: the Rust orchestrator writes it into the Bun worker script
|
|
8
|
+
* (`core/orchestrator/src/worker_runtime.rs`) — one worker per spec batch.
|
|
9
|
+
* - Component testing: `@testspectra/react`'s browser prelude publishes it
|
|
10
|
+
* (`tools/react/src/prelude.ts`) — one page per spec file.
|
|
11
|
+
*
|
|
12
|
+
* `core/worker-runtime/src/harness/config.ts`'s `getWorkerConfig()` reads it back with the
|
|
13
|
+
* priority: in-memory override → this global → `process.env.TESTSPECTRA_CONFIG` → hard defaults,
|
|
14
|
+
* so both hosts resolve runtime knobs (step delay, implicit wait, env vars, network monitoring)
|
|
15
|
+
* identically instead of each keeping a private config shape.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Metadata for an auto-discovered Page Object class. */
|
|
19
|
+
export interface PageObjectInfo {
|
|
20
|
+
name: string;
|
|
21
|
+
file_path: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Metadata for an auto-discovered Fixture data file. */
|
|
25
|
+
export interface FixtureInfo {
|
|
26
|
+
name: string;
|
|
27
|
+
file_path: string;
|
|
28
|
+
is_json: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Metadata for an auto-discovered Step definition. */
|
|
32
|
+
export interface StepInfo {
|
|
33
|
+
name: string;
|
|
34
|
+
file_path: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Metadata for an auto-discovered custom Action. */
|
|
38
|
+
export interface ActionInfo {
|
|
39
|
+
name: string;
|
|
40
|
+
file_path: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Metadata for an auto-discovered lifecycle Hook. */
|
|
44
|
+
export interface HookInfo {
|
|
45
|
+
hook_type: 'before' | 'after' | 'beforeEach' | 'afterEach' | string;
|
|
46
|
+
file_path: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Auto-import manifest containing all discovered support files. */
|
|
50
|
+
export interface AutoImportManifestConfig {
|
|
51
|
+
page_objects?: PageObjectInfo[];
|
|
52
|
+
fixtures?: FixtureInfo[];
|
|
53
|
+
steps?: StepInfo[];
|
|
54
|
+
actions?: ActionInfo[];
|
|
55
|
+
global_hooks?: HookInfo[];
|
|
56
|
+
suite_hooks?: Record<string, HookInfo[]>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** One targeted test case inside a worker's batch. */
|
|
60
|
+
export interface TestCaseTargetItem {
|
|
61
|
+
id: string;
|
|
62
|
+
title: string;
|
|
63
|
+
filePath: string;
|
|
64
|
+
suite: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Runtime configuration injected by a host (Rust orchestrator or `@testspectra/react`) via
|
|
69
|
+
* `globalThis.__TESTSPECTRA_CONFIG__`.
|
|
70
|
+
*/
|
|
71
|
+
export interface TestSpectraWorkerConfig {
|
|
72
|
+
workerId?: number;
|
|
73
|
+
rootDir: string;
|
|
74
|
+
testFilePath?: string;
|
|
75
|
+
testFiles?: TestCaseTargetItem[];
|
|
76
|
+
activePlatform: string;
|
|
77
|
+
configuredBaseUrl: string;
|
|
78
|
+
cdpWsUrl: string;
|
|
79
|
+
driverServerUrl: string;
|
|
80
|
+
manifest?: AutoImportManifestConfig;
|
|
81
|
+
/** Target app package (Android). Paired with androidSerial/adbPath for on-demand adb actions. */
|
|
82
|
+
appPackage?: string;
|
|
83
|
+
/** Target adb device serial for this worker (Android only). */
|
|
84
|
+
androidSerial?: string;
|
|
85
|
+
/** Resolved `adb` binary path (Android only), paired with androidSerial above. */
|
|
86
|
+
adbPath?: string;
|
|
87
|
+
/** Host port this worker's own MobileMockProxyServer should listen on (Android only). */
|
|
88
|
+
mockProxyPort?: number;
|
|
89
|
+
implicitWaitMs?: number;
|
|
90
|
+
timeoutMs?: number;
|
|
91
|
+
stepDelayMs?: number;
|
|
92
|
+
/** Video recording options or boolean toggle */
|
|
93
|
+
video?: boolean | Record<string, any>;
|
|
94
|
+
/** Configured host aliases (e.g. auth: 'http://auth.local'). */
|
|
95
|
+
hosts?: Record<string, string>;
|
|
96
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.networkMonitoringEnabled` (default: true). */
|
|
97
|
+
networkMonitoringEnabled?: boolean;
|
|
98
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.monitoredDomains`. Empty/absent = capture all. */
|
|
99
|
+
monitoredDomains?: { domain: string; enabled: boolean }[];
|
|
100
|
+
/** Mirrors `spectra.config.ts`'s `executionConfig.environmentVariables`. */
|
|
101
|
+
environmentVariables?: Record<string, string>;
|
|
102
|
+
}
|
|
Binary file
|
package/tsconfig.json
CHANGED
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fluent assertion matchers for `SingleElementProxy`.
|
|
3
|
-
*
|
|
4
|
-
* Each matcher polls the bound `PlatformDriverBridge` (or the delegated state getters) with
|
|
5
|
-
* `trackStep('assertion')` instrumentation. There is zero `activePlatform` branching here —
|
|
6
|
-
* platform-specific behavior lives entirely in the driver's `isClickable` / `hasClass` /
|
|
7
|
-
* state-inspection methods.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { AssertionOptions, ScopedSelector } from '../types.js';
|
|
11
|
-
|
|
12
|
-
export function createElementAssertions(
|
|
13
|
-
selector: string | ScopedSelector,
|
|
14
|
-
index: number | null,
|
|
15
|
-
state: Record<string, any>,
|
|
16
|
-
): Record<string, any> {
|
|
17
|
-
const driver = () => globalThis.__TS_RUNTIME__.activeDriver!;
|
|
18
|
-
const selectorText = typeof selector === 'string' ? selector : selector.selector;
|
|
19
|
-
|
|
20
|
-
async function shouldBeVisible(options?: AssertionOptions): Promise<void> {
|
|
21
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
22
|
-
'assertion',
|
|
23
|
-
{ type: 'assertion', key: 'be.visible', target: selector, args: [] },
|
|
24
|
-
async () => {
|
|
25
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
26
|
-
() => state.isVisible(),
|
|
27
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
28
|
-
);
|
|
29
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to be visible`);
|
|
30
|
-
},
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function shouldNotBeVisible(options?: AssertionOptions): Promise<void> {
|
|
35
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
36
|
-
'assertion',
|
|
37
|
-
{ type: 'assertion', key: 'not.be.visible', target: selector, args: [] },
|
|
38
|
-
async () => {
|
|
39
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
40
|
-
async () => !(await state.isVisible()),
|
|
41
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
42
|
-
);
|
|
43
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to be visible`);
|
|
44
|
-
},
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function shouldExist(options?: AssertionOptions): Promise<void> {
|
|
49
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
50
|
-
'assertion',
|
|
51
|
-
{ type: 'assertion', key: 'exist', target: selector, args: [] },
|
|
52
|
-
async () => {
|
|
53
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
54
|
-
() => state.isExisting(),
|
|
55
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
56
|
-
);
|
|
57
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to exist in DOM`);
|
|
58
|
-
},
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async function shouldNotExist(options?: AssertionOptions): Promise<void> {
|
|
63
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
64
|
-
'assertion',
|
|
65
|
-
{ type: 'assertion', key: 'not.exist', target: selector, args: [] },
|
|
66
|
-
async () => {
|
|
67
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
68
|
-
async () => !(await state.isExisting()),
|
|
69
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
70
|
-
);
|
|
71
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to exist in DOM`);
|
|
72
|
-
},
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function shouldBeEnabled(options?: AssertionOptions): Promise<void> {
|
|
77
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
78
|
-
'assertion',
|
|
79
|
-
{ type: 'assertion', key: 'be.enabled', target: selector, args: [] },
|
|
80
|
-
async () => {
|
|
81
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
82
|
-
() => state.isEnabled(),
|
|
83
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
84
|
-
);
|
|
85
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to be enabled`);
|
|
86
|
-
},
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async function shouldBeDisabled(options?: AssertionOptions): Promise<void> {
|
|
91
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
92
|
-
'assertion',
|
|
93
|
-
{ type: 'assertion', key: 'be.disabled', target: selector, args: [] },
|
|
94
|
-
async () => {
|
|
95
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
96
|
-
async () => !(await state.isEnabled()),
|
|
97
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
98
|
-
);
|
|
99
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to be disabled`);
|
|
100
|
-
},
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async function shouldBeClickable(options?: AssertionOptions): Promise<void> {
|
|
105
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
106
|
-
'assertion',
|
|
107
|
-
{ type: 'assertion', key: 'be.clickable', target: selector, args: [] },
|
|
108
|
-
async () => {
|
|
109
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
110
|
-
() => driver().isClickable(selector, index),
|
|
111
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
112
|
-
);
|
|
113
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to be clickable`);
|
|
114
|
-
},
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async function shouldNotBeClickable(options?: AssertionOptions): Promise<void> {
|
|
119
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
120
|
-
'assertion',
|
|
121
|
-
{ type: 'assertion', key: 'not.be.clickable', target: selector, args: [] },
|
|
122
|
-
async () => {
|
|
123
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
124
|
-
async () => !(await driver().isClickable(selector, index)),
|
|
125
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
126
|
-
);
|
|
127
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to be clickable`);
|
|
128
|
-
},
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async function shouldBeChecked(options?: AssertionOptions): Promise<void> {
|
|
133
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
134
|
-
'assertion',
|
|
135
|
-
{ type: 'assertion', key: 'be.checked', target: selector, args: [] },
|
|
136
|
-
async () => {
|
|
137
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
138
|
-
() => state.isChecked(),
|
|
139
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
140
|
-
);
|
|
141
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to be checked`);
|
|
142
|
-
},
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function shouldNotBeChecked(options?: AssertionOptions): Promise<void> {
|
|
147
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
148
|
-
'assertion',
|
|
149
|
-
{ type: 'assertion', key: 'not.be.checked', target: selector, args: [] },
|
|
150
|
-
async () => {
|
|
151
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
152
|
-
async () => !(await state.isChecked()),
|
|
153
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
154
|
-
);
|
|
155
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to be checked`);
|
|
156
|
-
},
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async function shouldBeFocused(options?: AssertionOptions): Promise<void> {
|
|
161
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
162
|
-
'assertion',
|
|
163
|
-
{ type: 'assertion', key: 'be.focused', target: selector, args: [] },
|
|
164
|
-
async () => {
|
|
165
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
166
|
-
() => state.isFocused(),
|
|
167
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
168
|
-
);
|
|
169
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to be focused`);
|
|
170
|
-
},
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
async function shouldNotBeFocused(options?: AssertionOptions): Promise<void> {
|
|
175
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
176
|
-
'assertion',
|
|
177
|
-
{ type: 'assertion', key: 'not.be.focused', target: selector, args: [] },
|
|
178
|
-
async () => {
|
|
179
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
180
|
-
async () => !(await state.isFocused()),
|
|
181
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
182
|
-
);
|
|
183
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to be focused`);
|
|
184
|
-
},
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async function shouldHaveValue(value: unknown, options?: AssertionOptions): Promise<void> {
|
|
189
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
190
|
-
'assertion',
|
|
191
|
-
{ type: 'assertion', key: 'have.value', target: selector, args: [value] },
|
|
192
|
-
async () => {
|
|
193
|
-
let actual = '';
|
|
194
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
195
|
-
actual = await state.getValue();
|
|
196
|
-
return actual === String(value);
|
|
197
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
198
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to have value "${value}", but got "${actual}"`);
|
|
199
|
-
},
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
async function shouldNotHaveValue(value: unknown, options?: AssertionOptions): Promise<void> {
|
|
204
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
205
|
-
'assertion',
|
|
206
|
-
{ type: 'assertion', key: 'not.have.value', target: selector, args: [value] },
|
|
207
|
-
async () => {
|
|
208
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
209
|
-
const actual = await state.getValue();
|
|
210
|
-
return actual !== String(value);
|
|
211
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
212
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to have value "${value}"`);
|
|
213
|
-
},
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async function shouldContainValue(value: unknown, options?: AssertionOptions): Promise<void> {
|
|
218
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
219
|
-
'assertion',
|
|
220
|
-
{ type: 'assertion', key: 'contain.value', target: selector, args: [value] },
|
|
221
|
-
async () => {
|
|
222
|
-
let actual = '';
|
|
223
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
224
|
-
actual = await state.getValue();
|
|
225
|
-
return actual.includes(String(value));
|
|
226
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
227
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to contain value "${value}", but got "${actual}"`);
|
|
228
|
-
},
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async function shouldNotContainValue(value: unknown, options?: AssertionOptions): Promise<void> {
|
|
233
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
234
|
-
'assertion',
|
|
235
|
-
{ type: 'assertion', key: 'not.contain.value', target: selector, args: [value] },
|
|
236
|
-
async () => {
|
|
237
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
238
|
-
const actual = await state.getValue();
|
|
239
|
-
return !actual.includes(String(value));
|
|
240
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
241
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to contain value "${value}"`);
|
|
242
|
-
},
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async function shouldHaveText(expected: string | RegExp, options?: AssertionOptions): Promise<void> {
|
|
247
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
248
|
-
'assertion',
|
|
249
|
-
{ type: 'assertion', key: 'have.text', target: selector, args: [expected] },
|
|
250
|
-
async () => {
|
|
251
|
-
let actual = '';
|
|
252
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
253
|
-
actual = await state.getText();
|
|
254
|
-
if (expected instanceof RegExp) return expected.test(actual);
|
|
255
|
-
return actual === String(expected) || actual.trim() === String(expected).trim();
|
|
256
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
257
|
-
if (!ok) {
|
|
258
|
-
if (expected instanceof RegExp)
|
|
259
|
-
throw new Error(`Expected element "${selectorText}" text to match ${expected}, but got "${actual}"`);
|
|
260
|
-
throw new Error(`Expected element "${selectorText}" to have text "${expected}", but got "${actual}"`);
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
async function shouldNotHaveText(expected: string | RegExp, options?: AssertionOptions): Promise<void> {
|
|
267
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
268
|
-
'assertion',
|
|
269
|
-
{ type: 'assertion', key: 'not.have.text', target: selector, args: [expected] },
|
|
270
|
-
async () => {
|
|
271
|
-
let actual = '';
|
|
272
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
273
|
-
if (!(await state.isExisting())) return false;
|
|
274
|
-
actual = await state.getText();
|
|
275
|
-
if (expected instanceof RegExp) return !expected.test(actual);
|
|
276
|
-
return actual !== String(expected) && actual.trim() !== String(expected).trim();
|
|
277
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
278
|
-
if (!ok) {
|
|
279
|
-
if (expected instanceof RegExp)
|
|
280
|
-
throw new Error(`Expected element "${selectorText}" text not to match ${expected}`);
|
|
281
|
-
throw new Error(`Expected element "${selectorText}" not to have text "${expected}"`);
|
|
282
|
-
}
|
|
283
|
-
},
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
async function shouldContainText(substring: string, options?: AssertionOptions): Promise<void> {
|
|
288
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
289
|
-
'assertion',
|
|
290
|
-
{ type: 'assertion', key: 'contain.text', target: selector, args: [substring] },
|
|
291
|
-
async () => {
|
|
292
|
-
let actual = '';
|
|
293
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
294
|
-
actual = await state.getText();
|
|
295
|
-
return actual.includes(String(substring));
|
|
296
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
297
|
-
if (!ok)
|
|
298
|
-
throw new Error(`Expected element "${selectorText}" to contain text "${substring}", but got "${actual}"`);
|
|
299
|
-
},
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
async function shouldNotContainText(substring: string, options?: AssertionOptions): Promise<void> {
|
|
304
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
305
|
-
'assertion',
|
|
306
|
-
{ type: 'assertion', key: 'not.contain.text', target: selector, args: [substring] },
|
|
307
|
-
async () => {
|
|
308
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
309
|
-
const actual = await state.getText();
|
|
310
|
-
return !actual.includes(String(substring));
|
|
311
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
312
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to contain text "${substring}"`);
|
|
313
|
-
},
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
async function shouldHaveClass(className: string, options?: AssertionOptions): Promise<void> {
|
|
318
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
319
|
-
'assertion',
|
|
320
|
-
{ type: 'assertion', key: 'have.class', target: selector, args: [className] },
|
|
321
|
-
async () => {
|
|
322
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
323
|
-
() => driver().hasClass(selector, className, index),
|
|
324
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
325
|
-
);
|
|
326
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" to have class "${className}"`);
|
|
327
|
-
},
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
async function shouldNotHaveClass(className: string, options?: AssertionOptions): Promise<void> {
|
|
332
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
333
|
-
'assertion',
|
|
334
|
-
{ type: 'assertion', key: 'not.have.class', target: selector, args: [className] },
|
|
335
|
-
async () => {
|
|
336
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(
|
|
337
|
-
async () => !(await driver().hasClass(selector, className, index)),
|
|
338
|
-
options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs(),
|
|
339
|
-
);
|
|
340
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to have class "${className}"`);
|
|
341
|
-
},
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
async function shouldHaveAttribute(name: string, value?: string, options?: AssertionOptions): Promise<void> {
|
|
346
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
347
|
-
'assertion',
|
|
348
|
-
{ type: 'assertion', key: 'have.attr', target: selector, args: value !== undefined ? [name, value] : [name] },
|
|
349
|
-
async () => {
|
|
350
|
-
let actual: string | null = null;
|
|
351
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
352
|
-
actual = await state.getAttribute(name);
|
|
353
|
-
if (value !== undefined) return actual === String(value);
|
|
354
|
-
return actual !== null;
|
|
355
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
356
|
-
if (!ok) {
|
|
357
|
-
if (value !== undefined)
|
|
358
|
-
throw new Error(
|
|
359
|
-
`Expected element "${selectorText}" to have attribute "${name}" = "${value}", but got "${actual}"`,
|
|
360
|
-
);
|
|
361
|
-
throw new Error(`Expected element "${selectorText}" to have attribute "${name}"`);
|
|
362
|
-
}
|
|
363
|
-
},
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
async function shouldNotHaveAttribute(name: string, options?: AssertionOptions): Promise<void> {
|
|
368
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
369
|
-
'assertion',
|
|
370
|
-
{ type: 'assertion', key: 'not.have.attr', target: selector, args: [name] },
|
|
371
|
-
async () => {
|
|
372
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
373
|
-
const actual = await state.getAttribute(name);
|
|
374
|
-
return actual === null;
|
|
375
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
376
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to have attribute "${name}"`);
|
|
377
|
-
},
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
async function shouldHaveCss(property: string, value: string, options?: AssertionOptions): Promise<void> {
|
|
382
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
383
|
-
'assertion',
|
|
384
|
-
{ type: 'assertion', key: 'have.css', target: selector, args: [property, value] },
|
|
385
|
-
async () => {
|
|
386
|
-
const norm = (v: any) =>
|
|
387
|
-
String(v ?? '')
|
|
388
|
-
.replace(/\s+/g, '')
|
|
389
|
-
.replace(/rgba\((.+?),1\)/, 'rgb($1)')
|
|
390
|
-
.toLowerCase();
|
|
391
|
-
let actualCss = '';
|
|
392
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
393
|
-
const css = await state.getCSSProperty(property);
|
|
394
|
-
actualCss = css.value;
|
|
395
|
-
return norm(actualCss) === norm(value);
|
|
396
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
397
|
-
if (!ok)
|
|
398
|
-
throw new Error(
|
|
399
|
-
`Expected element "${selectorText}" to have CSS "${property}" = "${value}", but got "${actualCss}"`,
|
|
400
|
-
);
|
|
401
|
-
},
|
|
402
|
-
);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
async function shouldNotHaveCss(property: string, value: string, options?: AssertionOptions): Promise<void> {
|
|
406
|
-
return globalThis.__TS_RUNTIME__.trackStep(
|
|
407
|
-
'assertion',
|
|
408
|
-
{ type: 'assertion', key: 'not.have.css', target: selector, args: [property, value] },
|
|
409
|
-
async () => {
|
|
410
|
-
const norm = (v: any) =>
|
|
411
|
-
String(v ?? '')
|
|
412
|
-
.replace(/\s+/g, '')
|
|
413
|
-
.replace(/rgba\((.+?),1\)/, 'rgb($1)')
|
|
414
|
-
.toLowerCase();
|
|
415
|
-
const ok = await globalThis.__TS_RUNTIME__.pollCondition(async () => {
|
|
416
|
-
const css = await state.getCSSProperty(property);
|
|
417
|
-
return norm(css.value) !== norm(value);
|
|
418
|
-
}, options?.timeoutMs ?? globalThis.__TS_RUNTIME__.getAssertionTimeoutMs());
|
|
419
|
-
if (!ok) throw new Error(`Expected element "${selectorText}" not to have CSS "${property}" = "${value}"`);
|
|
420
|
-
},
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return {
|
|
425
|
-
shouldBeVisible,
|
|
426
|
-
shouldNotBeVisible,
|
|
427
|
-
shouldExist,
|
|
428
|
-
shouldNotExist,
|
|
429
|
-
shouldBeEnabled,
|
|
430
|
-
shouldBeDisabled,
|
|
431
|
-
shouldBeClickable,
|
|
432
|
-
shouldNotBeClickable,
|
|
433
|
-
shouldBeChecked,
|
|
434
|
-
shouldNotBeChecked,
|
|
435
|
-
shouldBeFocused,
|
|
436
|
-
shouldNotBeFocused,
|
|
437
|
-
shouldHaveValue,
|
|
438
|
-
shouldNotHaveValue,
|
|
439
|
-
shouldContainValue,
|
|
440
|
-
shouldNotContainValue,
|
|
441
|
-
shouldHaveText,
|
|
442
|
-
shouldNotHaveText,
|
|
443
|
-
shouldContainText,
|
|
444
|
-
shouldNotContainText,
|
|
445
|
-
shouldHaveClass,
|
|
446
|
-
shouldNotHaveClass,
|
|
447
|
-
shouldHaveAttribute,
|
|
448
|
-
shouldNotHaveAttribute,
|
|
449
|
-
shouldHaveCss,
|
|
450
|
-
shouldNotHaveCss,
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
globalThis.__TS_RUNTIME__.createElementAssertions = createElementAssertions;
|