browsecraft 0.1.0
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/LICENSE +21 -0
- package/dist/chunk-77HRTGXZ.js +2004 -0
- package/dist/chunk-77HRTGXZ.js.map +1 -0
- package/dist/chunk-KIPQFK3Y.cjs +2021 -0
- package/dist/chunk-KIPQFK3Y.cjs.map +1 -0
- package/dist/cli.cjs +297 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +295 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +831 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +984 -0
- package/dist/index.d.ts +984 -0
- package/dist/index.js +632 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
import { NodeRemoteValue, BrowserName, BiDiSession, StorageCookie } from 'browsecraft-bidi';
|
|
2
|
+
export { StorageCookie } from 'browsecraft-bidi';
|
|
3
|
+
export { After, AfterFeature, AfterStep, AutoStepOptions, AutoStepResult, AfterAll as BddAfterAll, BeforeAll as BddBeforeAll, BddExecutor, Before, BeforeFeature, BeforeStep, BrowsecraftDataTable, ExecutorOptions, FeatureResult, GeneratedStepDef, GherkinDocument, Feature as GherkinFeature, Scenario as GherkinScenario, Given, RunResult, ScenarioContext, ScenarioResult, Step, StepDefinition, StepFunction, StepMatch, StepResult, StepStatus, StepWorld, Then, TsBddOptions, When, and, autoGenerateSteps, autoGenerateStepsFromDocument, but, clearFeatures, createExecutor, defineParameterType, feature, getSupportedLanguages, given, globalRegistry, matchesTags, parseGherkin, parseTagExpression, pending, runFeatures, scenario, then, when } from 'browsecraft-bdd';
|
|
4
|
+
|
|
5
|
+
/** What the user passes to click(), fill(), get() */
|
|
6
|
+
type ElementTarget = string | LocatorOptions;
|
|
7
|
+
/** Advanced locator options (for when you need precision) */
|
|
8
|
+
interface LocatorOptions {
|
|
9
|
+
/** Find by ARIA role (e.g., 'button', 'link', 'textbox') */
|
|
10
|
+
role?: string;
|
|
11
|
+
/** Find by accessible name or visible text */
|
|
12
|
+
name?: string;
|
|
13
|
+
/** Find by <label> text (for form inputs) */
|
|
14
|
+
label?: string;
|
|
15
|
+
/** Find by visible text content */
|
|
16
|
+
text?: string;
|
|
17
|
+
/** Find by data-testid attribute */
|
|
18
|
+
testId?: string;
|
|
19
|
+
/** Find by CSS selector */
|
|
20
|
+
selector?: string;
|
|
21
|
+
/** Require exact text match (default: false = partial match) */
|
|
22
|
+
exact?: boolean;
|
|
23
|
+
/** Which match to use if multiple found (0-based, default: 0) */
|
|
24
|
+
index?: number;
|
|
25
|
+
}
|
|
26
|
+
/** Result of locating an element */
|
|
27
|
+
interface LocatedElement {
|
|
28
|
+
/** The node reference for BiDi commands */
|
|
29
|
+
node: NodeRemoteValue;
|
|
30
|
+
/** How we found it (for debugging/logging) */
|
|
31
|
+
strategy: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Full configuration with all options */
|
|
35
|
+
interface BrowsecraftConfig {
|
|
36
|
+
/** Which browser to use (default: 'chrome') */
|
|
37
|
+
browser: BrowserName;
|
|
38
|
+
/** Run in headless mode (default: true) */
|
|
39
|
+
headless: boolean;
|
|
40
|
+
/** Global timeout for actions in ms (default: 30000) */
|
|
41
|
+
timeout: number;
|
|
42
|
+
/** How many times to retry a failed test (default: 0) */
|
|
43
|
+
retries: number;
|
|
44
|
+
/** Take screenshots: 'always', 'on-failure', or 'never' (default: 'on-failure') */
|
|
45
|
+
screenshot: 'always' | 'on-failure' | 'never';
|
|
46
|
+
/** Base URL prepended to all page.goto() calls (default: '') */
|
|
47
|
+
baseURL: string;
|
|
48
|
+
/** Custom browser executable path */
|
|
49
|
+
executablePath?: string;
|
|
50
|
+
/** Viewport size (default: 1280x720) */
|
|
51
|
+
viewport: {
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
};
|
|
55
|
+
/** Start the browser window maximized (headed mode only, default: false) */
|
|
56
|
+
maximized: boolean;
|
|
57
|
+
/** Number of parallel workers (default: CPU cores / 2) */
|
|
58
|
+
workers: number;
|
|
59
|
+
/** Test file pattern (default: '**\/*.test.{ts,js,mts,mjs}') */
|
|
60
|
+
testMatch: string;
|
|
61
|
+
/** Output directory for reports/screenshots (default: '.browsecraft') */
|
|
62
|
+
outputDir: string;
|
|
63
|
+
/** AI mode: 'auto' detects GitHub Models availability, 'off' disables (default: 'auto') */
|
|
64
|
+
ai: 'auto' | 'off' | AIConfig;
|
|
65
|
+
/** Enable verbose debug logging (default: false) */
|
|
66
|
+
debug: boolean;
|
|
67
|
+
}
|
|
68
|
+
interface AIConfig {
|
|
69
|
+
provider: 'github-models';
|
|
70
|
+
/** Model to use (default: 'openai/gpt-4o-mini') */
|
|
71
|
+
model?: string;
|
|
72
|
+
/** Explicit GitHub token (overrides env vars) */
|
|
73
|
+
token?: string;
|
|
74
|
+
}
|
|
75
|
+
/** Users provide a partial config -- everything has smart defaults */
|
|
76
|
+
type UserConfig = Partial<BrowsecraftConfig>;
|
|
77
|
+
/**
|
|
78
|
+
* Define your Browsecraft config with full type safety and IntelliSense.
|
|
79
|
+
* This function is optional -- it's just a type helper for your IDE.
|
|
80
|
+
*
|
|
81
|
+
* ```ts
|
|
82
|
+
* // browsecraft.config.ts
|
|
83
|
+
* import { defineConfig } from 'browsecraft';
|
|
84
|
+
*
|
|
85
|
+
* export default defineConfig({
|
|
86
|
+
* browser: 'firefox',
|
|
87
|
+
* timeout: 60_000,
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function defineConfig(config: UserConfig): UserConfig;
|
|
92
|
+
/**
|
|
93
|
+
* Resolve user config by merging with defaults.
|
|
94
|
+
* This is used internally -- users never call this.
|
|
95
|
+
*/
|
|
96
|
+
declare function resolveConfig(userConfig?: UserConfig): BrowsecraftConfig;
|
|
97
|
+
|
|
98
|
+
/** Options for page.goto() */
|
|
99
|
+
interface GotoOptions {
|
|
100
|
+
/** Wait until page reaches this state (default: 'complete') */
|
|
101
|
+
waitUntil?: 'none' | 'interactive' | 'complete';
|
|
102
|
+
/** Timeout in ms (default: config.timeout) */
|
|
103
|
+
timeout?: number;
|
|
104
|
+
}
|
|
105
|
+
/** Options for page.fill() */
|
|
106
|
+
interface FillOptions {
|
|
107
|
+
/** Timeout in ms (default: config.timeout) */
|
|
108
|
+
timeout?: number;
|
|
109
|
+
}
|
|
110
|
+
/** Options for page.click() */
|
|
111
|
+
interface ClickOptions {
|
|
112
|
+
/** Timeout in ms (default: config.timeout) */
|
|
113
|
+
timeout?: number;
|
|
114
|
+
/** Mouse button (default: 0 = left) */
|
|
115
|
+
button?: number;
|
|
116
|
+
/** Number of clicks (default: 1, use 2 for double-click) */
|
|
117
|
+
clickCount?: number;
|
|
118
|
+
}
|
|
119
|
+
/** Mock response definition */
|
|
120
|
+
interface MockResponse {
|
|
121
|
+
/** HTTP status code */
|
|
122
|
+
status?: number;
|
|
123
|
+
/** Response headers */
|
|
124
|
+
headers?: Record<string, string>;
|
|
125
|
+
/** Response body (string or object that will be JSON-stringified) */
|
|
126
|
+
body?: string | Record<string, unknown>;
|
|
127
|
+
/** Content type (default: 'application/json' for objects, 'text/plain' for strings) */
|
|
128
|
+
contentType?: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Page represents a single browser tab/page.
|
|
132
|
+
* This is the main API surface users interact with.
|
|
133
|
+
*
|
|
134
|
+
* Every action auto-waits for the element to be ready.
|
|
135
|
+
* No sleep(). No waitFor(). It just works.
|
|
136
|
+
*/
|
|
137
|
+
declare class Page {
|
|
138
|
+
/** @internal */
|
|
139
|
+
readonly session: BiDiSession;
|
|
140
|
+
/** @internal */
|
|
141
|
+
readonly contextId: string;
|
|
142
|
+
/** @internal */
|
|
143
|
+
private config;
|
|
144
|
+
/** @internal */
|
|
145
|
+
private interceptIds;
|
|
146
|
+
/** @internal -- event listener unsubscribe functions for cleanup */
|
|
147
|
+
private eventCleanups;
|
|
148
|
+
constructor(session: BiDiSession, contextId: string, config: BrowsecraftConfig);
|
|
149
|
+
/**
|
|
150
|
+
* Navigate to a URL.
|
|
151
|
+
*
|
|
152
|
+
* ```ts
|
|
153
|
+
* await page.goto('https://example.com');
|
|
154
|
+
* await page.goto('/login'); // uses baseURL from config
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
goto(url: string, options?: GotoOptions): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Reload the current page.
|
|
160
|
+
*/
|
|
161
|
+
reload(options?: GotoOptions): Promise<void>;
|
|
162
|
+
/**
|
|
163
|
+
* Go back in browser history.
|
|
164
|
+
*/
|
|
165
|
+
goBack(): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* Go forward in browser history.
|
|
168
|
+
*/
|
|
169
|
+
goForward(): Promise<void>;
|
|
170
|
+
/**
|
|
171
|
+
* Click an element. Finds it by text, role, or selector -- auto-waits.
|
|
172
|
+
*
|
|
173
|
+
* ```ts
|
|
174
|
+
* await page.click('Submit'); // by text
|
|
175
|
+
* await page.click({ role: 'button', name: 'Submit' }); // precise
|
|
176
|
+
* await page.click({ selector: '#my-button' }); // CSS
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
click(target: ElementTarget, options?: ClickOptions): Promise<void>;
|
|
180
|
+
/**
|
|
181
|
+
* Fill a text input. First arg finds the input, second is the value.
|
|
182
|
+
*
|
|
183
|
+
* ```ts
|
|
184
|
+
* await page.fill('Email', 'user@test.com'); // by label
|
|
185
|
+
* await page.fill('Search', 'browsecraft'); // by placeholder
|
|
186
|
+
* await page.fill({ selector: '#email' }, 'test'); // by CSS
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
fill(target: ElementTarget, value: string, options?: FillOptions): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Type text character by character (triggers keyboard events).
|
|
192
|
+
* Use this instead of fill() when you need realistic keyboard input.
|
|
193
|
+
*
|
|
194
|
+
* ```ts
|
|
195
|
+
* await page.type('Search', 'browsecraft');
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
type(target: ElementTarget, text: string, options?: FillOptions): Promise<void>;
|
|
199
|
+
/**
|
|
200
|
+
* Select an option from a <select> dropdown.
|
|
201
|
+
*
|
|
202
|
+
* ```ts
|
|
203
|
+
* await page.select('Country', 'United States');
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
select(target: ElementTarget, value: string, options?: FillOptions): Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Check a checkbox or radio button.
|
|
209
|
+
*
|
|
210
|
+
* ```ts
|
|
211
|
+
* await page.check('I agree to the terms');
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
check(target: ElementTarget, options?: ClickOptions): Promise<void>;
|
|
215
|
+
/**
|
|
216
|
+
* Uncheck a checkbox.
|
|
217
|
+
*/
|
|
218
|
+
uncheck(target: ElementTarget, options?: ClickOptions): Promise<void>;
|
|
219
|
+
/**
|
|
220
|
+
* Hover over an element.
|
|
221
|
+
*
|
|
222
|
+
* ```ts
|
|
223
|
+
* await page.hover('Profile Menu');
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
hover(target: ElementTarget, options?: {
|
|
227
|
+
timeout?: number;
|
|
228
|
+
}): Promise<void>;
|
|
229
|
+
/**
|
|
230
|
+
* Get a single element. Returns an ElementHandle for assertions.
|
|
231
|
+
*
|
|
232
|
+
* ```ts
|
|
233
|
+
* const heading = page.get('Welcome back!');
|
|
234
|
+
* await expect(heading).toBeVisible();
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
get(target: ElementTarget): ElementHandle;
|
|
238
|
+
/**
|
|
239
|
+
* Get a locator by visible text. Alias for get() with text matching.
|
|
240
|
+
*
|
|
241
|
+
* ```ts
|
|
242
|
+
* const btn = page.getByText('Submit');
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
getByText(text: string, options?: {
|
|
246
|
+
exact?: boolean;
|
|
247
|
+
}): ElementHandle;
|
|
248
|
+
/**
|
|
249
|
+
* Get a locator by ARIA role and optional name.
|
|
250
|
+
*
|
|
251
|
+
* ```ts
|
|
252
|
+
* const btn = page.getByRole('button', { name: 'Submit' });
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
getByRole(role: string, options?: {
|
|
256
|
+
name?: string;
|
|
257
|
+
exact?: boolean;
|
|
258
|
+
}): ElementHandle;
|
|
259
|
+
/**
|
|
260
|
+
* Get a locator by label text (for form inputs).
|
|
261
|
+
*
|
|
262
|
+
* ```ts
|
|
263
|
+
* const email = page.getByLabel('Email Address');
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
getByLabel(label: string, options?: {
|
|
267
|
+
exact?: boolean;
|
|
268
|
+
}): ElementHandle;
|
|
269
|
+
/**
|
|
270
|
+
* Get a locator by data-testid attribute.
|
|
271
|
+
*
|
|
272
|
+
* ```ts
|
|
273
|
+
* const card = page.getByTestId('user-card');
|
|
274
|
+
* ```
|
|
275
|
+
*/
|
|
276
|
+
getByTestId(testId: string): ElementHandle;
|
|
277
|
+
/** Get the current page URL */
|
|
278
|
+
url(): Promise<string>;
|
|
279
|
+
/** Get the page title */
|
|
280
|
+
title(): Promise<string>;
|
|
281
|
+
/** Get the full page HTML content */
|
|
282
|
+
content(): Promise<string>;
|
|
283
|
+
/**
|
|
284
|
+
* Get cookies for the current page's browsing context.
|
|
285
|
+
*
|
|
286
|
+
* ```ts
|
|
287
|
+
* const cookies = await page.cookies();
|
|
288
|
+
* const session = cookies.find(c => c.name === 'session_id');
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
cookies(filter?: {
|
|
292
|
+
name?: string;
|
|
293
|
+
domain?: string;
|
|
294
|
+
path?: string;
|
|
295
|
+
}): Promise<StorageCookie[]>;
|
|
296
|
+
/**
|
|
297
|
+
* Set one or more cookies.
|
|
298
|
+
*
|
|
299
|
+
* ```ts
|
|
300
|
+
* await page.setCookies([
|
|
301
|
+
* { name: 'token', value: 'abc123', domain: 'example.com' },
|
|
302
|
+
* { name: 'theme', value: 'dark', domain: 'example.com' },
|
|
303
|
+
* ]);
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
setCookies(cookies: Array<{
|
|
307
|
+
name: string;
|
|
308
|
+
value: string;
|
|
309
|
+
domain?: string;
|
|
310
|
+
path?: string;
|
|
311
|
+
httpOnly?: boolean;
|
|
312
|
+
secure?: boolean;
|
|
313
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
314
|
+
expiry?: number;
|
|
315
|
+
}>): Promise<void>;
|
|
316
|
+
/**
|
|
317
|
+
* Clear all cookies (or those matching a filter).
|
|
318
|
+
*
|
|
319
|
+
* ```ts
|
|
320
|
+
* await page.clearCookies(); // all cookies
|
|
321
|
+
* await page.clearCookies({ name: 'session_id' }); // specific cookie
|
|
322
|
+
* await page.clearCookies({ domain: 'example.com' }); // by domain
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
clearCookies(filter?: {
|
|
326
|
+
name?: string;
|
|
327
|
+
domain?: string;
|
|
328
|
+
path?: string;
|
|
329
|
+
}): Promise<void>;
|
|
330
|
+
/**
|
|
331
|
+
* Execute JavaScript in the page and return the result.
|
|
332
|
+
*
|
|
333
|
+
* ```ts
|
|
334
|
+
* const title = await page.evaluate('document.title');
|
|
335
|
+
* const count = await page.evaluate(() => document.querySelectorAll('li').length);
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
evaluate<T = unknown>(expression: string | (() => T)): Promise<T>;
|
|
339
|
+
/**
|
|
340
|
+
* Take a screenshot of the page.
|
|
341
|
+
*
|
|
342
|
+
* ```ts
|
|
343
|
+
* const buffer = await page.screenshot();
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
screenshot(): Promise<Buffer>;
|
|
347
|
+
/**
|
|
348
|
+
* Mock a network request with a fake response.
|
|
349
|
+
*
|
|
350
|
+
* ```ts
|
|
351
|
+
* await page.mock('POST /api/login', { status: 200, body: { token: 'abc' } });
|
|
352
|
+
* await page.mock('GET /api/users', { status: 500 });
|
|
353
|
+
* await page.mock('https://api.example.com/data', { body: { items: [] } });
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
mock(pattern: string, response: MockResponse): Promise<void>;
|
|
357
|
+
/**
|
|
358
|
+
* Remove all network mocks and clean up event listeners.
|
|
359
|
+
*/
|
|
360
|
+
clearMocks(): Promise<void>;
|
|
361
|
+
/**
|
|
362
|
+
* Accept the next dialog (alert, confirm, prompt).
|
|
363
|
+
*
|
|
364
|
+
* ```ts
|
|
365
|
+
* await page.acceptDialog();
|
|
366
|
+
* page.click('Delete'); // triggers confirm dialog
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
acceptDialog(text?: string): Promise<void>;
|
|
370
|
+
/**
|
|
371
|
+
* Dismiss the next dialog.
|
|
372
|
+
*/
|
|
373
|
+
dismissDialog(): Promise<void>;
|
|
374
|
+
/**
|
|
375
|
+
* Double-click an element.
|
|
376
|
+
*
|
|
377
|
+
* ```ts
|
|
378
|
+
* await page.dblclick('Edit');
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
dblclick(target: ElementTarget, options?: ClickOptions): Promise<void>;
|
|
382
|
+
/**
|
|
383
|
+
* Tap an element (touch gesture).
|
|
384
|
+
*
|
|
385
|
+
* ```ts
|
|
386
|
+
* await page.tap('Menu');
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
tap(target: ElementTarget, options?: {
|
|
390
|
+
timeout?: number;
|
|
391
|
+
}): Promise<void>;
|
|
392
|
+
/**
|
|
393
|
+
* Focus an element.
|
|
394
|
+
*
|
|
395
|
+
* ```ts
|
|
396
|
+
* await page.focus('Email');
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
focus(target: ElementTarget, options?: {
|
|
400
|
+
timeout?: number;
|
|
401
|
+
}): Promise<void>;
|
|
402
|
+
/**
|
|
403
|
+
* Remove focus from an element.
|
|
404
|
+
*
|
|
405
|
+
* ```ts
|
|
406
|
+
* await page.blur('Email');
|
|
407
|
+
* ```
|
|
408
|
+
*/
|
|
409
|
+
blur(target: ElementTarget, options?: {
|
|
410
|
+
timeout?: number;
|
|
411
|
+
}): Promise<void>;
|
|
412
|
+
/**
|
|
413
|
+
* Get the visible inner text of an element (like element.innerText).
|
|
414
|
+
*
|
|
415
|
+
* ```ts
|
|
416
|
+
* const text = await page.innerText('h1');
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
innerText(target: ElementTarget, options?: {
|
|
420
|
+
timeout?: number;
|
|
421
|
+
}): Promise<string>;
|
|
422
|
+
/**
|
|
423
|
+
* Get the innerHTML of an element.
|
|
424
|
+
*
|
|
425
|
+
* ```ts
|
|
426
|
+
* const html = await page.innerHTML('.container');
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
innerHTML(target: ElementTarget, options?: {
|
|
430
|
+
timeout?: number;
|
|
431
|
+
}): Promise<string>;
|
|
432
|
+
/**
|
|
433
|
+
* Get the current value of an input/textarea/select.
|
|
434
|
+
*
|
|
435
|
+
* ```ts
|
|
436
|
+
* const email = await page.inputValue('Email');
|
|
437
|
+
* ```
|
|
438
|
+
*/
|
|
439
|
+
inputValue(target: ElementTarget, options?: {
|
|
440
|
+
timeout?: number;
|
|
441
|
+
}): Promise<string>;
|
|
442
|
+
/**
|
|
443
|
+
* Select multiple options from a <select multiple> dropdown.
|
|
444
|
+
*
|
|
445
|
+
* ```ts
|
|
446
|
+
* await page.selectOption('Colors', ['red', 'blue']);
|
|
447
|
+
* ```
|
|
448
|
+
*/
|
|
449
|
+
selectOption(target: ElementTarget, values: string | string[], options?: FillOptions): Promise<void>;
|
|
450
|
+
/**
|
|
451
|
+
* Drag an element to another element or position.
|
|
452
|
+
*
|
|
453
|
+
* ```ts
|
|
454
|
+
* await page.dragTo('Draggable', 'Drop Zone');
|
|
455
|
+
* ```
|
|
456
|
+
*/
|
|
457
|
+
dragTo(source: ElementTarget, dest: ElementTarget, options?: {
|
|
458
|
+
timeout?: number;
|
|
459
|
+
}): Promise<void>;
|
|
460
|
+
/**
|
|
461
|
+
* Wait for an element matching the target to appear in the DOM.
|
|
462
|
+
*
|
|
463
|
+
* ```ts
|
|
464
|
+
* await page.waitForSelector('.loaded');
|
|
465
|
+
* await page.waitForSelector({ role: 'dialog' });
|
|
466
|
+
* ```
|
|
467
|
+
*/
|
|
468
|
+
waitForSelector(target: ElementTarget, options?: {
|
|
469
|
+
timeout?: number;
|
|
470
|
+
state?: 'attached' | 'visible' | 'hidden';
|
|
471
|
+
}): Promise<ElementHandle>;
|
|
472
|
+
/**
|
|
473
|
+
* Wait for a JavaScript function to return a truthy value.
|
|
474
|
+
*
|
|
475
|
+
* ```ts
|
|
476
|
+
* await page.waitForFunction('document.querySelectorAll("li").length > 5');
|
|
477
|
+
* await page.waitForFunction(() => window.appReady === true);
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
waitForFunction<T = unknown>(expression: string | (() => T), options?: {
|
|
481
|
+
timeout?: number;
|
|
482
|
+
}): Promise<T>;
|
|
483
|
+
/**
|
|
484
|
+
* Wait for a specific URL. Usually you use expect(page).toHaveURL() instead.
|
|
485
|
+
*/
|
|
486
|
+
waitForURL(url: string | RegExp, options?: {
|
|
487
|
+
timeout?: number;
|
|
488
|
+
}): Promise<void>;
|
|
489
|
+
/**
|
|
490
|
+
* Wait for the page to finish loading.
|
|
491
|
+
*/
|
|
492
|
+
waitForLoadState(state?: 'load' | 'domcontentloaded'): Promise<void>;
|
|
493
|
+
/**
|
|
494
|
+
* Close this page/tab.
|
|
495
|
+
*/
|
|
496
|
+
close(): Promise<void>;
|
|
497
|
+
/**
|
|
498
|
+
* Press a keyboard key.
|
|
499
|
+
*
|
|
500
|
+
* ```ts
|
|
501
|
+
* await page.press('Enter');
|
|
502
|
+
* await page.press('Control+a');
|
|
503
|
+
* ```
|
|
504
|
+
*/
|
|
505
|
+
press(key: string): Promise<void>;
|
|
506
|
+
/** Resolve a relative URL against the baseURL */
|
|
507
|
+
private resolveURL;
|
|
508
|
+
/** Get a shared reference from a located node */
|
|
509
|
+
private getSharedRef;
|
|
510
|
+
/** Get the center coordinates of an element */
|
|
511
|
+
private getElementCenter;
|
|
512
|
+
/**
|
|
513
|
+
* Scroll element into view and click it.
|
|
514
|
+
*
|
|
515
|
+
* Uses JavaScript `.click()` as the primary mechanism because it is
|
|
516
|
+
* immune to viewport coordinate mismatches, DPI scaling, layout shifts,
|
|
517
|
+
* and Chrome BiDi's unreliable element-origin support. This works
|
|
518
|
+
* identically in headless and headed mode, with or without slowMo delays.
|
|
519
|
+
*
|
|
520
|
+
* The element is scrolled into view first so it's visible in headed mode
|
|
521
|
+
* (important when users are watching the test run).
|
|
522
|
+
*/
|
|
523
|
+
private scrollIntoViewAndClick;
|
|
524
|
+
/** Extract a string from a script evaluation result */
|
|
525
|
+
private extractStringResult;
|
|
526
|
+
/** Convert a BiDi RemoteValue back to a JS value */
|
|
527
|
+
private deserializeRemoteValue;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* A lazy reference to an element. Does not locate the element until
|
|
531
|
+
* you interact with it or assert on it.
|
|
532
|
+
*/
|
|
533
|
+
declare class ElementHandle {
|
|
534
|
+
/** @internal */
|
|
535
|
+
readonly page: Page;
|
|
536
|
+
/** @internal */
|
|
537
|
+
readonly target: ElementTarget;
|
|
538
|
+
constructor(page: Page, target: ElementTarget);
|
|
539
|
+
/** Click this element */
|
|
540
|
+
click(options?: ClickOptions): Promise<void>;
|
|
541
|
+
/** Fill this element with text */
|
|
542
|
+
fill(value: string, options?: FillOptions): Promise<void>;
|
|
543
|
+
/** Get the visible text content of this element */
|
|
544
|
+
textContent(): Promise<string>;
|
|
545
|
+
/** Get an attribute value */
|
|
546
|
+
getAttribute(name: string): Promise<string | null>;
|
|
547
|
+
/** Check if the element is visible on the page */
|
|
548
|
+
isVisible(): Promise<boolean>;
|
|
549
|
+
/** Count matching elements */
|
|
550
|
+
count(): Promise<number>;
|
|
551
|
+
/** Get the visible inner text (like element.innerText, not textContent) */
|
|
552
|
+
innerText(): Promise<string>;
|
|
553
|
+
/** Get the innerHTML of this element */
|
|
554
|
+
innerHTML(): Promise<string>;
|
|
555
|
+
/** Get the current value of an input/textarea/select */
|
|
556
|
+
inputValue(): Promise<string>;
|
|
557
|
+
/** Check if the element is enabled (not disabled) */
|
|
558
|
+
isEnabled(): Promise<boolean>;
|
|
559
|
+
/** Check if a checkbox/radio is checked */
|
|
560
|
+
isChecked(): Promise<boolean>;
|
|
561
|
+
/** Get the bounding box of the element */
|
|
562
|
+
boundingBox(): Promise<{
|
|
563
|
+
x: number;
|
|
564
|
+
y: number;
|
|
565
|
+
width: number;
|
|
566
|
+
height: number;
|
|
567
|
+
} | null>;
|
|
568
|
+
/** Take a screenshot of just this element */
|
|
569
|
+
screenshot(): Promise<Buffer>;
|
|
570
|
+
/** Double-click this element */
|
|
571
|
+
dblclick(options?: ClickOptions): Promise<void>;
|
|
572
|
+
/** Hover over this element */
|
|
573
|
+
hover(options?: {
|
|
574
|
+
timeout?: number;
|
|
575
|
+
}): Promise<void>;
|
|
576
|
+
/** Type text into this element character by character */
|
|
577
|
+
type(text: string, options?: FillOptions): Promise<void>;
|
|
578
|
+
/** Focus this element */
|
|
579
|
+
focus(options?: {
|
|
580
|
+
timeout?: number;
|
|
581
|
+
}): Promise<void>;
|
|
582
|
+
/** Remove focus from this element */
|
|
583
|
+
blur(options?: {
|
|
584
|
+
timeout?: number;
|
|
585
|
+
}): Promise<void>;
|
|
586
|
+
/** @internal Locate the element with auto-wait */
|
|
587
|
+
locate(timeout?: number): Promise<LocatedElement>;
|
|
588
|
+
private getRef;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Browser represents a running browser instance.
|
|
593
|
+
* Use `Browser.launch()` to start one, or let the test() fixtures do it for you.
|
|
594
|
+
*
|
|
595
|
+
* ```ts
|
|
596
|
+
* const browser = await Browser.launch();
|
|
597
|
+
* const page = await browser.newPage();
|
|
598
|
+
* await page.goto('https://example.com');
|
|
599
|
+
* await browser.close();
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
declare class Browser {
|
|
603
|
+
/** @internal */
|
|
604
|
+
readonly session: BiDiSession;
|
|
605
|
+
/** @internal */
|
|
606
|
+
private config;
|
|
607
|
+
/** @internal */
|
|
608
|
+
private pages;
|
|
609
|
+
private constructor();
|
|
610
|
+
/**
|
|
611
|
+
* Launch a new browser instance.
|
|
612
|
+
*
|
|
613
|
+
* ```ts
|
|
614
|
+
* const browser = await Browser.launch(); // Chrome, headless
|
|
615
|
+
* const browser = await Browser.launch({ browser: 'firefox', headless: false });
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
static launch(userConfig?: UserConfig): Promise<Browser>;
|
|
619
|
+
/**
|
|
620
|
+
* Connect to an already-running browser.
|
|
621
|
+
*
|
|
622
|
+
* ```ts
|
|
623
|
+
* const browser = await Browser.connect('ws://localhost:9222/session');
|
|
624
|
+
* ```
|
|
625
|
+
*/
|
|
626
|
+
static connect(wsEndpoint: string, userConfig?: UserConfig): Promise<Browser>;
|
|
627
|
+
/**
|
|
628
|
+
* Create a new page (tab).
|
|
629
|
+
*
|
|
630
|
+
* ```ts
|
|
631
|
+
* const page = await browser.newPage();
|
|
632
|
+
* await page.goto('https://example.com');
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
newPage(): Promise<Page>;
|
|
636
|
+
/** Get all open pages. */
|
|
637
|
+
get openPages(): Page[];
|
|
638
|
+
/**
|
|
639
|
+
* Create an isolated browser context (like incognito).
|
|
640
|
+
* Returns a BrowserContext that can create its own pages.
|
|
641
|
+
*/
|
|
642
|
+
newContext(): Promise<BrowserContext>;
|
|
643
|
+
/** Close the browser and clean up all resources. */
|
|
644
|
+
close(): Promise<void>;
|
|
645
|
+
/** Whether the browser is still connected */
|
|
646
|
+
get isConnected(): boolean;
|
|
647
|
+
/** Get the resolved config */
|
|
648
|
+
getConfig(): BrowsecraftConfig;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* An isolated browser context. Pages created in different contexts
|
|
652
|
+
* don't share cookies, storage, or cache.
|
|
653
|
+
*/
|
|
654
|
+
declare class BrowserContext {
|
|
655
|
+
/** @internal */
|
|
656
|
+
private session;
|
|
657
|
+
/** @internal */
|
|
658
|
+
private config;
|
|
659
|
+
/** @internal */
|
|
660
|
+
private userContext;
|
|
661
|
+
/** @internal */
|
|
662
|
+
private pages;
|
|
663
|
+
constructor(session: BiDiSession, config: BrowsecraftConfig, userContext: string | null);
|
|
664
|
+
/** Create a new page in this context. */
|
|
665
|
+
newPage(): Promise<Page>;
|
|
666
|
+
/** Close this context and all its pages. */
|
|
667
|
+
close(): Promise<void>;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/** Fixtures available in every test */
|
|
671
|
+
interface TestFixtures {
|
|
672
|
+
/** A fresh page in a new browser context. Auto-closed after the test. */
|
|
673
|
+
page: Page;
|
|
674
|
+
/** The browser context for this test. */
|
|
675
|
+
context: BrowserContext;
|
|
676
|
+
/** The browser instance (shared across tests in a worker). */
|
|
677
|
+
browser: Browser;
|
|
678
|
+
}
|
|
679
|
+
/** A single test case, registered by test() */
|
|
680
|
+
interface TestCase {
|
|
681
|
+
/** Test title */
|
|
682
|
+
title: string;
|
|
683
|
+
/** The test function */
|
|
684
|
+
fn: (fixtures: TestFixtures) => Promise<void>;
|
|
685
|
+
/** Test options */
|
|
686
|
+
options: TestOptions;
|
|
687
|
+
/** File this test was defined in */
|
|
688
|
+
file?: string;
|
|
689
|
+
/** Suite/describe path (e.g., ['Login', 'form validation']) */
|
|
690
|
+
suitePath: string[];
|
|
691
|
+
/** Whether this test is skipped */
|
|
692
|
+
skip: boolean;
|
|
693
|
+
/** Whether only this test should run */
|
|
694
|
+
only: boolean;
|
|
695
|
+
}
|
|
696
|
+
/** Options for individual tests */
|
|
697
|
+
interface TestOptions {
|
|
698
|
+
/** Override timeout for this specific test */
|
|
699
|
+
timeout?: number;
|
|
700
|
+
/** Number of retries for this specific test */
|
|
701
|
+
retries?: number;
|
|
702
|
+
/** Tags for filtering (e.g., ['smoke', 'regression']) */
|
|
703
|
+
tags?: string[];
|
|
704
|
+
}
|
|
705
|
+
/** Internal test registry -- the runner reads from here */
|
|
706
|
+
declare const testRegistry: TestCase[];
|
|
707
|
+
/**
|
|
708
|
+
* Define a browser test.
|
|
709
|
+
*
|
|
710
|
+
* ```ts
|
|
711
|
+
* import { test, expect } from 'browsecraft';
|
|
712
|
+
*
|
|
713
|
+
* test('user can log in', async ({ page }) => {
|
|
714
|
+
* await page.goto('/login');
|
|
715
|
+
* await page.fill('Email', 'user@test.com');
|
|
716
|
+
* await page.fill('Password', 'secret');
|
|
717
|
+
* await page.click('Sign In');
|
|
718
|
+
* await expect(page).toHaveURL('/dashboard');
|
|
719
|
+
* });
|
|
720
|
+
* ```
|
|
721
|
+
*/
|
|
722
|
+
declare function test(title: string, fn: (fixtures: TestFixtures) => Promise<void>): void;
|
|
723
|
+
declare function test(title: string, options: TestOptions, fn: (fixtures: TestFixtures) => Promise<void>): void;
|
|
724
|
+
declare namespace test {
|
|
725
|
+
var skip: (title: string, fn: (fixtures: TestFixtures) => Promise<void>) => void;
|
|
726
|
+
var only: (title: string, fn: (fixtures: TestFixtures) => Promise<void>) => void;
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Group related tests together.
|
|
730
|
+
*
|
|
731
|
+
* ```ts
|
|
732
|
+
* describe('Login', () => {
|
|
733
|
+
* test('shows form', async ({ page }) => { ... });
|
|
734
|
+
* test('validates email', async ({ page }) => { ... });
|
|
735
|
+
* });
|
|
736
|
+
* ```
|
|
737
|
+
*/
|
|
738
|
+
declare function describe(title: string, fn: () => void): void;
|
|
739
|
+
declare namespace describe {
|
|
740
|
+
var skip: (title: string, fn: () => void) => void;
|
|
741
|
+
var only: (title: string, fn: () => void) => void;
|
|
742
|
+
}
|
|
743
|
+
/** Before/after hooks for a describe block */
|
|
744
|
+
type HookFn = (fixtures: TestFixtures) => Promise<void>;
|
|
745
|
+
/**
|
|
746
|
+
* Run before all tests in the current describe block.
|
|
747
|
+
*/
|
|
748
|
+
declare function beforeAll(fn: HookFn): void;
|
|
749
|
+
/**
|
|
750
|
+
* Run after all tests in the current describe block.
|
|
751
|
+
*/
|
|
752
|
+
declare function afterAll(fn: HookFn): void;
|
|
753
|
+
/**
|
|
754
|
+
* Run before each test in the current describe block.
|
|
755
|
+
*/
|
|
756
|
+
declare function beforeEach(fn: HookFn): void;
|
|
757
|
+
/**
|
|
758
|
+
* Run after each test in the current describe block.
|
|
759
|
+
*/
|
|
760
|
+
declare function afterEach(fn: HookFn): void;
|
|
761
|
+
/**
|
|
762
|
+
* Execute a single test case with proper fixture setup/teardown.
|
|
763
|
+
* This is called by the test runner.
|
|
764
|
+
*/
|
|
765
|
+
declare function runTest(testCase: TestCase, sharedBrowser?: Browser, userConfig?: UserConfig): Promise<TestResult>;
|
|
766
|
+
/**
|
|
767
|
+
* Run afterAll hooks for the given suite path.
|
|
768
|
+
* Called by the runner after all tests in a suite have completed.
|
|
769
|
+
*/
|
|
770
|
+
declare function runAfterAllHooks(suitePath: string[], fixtures: TestFixtures): Promise<void>;
|
|
771
|
+
/**
|
|
772
|
+
* Reset all hooks and registries (for test isolation between files).
|
|
773
|
+
*/
|
|
774
|
+
declare function resetTestState(): void;
|
|
775
|
+
/** Result of running a single test */
|
|
776
|
+
interface TestResult {
|
|
777
|
+
title: string;
|
|
778
|
+
suitePath: string[];
|
|
779
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
780
|
+
duration: number;
|
|
781
|
+
error?: Error;
|
|
782
|
+
/** Path to screenshot file (if captured on failure) */
|
|
783
|
+
screenshotPath?: string;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/** Options shared by all assertion matchers */
|
|
787
|
+
interface MatcherOptions {
|
|
788
|
+
/** Timeout in ms (default: 5000) */
|
|
789
|
+
timeout?: number;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Create assertions on Pages or ElementHandles.
|
|
793
|
+
* All matchers auto-retry until they pass or timeout.
|
|
794
|
+
*
|
|
795
|
+
* ```ts
|
|
796
|
+
* await expect(page).toHaveURL('/dashboard');
|
|
797
|
+
* await expect(page).toHaveTitle('My App');
|
|
798
|
+
* await expect(page.get('Welcome')).toBeVisible();
|
|
799
|
+
* await expect(page.get('Submit')).toHaveText('Submit Order');
|
|
800
|
+
* ```
|
|
801
|
+
*/
|
|
802
|
+
declare function expect(subject: Page): PageAssertions;
|
|
803
|
+
declare function expect(subject: ElementHandle): ElementAssertions;
|
|
804
|
+
/**
|
|
805
|
+
* Assertions for a Page. All matchers auto-retry.
|
|
806
|
+
*/
|
|
807
|
+
declare class PageAssertions {
|
|
808
|
+
private page;
|
|
809
|
+
private _not;
|
|
810
|
+
constructor(page: Page);
|
|
811
|
+
/** Negate the assertion */
|
|
812
|
+
get not(): PageAssertions;
|
|
813
|
+
/**
|
|
814
|
+
* Assert the page URL contains or matches the expected value.
|
|
815
|
+
*
|
|
816
|
+
* ```ts
|
|
817
|
+
* await expect(page).toHaveURL('/dashboard');
|
|
818
|
+
* await expect(page).toHaveURL(/dashboard/);
|
|
819
|
+
* ```
|
|
820
|
+
*/
|
|
821
|
+
toHaveURL(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
822
|
+
/**
|
|
823
|
+
* Assert the page title matches.
|
|
824
|
+
*
|
|
825
|
+
* ```ts
|
|
826
|
+
* await expect(page).toHaveTitle('Dashboard');
|
|
827
|
+
* await expect(page).toHaveTitle(/Dashboard/);
|
|
828
|
+
* ```
|
|
829
|
+
*/
|
|
830
|
+
toHaveTitle(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
831
|
+
/**
|
|
832
|
+
* Assert the page content (HTML body text) contains the expected text.
|
|
833
|
+
*
|
|
834
|
+
* ```ts
|
|
835
|
+
* await expect(page).toHaveContent('Welcome back');
|
|
836
|
+
* await expect(page).toHaveContent(/logged in as \w+/);
|
|
837
|
+
* ```
|
|
838
|
+
*/
|
|
839
|
+
toHaveContent(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Assertions for an ElementHandle. All matchers auto-retry.
|
|
843
|
+
*/
|
|
844
|
+
declare class ElementAssertions {
|
|
845
|
+
private element;
|
|
846
|
+
private _not;
|
|
847
|
+
constructor(element: ElementHandle);
|
|
848
|
+
/** Negate the assertion */
|
|
849
|
+
get not(): ElementAssertions;
|
|
850
|
+
/**
|
|
851
|
+
* Assert the element is visible on the page.
|
|
852
|
+
*
|
|
853
|
+
* ```ts
|
|
854
|
+
* await expect(page.get('Welcome')).toBeVisible();
|
|
855
|
+
* await expect(page.get('Error')).not.toBeVisible();
|
|
856
|
+
* ```
|
|
857
|
+
*/
|
|
858
|
+
toBeVisible(options?: MatcherOptions): Promise<void>;
|
|
859
|
+
/**
|
|
860
|
+
* Assert the element is hidden (not visible).
|
|
861
|
+
*
|
|
862
|
+
* ```ts
|
|
863
|
+
* await expect(page.get('Loading')).toBeHidden();
|
|
864
|
+
* ```
|
|
865
|
+
*/
|
|
866
|
+
toBeHidden(options?: MatcherOptions): Promise<void>;
|
|
867
|
+
/**
|
|
868
|
+
* Assert the element's text content matches exactly.
|
|
869
|
+
*
|
|
870
|
+
* ```ts
|
|
871
|
+
* await expect(page.get('h1')).toHaveText('Welcome');
|
|
872
|
+
* await expect(page.get('.count')).toHaveText(/\d+ items/);
|
|
873
|
+
* ```
|
|
874
|
+
*/
|
|
875
|
+
toHaveText(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
876
|
+
/**
|
|
877
|
+
* Assert the element's text content contains the expected substring.
|
|
878
|
+
*
|
|
879
|
+
* ```ts
|
|
880
|
+
* await expect(page.get('.message')).toContainText('success');
|
|
881
|
+
* ```
|
|
882
|
+
*/
|
|
883
|
+
toContainText(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
884
|
+
/**
|
|
885
|
+
* Assert the number of matching elements.
|
|
886
|
+
*
|
|
887
|
+
* ```ts
|
|
888
|
+
* await expect(page.get('li')).toHaveCount(5);
|
|
889
|
+
* ```
|
|
890
|
+
*/
|
|
891
|
+
toHaveCount(expected: number, options?: MatcherOptions): Promise<void>;
|
|
892
|
+
/**
|
|
893
|
+
* Assert the element has a specific attribute value.
|
|
894
|
+
*
|
|
895
|
+
* ```ts
|
|
896
|
+
* await expect(page.get('input')).toHaveAttribute('type', 'email');
|
|
897
|
+
* await expect(page.get('a')).toHaveAttribute('href', /login/);
|
|
898
|
+
* ```
|
|
899
|
+
*/
|
|
900
|
+
toHaveAttribute(name: string, expected?: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
901
|
+
/**
|
|
902
|
+
* Assert an input/textarea/select has a specific value.
|
|
903
|
+
*
|
|
904
|
+
* ```ts
|
|
905
|
+
* await expect(page.get('Email')).toHaveValue('user@test.com');
|
|
906
|
+
* ```
|
|
907
|
+
*/
|
|
908
|
+
toHaveValue(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
909
|
+
/**
|
|
910
|
+
* Assert a checkbox/radio is checked.
|
|
911
|
+
*
|
|
912
|
+
* ```ts
|
|
913
|
+
* await expect(page.get('Terms')).toBeChecked();
|
|
914
|
+
* await expect(page.get('Newsletter')).not.toBeChecked();
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
toBeChecked(options?: MatcherOptions): Promise<void>;
|
|
918
|
+
/**
|
|
919
|
+
* Assert an element is enabled (not disabled).
|
|
920
|
+
*
|
|
921
|
+
* ```ts
|
|
922
|
+
* await expect(page.get('Submit')).toBeEnabled();
|
|
923
|
+
* ```
|
|
924
|
+
*/
|
|
925
|
+
toBeEnabled(options?: MatcherOptions): Promise<void>;
|
|
926
|
+
/**
|
|
927
|
+
* Assert an element is disabled.
|
|
928
|
+
*
|
|
929
|
+
* ```ts
|
|
930
|
+
* await expect(page.get('Submit')).toBeDisabled();
|
|
931
|
+
* ```
|
|
932
|
+
*/
|
|
933
|
+
toBeDisabled(options?: MatcherOptions): Promise<void>;
|
|
934
|
+
/**
|
|
935
|
+
* Assert an element has a specific CSS class.
|
|
936
|
+
*
|
|
937
|
+
* ```ts
|
|
938
|
+
* await expect(page.get('.alert')).toHaveClass('alert-success');
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
941
|
+
toHaveClass(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
942
|
+
/**
|
|
943
|
+
* Assert an element has a specific CSS property value.
|
|
944
|
+
*
|
|
945
|
+
* ```ts
|
|
946
|
+
* await expect(page.get('.banner')).toHaveCSS('color', 'rgb(255, 0, 0)');
|
|
947
|
+
* await expect(page.get('.box')).toHaveCSS('display', 'flex');
|
|
948
|
+
* ```
|
|
949
|
+
*/
|
|
950
|
+
toHaveCSS(property: string, expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
951
|
+
/**
|
|
952
|
+
* Assert an element has a specific id attribute.
|
|
953
|
+
*
|
|
954
|
+
* ```ts
|
|
955
|
+
* await expect(page.get('Submit')).toHaveId('submit-btn');
|
|
956
|
+
* ```
|
|
957
|
+
*/
|
|
958
|
+
toHaveId(expected: string, options?: MatcherOptions): Promise<void>;
|
|
959
|
+
/**
|
|
960
|
+
* Assert an element has a specific placeholder text.
|
|
961
|
+
*
|
|
962
|
+
* ```ts
|
|
963
|
+
* await expect(page.get({ selector: '#email' })).toHavePlaceholder('Enter your email');
|
|
964
|
+
* ```
|
|
965
|
+
*/
|
|
966
|
+
toHavePlaceholder(expected: string | RegExp, options?: MatcherOptions): Promise<void>;
|
|
967
|
+
/**
|
|
968
|
+
* Assert an element has a specific ARIA role.
|
|
969
|
+
*
|
|
970
|
+
* ```ts
|
|
971
|
+
* await expect(page.get('Submit')).toHaveRole('button');
|
|
972
|
+
* ```
|
|
973
|
+
*/
|
|
974
|
+
toHaveRole(expected: string, options?: MatcherOptions): Promise<void>;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Error thrown when an assertion fails.
|
|
978
|
+
*/
|
|
979
|
+
declare class AssertionError extends Error {
|
|
980
|
+
readonly name = "AssertionError";
|
|
981
|
+
constructor(message: string);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
export { type AIConfig, AssertionError, type BrowsecraftConfig, Browser, BrowserContext, type ClickOptions, ElementHandle, type ElementTarget, type FillOptions, type GotoOptions, type LocatorOptions, type MockResponse, Page, type TestCase, type TestFixtures, type TestOptions, type TestResult, type UserConfig, afterAll, afterEach, beforeAll, beforeEach, defineConfig, describe, expect, resetTestState, resolveConfig, runAfterAllHooks, runTest, test, testRegistry };
|