codeceptjs 4.1.0 → 4.2.0-beta.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/docs/alternative-browsers.md +153 -0
- package/docs/basics.md +9 -1
- package/docs/configuration.md +2 -0
- package/docs/helpers/CDPBrowser.md +2138 -0
- package/docs/helpers/Kitesurf.md +118 -0
- package/docs/helpers/Obscura.md +210 -0
- package/docs/migration-4.md +3 -1
- package/docs/parallel.md +10 -0
- package/docs/plugins/screencast.md +18 -13
- package/docs/plugins.md +1 -1
- package/lib/command/info.js +11 -3
- package/lib/command/workers/runTests.js +14 -20
- package/lib/container.js +6 -0
- package/lib/data/context.js +4 -0
- package/lib/element/WebElement.js +5 -0
- package/lib/helper/Appium.js +14 -2
- package/lib/helper/CDPBrowser.js +3004 -0
- package/lib/helper/Kitesurf.js +139 -0
- package/lib/helper/Obscura.js +344 -0
- package/lib/helper/Playwright.js +30 -3
- package/lib/helper/Puppeteer.js +43 -16
- package/lib/helper/WebDriver.js +43 -8
- package/lib/helper/clientscripts/cdpBrowserClient.js +486 -0
- package/lib/helper/clientscripts/xpathPolyfill.js +31 -0
- package/lib/helper/extras/CDPConnection.js +92 -0
- package/lib/helper/extras/CDPElementHandle.js +27 -0
- package/lib/helper/extras/apngAssembler.js +156 -0
- package/lib/html.js +9 -2
- package/lib/listener/retryEnhancer.js +2 -1
- package/lib/listener/steps.js +8 -0
- package/lib/mocha/hooks.js +10 -0
- package/lib/parser.js +14 -2
- package/lib/plugin/junitReporter.js +17 -1
- package/lib/plugin/screencast.js +116 -24
- package/lib/step/base.js +15 -3
- package/lib/utils/loaderCheck.js +6 -0
- package/lib/utils.js +1 -1
- package/lib/workers.js +17 -0
- package/package.json +4 -1
- package/typings/promiseBasedTypes.d.ts +1833 -0
- package/typings/types.d.ts +1840 -0
|
@@ -1162,6 +1162,1567 @@ declare namespace CodeceptJS {
|
|
|
1162
1162
|
*/
|
|
1163
1163
|
waitForText(text: string, sec?: number, context?: CodeceptJS.LocatorOrString): Promise<any>;
|
|
1164
1164
|
}
|
|
1165
|
+
/**
|
|
1166
|
+
* ## Configuration
|
|
1167
|
+
*
|
|
1168
|
+
* This helper should be configured in codecept.conf.js
|
|
1169
|
+
* @property [url = http://localhost] - base url of website to be tested.
|
|
1170
|
+
* @property [endpoint = http://127.0.0.1:9222] - Chrome DevTools Protocol endpoint. Either an `http(s)://` address exposing `/json/version` (from which the `webSocketDebuggerUrl` is resolved) or a raw `ws(s)://` debugger URL.
|
|
1171
|
+
* @property [headers = {}] - headers sent with the endpoint resolution request and the WebSocket handshake. Useful for authenticated remote browser providers.
|
|
1172
|
+
* @property [input = auto] - how synthetic user actions (click, fill, etc.) are dispatched by helpers built on top of this class. `auto` picks `cdp` when a real layout engine is detected and `synthetic` otherwise; can be pinned to `cdp` or `synthetic`.
|
|
1173
|
+
* @property [xpathPolyfill = auto] - whether to inject the bundled XPath polyfill before installing the in-page client. `auto` probes the page and only injects when `document.evaluate` is unavailable or broken; `true`/`false` force the behavior.
|
|
1174
|
+
* @property [capabilities = {}] - pre-seed detected browser capabilities (`layout`, `xpath`, `screenshot`, `innerText`) to skip runtime probing. Values set here are never overwritten by `_probeCapabilities`/`_ensureClient`.
|
|
1175
|
+
* @property [waitForTimeout = 5] - default wait* timeout in seconds, used by helpers built on top of this class.
|
|
1176
|
+
* @property [waitForAction = 100] - only takes effect when set explicitly: a literal fixed pacing sleep (in milliseconds) after click, type, or other interactions, mirroring other browser helpers. Left unset, actions settle in an event-aware way instead — near-instant when nothing navigates, waiting for the navigation to actually finish (not a guessed fixed delay) when one does.
|
|
1177
|
+
* @property [pollInterval = 25] - interval in milliseconds between retries while polling for a condition (e.g. page ready state, `waitFor*`). Distinct from `waitForAction`.
|
|
1178
|
+
* @property [getPageTimeout = 30] - maximum time in seconds to wait for a page to finish loading after navigation or reload; also used as the CDP command timeout (in ms, x1000).
|
|
1179
|
+
* @property [waitForNavigation = load] - when to consider a navigation finished: `load`, `domcontentloaded`, or `networkidle`. Mirrors the Puppeteer helper's option name. `networkidle` waits for the CDP `networkIdle` lifecycle event, which on a busy page can lag `load` by a second or more — only opt in if the extra wait is actually needed.
|
|
1180
|
+
*/
|
|
1181
|
+
type CDPBrowserConfig = {
|
|
1182
|
+
url?: string;
|
|
1183
|
+
endpoint?: string;
|
|
1184
|
+
headers?: any;
|
|
1185
|
+
input?: string;
|
|
1186
|
+
xpathPolyfill?: string | boolean;
|
|
1187
|
+
capabilities?: any;
|
|
1188
|
+
waitForTimeout?: number;
|
|
1189
|
+
waitForAction?: number;
|
|
1190
|
+
pollInterval?: number;
|
|
1191
|
+
getPageTimeout?: number;
|
|
1192
|
+
waitForNavigation?: string;
|
|
1193
|
+
};
|
|
1194
|
+
/**
|
|
1195
|
+
* CDPBrowser drives a browser directly over the raw Chrome DevTools Protocol, without depending
|
|
1196
|
+
* on Puppeteer, Playwright, or WebDriver. It opens its own WebSocket connection (via `CDPConnection`),
|
|
1197
|
+
* creates and attaches to a fresh target per test, and evaluates expressions through `Runtime.evaluate`.
|
|
1198
|
+
*
|
|
1199
|
+
* It is intended as the minimal, dependency-light base class for helpers that only need navigation,
|
|
1200
|
+
* script evaluation, and simple in-page element interaction (installed lazily through the
|
|
1201
|
+
* `window.__codecept` client script). It does not launch a browser itself — point `endpoint` at an
|
|
1202
|
+
* already-running Chrome (or any CDP-compatible browser) started with `--remote-debugging-port`.
|
|
1203
|
+
*
|
|
1204
|
+
* ## Example
|
|
1205
|
+
*
|
|
1206
|
+
* ```js
|
|
1207
|
+
* // inside codecept.conf.js
|
|
1208
|
+
* {
|
|
1209
|
+
* helpers: {
|
|
1210
|
+
* CDPBrowser: {
|
|
1211
|
+
* url: 'http://localhost',
|
|
1212
|
+
* endpoint: 'http://127.0.0.1:9222',
|
|
1213
|
+
* }
|
|
1214
|
+
* }
|
|
1215
|
+
* }
|
|
1216
|
+
* ```
|
|
1217
|
+
*
|
|
1218
|
+
* <!-- configuration -->
|
|
1219
|
+
*
|
|
1220
|
+
* ## Methods
|
|
1221
|
+
*/
|
|
1222
|
+
class CDPBrowserTs {
|
|
1223
|
+
constructor(config: CDPBrowserConfig);
|
|
1224
|
+
/**
|
|
1225
|
+
* No-op hook kept for interface parity with other browser helpers. Connecting to the CDP
|
|
1226
|
+
* endpoint is deferred to `_before`, since a fresh target/session is opened per test.
|
|
1227
|
+
*/
|
|
1228
|
+
_init(): Promise<any>;
|
|
1229
|
+
/**
|
|
1230
|
+
* Resolves `options.endpoint` to a raw WebSocket debugger URL. If the configured endpoint is
|
|
1231
|
+
* an `http(s)://` address, this fetches `/json/version` from it and reads `webSocketDebuggerUrl`
|
|
1232
|
+
* from the response, matching the discovery flow exposed by Chrome's `--remote-debugging-port`.
|
|
1233
|
+
* A `ws(s)://` endpoint is returned unchanged.
|
|
1234
|
+
*
|
|
1235
|
+
* This is the subclass override point for helpers that connect through a different discovery
|
|
1236
|
+
* mechanism (e.g. a cloud browser provider with its own session-creation API).
|
|
1237
|
+
* @returns a `ws(s)://` debugger URL ready to be passed to `CDPConnection`.
|
|
1238
|
+
*/
|
|
1239
|
+
protected _resolveEndpoint(): Promise<string>;
|
|
1240
|
+
/**
|
|
1241
|
+
* Resolves the CDP endpoint and opens the underlying `CDPConnection`, storing it on `this.cdp`.
|
|
1242
|
+
*/
|
|
1243
|
+
protected _connect(): Promise<any>;
|
|
1244
|
+
/**
|
|
1245
|
+
* Hook executed before each test. Ensures a live `CDPConnection` exists (connecting lazily on
|
|
1246
|
+
* first use, and reconnecting if a previous connection was closed), then creates a fresh
|
|
1247
|
+
* `about:blank` target and attaches to it with `Target.attachToTarget`, storing `this.targetId`
|
|
1248
|
+
* and `this.sessionId`. `Page` and `Runtime` domains are enabled on the new session, and engine
|
|
1249
|
+
* capabilities are probed here (against `about:blank`, uncontended) rather than only lazily on
|
|
1250
|
+
* the first real page — see `_probeCapabilities`.
|
|
1251
|
+
*
|
|
1252
|
+
* Also resets `_navStartWaiters` and `_lastMainFrameNav`: both are scoped to a single
|
|
1253
|
+
* `sessionId`/`targetId`, which are about to change, so anything left over from the previous test
|
|
1254
|
+
* (e.g. an action-settle waiter still armed because its test threw between arming and settling)
|
|
1255
|
+
* can never legitimately resolve against the new session — better to drop it here than leave it
|
|
1256
|
+
* waiting for the rest of the run.
|
|
1257
|
+
*/
|
|
1258
|
+
protected _before(): Promise<any>;
|
|
1259
|
+
/**
|
|
1260
|
+
* Lazily installs a single, persistent `Page.lifecycleEvent` listener on the underlying
|
|
1261
|
+
* `CDPConnection` and drains it into whichever `_waitForLoadEvent` calls are currently pending,
|
|
1262
|
+
* matched by `loaderId`. Installed once per helper instance (the connection outlives individual
|
|
1263
|
+
* tests), never removed — `CDPConnection` has no listener-removal API, so a single persistent
|
|
1264
|
+
* dispatcher (rather than one listener per navigation) is what keeps this leak-free.
|
|
1265
|
+
*
|
|
1266
|
+
* Also, for the main frame (`params.frameId === this.targetId`, which holds for a page target's
|
|
1267
|
+
* own top-level frame) only:
|
|
1268
|
+
* - Drains `_navStartWaiters` (armed by `_armActionSettle`, before an action, for `_waitForAction`'s
|
|
1269
|
+
* event-aware settle) on an `'init'` event — confirmed via a raw probe (against both Obscura and
|
|
1270
|
+
* Chrome, through the actual CLI path) to be the earliest signal CDP emits when a new top-level
|
|
1271
|
+
* navigation begins. Arming happens *before* the action is dispatched, not after: the same probe
|
|
1272
|
+
* found `'init'` can arrive while the action's own CDP round trip is still in flight, sometimes
|
|
1273
|
+
* only a millisecond or two after it started — a listener installed only once the action's
|
|
1274
|
+
* promise resolves can already be too late, not merely unlucky.
|
|
1275
|
+
* - Maintains `_lastMainFrameNav`, a rolling `{loaderId, events}` record of every lifecycle event
|
|
1276
|
+
* name seen for the current main-frame navigation (reset whenever `loaderId` changes). On a
|
|
1277
|
+
* fast/local navigation, the same raw probe found the *entire* sequence — `init` through
|
|
1278
|
+
* `networkIdle` — arriving as one batch while the triggering action's own round trip was still
|
|
1279
|
+
* in flight. Without this cache, `_waitForAction` would correctly detect that a navigation
|
|
1280
|
+
* started, then arm a *fresh* wait for the `load` event specifically — which, in that common
|
|
1281
|
+
* case, had already fired and will never fire again, paying the full grace-window-plus-poll cost
|
|
1282
|
+
* of `_waitForPageLoad` on every single navigating action instead of settling immediately.
|
|
1283
|
+
*/
|
|
1284
|
+
protected _ensureLifecycleListener(): Promise<any>;
|
|
1285
|
+
/**
|
|
1286
|
+
* Starts waiting for a `Page.lifecycleEvent` named `eventName` for the given `loaderId` on the
|
|
1287
|
+
* current session. `loaderId` (from the `Page.navigate` response) discriminates the awaited
|
|
1288
|
+
* navigation from any other in-flight or stale lifecycle events (e.g. the `about:blank` target
|
|
1289
|
+
* created in `_before`), which is essential since Chrome emits the target's initial `about:blank`
|
|
1290
|
+
* lifecycle sequence asynchronously, sometimes after this listener is already installed.
|
|
1291
|
+
*
|
|
1292
|
+
* Returns a `{promise, cancel}` pair rather than a bare promise: `_waitForPageLoad` races this
|
|
1293
|
+
* against a readyState poll, and whichever side loses must be actively torn down (not just have
|
|
1294
|
+
* its rejection swallowed) — an abandoned-but-still-pending wait would sit in `_pageLoadWaiters`
|
|
1295
|
+
* for the full timeout on every single navigation, for no purpose.
|
|
1296
|
+
* @param loaderId - the loader id of the navigation to wait for, from `Page.navigate`'s response.
|
|
1297
|
+
* @param eventName - the `Page.lifecycleEvent` name to wait for (e.g. `load`, `DOMContentLoaded`, `networkIdle`).
|
|
1298
|
+
* @param timeoutSec - maximum time to wait, in seconds.
|
|
1299
|
+
*/
|
|
1300
|
+
protected _waitForLoadEvent(loaderId: string, eventName: string, timeoutSec: number): Promise<any>;
|
|
1301
|
+
/**
|
|
1302
|
+
* Arms the event-aware settle's navigation-start listener. Must be called *before* the action
|
|
1303
|
+
* that might trigger a navigation is dispatched, not after — see `_ensureLifecycleListener` for
|
|
1304
|
+
* why. Returns `null` when `options.waitForAction` was set explicitly, since `_waitForAction`
|
|
1305
|
+
* ignores the armed listener entirely in that case (a literal fixed sleep, as before this round).
|
|
1306
|
+
*
|
|
1307
|
+
* No timeout here: `_waitForAction` applies the grace window itself, starting from when *it*
|
|
1308
|
+
* runs (after the action's own dispatch already resolved), racing this already-armed listener
|
|
1309
|
+
* against a fresh timer instead of one that started ticking before the action even began.
|
|
1310
|
+
*/
|
|
1311
|
+
protected _armActionSettle(): Promise<any>;
|
|
1312
|
+
/**
|
|
1313
|
+
* Waits for a page to finish loading after `Page.navigate`/`Page.reload`, per `options.waitForNavigation`.
|
|
1314
|
+
*
|
|
1315
|
+
* Purely event-driven for the first `PAGE_LOAD_GRACE_MS`: only the push-based
|
|
1316
|
+
* `Page.lifecycleEvent` signal (matched by `loaderId`) is awaited, issuing zero `_evaluate` calls
|
|
1317
|
+
* — this matters because an `_evaluate` sent while the page's own JavaScript is still busy (e.g.
|
|
1318
|
+
* a real-world page doing post-load hydration/analytics work) can queue behind it for hundreds of
|
|
1319
|
+
* ms to multiple seconds, measured directly against a JS-heavy page. Only if the grace window
|
|
1320
|
+
* elapses without the event (an engine that doesn't emit it, or a genuinely slow navigation) does
|
|
1321
|
+
* the `document.readyState` poll (via `_poll`) start, racing the still-pending lifecycle wait —
|
|
1322
|
+
* both bounded by the same `options.getPageTimeout`, so a lifecycle-less engine costs at most
|
|
1323
|
+
* `PAGE_LOAD_GRACE_MS` more than the poll alone would have, never double the timeout. No
|
|
1324
|
+
* `loaderId` (e.g. from `Page.reload`, which returns none) skips straight to the poll.
|
|
1325
|
+
*
|
|
1326
|
+
* Whichever side ultimately loses is actively cancelled, not merely abandoned — an abandoned poll
|
|
1327
|
+
* or lifecycle wait would otherwise keep running (issuing readyState `_evaluate` calls every
|
|
1328
|
+
* `pollInterval`, or holding a `_pageLoadWaiters` entry) for up to the full timeout on every
|
|
1329
|
+
* navigation, competing for the same CDP connection with real work.
|
|
1330
|
+
* @param loaderId - loader id from the triggering `Page.navigate` response, if any.
|
|
1331
|
+
* @param timeoutMessage - error message used if the readyState poll times out.
|
|
1332
|
+
*/
|
|
1333
|
+
protected _waitForPageLoad(loaderId: string | null, timeoutMessage: string): Promise<void>;
|
|
1334
|
+
/**
|
|
1335
|
+
* Hook executed after each test. Closes the target opened in `_before` via `Target.closeTarget`
|
|
1336
|
+
* and clears `this.targetId`/`this.sessionId`. The underlying `CDPConnection` is left open so it
|
|
1337
|
+
* can be reused by the next test.
|
|
1338
|
+
*/
|
|
1339
|
+
protected _after(): Promise<any>;
|
|
1340
|
+
/**
|
|
1341
|
+
* Hook executed after all tests are run. Closes the underlying `CDPConnection` (and its
|
|
1342
|
+
* WebSocket) and clears `this.cdp`. Must leave no open sockets or pending timers behind, so the
|
|
1343
|
+
* process can exit on its own.
|
|
1344
|
+
*/
|
|
1345
|
+
protected _finishTest(): Promise<any>;
|
|
1346
|
+
/**
|
|
1347
|
+
* Evaluates a JavaScript expression in the page attached to the current session via
|
|
1348
|
+
* `Runtime.evaluate`, awaiting any returned promise and returning the value by reference
|
|
1349
|
+
* (`returnByValue: true`). If the expression throws, the browser-side exception description
|
|
1350
|
+
* (or fallback text) is re-thrown as a JS `Error`.
|
|
1351
|
+
* @param expression - a JavaScript expression (or IIFE) to run in the page context.
|
|
1352
|
+
* @returns the evaluated value, or `undefined` if the expression has no result.
|
|
1353
|
+
*/
|
|
1354
|
+
protected _evaluate(expression: string): Promise<any>;
|
|
1355
|
+
/**
|
|
1356
|
+
* Ensures the in-page client (`window.__codecept`, installed from `cdpBrowserClient.js`) is
|
|
1357
|
+
* present on the current page, installing it (and the XPath polyfill, if needed) exactly once.
|
|
1358
|
+
* Safe to call repeatedly; it is a no-op once the client is detected.
|
|
1359
|
+
*/
|
|
1360
|
+
protected _ensureClient(): Promise<any>;
|
|
1361
|
+
/**
|
|
1362
|
+
* Installs the in-page client unconditionally — no `typeof window.__codecept` presence check.
|
|
1363
|
+
* Used by callers that already know, from a sentinel value returned alongside a failed action,
|
|
1364
|
+
* that the client is missing on the current page, so re-checking would just be a redundant
|
|
1365
|
+
* contended round trip.
|
|
1366
|
+
*
|
|
1367
|
+
* The 171KB XPath polyfill is only injected alongside the client when `needsXPath` is true (the
|
|
1368
|
+
* default, for callers without candidate information) *and* the engine actually needs it
|
|
1369
|
+
* (`capabilities.xpath === 'polyfill'`, cached from `_before`'s probe). Callers that know their
|
|
1370
|
+
* candidates never resolve to an `xpath` strategy (e.g. `_runSelected`, once it has inspected
|
|
1371
|
+
* `candidates`/`within`) can pass `false` to skip that inject — the client is still told, via the
|
|
1372
|
+
* `xpathNeedsPolyfill` flag baked in at install time, that the *engine* will eventually need it,
|
|
1373
|
+
* so a later call that does hit an xpath candidate gets a clean `'__NO_XPATH__'` miss signal
|
|
1374
|
+
* (from `window.__codecept.run`) instead of silently falling through to a broken native
|
|
1375
|
+
* `document.evaluate` — `_runSelected` reacts to that sentinel by injecting the polyfill and
|
|
1376
|
+
* retrying once, mirroring the `'__NO_CLIENT__'` handling right next to it.
|
|
1377
|
+
*/
|
|
1378
|
+
protected _installClient(needsXPath?: boolean): Promise<any>;
|
|
1379
|
+
/**
|
|
1380
|
+
* Whether any candidate strategy — in `candidates` itself, or in any of the `within` scoping
|
|
1381
|
+
* `layers` searched before it — is an `xpath` locator. Used to decide, before the client is even
|
|
1382
|
+
* installed, whether the XPath polyfill needs to be bundled into that install or can be deferred.
|
|
1383
|
+
*/
|
|
1384
|
+
protected _candidatesNeedXPath(candidates: { type: string; value: string; }[], layers: { type: string; value: string; }[][]): Promise<any>;
|
|
1385
|
+
/**
|
|
1386
|
+
* Determines whether the bundled XPath polyfill must be injected before the in-page client is
|
|
1387
|
+
* installed. Honors an explicit `options.xpathPolyfill` boolean; otherwise reuses a previously
|
|
1388
|
+
* probed `capabilities.xpath`, or probes the page's native `document.evaluate`. The probe appends
|
|
1389
|
+
* two throwaway elements distinguished only by text content and asserts that a text-value XPath
|
|
1390
|
+
* predicate (`normalize-space(string(.))=...`, the basis of every fuzzy/clickable locator) resolves
|
|
1391
|
+
* to exactly the matching one — merely checking that `document.evaluate` runs without throwing is
|
|
1392
|
+
* not enough, since some engines execute a text-value predicate without actually filtering by it,
|
|
1393
|
+
* silently returning every candidate node instead of none or one. The result is cached on
|
|
1394
|
+
* `capabilities.xpath` (`'native'` or `'polyfill'`).
|
|
1395
|
+
* @returns `true` if the polyfill should be injected.
|
|
1396
|
+
*/
|
|
1397
|
+
protected _needsXPathPolyfill(): Promise<boolean>;
|
|
1398
|
+
/**
|
|
1399
|
+
* Determines whether `see`/`dontSee`/`waitForText` should read whole-page text through the
|
|
1400
|
+
* client's own visibility-aware `visibleText()` walker instead of the native
|
|
1401
|
+
* `document.body.innerText`. Probes once per page by appending a `display:none` element and a
|
|
1402
|
+
* `<script>` element, each with distinguishing text, and checking that native `innerText`
|
|
1403
|
+
* excludes both — some engines return an `innerText` that does not honor computed visibility or
|
|
1404
|
+
* exclude script/style content, even when `getComputedStyle`/layout are otherwise reliable. The
|
|
1405
|
+
* result is cached on `capabilities.innerText` (`'native'` or `'computed'`).
|
|
1406
|
+
* @returns `true` if the `visibleText()` fallback should be used.
|
|
1407
|
+
*/
|
|
1408
|
+
protected _needsVisibleTextFallback(): Promise<boolean>;
|
|
1409
|
+
/**
|
|
1410
|
+
* Probes and caches capabilities that depend on the actual browser *engine* rather than any
|
|
1411
|
+
* particular page's content: `capabilities.layout` (via `getComputedStyle`), `capabilities.screenshot`
|
|
1412
|
+
* (inferred from `layout`), `capabilities.xpath` (via `_needsXPathPolyfill`), and
|
|
1413
|
+
* `capabilities.innerText` (via `_needsVisibleTextFallback`). Already-known capabilities
|
|
1414
|
+
* (pre-seeded through `options.capabilities`, or probed earlier) are never re-probed — so, across
|
|
1415
|
+
* a whole run, this issues a handful of `_evaluate` calls exactly once and is a no-op afterward.
|
|
1416
|
+
*
|
|
1417
|
+
* Called from `_before`, against the fresh `about:blank` target created there, specifically so
|
|
1418
|
+
* these probes run before any real navigation — measured directly (a full stall ledger against
|
|
1419
|
+
* `github.com`) that running them on the first *real* page instead can cost seconds each, since
|
|
1420
|
+
* every one is an `_evaluate` competing with that page's own JavaScript for the V8 isolate.
|
|
1421
|
+
* `about:blank` has no such competition. Also called (cheaply, already cached by then) from
|
|
1422
|
+
* `amOnPage`, so a helper that skips `_before` for some reason still probes correctly.
|
|
1423
|
+
*
|
|
1424
|
+
* The `xpath`/`innerText` probes determine *whether* their respective fallback is needed; they
|
|
1425
|
+
* do not install anything — injection stays deferred to `_ensureClient`'s reactive install and
|
|
1426
|
+
* `_textSource`'s own read, matching `amOnPage` no longer eagerly installing the client.
|
|
1427
|
+
*/
|
|
1428
|
+
protected _probeCapabilities(): Promise<any>;
|
|
1429
|
+
/**
|
|
1430
|
+
* Delegates a find-and-act call to `window.__codecept.run(candidates, action, payload)`. This is
|
|
1431
|
+
* the primary extension point used by helpers built on top of this class for element queries and
|
|
1432
|
+
* interactions.
|
|
1433
|
+
*
|
|
1434
|
+
* A per-call `context` locator, when given, is resolved and layered on top of any active
|
|
1435
|
+
* `within` block (searched inside it, not instead of it), so `context` narrows the search
|
|
1436
|
+
* without breaking out of a surrounding `within`.
|
|
1437
|
+
* @param candidates - locator strategies to try, in order, until one matches at least one element.
|
|
1438
|
+
* @param action - name of the action to run against the matched elements (e.g. `count`, `click`, `fill`).
|
|
1439
|
+
* @param [payload] - extra data the action needs (e.g. `{ value }` for `fill`).
|
|
1440
|
+
* @param [context = null] - element to search in, narrowing the candidates below it.
|
|
1441
|
+
* @returns number of matched elements and the action's result.
|
|
1442
|
+
*/
|
|
1443
|
+
protected _run(candidates: { type: 'css' | 'xpath'; value: string; }[], action: string, payload?: any, context?: CodeceptJS.LocatorOrString): Promise<{ found: number; result: any; }>;
|
|
1444
|
+
/**
|
|
1445
|
+
* Same as `_run`, but takes an explicit selection descriptor instead of reading one from
|
|
1446
|
+
* `store.currentStep`/`options.strict`. Used internally by `CDPElementHandle` to address one
|
|
1447
|
+
* specific element out of a candidate set by its 1-based index.
|
|
1448
|
+
*
|
|
1449
|
+
* The in-page client's presence is checked in the same round-trip as the action itself: the
|
|
1450
|
+
* evaluated expression resolves to a sentinel string when `window.__codecept` is missing (e.g.
|
|
1451
|
+
* right after a navigation the registered script didn't reach), in which case the client is
|
|
1452
|
+
* installed and the call is retried exactly once. Separately, if the client is already present
|
|
1453
|
+
* but reports (via its own `'__NO_XPATH__'` sentinel) that this call needs the XPath polyfill and
|
|
1454
|
+
* it was not bundled into that earlier install, the polyfill is injected and the call is retried
|
|
1455
|
+
* once more — see `_installClient`.
|
|
1456
|
+
* @param selection - `{index}` or `{strict: true}`, mirroring `_selectionDescriptor`.
|
|
1457
|
+
*/
|
|
1458
|
+
protected _runSelected(candidates: { type: 'css' | 'xpath'; value: string; }[], action: string, payload: any | null, selection: any | null, context?: CodeceptJS.LocatorOrString): Promise<{ found: number; result: any; }>;
|
|
1459
|
+
/**
|
|
1460
|
+
* Builds the `{index, strict}` element-selection descriptor from the current step's options
|
|
1461
|
+
* (`store.currentStep.opts`) and `options.strict`, mirroring the semantics of
|
|
1462
|
+
* `lib/helper/extras/elementSelection.js` (used by Puppeteer/WebDriver): a per-step
|
|
1463
|
+
* `elementIndex` (numeric, or the `'first'`/`'last'` aliases) always takes precedence and
|
|
1464
|
+
* disables strict mode for that step; otherwise `exact`/`strictMode` per-step options
|
|
1465
|
+
* override `options.strict` to enable or cancel strict mode.
|
|
1466
|
+
*/
|
|
1467
|
+
protected _selectionDescriptor(): Promise<any>;
|
|
1468
|
+
/**
|
|
1469
|
+
* A short, human-readable label built from `candidates`, used in `_run`'s elementIndex/strict
|
|
1470
|
+
* error messages when no locator string is otherwise available.
|
|
1471
|
+
*/
|
|
1472
|
+
protected _candidatesLabel(candidates: { type: 'css' | 'xpath'; value: string; }[]): Promise<any>;
|
|
1473
|
+
/**
|
|
1474
|
+
* Starts a `within` block, scoping every subsequent `_run` call (and therefore every element
|
|
1475
|
+
* lookup performed by this helper) to the descendants of the element matched by `locator`.
|
|
1476
|
+
* Verifies the element exists (against the full document, i.e. unscoped) before narrowing.
|
|
1477
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1478
|
+
*/
|
|
1479
|
+
_withinBegin(locator: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1480
|
+
/**
|
|
1481
|
+
* Ends the current `within` block, restoring unscoped element lookups.
|
|
1482
|
+
*/
|
|
1483
|
+
_withinEnd(): Promise<void>;
|
|
1484
|
+
/**
|
|
1485
|
+
* Repeatedly calls `fn` until it returns a truthy value or `timeoutSec` elapses, checking
|
|
1486
|
+
* immediately and waiting `options.pollInterval` milliseconds between subsequent attempts.
|
|
1487
|
+
* @param fn - the condition to poll; should resolve to a truthy value once satisfied.
|
|
1488
|
+
* @param timeoutSec - maximum time to poll, in seconds.
|
|
1489
|
+
* @param message - error message used when the timeout is reached.
|
|
1490
|
+
* @param [cancelToken] - when `cancelled` becomes `true` (set by the caller from outside), polling stops early with an error instead of continuing to `timeoutSec`. Used by `_waitForPageLoad` to tear down the losing side of a race instead of leaving it running.
|
|
1491
|
+
* @returns the truthy value returned by `fn`.
|
|
1492
|
+
*/
|
|
1493
|
+
protected _poll(fn: (...params: any[]) => any, timeoutSec: number, message: string, cancelToken?: any): Promise<any>;
|
|
1494
|
+
/**
|
|
1495
|
+
* Resolves a path against `options.url`. Absolute URLs (matching `scheme://`) are returned
|
|
1496
|
+
* unchanged; anything else is appended to `options.url` with its trailing slash stripped.
|
|
1497
|
+
* @param path - an absolute URL or a path relative to `options.url`.
|
|
1498
|
+
*/
|
|
1499
|
+
protected _url(path: string): Promise<any>;
|
|
1500
|
+
/**
|
|
1501
|
+
* Opens a web page in the current session.
|
|
1502
|
+
*
|
|
1503
|
+
* ```js
|
|
1504
|
+
* I.amOnPage('/'); // opens main page of website
|
|
1505
|
+
* I.amOnPage('https://github.com'); // opens github
|
|
1506
|
+
* I.amOnPage('/login'); // opens a login page
|
|
1507
|
+
* ```
|
|
1508
|
+
*
|
|
1509
|
+
* Navigates via `Page.navigate`, then waits (up to `options.getPageTimeout` seconds) for the page
|
|
1510
|
+
* to finish loading, preferring the push-based `Page.lifecycleEvent` signal (per
|
|
1511
|
+
* `options.waitForNavigation`) over polling `document.readyState`. Capabilities are (re-)probed
|
|
1512
|
+
* (a no-op after the first page, since they're cached for the helper's lifetime).
|
|
1513
|
+
*
|
|
1514
|
+
* The in-page client is deliberately *not* eagerly (re-)installed here — navigation discards any
|
|
1515
|
+
* previously injected script, but installing it is deferred to the first actual action after
|
|
1516
|
+
* this call, via `_runSelected`'s sentinel-and-retry. This keeps `amOnPage` itself down to the
|
|
1517
|
+
* navigate command plus the push-based wait: no `_evaluate` call is issued on this hot path,
|
|
1518
|
+
* which matters most right when the page's own JavaScript may still be busy (measured directly:
|
|
1519
|
+
* an `_evaluate` sent in that window can queue behind it for hundreds of ms to multiple seconds
|
|
1520
|
+
* on a JS-heavy real-world page, regardless of how small the evaluated expression is).
|
|
1521
|
+
* @param url - url path or global url.
|
|
1522
|
+
*/
|
|
1523
|
+
amOnPage(url: string): Promise<void>;
|
|
1524
|
+
/**
|
|
1525
|
+
* Reloads the current page.
|
|
1526
|
+
*
|
|
1527
|
+
* ```js
|
|
1528
|
+
* I.refreshPage();
|
|
1529
|
+
* ```
|
|
1530
|
+
*
|
|
1531
|
+
* Triggers `Page.reload` and waits (up to `options.getPageTimeout` seconds) for
|
|
1532
|
+
* `document.readyState` to reach `'complete'`.
|
|
1533
|
+
*/
|
|
1534
|
+
refreshPage(): Promise<void>;
|
|
1535
|
+
/**
|
|
1536
|
+
* Executes a JavaScript function in the browser context and returns its result.
|
|
1537
|
+
*
|
|
1538
|
+
* If a function is passed, it is serialized with `Function.prototype.toString()`, so it must
|
|
1539
|
+
* not reference variables from the outer (Node.js) scope — pass any needed data as arguments
|
|
1540
|
+
* instead. A string is evaluated as-is.
|
|
1541
|
+
*
|
|
1542
|
+
* ```js
|
|
1543
|
+
* let title = await I.executeScript(() => document.title);
|
|
1544
|
+
* let sum = await I.executeScript((a, b) => a + b, 2, 3);
|
|
1545
|
+
* ```
|
|
1546
|
+
*
|
|
1547
|
+
* If the function returns a promise, `executeScript` waits for it to resolve.
|
|
1548
|
+
* @param fn - a JavaScript function to be executed in the browser context, or a string expression.
|
|
1549
|
+
* @param args - arguments to pass into the function.
|
|
1550
|
+
* @returns the value returned (or resolved) by the function.
|
|
1551
|
+
*/
|
|
1552
|
+
executeScript(fn: string | ((...params: any[]) => any), ...args: any[]): Promise<any>;
|
|
1553
|
+
/**
|
|
1554
|
+
* Retrieves the page URL of the current page.
|
|
1555
|
+
*
|
|
1556
|
+
* ```js
|
|
1557
|
+
* let url = await I.grabCurrentUrl();
|
|
1558
|
+
* console.log(`Current URL is [${url}]`);
|
|
1559
|
+
* ```
|
|
1560
|
+
* @returns current URL.
|
|
1561
|
+
*/
|
|
1562
|
+
grabCurrentUrl(): Promise<string>;
|
|
1563
|
+
/**
|
|
1564
|
+
* Retrieves a page title.
|
|
1565
|
+
*
|
|
1566
|
+
* ```js
|
|
1567
|
+
* let title = await I.grabTitle();
|
|
1568
|
+
* ```
|
|
1569
|
+
* @returns title of the page.
|
|
1570
|
+
*/
|
|
1571
|
+
grabTitle(): Promise<string>;
|
|
1572
|
+
/**
|
|
1573
|
+
* Retrieves the source code of the current page.
|
|
1574
|
+
*
|
|
1575
|
+
* ```js
|
|
1576
|
+
* let pageSource = await I.grabSource();
|
|
1577
|
+
* ```
|
|
1578
|
+
* @returns source code of the current page (the outer HTML of `<html>`).
|
|
1579
|
+
*/
|
|
1580
|
+
grabSource(): Promise<string>;
|
|
1581
|
+
/**
|
|
1582
|
+
* Builds the list of `{type, value}` candidates `_run` should try, in order, for a given
|
|
1583
|
+
* locator and `kind`. A strict locator (CSS/XPath/object form) resolves to a single candidate.
|
|
1584
|
+
* A fuzzy (plain-text) locator is expanded into a strategy-specific list of XPath expressions
|
|
1585
|
+
* mirroring the click/field/checkbox matching used by other browser helpers (matching by
|
|
1586
|
+
* visible text, label, name, placeholder, ARIA attributes, etc.), falling back to treating the
|
|
1587
|
+
* raw text as a CSS selector.
|
|
1588
|
+
*
|
|
1589
|
+
* A role locator (`{role, text, exact}`) resolves to a single `role`-type candidate, resolved
|
|
1590
|
+
* in-page by the client's implicit ARIA role mapping (native elements) plus explicit `role`
|
|
1591
|
+
* attributes, filtered by accessible name/text when `text` is given.
|
|
1592
|
+
* @param locator - element located by CSS|XPath|strict locator, or plain fuzzy text.
|
|
1593
|
+
* @param [kind = 'element'] - matching strategy to use when `locator` is fuzzy.
|
|
1594
|
+
*/
|
|
1595
|
+
protected _candidates(locator: CodeceptJS.LocatorOrString, kind?: 'element' | 'clickable' | 'field' | 'checkable'): Promise<any>;
|
|
1596
|
+
/**
|
|
1597
|
+
* Resolves the text to search `see`/`dontSee`/`waitForText` against, when no explicit `context`
|
|
1598
|
+
* locator is given. An explicit `context` is always resolved through `_run`, so it is implicitly
|
|
1599
|
+
* scoped to the active `within` block, if any. Without a `context`, this reads the `within` root's
|
|
1600
|
+
* text when a `within` block is active, or the whole page's text otherwise — via native
|
|
1601
|
+
* `document.body.innerText`, or the client's `visibleText()` walker when
|
|
1602
|
+
* `_needsVisibleTextFallback` determines native `innerText` is not trustworthy.
|
|
1603
|
+
*/
|
|
1604
|
+
protected _textSource(context: CodeceptJS.LocatorOrString): Promise<string>;
|
|
1605
|
+
/**
|
|
1606
|
+
* Runs the in-page `containsText` check against the whole page (no `context`/`within` scoping —
|
|
1607
|
+
* those stay on `_textSource`'s per-element path, already small). Returns only `{found, snippet}`
|
|
1608
|
+
* instead of the full haystack: on a page with a large body, serializing that whole string across
|
|
1609
|
+
* the CDP wire (and, on engines where `capabilities.innerText` requires the `visibleText()`
|
|
1610
|
+
* walker, holding it in memory) is avoidable work `see`/`dontSee`/`waitForText` don't actually
|
|
1611
|
+
* need on their common, non-throwing path.
|
|
1612
|
+
*
|
|
1613
|
+
* Also folds the client's install into the very same round trip when it is still missing, instead
|
|
1614
|
+
* of a separate presence-check evaluate followed by an install evaluate before the check itself
|
|
1615
|
+
* can even run — mirroring `_runSelected`'s sentinel-retry design, but collapsed into one evaluate
|
|
1616
|
+
* since the install source itself is known and cacheable up front. That install is client-only,
|
|
1617
|
+
* never the 171KB XPath polyfill: `containsText` never calls `document.evaluate`, so bundling it
|
|
1618
|
+
* here would be pure waste for a scenario that never resolves an xpath locator. The client is
|
|
1619
|
+
* still told, via `installCodeceptClient`'s `xpathNeedsPolyfill` flag, whether the *engine*
|
|
1620
|
+
* (`capabilities.xpath`, cached by `_before`'s `about:blank` probe) will eventually need it, so a
|
|
1621
|
+
* later xpath-resolving action on the same page gets a clean `'__NO_XPATH__'` miss signal from
|
|
1622
|
+
* `window.__codecept.run` instead of silently hitting a broken native `document.evaluate` —
|
|
1623
|
+
* `_runSelected` reacts to that sentinel already. The bootstrap source is built once and reused
|
|
1624
|
+
* for the life of the instance, since whether the engine needs the polyfill never changes.
|
|
1625
|
+
*/
|
|
1626
|
+
protected _runTextCheck(text: string, opts: any): Promise<{ found: boolean; snippet: string | null; }>;
|
|
1627
|
+
/**
|
|
1628
|
+
* Shared implementation for `see`/`dontSee`. Without a `context` locator and outside any `within`
|
|
1629
|
+
* block, checks presence via `_runTextCheck`'s fast, boolean-only round trip; the full haystack is
|
|
1630
|
+
* only fetched (one extra, rare evaluate) when the assertion is about to fail, to build the same
|
|
1631
|
+
* `stringIncludes` error as before this optimization. With a `context` or inside `within`, this is
|
|
1632
|
+
* unchanged from before — already a small, per-element read, not the identified cost.
|
|
1633
|
+
*/
|
|
1634
|
+
protected _checkText(text: string, context: CodeceptJS.LocatorOrString, negate: boolean): Promise<void>;
|
|
1635
|
+
/**
|
|
1636
|
+
* Checks that a page contains a visible text.
|
|
1637
|
+
* Use context parameter to narrow down the search.
|
|
1638
|
+
*
|
|
1639
|
+
* ```js
|
|
1640
|
+
* I.see('Welcome'); // text welcome on a page
|
|
1641
|
+
* I.see('Welcome', '.content'); // text inside .content div
|
|
1642
|
+
* I.see('Register', {css: 'form.register'}); // use strict locator
|
|
1643
|
+
* ```
|
|
1644
|
+
* @param text - expected on page.
|
|
1645
|
+
* @param [context = null] - (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
|
|
1646
|
+
*/
|
|
1647
|
+
see(text: string, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1648
|
+
/**
|
|
1649
|
+
* Opposite to `see`. Checks that a text is not present on a page.
|
|
1650
|
+
* Use context parameter to narrow down the search.
|
|
1651
|
+
*
|
|
1652
|
+
* ```js
|
|
1653
|
+
* I.dontSee('Login'); // assume we are already logged in.
|
|
1654
|
+
* I.dontSee('Login', '.nav'); // no login inside .nav element
|
|
1655
|
+
* ```
|
|
1656
|
+
* @param text - which is not present.
|
|
1657
|
+
* @param [context = null] - (optional) element located by CSS|XPath|strict locator in which to perform search.
|
|
1658
|
+
*/
|
|
1659
|
+
dontSee(text: string, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1660
|
+
/**
|
|
1661
|
+
* Checks that the current page contains the given string in its raw source code.
|
|
1662
|
+
*
|
|
1663
|
+
* ```js
|
|
1664
|
+
* I.seeInSource('<h1>Green eggs & ham</h1>');
|
|
1665
|
+
* ```
|
|
1666
|
+
* @param text - value to check.
|
|
1667
|
+
*/
|
|
1668
|
+
seeInSource(text: string): Promise<void>;
|
|
1669
|
+
/**
|
|
1670
|
+
* Checks that the current page does not contain the given string in its raw source code.
|
|
1671
|
+
* @param text - value to check.
|
|
1672
|
+
*/
|
|
1673
|
+
dontSeeInSource(text: string): Promise<void>;
|
|
1674
|
+
/**
|
|
1675
|
+
* Checks that current url contains a provided fragment.
|
|
1676
|
+
*
|
|
1677
|
+
* ```js
|
|
1678
|
+
* I.seeInCurrentUrl('/register'); // we are on registration page
|
|
1679
|
+
* ```
|
|
1680
|
+
* @param url - a fragment to check
|
|
1681
|
+
*/
|
|
1682
|
+
seeInCurrentUrl(url: string): Promise<void>;
|
|
1683
|
+
/**
|
|
1684
|
+
* Checks that current url does not contain a provided fragment.
|
|
1685
|
+
* @param url - value to check.
|
|
1686
|
+
*/
|
|
1687
|
+
dontSeeInCurrentUrl(url: string): Promise<void>;
|
|
1688
|
+
/**
|
|
1689
|
+
* Checks that title contains text.
|
|
1690
|
+
*
|
|
1691
|
+
* ```js
|
|
1692
|
+
* I.seeInTitle('Home Page');
|
|
1693
|
+
* ```
|
|
1694
|
+
* @param text - text value to check.
|
|
1695
|
+
*/
|
|
1696
|
+
seeInTitle(text: string): Promise<void>;
|
|
1697
|
+
/**
|
|
1698
|
+
* Checks that a given Element is present in the DOM.
|
|
1699
|
+
* Element is located by CSS or XPath.
|
|
1700
|
+
*
|
|
1701
|
+
* ```js
|
|
1702
|
+
* I.seeElementInDOM('#modal');
|
|
1703
|
+
* ```
|
|
1704
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1705
|
+
*/
|
|
1706
|
+
seeElementInDOM(locator: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1707
|
+
/**
|
|
1708
|
+
* Opposite to `seeElementInDOM`. Checks that element is not on page.
|
|
1709
|
+
*
|
|
1710
|
+
* ```js
|
|
1711
|
+
* I.dontSeeElementInDOM('.nav'); // checks that element is not on page visible or not
|
|
1712
|
+
* ```
|
|
1713
|
+
* @param locator - located by CSS|XPath|strict locator.
|
|
1714
|
+
*/
|
|
1715
|
+
dontSeeElementInDOM(locator: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1716
|
+
/**
|
|
1717
|
+
* Throws if the current page has no real layout engine (`capabilities.layout === 'none'`),
|
|
1718
|
+
* used to guard visibility-dependent assertions that cannot be evaluated without one.
|
|
1719
|
+
* @param action - name of the calling assertion, used in the error message.
|
|
1720
|
+
*/
|
|
1721
|
+
protected _assertLayoutSupported(action: string): Promise<any>;
|
|
1722
|
+
/**
|
|
1723
|
+
* Checks that a given Element is visible.
|
|
1724
|
+
* Element is located by CSS or XPath.
|
|
1725
|
+
*
|
|
1726
|
+
* ```js
|
|
1727
|
+
* I.seeElement('#modal');
|
|
1728
|
+
* ```
|
|
1729
|
+
* @param locator - located by CSS|XPath|strict locator.
|
|
1730
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1731
|
+
*/
|
|
1732
|
+
seeElement(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1733
|
+
/**
|
|
1734
|
+
* Opposite to `seeElement`. Checks that element is not visible.
|
|
1735
|
+
*
|
|
1736
|
+
* ```js
|
|
1737
|
+
* I.dontSeeElement('.modal'); // modal is not shown
|
|
1738
|
+
* ```
|
|
1739
|
+
* @param locator - located by CSS|XPath|strict locator.
|
|
1740
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1741
|
+
*/
|
|
1742
|
+
dontSeeElement(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1743
|
+
/**
|
|
1744
|
+
* Verifies that the specified checkbox is checked.
|
|
1745
|
+
*
|
|
1746
|
+
* ```js
|
|
1747
|
+
* I.seeCheckboxIsChecked('Agree');
|
|
1748
|
+
* I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms
|
|
1749
|
+
* I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
1750
|
+
* ```
|
|
1751
|
+
* @param locator - located by label|name|CSS|XPath|strict locator.
|
|
1752
|
+
*/
|
|
1753
|
+
seeCheckboxIsChecked(locator: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1754
|
+
/**
|
|
1755
|
+
* Verifies that the specified checkbox is not checked.
|
|
1756
|
+
*
|
|
1757
|
+
* ```js
|
|
1758
|
+
* I.dontSeeCheckboxIsChecked('#agree'); // located by ID
|
|
1759
|
+
* I.dontSeeCheckboxIsChecked('I agree to terms'); // located by label
|
|
1760
|
+
* ```
|
|
1761
|
+
* @param locator - located by label|name|CSS|XPath|strict locator.
|
|
1762
|
+
*/
|
|
1763
|
+
dontSeeCheckboxIsChecked(locator: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1764
|
+
/**
|
|
1765
|
+
* Retrieves a text from an element located by CSS or XPath and returns it to test.
|
|
1766
|
+
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1767
|
+
*
|
|
1768
|
+
* ```js
|
|
1769
|
+
* let pin = await I.grabTextFrom('#pin');
|
|
1770
|
+
* ```
|
|
1771
|
+
* If multiple elements found returns first element.
|
|
1772
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1773
|
+
* @returns text value
|
|
1774
|
+
*/
|
|
1775
|
+
grabTextFrom(locator: CodeceptJS.LocatorOrString): Promise<string>;
|
|
1776
|
+
/**
|
|
1777
|
+
* Retrieves all texts from elements located by CSS or XPath and returns it to test.
|
|
1778
|
+
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1779
|
+
*
|
|
1780
|
+
* ```js
|
|
1781
|
+
* let pins = await I.grabTextFromAll('#pin li');
|
|
1782
|
+
* ```
|
|
1783
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1784
|
+
* @returns array of text values
|
|
1785
|
+
*/
|
|
1786
|
+
grabTextFromAll(locator: CodeceptJS.LocatorOrString): Promise<string[]>;
|
|
1787
|
+
/**
|
|
1788
|
+
* Retrieves an array of `WebElement`s matching a locator (`lib/element/WebElement.js`,
|
|
1789
|
+
* wrapping a `CDPElementHandle`). Element handles are re-resolved on demand by re-running
|
|
1790
|
+
* `candidates` and picking the matching index, since `CDPBrowser` never keeps a persistent
|
|
1791
|
+
* handle to a DOM node on the Node side.
|
|
1792
|
+
*
|
|
1793
|
+
* ```js
|
|
1794
|
+
* const buttons = await I.grabWebElements({ role: 'button' });
|
|
1795
|
+
* ```
|
|
1796
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1797
|
+
* @returns array of WebElement instances.
|
|
1798
|
+
*/
|
|
1799
|
+
grabWebElements(locator: CodeceptJS.LocatorOrString): Promise<object[]>;
|
|
1800
|
+
/**
|
|
1801
|
+
* Retrieves the first `WebElement` matching a locator.
|
|
1802
|
+
*
|
|
1803
|
+
* ```js
|
|
1804
|
+
* const button = await I.grabWebElement({ role: 'button', text: 'Submit' });
|
|
1805
|
+
* ```
|
|
1806
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1807
|
+
* @returns a WebElement instance.
|
|
1808
|
+
*/
|
|
1809
|
+
grabWebElement(locator: CodeceptJS.LocatorOrString): Promise<object>;
|
|
1810
|
+
/**
|
|
1811
|
+
* Resolves whether the `texts` action should read via the client's `visibleText()` walker
|
|
1812
|
+
* (probed once via `_needsVisibleTextFallback` and cached on `capabilities.innerText`) instead
|
|
1813
|
+
* of each element's native `innerText`, then runs it.
|
|
1814
|
+
*/
|
|
1815
|
+
protected _texts(candidates: { type: string; value: string | object; }[]): Promise<{ found: number; result: any; }>;
|
|
1816
|
+
/**
|
|
1817
|
+
* Retrieves a value from a form element located by CSS or XPath and returns it to test.
|
|
1818
|
+
* Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
1819
|
+
* If more than one element is found - value of first element is returned.
|
|
1820
|
+
*
|
|
1821
|
+
* ```js
|
|
1822
|
+
* let email = await I.grabValueFrom('input[name=email]');
|
|
1823
|
+
* ```
|
|
1824
|
+
* @param locator - field located by label|name|CSS|XPath|strict locator.
|
|
1825
|
+
* @returns attribute value
|
|
1826
|
+
*/
|
|
1827
|
+
grabValueFrom(locator: CodeceptJS.LocatorOrString): Promise<string>;
|
|
1828
|
+
/**
|
|
1829
|
+
* Retrieves an array of values from fields located by CSS or XPath and returns it to test.
|
|
1830
|
+
* Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
1831
|
+
*
|
|
1832
|
+
* ```js
|
|
1833
|
+
* let inputs = await I.grabValueFromAll('//form/input');
|
|
1834
|
+
* ```
|
|
1835
|
+
* @param locator - field located by label|name|CSS|XPath|strict locator.
|
|
1836
|
+
* @returns array of attribute values
|
|
1837
|
+
*/
|
|
1838
|
+
grabValueFromAll(locator: CodeceptJS.LocatorOrString): Promise<string[]>;
|
|
1839
|
+
/**
|
|
1840
|
+
* Retrieves an attribute from an element located by CSS or XPath and returns it to test.
|
|
1841
|
+
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1842
|
+
* If more than one element is found - attribute of first element is returned.
|
|
1843
|
+
*
|
|
1844
|
+
* ```js
|
|
1845
|
+
* let hint = await I.grabAttributeFrom('#tooltip', 'title');
|
|
1846
|
+
* ```
|
|
1847
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1848
|
+
* @param attr - attribute name.
|
|
1849
|
+
* @returns attribute value
|
|
1850
|
+
*/
|
|
1851
|
+
grabAttributeFrom(locator: CodeceptJS.LocatorOrString, attr: string): Promise<string>;
|
|
1852
|
+
/**
|
|
1853
|
+
* Retrieves an array of attributes from elements located by CSS or XPath and returns it to test.
|
|
1854
|
+
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1855
|
+
*
|
|
1856
|
+
* ```js
|
|
1857
|
+
* let hints = await I.grabAttributeFromAll('.tooltip', 'title');
|
|
1858
|
+
* ```
|
|
1859
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
1860
|
+
* @param attr - attribute name.
|
|
1861
|
+
* @returns array of attribute values
|
|
1862
|
+
*/
|
|
1863
|
+
grabAttributeFromAll(locator: CodeceptJS.LocatorOrString, attr: string): Promise<string[]>;
|
|
1864
|
+
/**
|
|
1865
|
+
* Grab number of elements by locator.
|
|
1866
|
+
* Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
1867
|
+
*
|
|
1868
|
+
* ```js
|
|
1869
|
+
* let numOfElements = await I.grabNumberOfElements('p');
|
|
1870
|
+
* ```
|
|
1871
|
+
* @param locator - located by CSS|XPath|strict locator.
|
|
1872
|
+
* @returns number of matched elements.
|
|
1873
|
+
*/
|
|
1874
|
+
grabNumberOfElements(locator: CodeceptJS.LocatorOrString): Promise<number>;
|
|
1875
|
+
/**
|
|
1876
|
+
* Perform a click on a link or a button, given by a locator.
|
|
1877
|
+
* If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
|
|
1878
|
+
* For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
|
|
1879
|
+
* For images, the "alt" attribute and inner text of any parent links are searched.
|
|
1880
|
+
*
|
|
1881
|
+
* When `options.input` is `'cdp'`, the click is dispatched as real `Input.dispatchMouseEvent` mouse events
|
|
1882
|
+
* (`mouseMoved` / `mousePressed` / `mouseReleased`) at the center of the element's bounding box, so it
|
|
1883
|
+
* exercises the same input pipeline a real user would. Otherwise it delegates to `forceClick`. A matched
|
|
1884
|
+
* element with a zero-size bounding box (e.g. `display: none`) has no valid coordinate to click and throws;
|
|
1885
|
+
* use `forceClick` to dispatch a synthetic click on such elements instead.
|
|
1886
|
+
*
|
|
1887
|
+
* ```js
|
|
1888
|
+
* // simple link
|
|
1889
|
+
* I.click('Logout');
|
|
1890
|
+
* // button of form
|
|
1891
|
+
* I.click('Submit');
|
|
1892
|
+
* // CSS button
|
|
1893
|
+
* I.click('#form input[type=submit]');
|
|
1894
|
+
* // XPath
|
|
1895
|
+
* I.click('//form/*[@type=submit]');
|
|
1896
|
+
* // using strict locator
|
|
1897
|
+
* I.click({css: 'nav a.login'});
|
|
1898
|
+
* ```
|
|
1899
|
+
* @param locator - clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1900
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1901
|
+
*/
|
|
1902
|
+
click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1903
|
+
/**
|
|
1904
|
+
* Perform an emulated click on a link or a button, given by a locator.
|
|
1905
|
+
* Unlike `click`, this always dispatches a synthetic in-page `el.click()` instead of sending native
|
|
1906
|
+
* CDP input events. This works on hidden, animated or inactive elements as well.
|
|
1907
|
+
*
|
|
1908
|
+
* If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
|
|
1909
|
+
* For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
|
|
1910
|
+
* For images, the "alt" attribute and inner text of any parent links are searched.
|
|
1911
|
+
*
|
|
1912
|
+
* ```js
|
|
1913
|
+
* // simple link
|
|
1914
|
+
* I.forceClick('Logout');
|
|
1915
|
+
* // button of form
|
|
1916
|
+
* I.forceClick('Submit');
|
|
1917
|
+
* // CSS button
|
|
1918
|
+
* I.forceClick('#form input[type=submit]');
|
|
1919
|
+
* // XPath
|
|
1920
|
+
* I.forceClick('//form/*[@type=submit]');
|
|
1921
|
+
* // using strict locator
|
|
1922
|
+
* I.forceClick({css: 'nav a.login'});
|
|
1923
|
+
* ```
|
|
1924
|
+
* @param locator - clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1925
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1926
|
+
*/
|
|
1927
|
+
forceClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1928
|
+
/**
|
|
1929
|
+
* Settles after an interaction (click, key press, etc.) before the next step runs, using the
|
|
1930
|
+
* listener `_armActionSettle` started *before* the interaction was dispatched (`armed`; a fresh
|
|
1931
|
+
* one is armed here too, as a safety net, if a call site forgot to — but arming this late can
|
|
1932
|
+
* only miss a navigation that already started during the action's own dispatch, exactly the race
|
|
1933
|
+
* this design exists to avoid, so every call site should pass its own pre-armed `armed`, not rely
|
|
1934
|
+
* on this fallback).
|
|
1935
|
+
*
|
|
1936
|
+
* If `options.waitForAction` was set explicitly in the config, honors it literally as a fixed
|
|
1937
|
+
* pacing sleep, exactly as before this round — an explicit value is a deliberate choice
|
|
1938
|
+
* (slow-motion debugging, a known-slow app) this never second-guesses.
|
|
1939
|
+
*
|
|
1940
|
+
* Otherwise, event-aware: races the armed listener against a *fresh* `ACTION_SETTLE_GRACE_MS`
|
|
1941
|
+
* window (started now, not when it was armed — the action's own dispatch already ran concurrently
|
|
1942
|
+
* with the arm, so this is genuinely bounded extra time, not a guess). If nothing declares a
|
|
1943
|
+
* navigation, returns immediately once the window elapses — the common case for most actions
|
|
1944
|
+
* (typing, toggling a checkbox, focusing a field) — instead of a fixed `options.waitForAction`
|
|
1945
|
+
* (100ms by default) sleep on every single action regardless of whether anything is happening.
|
|
1946
|
+
*
|
|
1947
|
+
* If a navigation *did* start, `_lastMainFrameNav` (see `_ensureLifecycleListener`) is checked
|
|
1948
|
+
* first: on a fast/local page, the entire lifecycle sequence through the target event has
|
|
1949
|
+
* typically already arrived in the same batch that announced the navigation started, in which
|
|
1950
|
+
* case this returns immediately. Only a navigation still genuinely in flight falls through to
|
|
1951
|
+
* `_waitForPageLoad` (the same mechanism `amOnPage`/`refreshPage` use) — which waits for it to
|
|
1952
|
+
* actually finish, rather than a fixed sleep that has no relationship to how long the navigation
|
|
1953
|
+
* actually takes: strictly more correct for a slow navigation, not just faster for a fast one.
|
|
1954
|
+
* @param [armed] - from `_armActionSettle`, called before the action.
|
|
1955
|
+
*/
|
|
1956
|
+
protected _waitForAction(armed?: any | null): Promise<void>;
|
|
1957
|
+
/**
|
|
1958
|
+
* Fills a text field or textarea, after clearing its value, with the given string.
|
|
1959
|
+
* Field is located by name, label, CSS, or XPath.
|
|
1960
|
+
*
|
|
1961
|
+
* ```js
|
|
1962
|
+
* // by label
|
|
1963
|
+
* I.fillField('Email', 'hello@world.com');
|
|
1964
|
+
* // by name
|
|
1965
|
+
* I.fillField('password', secret('123456'));
|
|
1966
|
+
* // by CSS
|
|
1967
|
+
* I.fillField('form#login input[name=username]', 'John');
|
|
1968
|
+
* // or by strict locator
|
|
1969
|
+
* I.fillField({css: 'form#login input[name=username]'}, 'John');
|
|
1970
|
+
* ```
|
|
1971
|
+
* @param field - located by label|name|CSS|XPath|strict locator.
|
|
1972
|
+
* @param value - text value to fill.
|
|
1973
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1974
|
+
*/
|
|
1975
|
+
fillField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1976
|
+
/**
|
|
1977
|
+
* Appends text to a input field or textarea.
|
|
1978
|
+
* Field is located by name, label, CSS or XPath
|
|
1979
|
+
*
|
|
1980
|
+
* ```js
|
|
1981
|
+
* I.appendField('#myTextField', 'appended');
|
|
1982
|
+
* // typing secret
|
|
1983
|
+
* I.appendField('password', secret('123456'));
|
|
1984
|
+
* ```
|
|
1985
|
+
* @param field - located by label|name|CSS|XPath|strict locator
|
|
1986
|
+
* @param value - text value to append.
|
|
1987
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1988
|
+
*/
|
|
1989
|
+
appendField(field: CodeceptJS.LocatorOrString, value: string, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
1990
|
+
/**
|
|
1991
|
+
* Clears a `<textarea>` or text `<input>` element's value.
|
|
1992
|
+
*
|
|
1993
|
+
* ```js
|
|
1994
|
+
* I.clearField('Email');
|
|
1995
|
+
* I.clearField('user[email]');
|
|
1996
|
+
* I.clearField('#email');
|
|
1997
|
+
* ```
|
|
1998
|
+
* @param field - editable field located by label|name|CSS|XPath|strict locator.
|
|
1999
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
2000
|
+
*/
|
|
2001
|
+
clearField(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2002
|
+
/**
|
|
2003
|
+
* Selects an option in a drop-down select.
|
|
2004
|
+
* Field is searched by label | name | CSS | XPath.
|
|
2005
|
+
* Option is selected by visible text or by value.
|
|
2006
|
+
*
|
|
2007
|
+
* ```js
|
|
2008
|
+
* I.selectOption('Choose Plan', 'Monthly'); // select by label
|
|
2009
|
+
* I.selectOption('subscription', 'Monthly'); // match option by text
|
|
2010
|
+
* I.selectOption('subscription', '0'); // or by value
|
|
2011
|
+
* I.selectOption('//form/select[@name=account]','Premium');
|
|
2012
|
+
* I.selectOption('form select[name=account]', 'Premium');
|
|
2013
|
+
* I.selectOption({css: 'form select[name=account]'}, 'Premium');
|
|
2014
|
+
* ```
|
|
2015
|
+
* @param select - field located by label|name|CSS|XPath|strict locator.
|
|
2016
|
+
* @param option - visible text or value of option, or an array of them for a multi-select.
|
|
2017
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
2018
|
+
*/
|
|
2019
|
+
selectOption(select: CodeceptJS.LocatorOrString, option: string | string[], context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2020
|
+
/**
|
|
2021
|
+
* Selects a checkbox or radio button.
|
|
2022
|
+
* Element is located by label or name or CSS or XPath.
|
|
2023
|
+
*
|
|
2024
|
+
* ```js
|
|
2025
|
+
* I.checkOption('#agree');
|
|
2026
|
+
* I.checkOption('I Agree to Terms and Conditions');
|
|
2027
|
+
* I.checkOption('agree', '//form');
|
|
2028
|
+
* ```
|
|
2029
|
+
* @param field - checkbox located by label | name | CSS | XPath | strict locator.
|
|
2030
|
+
* @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator.
|
|
2031
|
+
*/
|
|
2032
|
+
checkOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2033
|
+
/**
|
|
2034
|
+
* Unselects a checkbox or radio button.
|
|
2035
|
+
* Element is located by label or name or CSS or XPath.
|
|
2036
|
+
*
|
|
2037
|
+
* ```js
|
|
2038
|
+
* I.uncheckOption('#agree');
|
|
2039
|
+
* I.uncheckOption('I Agree to Terms and Conditions');
|
|
2040
|
+
* I.uncheckOption('agree', '//form');
|
|
2041
|
+
* ```
|
|
2042
|
+
* @param field - checkbox located by label | name | CSS | XPath | strict locator.
|
|
2043
|
+
* @param [context = null] - (optional, `null` by default) element located by CSS | XPath | strict locator.
|
|
2044
|
+
*/
|
|
2045
|
+
uncheckOption(field: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2046
|
+
/**
|
|
2047
|
+
* Attaches a file to a file input field, or drops it onto a drag-and-drop dropzone element,
|
|
2048
|
+
* resolved by label|name|CSS|XPath|strict locator. `pathToFile` is resolved relative to
|
|
2049
|
+
* `codecept_dir` (matching Puppeteer/WebDriver). Since `CDPBrowser` never brings element handles
|
|
2050
|
+
* back to Node, the resolved element is marked with a throwaway `data-codecept-upload` attribute
|
|
2051
|
+
* in-page (respecting `context`/`within`/elementIndex exactly like every other action). A real
|
|
2052
|
+
* `<input type="file">` is then addressed by that attribute through the CDP `DOM` domain, which
|
|
2053
|
+
* `CDPBrowser` otherwise never uses, to call `DOM.setFileInputFiles`; any other element (a
|
|
2054
|
+
* drag-and-drop dropzone) instead gets a synthetic `dragenter`/`dragover`/`drop` sequence with a
|
|
2055
|
+
* `DataTransfer` built from the file's contents, entirely in-page. The marker is removed again in
|
|
2056
|
+
* a `finally`.
|
|
2057
|
+
*
|
|
2058
|
+
* ```js
|
|
2059
|
+
* I.attachFile('Avatar', 'data/avatar.jpg');
|
|
2060
|
+
* I.attachFile('#file', 'data/avatar.jpg');
|
|
2061
|
+
* I.attachFile('#dropzone', 'data/avatar.jpg');
|
|
2062
|
+
* ```
|
|
2063
|
+
* @param field - located by label|name|CSS|XPath|strict locator.
|
|
2064
|
+
* @param pathToFile - path to file, relative to `codecept_dir`.
|
|
2065
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
2066
|
+
*/
|
|
2067
|
+
attachFile(field: CodeceptJS.LocatorOrString, pathToFile: string, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2068
|
+
/**
|
|
2069
|
+
* Waits for element to be present on page (by default waits for `options.waitForTimeout` seconds).
|
|
2070
|
+
* Element can be located by CSS or XPath.
|
|
2071
|
+
*
|
|
2072
|
+
* ```js
|
|
2073
|
+
* I.waitForElement('.btn.continue');
|
|
2074
|
+
* I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
2075
|
+
* ```
|
|
2076
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2077
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2078
|
+
*/
|
|
2079
|
+
waitForElement(locator: CodeceptJS.LocatorOrString, sec?: number): Promise<void>;
|
|
2080
|
+
/**
|
|
2081
|
+
* Waits for a text to appear (by default waits for `options.waitForTimeout` seconds).
|
|
2082
|
+
* Element can be located by CSS or XPath.
|
|
2083
|
+
* Narrow down search results by providing context.
|
|
2084
|
+
*
|
|
2085
|
+
* ```js
|
|
2086
|
+
* I.waitForText('Thank you, form has been submitted');
|
|
2087
|
+
* I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
2088
|
+
* ```
|
|
2089
|
+
* @param text - to wait for.
|
|
2090
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2091
|
+
* @param [context = null] - (optional) element located by CSS|XPath|strict locator.
|
|
2092
|
+
*/
|
|
2093
|
+
waitForText(text: string, sec?: number, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2094
|
+
/**
|
|
2095
|
+
* Waiting for the part of the URL to match the expected. Useful for SPA to understand that page was changed.
|
|
2096
|
+
*
|
|
2097
|
+
* ```js
|
|
2098
|
+
* I.waitInUrl('/info', 2);
|
|
2099
|
+
* ```
|
|
2100
|
+
* @param urlPart - value to check.
|
|
2101
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2102
|
+
*/
|
|
2103
|
+
waitInUrl(urlPart: string, sec?: number): Promise<void>;
|
|
2104
|
+
/**
|
|
2105
|
+
* Waits for a function to return true (waits for `options.waitForTimeout` seconds by default).
|
|
2106
|
+
* Running in browser context.
|
|
2107
|
+
*
|
|
2108
|
+
* ```js
|
|
2109
|
+
* I.waitForFunction(() => window.requests == 0);
|
|
2110
|
+
* I.waitForFunction(() => window.requests == 0, 5); // waits for 5 sec
|
|
2111
|
+
* I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and wait for 5 sec
|
|
2112
|
+
* ```
|
|
2113
|
+
* @param fn - to be executed in browser context.
|
|
2114
|
+
* @param [argsOrSec = null] - (optional) arguments for function or, if a number, seconds to wait.
|
|
2115
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2116
|
+
*/
|
|
2117
|
+
waitForFunction(fn: string | ((...params: any[]) => any), argsOrSec?: any[] | number, sec?: number): Promise<void>;
|
|
2118
|
+
/**
|
|
2119
|
+
* Sets cookie(s).
|
|
2120
|
+
*
|
|
2121
|
+
* Can be a single cookie object or an array of cookies:
|
|
2122
|
+
*
|
|
2123
|
+
* ```js
|
|
2124
|
+
* I.setCookie({name: 'auth', value: true});
|
|
2125
|
+
*
|
|
2126
|
+
* // as array
|
|
2127
|
+
* I.setCookie([
|
|
2128
|
+
* {name: 'auth', value: true},
|
|
2129
|
+
* {name: 'agree', value: true}
|
|
2130
|
+
* ]);
|
|
2131
|
+
* ```
|
|
2132
|
+
* @param cookie - a cookie object or array of cookie objects.
|
|
2133
|
+
*/
|
|
2134
|
+
setCookie(cookie: CodeceptJS.Cookie | CodeceptJS.Cookie[]): Promise<void>;
|
|
2135
|
+
/**
|
|
2136
|
+
* Retrieves all cookies visible to the current page.
|
|
2137
|
+
* Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
2138
|
+
*
|
|
2139
|
+
* ```js
|
|
2140
|
+
* let cookies = await I.grabCookies();
|
|
2141
|
+
* ```
|
|
2142
|
+
* @returns array of cookie objects.
|
|
2143
|
+
*/
|
|
2144
|
+
grabCookies(): Promise<CodeceptJS.Cookie[]>;
|
|
2145
|
+
/**
|
|
2146
|
+
* Gets a cookie object by name.
|
|
2147
|
+
* If none provided gets all cookies.
|
|
2148
|
+
* Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
2149
|
+
*
|
|
2150
|
+
* ```js
|
|
2151
|
+
* let cookie = await I.grabCookie('auth');
|
|
2152
|
+
* assert(cookie.value, '123456');
|
|
2153
|
+
* ```
|
|
2154
|
+
* @param [name = null] - cookie name.
|
|
2155
|
+
* @returns a cookie object, or an array of all cookies when `name` is not provided.
|
|
2156
|
+
*/
|
|
2157
|
+
grabCookie(name?: string | null): Promise<CodeceptJS.Cookie | CodeceptJS.Cookie[]>;
|
|
2158
|
+
/**
|
|
2159
|
+
* Clears a cookie by name,
|
|
2160
|
+
* if none provided clears all cookies.
|
|
2161
|
+
*
|
|
2162
|
+
* ```js
|
|
2163
|
+
* I.clearCookie();
|
|
2164
|
+
* I.clearCookie('test');
|
|
2165
|
+
* ```
|
|
2166
|
+
* @param [name = null] - (optional, `null` by default) cookie name
|
|
2167
|
+
*/
|
|
2168
|
+
clearCookie(name?: string | null): Promise<void>;
|
|
2169
|
+
/**
|
|
2170
|
+
* Saves a screenshot to the output folder (set in codecept.conf.ts or codecept.conf.js).
|
|
2171
|
+
* Filename is relative to the output folder.
|
|
2172
|
+
*
|
|
2173
|
+
* ```js
|
|
2174
|
+
* I.saveScreenshot('debug.png');
|
|
2175
|
+
* ```
|
|
2176
|
+
* @param fileName - file name to save.
|
|
2177
|
+
*/
|
|
2178
|
+
saveScreenshot(fileName: string): Promise<void>;
|
|
2179
|
+
/**
|
|
2180
|
+
* Saves a screenshot of a single element to the output folder.
|
|
2181
|
+
*
|
|
2182
|
+
* ```js
|
|
2183
|
+
* I.saveElementScreenshot('#logo', 'logo.png');
|
|
2184
|
+
* ```
|
|
2185
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2186
|
+
* @param fileName - file name to save.
|
|
2187
|
+
*/
|
|
2188
|
+
saveElementScreenshot(locator: CodeceptJS.LocatorOrString, fileName: string): Promise<void>;
|
|
2189
|
+
/**
|
|
2190
|
+
* Pauses execution for a number of seconds.
|
|
2191
|
+
*
|
|
2192
|
+
* ```js
|
|
2193
|
+
* I.wait(2); // waits 2 secs
|
|
2194
|
+
* ```
|
|
2195
|
+
* @param sec - number of seconds to wait.
|
|
2196
|
+
*/
|
|
2197
|
+
wait(sec: number): Promise<void>;
|
|
2198
|
+
/**
|
|
2199
|
+
* Checks that title does not contain text.
|
|
2200
|
+
* @param text - value to check.
|
|
2201
|
+
*/
|
|
2202
|
+
dontSeeInTitle(text: string): Promise<void>;
|
|
2203
|
+
/**
|
|
2204
|
+
* Checks that current url is equal to provided one.
|
|
2205
|
+
* Unlike `seeInCurrentUrl` performs a strict comparison.
|
|
2206
|
+
*
|
|
2207
|
+
* ```js
|
|
2208
|
+
* I.seeCurrentUrlEquals('/register');
|
|
2209
|
+
* ```
|
|
2210
|
+
* @param url - value to check.
|
|
2211
|
+
*/
|
|
2212
|
+
seeCurrentUrlEquals(url: string): Promise<void>;
|
|
2213
|
+
/**
|
|
2214
|
+
* Checks that current url is not equal to provided one.
|
|
2215
|
+
* Unlike `dontSeeInCurrentUrl` performs a strict comparison.
|
|
2216
|
+
* @param url - value to check.
|
|
2217
|
+
*/
|
|
2218
|
+
dontSeeCurrentUrlEquals(url: string): Promise<void>;
|
|
2219
|
+
/**
|
|
2220
|
+
* Resolves the current page URL to a `pathname`, ignoring the origin, query string, and hash.
|
|
2221
|
+
* @returns the pathname of the current page.
|
|
2222
|
+
*/
|
|
2223
|
+
protected _grabCurrentPath(): Promise<string>;
|
|
2224
|
+
/**
|
|
2225
|
+
* Checks that current url path (ignoring query string and hash) equals to provided one.
|
|
2226
|
+
*
|
|
2227
|
+
* ```js
|
|
2228
|
+
* I.seeCurrentPathEquals('/info');
|
|
2229
|
+
* ```
|
|
2230
|
+
* @param path - value to check.
|
|
2231
|
+
*/
|
|
2232
|
+
seeCurrentPathEquals(path: string): Promise<void>;
|
|
2233
|
+
/**
|
|
2234
|
+
* Opposite to `seeCurrentPathEquals`.
|
|
2235
|
+
* @param path - value to check.
|
|
2236
|
+
*/
|
|
2237
|
+
dontSeeCurrentPathEquals(path: string): Promise<void>;
|
|
2238
|
+
/**
|
|
2239
|
+
* Waits for the entire URL to match the expected (by default waits for `options.waitForTimeout` seconds).
|
|
2240
|
+
*
|
|
2241
|
+
* ```js
|
|
2242
|
+
* I.waitUrlEquals('/info', 2);
|
|
2243
|
+
* ```
|
|
2244
|
+
* @param urlPart - value to check.
|
|
2245
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2246
|
+
*/
|
|
2247
|
+
waitUrlEquals(urlPart: string, sec?: number): Promise<void>;
|
|
2248
|
+
/**
|
|
2249
|
+
* Waits for current url path (ignoring query string and hash) to equal to the expected.
|
|
2250
|
+
*
|
|
2251
|
+
* ```js
|
|
2252
|
+
* I.waitCurrentPathEquals('/info', 2);
|
|
2253
|
+
* ```
|
|
2254
|
+
* @param path - value to check.
|
|
2255
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2256
|
+
*/
|
|
2257
|
+
waitCurrentPathEquals(path: string, sec?: number): Promise<void>;
|
|
2258
|
+
/**
|
|
2259
|
+
* Checks that the given input field or textarea equals (contains) the given value.
|
|
2260
|
+
* For fuzzy locators, the field is searched by label|name|CSS|XPath|strict locator.
|
|
2261
|
+
*
|
|
2262
|
+
* ```js
|
|
2263
|
+
* I.seeInField('Username', 'davert');
|
|
2264
|
+
* ```
|
|
2265
|
+
* @param field - located by label|name|CSS|XPath|strict locator.
|
|
2266
|
+
* @param value - value to check.
|
|
2267
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
2268
|
+
*/
|
|
2269
|
+
seeInField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2270
|
+
/**
|
|
2271
|
+
* Opposite to `seeInField`.
|
|
2272
|
+
* @param field - located by label|name|CSS|XPath|strict locator.
|
|
2273
|
+
* @param value - value to check.
|
|
2274
|
+
* @param [context = null] - (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
2275
|
+
*/
|
|
2276
|
+
dontSeeInField(field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2277
|
+
/**
|
|
2278
|
+
* Shared implementation for `seeInField`/`dontSeeInField`.
|
|
2279
|
+
*/
|
|
2280
|
+
protected _seeInField(assertType: 'assert' | 'negate', field: CodeceptJS.LocatorOrString, value: CodeceptJS.StringOrSecret, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2281
|
+
/**
|
|
2282
|
+
* Grab number of visible elements by locator.
|
|
2283
|
+
*
|
|
2284
|
+
* ```js
|
|
2285
|
+
* let numOfVisibleElements = await I.grabNumberOfVisibleElements('p');
|
|
2286
|
+
* ```
|
|
2287
|
+
* @param locator - located by CSS|XPath|strict locator.
|
|
2288
|
+
* @returns number of visible matched elements.
|
|
2289
|
+
*/
|
|
2290
|
+
grabNumberOfVisibleElements(locator: CodeceptJS.LocatorOrString): Promise<number>;
|
|
2291
|
+
/**
|
|
2292
|
+
* Asserts that an element appears a given number of times on the page, and that all matching elements are visible.
|
|
2293
|
+
*
|
|
2294
|
+
* ```js
|
|
2295
|
+
* I.seeNumberOfVisibleElements('.buttons', 3);
|
|
2296
|
+
* ```
|
|
2297
|
+
* @param locator - located by CSS|XPath|strict locator.
|
|
2298
|
+
* @param num - expected number of elements.
|
|
2299
|
+
*/
|
|
2300
|
+
seeNumberOfVisibleElements(locator: CodeceptJS.LocatorOrString, num: number): Promise<void>;
|
|
2301
|
+
/**
|
|
2302
|
+
* Retrieves the current page scroll position.
|
|
2303
|
+
*
|
|
2304
|
+
* ```js
|
|
2305
|
+
* let { x, y } = await I.grabPageScrollPosition();
|
|
2306
|
+
* ```
|
|
2307
|
+
* @returns scroll position.
|
|
2308
|
+
*/
|
|
2309
|
+
grabPageScrollPosition(): Promise<{ x: number; y: number; }>;
|
|
2310
|
+
/**
|
|
2311
|
+
* Scrolls to the top of the page.
|
|
2312
|
+
*
|
|
2313
|
+
* ```js
|
|
2314
|
+
* I.scrollPageToTop();
|
|
2315
|
+
* ```
|
|
2316
|
+
*/
|
|
2317
|
+
scrollPageToTop(): Promise<void>;
|
|
2318
|
+
/**
|
|
2319
|
+
* Scrolls to the bottom of the page.
|
|
2320
|
+
*
|
|
2321
|
+
* ```js
|
|
2322
|
+
* I.scrollPageToBottom();
|
|
2323
|
+
* ```
|
|
2324
|
+
*/
|
|
2325
|
+
scrollPageToBottom(): Promise<void>;
|
|
2326
|
+
/**
|
|
2327
|
+
* Scrolls to the element matched by locator, or to given coordinates.
|
|
2328
|
+
*
|
|
2329
|
+
* ```js
|
|
2330
|
+
* I.scrollTo('#submit');
|
|
2331
|
+
* I.scrollTo(100, 200);
|
|
2332
|
+
* ```
|
|
2333
|
+
* @param locator - element to scroll to, or an X coordinate if no element.
|
|
2334
|
+
* @param [offsetX = 0] - X offset, or Y coordinate if `locator` is a number.
|
|
2335
|
+
* @param [offsetY = 0] - Y offset applied when scrolling to an element.
|
|
2336
|
+
*/
|
|
2337
|
+
scrollTo(locator: CodeceptJS.LocatorOrString | number, offsetX?: number, offsetY?: number): Promise<void>;
|
|
2338
|
+
/**
|
|
2339
|
+
* Retrieves a CSS property from an element located by CSS or XPath.
|
|
2340
|
+
* If more than one element is found - value of first element is returned.
|
|
2341
|
+
*
|
|
2342
|
+
* ```js
|
|
2343
|
+
* const value = await I.grabCssPropertyFrom('h3', 'font-weight');
|
|
2344
|
+
* ```
|
|
2345
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2346
|
+
* @param cssProperty - CSS property name.
|
|
2347
|
+
* @returns CSS value
|
|
2348
|
+
*/
|
|
2349
|
+
grabCssPropertyFrom(locator: CodeceptJS.LocatorOrString, cssProperty: string): Promise<string>;
|
|
2350
|
+
/**
|
|
2351
|
+
* Retrieves an array of CSS properties from elements located by CSS or XPath.
|
|
2352
|
+
*
|
|
2353
|
+
* ```js
|
|
2354
|
+
* const values = await I.grabCssPropertyFromAll('h3', 'font-weight');
|
|
2355
|
+
* ```
|
|
2356
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2357
|
+
* @param cssProperty - CSS property name.
|
|
2358
|
+
* @returns array of CSS values
|
|
2359
|
+
*/
|
|
2360
|
+
grabCssPropertyFromAll(locator: CodeceptJS.LocatorOrString, cssProperty: string): Promise<string[]>;
|
|
2361
|
+
/**
|
|
2362
|
+
* Checks that all elements matched by locator have the given CSS properties.
|
|
2363
|
+
*
|
|
2364
|
+
* ```js
|
|
2365
|
+
* I.seeCssPropertiesOnElements('h3', { 'font-weight': 'bold', display: 'block' });
|
|
2366
|
+
* ```
|
|
2367
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2368
|
+
* @param cssProperties - object with CSS properties and their values to check.
|
|
2369
|
+
*/
|
|
2370
|
+
seeCssPropertiesOnElements(locator: CodeceptJS.LocatorOrString, cssProperties: any): Promise<void>;
|
|
2371
|
+
/**
|
|
2372
|
+
* Checks that all elements matched by locator have the given attribute values.
|
|
2373
|
+
* An expected value is matched either as an exact match or as a regular expression against the actual value.
|
|
2374
|
+
*
|
|
2375
|
+
* ```js
|
|
2376
|
+
* I.seeAttributesOnElements('//form', { method: 'post' });
|
|
2377
|
+
* ```
|
|
2378
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2379
|
+
* @param attributes - object with attribute names and expected values.
|
|
2380
|
+
*/
|
|
2381
|
+
seeAttributesOnElements(locator: CodeceptJS.LocatorOrString, attributes: any): Promise<void>;
|
|
2382
|
+
/**
|
|
2383
|
+
* Focuses a given element.
|
|
2384
|
+
*
|
|
2385
|
+
* ```js
|
|
2386
|
+
* I.focus('#name');
|
|
2387
|
+
* ```
|
|
2388
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2389
|
+
*/
|
|
2390
|
+
focus(locator: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2391
|
+
/**
|
|
2392
|
+
* Removes focus from a given element.
|
|
2393
|
+
*
|
|
2394
|
+
* ```js
|
|
2395
|
+
* I.blur('#name');
|
|
2396
|
+
* ```
|
|
2397
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2398
|
+
*/
|
|
2399
|
+
blur(locator: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2400
|
+
/**
|
|
2401
|
+
* Types characters into the currently focused element (as set by `click`, `focus`, etc). Each
|
|
2402
|
+
* character dispatches a real `keydown` → `keypress` → (value mutated) → `input` → `keyup`
|
|
2403
|
+
* sequence, and mutates a `contenteditable` host's `textContent` instead of `.value`, so this
|
|
2404
|
+
* works on rich-text/contenteditable targets as well as `input`/`textarea`. Mirrors Puppeteer's
|
|
2405
|
+
* `type(text, options)` semantics.
|
|
2406
|
+
*
|
|
2407
|
+
* Without a `delay`, every character is dispatched in a single round-trip to the page. With a
|
|
2408
|
+
* `delay`, characters are dispatched one round-trip at a time so the requested pause actually
|
|
2409
|
+
* elapses between key presses.
|
|
2410
|
+
*
|
|
2411
|
+
* ```js
|
|
2412
|
+
* I.click('Name');
|
|
2413
|
+
* I.type('CodeceptJS');
|
|
2414
|
+
* I.type(['C', 'o', 'd', 'e']);
|
|
2415
|
+
* ```
|
|
2416
|
+
* @param keys - characters to type, either as a string or an array of characters.
|
|
2417
|
+
* @param [delay = null] - (optional) delay in milliseconds between key presses.
|
|
2418
|
+
*/
|
|
2419
|
+
type(keys: string | string[], delay?: number): Promise<void>;
|
|
2420
|
+
/**
|
|
2421
|
+
* Presses a key or key combination on the currently focused element.
|
|
2422
|
+
* Under `options.strict`, a modifier+editing-key combination (e.g. `Ctrl+A`) dispatched with no
|
|
2423
|
+
* element focused throws `NonFocusedType`, mirroring `focusCheck.js`'s behavior on other helpers.
|
|
2424
|
+
*
|
|
2425
|
+
* ```js
|
|
2426
|
+
* I.pressKey('Enter');
|
|
2427
|
+
* I.pressKey(['Control', 'a']);
|
|
2428
|
+
* ```
|
|
2429
|
+
* @param key - a key or an array of keys to combine (modifiers first).
|
|
2430
|
+
*/
|
|
2431
|
+
pressKey(key: string | string[]): Promise<void>;
|
|
2432
|
+
/**
|
|
2433
|
+
* Resizes the browser viewport.
|
|
2434
|
+
*
|
|
2435
|
+
* ```js
|
|
2436
|
+
* I.resizeWindow(1024, 768);
|
|
2437
|
+
* ```
|
|
2438
|
+
* @param width - window width, or `'maximize'`.
|
|
2439
|
+
* @param [height] - window height.
|
|
2440
|
+
*/
|
|
2441
|
+
resizeWindow(width: number | 'maximize', height?: number): Promise<void>;
|
|
2442
|
+
/**
|
|
2443
|
+
* Performs a double-click on an element matched by locator.
|
|
2444
|
+
*
|
|
2445
|
+
* ```js
|
|
2446
|
+
* I.doubleClick('Edit');
|
|
2447
|
+
* ```
|
|
2448
|
+
* @param locator - clickable element located by text, or any element located by CSS|XPath|strict locator.
|
|
2449
|
+
* @param [context = null] - (optional, `null` by default, currently ignored by this helper).
|
|
2450
|
+
*/
|
|
2451
|
+
doubleClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2452
|
+
/**
|
|
2453
|
+
* Performs a right-click on an element matched by locator.
|
|
2454
|
+
*
|
|
2455
|
+
* ```js
|
|
2456
|
+
* I.rightClick('Menu');
|
|
2457
|
+
* ```
|
|
2458
|
+
* @param locator - clickable element located by text, or any element located by CSS|XPath|strict locator.
|
|
2459
|
+
* @param [context = null] - (optional, `null` by default, currently ignored by this helper).
|
|
2460
|
+
*/
|
|
2461
|
+
rightClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): Promise<void>;
|
|
2462
|
+
/**
|
|
2463
|
+
* Clicks at global page coordinates, or at coordinates relative to an element.
|
|
2464
|
+
* Dispatches a real CDP mouse click and therefore requires a real layout engine.
|
|
2465
|
+
*
|
|
2466
|
+
* ```js
|
|
2467
|
+
* I.clickXY(100, 200); // global coordinates
|
|
2468
|
+
* I.clickXY('#area', 50, 30); // relative to #area
|
|
2469
|
+
* ```
|
|
2470
|
+
* @param locator - element to click relative to, or a global X coordinate.
|
|
2471
|
+
* @param [x] - X coordinate relative to element, or global Y coordinate if `locator` is a number.
|
|
2472
|
+
* @param [y] - Y coordinate relative to element.
|
|
2473
|
+
*/
|
|
2474
|
+
clickXY(locator: CodeceptJS.LocatorOrString | number, x?: number, y?: number): Promise<void>;
|
|
2475
|
+
/**
|
|
2476
|
+
* Waits for an element to become visible (by default waits for `options.waitForTimeout` seconds).
|
|
2477
|
+
*
|
|
2478
|
+
* ```js
|
|
2479
|
+
* I.waitForVisible('#popup', 5);
|
|
2480
|
+
* ```
|
|
2481
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2482
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2483
|
+
*/
|
|
2484
|
+
waitForVisible(locator: CodeceptJS.LocatorOrString, sec?: number): Promise<void>;
|
|
2485
|
+
/**
|
|
2486
|
+
* Waits for an element to become invisible (by default waits for `options.waitForTimeout` seconds).
|
|
2487
|
+
*
|
|
2488
|
+
* ```js
|
|
2489
|
+
* I.waitForInvisible('#popup', 5);
|
|
2490
|
+
* ```
|
|
2491
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2492
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2493
|
+
*/
|
|
2494
|
+
waitForInvisible(locator: CodeceptJS.LocatorOrString, sec?: number): Promise<void>;
|
|
2495
|
+
/**
|
|
2496
|
+
* Waits for an element to be hidden. Alias of `waitForInvisible`.
|
|
2497
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2498
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2499
|
+
*/
|
|
2500
|
+
waitToHide(locator: CodeceptJS.LocatorOrString, sec?: number): Promise<void>;
|
|
2501
|
+
/**
|
|
2502
|
+
* Waits for an element to be removed from the DOM (by default waits for `options.waitForTimeout` seconds).
|
|
2503
|
+
*
|
|
2504
|
+
* ```js
|
|
2505
|
+
* I.waitForDetached('#popup', 5);
|
|
2506
|
+
* ```
|
|
2507
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2508
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2509
|
+
*/
|
|
2510
|
+
waitForDetached(locator: CodeceptJS.LocatorOrString, sec?: number): Promise<void>;
|
|
2511
|
+
/**
|
|
2512
|
+
* Checks that a cookie with the given name is set.
|
|
2513
|
+
* @param name - cookie name.
|
|
2514
|
+
*/
|
|
2515
|
+
seeCookie(name: string): Promise<void>;
|
|
2516
|
+
/**
|
|
2517
|
+
* Checks that a cookie with the given name is not set.
|
|
2518
|
+
* @param name - cookie name.
|
|
2519
|
+
*/
|
|
2520
|
+
dontSeeCookie(name: string): Promise<void>;
|
|
2521
|
+
/**
|
|
2522
|
+
* Waits for a cookie with the given name to be set (by default waits for `options.waitForTimeout` seconds).
|
|
2523
|
+
*
|
|
2524
|
+
* ```js
|
|
2525
|
+
* I.waitForCookie('auth', 5);
|
|
2526
|
+
* ```
|
|
2527
|
+
* @param name - cookie name.
|
|
2528
|
+
* @param [sec = null] - (optional, `options.waitForTimeout` by default) time in seconds to wait
|
|
2529
|
+
*/
|
|
2530
|
+
waitForCookie(name: string, sec?: number): Promise<void>;
|
|
2531
|
+
/**
|
|
2532
|
+
* Retrieves the inner HTML from an element located by CSS or XPath.
|
|
2533
|
+
* If more than one element is found - HTML of first element is returned.
|
|
2534
|
+
*
|
|
2535
|
+
* ```js
|
|
2536
|
+
* let postHTML = await I.grabHTMLFrom('#post');
|
|
2537
|
+
* ```
|
|
2538
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2539
|
+
* @returns HTML code for an element
|
|
2540
|
+
*/
|
|
2541
|
+
grabHTMLFrom(locator: CodeceptJS.LocatorOrString): Promise<string>;
|
|
2542
|
+
/**
|
|
2543
|
+
* Retrieves the inner HTML from elements located by CSS or XPath.
|
|
2544
|
+
*
|
|
2545
|
+
* ```js
|
|
2546
|
+
* let postHTMLs = await I.grabHTMLFromAll('.post');
|
|
2547
|
+
* ```
|
|
2548
|
+
* @param locator - element located by CSS|XPath|strict locator.
|
|
2549
|
+
* @returns HTML code for matched elements
|
|
2550
|
+
*/
|
|
2551
|
+
grabHTMLFromAll(locator: CodeceptJS.LocatorOrString): Promise<string[]>;
|
|
2552
|
+
/**
|
|
2553
|
+
* Executes an asynchronous script (callback-style, in the same way `window.setTimeout` works)
|
|
2554
|
+
* in the browser context and returns the value passed to `done`.
|
|
2555
|
+
*
|
|
2556
|
+
* ```js
|
|
2557
|
+
* const val = await I.executeAsyncScript(function(val, done) {
|
|
2558
|
+
* setTimeout(() => done(val + 1), 100)
|
|
2559
|
+
* }, 5)
|
|
2560
|
+
* ```
|
|
2561
|
+
* @param fn - an asynchronous function to be executed in the browser context; its last argument is a `done` callback.
|
|
2562
|
+
* @param args - arguments to pass into the function (before `done`).
|
|
2563
|
+
* @returns the value passed to `done`.
|
|
2564
|
+
*/
|
|
2565
|
+
executeAsyncScript(fn: (...params: any[]) => any, ...args: any[]): Promise<any>;
|
|
2566
|
+
/**
|
|
2567
|
+
* Starts recording network traffic via CDP's `Network.requestWillBeSent`/`responseReceived`
|
|
2568
|
+
* events, in the same shape (`{url, method, requestHeaders, requestPostData, response}` per
|
|
2569
|
+
* request, `response` a promise of `{url(), status(), statusText(), body()}`) the shared
|
|
2570
|
+
* `lib/helper/network` actions expect from Puppeteer/Playwright. The CDP listeners are
|
|
2571
|
+
* installed once (lazily) and left in place afterwards, since `CDPConnection` has no listener
|
|
2572
|
+
* removal and `this.cdp` is reused across tests; they filter by `this.sessionId`, so only the
|
|
2573
|
+
* currently active test/page's requests are recorded.
|
|
2574
|
+
*
|
|
2575
|
+
* ```js
|
|
2576
|
+
* I.startRecordingTraffic();
|
|
2577
|
+
* ```
|
|
2578
|
+
*/
|
|
2579
|
+
startRecordingTraffic(): Promise<void>;
|
|
2580
|
+
/**
|
|
2581
|
+
* `Network.requestWillBeSent` handler, pushed into `this.requests` when it belongs to the
|
|
2582
|
+
* currently active session and recording is on.
|
|
2583
|
+
*/
|
|
2584
|
+
protected _onTrafficRequest(): Promise<any>;
|
|
2585
|
+
/**
|
|
2586
|
+
* `Network.responseReceived` handler, resolving the matching pending `response` promise pushed
|
|
2587
|
+
* by `_onTrafficRequest` with a Puppeteer-`HTTPResponse`-like object.
|
|
2588
|
+
*/
|
|
2589
|
+
protected _onTrafficResponse(): Promise<any>;
|
|
2590
|
+
/**
|
|
2591
|
+
* `Network.loadingFailed` handler, resolving a still-pending `response` promise to `null`
|
|
2592
|
+
* (matching Puppeteer's `request.response()` for a failed request) so `grabRecordedNetworkTraffics`
|
|
2593
|
+
* never awaits a promise that would otherwise never settle.
|
|
2594
|
+
*/
|
|
2595
|
+
protected _onTrafficLoadingFailed(): Promise<any>;
|
|
2596
|
+
/**
|
|
2597
|
+
* Grab the recording network traffics
|
|
2598
|
+
*
|
|
2599
|
+
* ```js
|
|
2600
|
+
* const traffics = await I.grabRecordedNetworkTraffics();
|
|
2601
|
+
* expect(traffics[0].url).to.equal('https://reqres.in/api/comments/1');
|
|
2602
|
+
* expect(traffics[0].response.status).to.equal(200);
|
|
2603
|
+
* expect(traffics[0].response.body).to.contain({ name: 'this was mocked' });
|
|
2604
|
+
* ```
|
|
2605
|
+
*/
|
|
2606
|
+
grabRecordedNetworkTraffics(): Promise<any>;
|
|
2607
|
+
/**
|
|
2608
|
+
* Verifies that a certain request is part of network traffic.
|
|
2609
|
+
*
|
|
2610
|
+
* ```js
|
|
2611
|
+
* // checking the request url contains certain query strings
|
|
2612
|
+
* I.amOnPage('https://openai.com/blog/chatgpt');
|
|
2613
|
+
* I.startRecordingTraffic();
|
|
2614
|
+
* await I.seeTraffic({
|
|
2615
|
+
* name: 'sentry event',
|
|
2616
|
+
* url: 'https://images.openai.com/blob/cf717bdb-0c8c-428a-b82b-3c3add87a600',
|
|
2617
|
+
* parameters: {
|
|
2618
|
+
* width: '1919',
|
|
2619
|
+
* height: '1138',
|
|
2620
|
+
* },
|
|
2621
|
+
* });
|
|
2622
|
+
* ```
|
|
2623
|
+
*
|
|
2624
|
+
* ```js
|
|
2625
|
+
* // checking the request url contains certain post data
|
|
2626
|
+
* I.amOnPage('https://openai.com/blog/chatgpt');
|
|
2627
|
+
* I.startRecordingTraffic();
|
|
2628
|
+
* await I.seeTraffic({
|
|
2629
|
+
* name: 'event',
|
|
2630
|
+
* url: 'https://cloudflareinsights.com/cdn-cgi/rum',
|
|
2631
|
+
* requestPostData: {
|
|
2632
|
+
* st: 2,
|
|
2633
|
+
* },
|
|
2634
|
+
* });
|
|
2635
|
+
* ```
|
|
2636
|
+
* @param opts - options when checking the traffic network.
|
|
2637
|
+
* @param opts.name - A name of that request. Can be any value. Only relevant to have a more meaningful error message in case of fail.
|
|
2638
|
+
* @param opts.url - Expected URL of request in network traffic
|
|
2639
|
+
* @param [opts.parameters] - Expected parameters of that request in network traffic
|
|
2640
|
+
* @param [opts.requestPostData] - Expected that request contains post data in network traffic
|
|
2641
|
+
* @param [opts.timeout] - Timeout to wait for request in seconds. Default is 10 seconds.
|
|
2642
|
+
*/
|
|
2643
|
+
seeTraffic(opts: {
|
|
2644
|
+
name: string;
|
|
2645
|
+
url: string;
|
|
2646
|
+
parameters?: any;
|
|
2647
|
+
requestPostData?: any;
|
|
2648
|
+
timeout?: number;
|
|
2649
|
+
}): Promise<any>;
|
|
2650
|
+
/**
|
|
2651
|
+
* Verifies that a certain request is not part of network traffic.
|
|
2652
|
+
*
|
|
2653
|
+
* Examples:
|
|
2654
|
+
*
|
|
2655
|
+
* ```js
|
|
2656
|
+
* I.dontSeeTraffic({ name: 'Unexpected API Call', url: 'https://api.example.com' });
|
|
2657
|
+
* I.dontSeeTraffic({ name: 'Unexpected API Call of "user" endpoint', url: /api.example.com.*user/ });
|
|
2658
|
+
* ```
|
|
2659
|
+
* @param opts - options when checking the traffic network.
|
|
2660
|
+
* @param opts.name - A name of that request. Can be any value. Only relevant to have a more meaningful error message in case of fail.
|
|
2661
|
+
* @param opts.url - Expected URL of request in network traffic. Can be a string or a regular expression.
|
|
2662
|
+
*/
|
|
2663
|
+
dontSeeTraffic(opts: {
|
|
2664
|
+
name: string;
|
|
2665
|
+
url: string | RegExp;
|
|
2666
|
+
}): Promise<any>;
|
|
2667
|
+
/**
|
|
2668
|
+
* Stops recording network traffic started by `startRecordingTraffic`. Already-recorded requests
|
|
2669
|
+
* in `this.requests` are kept; only new requests stop being appended.
|
|
2670
|
+
*
|
|
2671
|
+
* ```js
|
|
2672
|
+
* I.stopRecordingTraffic();
|
|
2673
|
+
* ```
|
|
2674
|
+
*/
|
|
2675
|
+
stopRecordingTraffic(): Promise<any>;
|
|
2676
|
+
/**
|
|
2677
|
+
* Resets all recorded network requests.
|
|
2678
|
+
*
|
|
2679
|
+
* ```js
|
|
2680
|
+
* I.flushNetworkTraffics();
|
|
2681
|
+
* ```
|
|
2682
|
+
*/
|
|
2683
|
+
flushNetworkTraffics(): Promise<any>;
|
|
2684
|
+
/**
|
|
2685
|
+
* Starts recording a CDP `Page.startScreencast` session for the current test's target: frames
|
|
2686
|
+
* arrive as `Page.screencastFrame` events, are acknowledged immediately (`Page.screencastFrameAck`,
|
|
2687
|
+
* required or the browser stops sending more), and buffered in `this._screencastFrames`. The
|
|
2688
|
+
* underlying `Page.screencastFrame` listener is installed once (lazily) and left in place, like
|
|
2689
|
+
* `startRecordingTraffic`'s listeners, since `CDPConnection` has no listener-removal API; it
|
|
2690
|
+
* filters by `this.sessionId` so only the currently active test's frames are buffered. Call
|
|
2691
|
+
* `stopScreencast` to end the capture and assemble the buffered frames into an APNG.
|
|
2692
|
+
*
|
|
2693
|
+
* ```js
|
|
2694
|
+
* I.startScreencast();
|
|
2695
|
+
* ```
|
|
2696
|
+
* @param [options] - {maxWidth: number, maxHeight: number, quality: number, everyNthFrame: number} — CDP `Page.startScreencast` pass-throughs. `format` is always `'png'`.
|
|
2697
|
+
*/
|
|
2698
|
+
startScreencast(options?: any): Promise<void>;
|
|
2699
|
+
/**
|
|
2700
|
+
* `Page.screencastFrame` handler: ignores frames from a session other than the currently active
|
|
2701
|
+
* one (stale frames from a previous test, since the listener is never removed), acknowledges the
|
|
2702
|
+
* frame so the browser keeps sending more, and buffers `{data, timestamp}` for `stopScreencast`
|
|
2703
|
+
* to assemble.
|
|
2704
|
+
*/
|
|
2705
|
+
protected _onScreencastFrame(): Promise<any>;
|
|
2706
|
+
/**
|
|
2707
|
+
* Stops the screencast started by `startScreencast` and assembles the buffered frames into a
|
|
2708
|
+
* single APNG (Animated PNG) file, returned as a Buffer. Frame delays are derived from the CDP
|
|
2709
|
+
* frame metadata's `timestamp` deltas (frame arrival is activity-driven — Obscura and Chrome both
|
|
2710
|
+
* only emit a frame on damage — so this reproduces the actual pacing of what happened, not a
|
|
2711
|
+
* fixed frame rate); the last frame is held for `options.lastFrameDelayMs` (default 1000ms) since
|
|
2712
|
+
* it has no "next" frame to derive a delay from. Every frame is checked for the PNG signature
|
|
2713
|
+
* before assembly — CDP's `format: 'png'` is honored by both Chrome and Obscura (verified
|
|
2714
|
+
* directly), but if some other engine ever sends a different format regardless, this reports it
|
|
2715
|
+
* via `debugSection` and returns `null` instead of muxing a broken file. Returns `null` if no
|
|
2716
|
+
* frames were captured (screencast never started, or stopped immediately after starting).
|
|
2717
|
+
*
|
|
2718
|
+
* ```js
|
|
2719
|
+
* const apngBuffer = await I.stopScreencast();
|
|
2720
|
+
* ```
|
|
2721
|
+
* @param [options] - {lastFrameDelayMs: number} — hold time in milliseconds for the final frame (default 1000).
|
|
2722
|
+
* @returns a Buffer with the assembled APNG, or null if there was nothing to assemble.
|
|
2723
|
+
*/
|
|
2724
|
+
stopScreencast(options?: any): Promise<object>;
|
|
2725
|
+
}
|
|
1165
2726
|
/**
|
|
1166
2727
|
* Helper for testing filesystem.
|
|
1167
2728
|
* Can be easily used to check file structures:
|
|
@@ -1734,6 +3295,278 @@ declare namespace CodeceptJS {
|
|
|
1734
3295
|
*/
|
|
1735
3296
|
seeResponseMatchesJsonSchema(fnOrSchema: any): Promise<any>;
|
|
1736
3297
|
}
|
|
3298
|
+
/**
|
|
3299
|
+
* ## Configuration
|
|
3300
|
+
*
|
|
3301
|
+
* This helper should be configured in codecept.conf.js. It accepts everything `CDPBrowser`
|
|
3302
|
+
* accepts (see its config table), plus:
|
|
3303
|
+
* @property [url = http://localhost] - base URL for tests
|
|
3304
|
+
* @property [accountId] - Cloudflare account ID; defaults to CF_ACCOUNT_ID env var
|
|
3305
|
+
* @property [apiToken] - Cloudflare API token; defaults to CF_API_TOKEN env var
|
|
3306
|
+
* @property [keepAlive = 240000] - session keep-alive time in milliseconds
|
|
3307
|
+
* @property [apiBase = https://api.cloudflare.com/client/v4] - Cloudflare API base URL
|
|
3308
|
+
* @property [input = cdp] - input method for user actions; defaults to 'cdp' for Kitesurf's real layout engine, but can be overridden
|
|
3309
|
+
* @property [capabilities] - pre-configured capabilities; Kitesurf uses { layout: 'real', screenshot: true }
|
|
3310
|
+
*/
|
|
3311
|
+
type KitesurfConfig = {
|
|
3312
|
+
url?: string;
|
|
3313
|
+
accountId?: string;
|
|
3314
|
+
apiToken?: string;
|
|
3315
|
+
keepAlive?: number;
|
|
3316
|
+
apiBase?: string;
|
|
3317
|
+
input?: string;
|
|
3318
|
+
capabilities?: any;
|
|
3319
|
+
};
|
|
3320
|
+
/**
|
|
3321
|
+
* Kitesurf is a cloud browser helper that extends CDPBrowser to run tests against
|
|
3322
|
+
* Cloudflare's Browser Run service (Kitesurf browser). It automates real browser
|
|
3323
|
+
* sessions in Cloudflare's cloud infrastructure, eliminating the need to manage
|
|
3324
|
+
* local browser instances.
|
|
3325
|
+
*
|
|
3326
|
+
* **Status:** Beta
|
|
3327
|
+
*
|
|
3328
|
+
* ## Requirements
|
|
3329
|
+
*
|
|
3330
|
+
* - Cloudflare account with Browser Run enabled
|
|
3331
|
+
* - API token with **Browser Rendering Edit** permission
|
|
3332
|
+
*
|
|
3333
|
+
* ## Setup
|
|
3334
|
+
*
|
|
3335
|
+
* To create an API token with Browser Rendering Edit permission:
|
|
3336
|
+
* 1. Log in to your Cloudflare dashboard
|
|
3337
|
+
* 2. Go to My Profile > API Tokens
|
|
3338
|
+
* 3. Click "Create Token"
|
|
3339
|
+
* 4. Use the "Custom token" template
|
|
3340
|
+
* 5. Under "Permissions", select "Browser Rendering" > "Edit"
|
|
3341
|
+
* 6. Set the account scope to your target account
|
|
3342
|
+
* 7. Copy the token and set it as `CF_API_TOKEN` environment variable
|
|
3343
|
+
*
|
|
3344
|
+
* For more details, see:
|
|
3345
|
+
* - [Cloudflare Browser Run Developers Docs](https://developers.cloudflare.com/browser-run/)
|
|
3346
|
+
* - [Cloudflare Blog - Kitesurf Announcement](https://blog.cloudflare.com/kitesurf/)
|
|
3347
|
+
*
|
|
3348
|
+
* ## Example
|
|
3349
|
+
*
|
|
3350
|
+
* ```js
|
|
3351
|
+
* // codecept.conf.js
|
|
3352
|
+
* {
|
|
3353
|
+
* helpers: {
|
|
3354
|
+
* Kitesurf: {
|
|
3355
|
+
* url: 'https://example.com',
|
|
3356
|
+
* accountId: process.env.CF_ACCOUNT_ID,
|
|
3357
|
+
* apiToken: process.env.CF_API_TOKEN,
|
|
3358
|
+
* }
|
|
3359
|
+
* }
|
|
3360
|
+
* }
|
|
3361
|
+
* ```
|
|
3362
|
+
*
|
|
3363
|
+
* Or set environment variables and rely on defaults:
|
|
3364
|
+
*
|
|
3365
|
+
* ```bash
|
|
3366
|
+
* export CF_ACCOUNT_ID="your-account-id"
|
|
3367
|
+
* export CF_API_TOKEN="your-api-token"
|
|
3368
|
+
* ```
|
|
3369
|
+
*
|
|
3370
|
+
* <!-- configuration -->
|
|
3371
|
+
*
|
|
3372
|
+
* ## Methods
|
|
3373
|
+
*/
|
|
3374
|
+
class KitesurfTs {
|
|
3375
|
+
constructor(config: KitesurfConfig);
|
|
3376
|
+
/**
|
|
3377
|
+
* Acquires a Kitesurf browser session from the Cloudflare Browser Run API and resolves it to
|
|
3378
|
+
* the `wss://` debugger URL `CDPConnection` connects to. Overrides `CDPBrowser._resolveEndpoint`,
|
|
3379
|
+
* which resolves a fixed local endpoint instead of provisioning a cloud session per test.
|
|
3380
|
+
* @returns a `wss://` debugger URL ready to be passed to `CDPConnection`.
|
|
3381
|
+
*/
|
|
3382
|
+
protected _resolveEndpoint(): Promise<string>;
|
|
3383
|
+
/**
|
|
3384
|
+
* Closes the target as `CDPBrowser._finishTest` does, then releases the cloud session acquired
|
|
3385
|
+
* in `_resolveEndpoint` via the Cloudflare API so it does not linger for the full `keepAlive`
|
|
3386
|
+
* window. The release runs in a `finally` so a rejection while closing the CDP connection still
|
|
3387
|
+
* frees the cloud session instead of leaving the browser alive until `keepAlive` expires; the
|
|
3388
|
+
* session id is cleared before the request, so a repeated call never releases it twice.
|
|
3389
|
+
*/
|
|
3390
|
+
protected _finishTest(): Promise<any>;
|
|
3391
|
+
}
|
|
3392
|
+
/**
|
|
3393
|
+
* ## Configuration
|
|
3394
|
+
*
|
|
3395
|
+
* This helper should be configured in codecept.conf.js. It accepts everything `CDPBrowser`
|
|
3396
|
+
* accepts (see its config table), plus:
|
|
3397
|
+
* @property [endpoint] - explicit CDP endpoint. Setting this switches the helper to ATTACH
|
|
3398
|
+
* mode: it only connects, and never spawns or kills a process, no matter what else is configured.
|
|
3399
|
+
* Leave it unset for SELF-MANAGED mode (see below).
|
|
3400
|
+
* @property [binaryPath] - path to the `obscura` executable, used in SELF-MANAGED mode
|
|
3401
|
+
* (`endpoint` unset). Checked before `OBSCURA_PATH` and `PATH`.
|
|
3402
|
+
* @property [port] - port `obscura serve` listens on, in SELF-MANAGED mode. When unset, a
|
|
3403
|
+
* free port is picked automatically, which is what makes `run-workers` collision-free — every
|
|
3404
|
+
* worker gets its own instance on its own port with zero config.
|
|
3405
|
+
* @property [serverStartTimeout = 15000] - milliseconds to wait for a spawned `obscura serve`
|
|
3406
|
+
* to answer `/json/version` before `_connect` gives up.
|
|
3407
|
+
*/
|
|
3408
|
+
type ObscuraConfig = {
|
|
3409
|
+
endpoint?: string;
|
|
3410
|
+
binaryPath?: string;
|
|
3411
|
+
port?: number;
|
|
3412
|
+
serverStartTimeout?: number;
|
|
3413
|
+
};
|
|
3414
|
+
/**
|
|
3415
|
+
* Obscura drives [Obscura](https://github.com/h4ckf0r0day/obscura), a minimal headless
|
|
3416
|
+
* browser exposed over the Chrome DevTools Protocol. From v0.2.0, default release builds ship a
|
|
3417
|
+
* real rendering engine (layout, paint, screenshots); `-no-render` variants and v0.1.x builds keep
|
|
3418
|
+
* the original single-V8-isolate, nothing-rendered mode. This helper does not hardcode which mode a
|
|
3419
|
+
* given binary is in — `CDPBrowser._probeCapabilities` detects `layout`/`screenshot` per binary at
|
|
3420
|
+
* runtime, so the same helper works against either.
|
|
3421
|
+
*
|
|
3422
|
+
* This helper is a thin `CDPBrowser` subclass: it changes nothing about how locating or acting on
|
|
3423
|
+
* elements works, it only pins the config presets Obscura requires and manages the `obscura serve`
|
|
3424
|
+
* process lifecycle, the same way Playwright manages its own browser process.
|
|
3425
|
+
*
|
|
3426
|
+
* ## Modes
|
|
3427
|
+
*
|
|
3428
|
+
* - **ATTACH** — `endpoint` is set explicitly in the config. The helper only connects to it; it
|
|
3429
|
+
* never spawns or kills anything, no matter what `binaryPath`/`port` are set to.
|
|
3430
|
+
* - **SELF-LAUNCH** — `endpoint` is unset and a binary can be resolved, in order: `binaryPath` in
|
|
3431
|
+
* the config, then the `OBSCURA_PATH` environment variable, then `obscura` on `PATH`. The helper
|
|
3432
|
+
* spawns `obscura serve --port <port> --allow-private-network` (`port` from the config, or a
|
|
3433
|
+
* free port picked automatically), waits for it to answer, connects, and kills it in
|
|
3434
|
+
* `_finishTest`.
|
|
3435
|
+
* - **COURTESY-ATTACH** — `endpoint` is unset and no binary can be resolved, but something already
|
|
3436
|
+
* answers `http://127.0.0.1:9222/json/version` (e.g. `obscura serve` started by hand, or by CI
|
|
3437
|
+
* before this process ever ran). The helper attaches to it and never kills it — it isn't the
|
|
3438
|
+
* helper's process to kill. If neither a binary nor a running server on :9222 can be found, the
|
|
3439
|
+
* helper throws a loud, actionable error.
|
|
3440
|
+
*
|
|
3441
|
+
* ## Install
|
|
3442
|
+
*
|
|
3443
|
+
* Download a release binary and put it on your `PATH` (or point `binaryPath`/`OBSCURA_PATH` at
|
|
3444
|
+
* it directly) and the helper launches and tears it down for you automatically:
|
|
3445
|
+
*
|
|
3446
|
+
* ```sh
|
|
3447
|
+
* curl -sL https://github.com/h4ckf0r0day/obscura/releases/download/v0.2.0/obscura-x86_64-linux.tar.gz | tar xz
|
|
3448
|
+
* ```
|
|
3449
|
+
*
|
|
3450
|
+
* `--allow-private-network` is always passed by this helper (it's required to reach apps running
|
|
3451
|
+
* on `localhost`/private IPs, e.g. a dev server on `127.0.0.1:8000` — Obscura blocks
|
|
3452
|
+
* private-network requests by default).
|
|
3453
|
+
*
|
|
3454
|
+
* ## Config presets
|
|
3455
|
+
*
|
|
3456
|
+
* These are set automatically and only need overriding for unusual setups:
|
|
3457
|
+
*
|
|
3458
|
+
* | option | value | why |
|
|
3459
|
+
* | --- | --- | --- |
|
|
3460
|
+
* | `input` | `synthetic` | coordinate-click navigation is unreliable over CDP on Obscura even on rendering builds (no `frameNavigated` event, stale `page.url()`); `click` always takes the `forceClick` path — on Obscura, `click` and `forceClick` are the same thing |
|
|
3461
|
+
* | `xpathPolyfill` | `auto` | probed per binary/page: Obscura's native `document.evaluate` still doesn't support attribute selection or `not()`, so the polyfill is used until that lands |
|
|
3462
|
+
*
|
|
3463
|
+
* `capabilities.layout`/`capabilities.screenshot`/`capabilities.xpath` are intentionally left
|
|
3464
|
+
* unset here — `CDPBrowser._probeCapabilities` detects them at runtime from the actual binary
|
|
3465
|
+
* (`'real'`/`true` on v0.2.0+ default builds, `'none'`/`false` on `-no-render` builds and v0.1.x).
|
|
3466
|
+
* Set them explicitly in your own config to skip probing or to force a mode.
|
|
3467
|
+
*
|
|
3468
|
+
* ## Limitations
|
|
3469
|
+
*
|
|
3470
|
+
* - `input` is always `synthetic`, even on rendering builds — see `input` above.
|
|
3471
|
+
* - No frames, popups, or file uploads.
|
|
3472
|
+
* - On `-no-render` builds and v0.1.x: no screenshots, no visibility assertions
|
|
3473
|
+
* (`seeElement`/`dontSeeElement` always throw) — only DOM presence
|
|
3474
|
+
* (`seeElementInDOM`/`dontSeeElementInDOM`) is meaningful without a layout engine.
|
|
3475
|
+
* - On v0.2.0+ default (rendering) builds: layout, screenshots, and CSS work, but it's a new,
|
|
3476
|
+
* independently implemented rendering/CSS engine — expect edge cases and gaps versus a real browser.
|
|
3477
|
+
* - Single V8 isolate: heavy or long-running pages, or many pages in parallel against one
|
|
3478
|
+
* `obscura serve` process, compete for the same isolate.
|
|
3479
|
+
*
|
|
3480
|
+
* <!-- configuration -->
|
|
3481
|
+
*
|
|
3482
|
+
* ## Example
|
|
3483
|
+
*
|
|
3484
|
+
* ```js
|
|
3485
|
+
* // inside codecept.conf.js — SELF-LAUNCH mode (recommended): the helper finds/starts/stops
|
|
3486
|
+
* // obscura serve on its own, on a free port. Ideal for run-workers: every worker gets its own
|
|
3487
|
+
* // instance with no config.
|
|
3488
|
+
* {
|
|
3489
|
+
* helpers: {
|
|
3490
|
+
* Obscura: {
|
|
3491
|
+
* url: 'http://localhost',
|
|
3492
|
+
* }
|
|
3493
|
+
* }
|
|
3494
|
+
* }
|
|
3495
|
+
* ```
|
|
3496
|
+
*
|
|
3497
|
+
* ```js
|
|
3498
|
+
* // ATTACH mode — connect to an Obscura instance you manage yourself (remote host, container, etc.)
|
|
3499
|
+
* {
|
|
3500
|
+
* helpers: {
|
|
3501
|
+
* Obscura: {
|
|
3502
|
+
* url: 'http://localhost',
|
|
3503
|
+
* endpoint: 'http://127.0.0.1:9222',
|
|
3504
|
+
* }
|
|
3505
|
+
* }
|
|
3506
|
+
* }
|
|
3507
|
+
* ```
|
|
3508
|
+
*
|
|
3509
|
+
* ## Methods
|
|
3510
|
+
*/
|
|
3511
|
+
class ObscuraTs {
|
|
3512
|
+
constructor(config: ObscuraConfig);
|
|
3513
|
+
/**
|
|
3514
|
+
* In ATTACH mode, connects exactly as `CDPBrowser._connect` would. In SELF-MANAGED mode,
|
|
3515
|
+
* resolves and spawns `obscura serve` (or courtesy-attaches to an already-running one on
|
|
3516
|
+
* :9222) exactly once via `_resolveSelfManaged`, then connects.
|
|
3517
|
+
*
|
|
3518
|
+
* A spawn failure (e.g. a bad binary) is delivered asynchronously by Node as an `error`
|
|
3519
|
+
* event; it is recorded on `this.serverError` and surfaced as a rejection from `_waitForServer`
|
|
3520
|
+
* instead of crashing the process as an uncaught exception.
|
|
3521
|
+
*/
|
|
3522
|
+
protected _connect(): Promise<any>;
|
|
3523
|
+
/**
|
|
3524
|
+
* Resolves how to reach Obscura when no explicit `endpoint` was configured, trying, in order:
|
|
3525
|
+
* spawn a binary (`binaryPath` config, then `OBSCURA_PATH` env, then `obscura` on `PATH`),
|
|
3526
|
+
* courtesy-attach to `http://127.0.0.1:9222` if something already answers there, or throw a
|
|
3527
|
+
* loud, actionable error. Sets `this.options.endpoint` as a side effect.
|
|
3528
|
+
*/
|
|
3529
|
+
protected _resolveSelfManaged(): Promise<any>;
|
|
3530
|
+
/**
|
|
3531
|
+
* Resolves the `obscura` binary to spawn, in priority order: `options.binaryPath`, then the
|
|
3532
|
+
* `OBSCURA_PATH` environment variable, then `obscura` on `PATH`. The `PATH` lookup walks the
|
|
3533
|
+
* directories itself instead of shelling out to `which`, which does not exist on Windows: on
|
|
3534
|
+
* Windows every `PATHEXT` suffix is tried, so an `obscura.exe` on `PATH` is found too.
|
|
3535
|
+
*/
|
|
3536
|
+
protected _resolveBinary(): Promise<any>;
|
|
3537
|
+
/**
|
|
3538
|
+
* Picks a free TCP port on 127.0.0.1 by briefly listening on port 0 and reading back the OS-assigned
|
|
3539
|
+
* port. Used as the SELF-LAUNCH default when `options.port` isn't explicitly set, so multiple
|
|
3540
|
+
* `run-workers` workers never collide on the same port.
|
|
3541
|
+
* @returns a free port.
|
|
3542
|
+
*/
|
|
3543
|
+
protected _findFreePort(): Promise<number>;
|
|
3544
|
+
/**
|
|
3545
|
+
* Probes a `/json/version`-style URL with a short timeout, used for the COURTESY-ATTACH check.
|
|
3546
|
+
* @returns true if the URL answered.
|
|
3547
|
+
*/
|
|
3548
|
+
protected _probeUp(url: string): Promise<boolean>;
|
|
3549
|
+
/**
|
|
3550
|
+
* Polls `http://127.0.0.1:<port>/json/version` until `obscura serve` responds, `this.serverError`
|
|
3551
|
+
* is set by the spawned process' `error` event, or `options.serverStartTimeout` elapses. The
|
|
3552
|
+
* process typically comes up within tens of milliseconds — a 20ms retry interval (down from a
|
|
3553
|
+
* previous 200ms) keeps the wasted tail after the server is actually ready small, since this cost
|
|
3554
|
+
* is paid once per run and counts directly toward real-world startup latency.
|
|
3555
|
+
*/
|
|
3556
|
+
protected _waitForServer(): Promise<any>;
|
|
3557
|
+
/**
|
|
3558
|
+
* Closes the CDP connection (via `CDPBrowser._finishTest`), then kills the `obscura serve`
|
|
3559
|
+
* process spawned by `_connect`, if any (never runs in ATTACH or COURTESY-ATTACH mode, since
|
|
3560
|
+
* `this.serverProcess` is only ever set in SELF-LAUNCH mode). Runs in a `finally` so the process
|
|
3561
|
+
* is always reaped even if closing the CDP connection throws. Sends `SIGTERM` first and waits for
|
|
3562
|
+
* the process to exit; a process that ignores `SIGTERM` is escalated to `SIGKILL` after 5s. The
|
|
3563
|
+
* promise only resolves once the child has actually exited (confirmed via the `exit` event, not
|
|
3564
|
+
* merely once `SIGKILL` was sent — the kernel needs a moment to reap it), with a final safety-net
|
|
3565
|
+
* timeout so a stuck child can never keep the event loop alive even if that confirmation is
|
|
3566
|
+
* somehow lost.
|
|
3567
|
+
*/
|
|
3568
|
+
protected _finishTest(): Promise<any>;
|
|
3569
|
+
}
|
|
1737
3570
|
/**
|
|
1738
3571
|
* ## Configuration
|
|
1739
3572
|
*
|