@playq/core 0.2.77
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/README.md +41 -0
- package/bin/playq.js +175 -0
- package/cucumber.js +10 -0
- package/dist/exec/featureFileCache.d.ts +21 -0
- package/dist/exec/featureFileCache.js +124 -0
- package/dist/exec/featureFilePreProcess.d.ts +12 -0
- package/dist/exec/featureFilePreProcess.js +208 -0
- package/dist/exec/preLoader.d.ts +1 -0
- package/dist/exec/preLoader.js +72 -0
- package/dist/exec/preProcessEntry.d.ts +1 -0
- package/dist/exec/preProcessEntry.js +83 -0
- package/dist/exec/preProcess_old_todelete.d.ts +1 -0
- package/dist/exec/preProcess_old_todelete.js +258 -0
- package/dist/exec/runner.d.ts +1 -0
- package/dist/exec/runner.js +221 -0
- package/dist/exec/runner_orchestrator.d.ts +1 -0
- package/dist/exec/runner_orchestrator.js +85 -0
- package/dist/exec/sgGenerator.d.ts +11 -0
- package/dist/exec/sgGenerator.js +310 -0
- package/dist/global.d.ts +15 -0
- package/dist/global.js +185 -0
- package/dist/helper/actions/api/apiRequestActions.d.ts +117 -0
- package/dist/helper/actions/api/apiRequestActions.js +374 -0
- package/dist/helper/actions/api/apiValidationActions.d.ts +119 -0
- package/dist/helper/actions/api/apiValidationActions.js +615 -0
- package/dist/helper/actions/apiActions.d.ts +18 -0
- package/dist/helper/actions/apiActions.js +34 -0
- package/dist/helper/actions/apiStepDefs.d.ts +1 -0
- package/dist/helper/actions/apiStepDefs.js +64 -0
- package/dist/helper/actions/comm/commonActions.d.ts +58 -0
- package/dist/helper/actions/comm/commonActions.js +198 -0
- package/dist/helper/actions/comm/utilityActions.d.ts +131 -0
- package/dist/helper/actions/comm/utilityActions.js +351 -0
- package/dist/helper/actions/commActions.d.ts +18 -0
- package/dist/helper/actions/commActions.js +34 -0
- package/dist/helper/actions/commStepDefs.d.ts +1 -0
- package/dist/helper/actions/commStepDefs.js +57 -0
- package/dist/helper/actions/stepGroupStepDefs.d.ts +1 -0
- package/dist/helper/actions/stepGroupStepDefs.js +15 -0
- package/dist/helper/actions/web/alertActions.d.ts +61 -0
- package/dist/helper/actions/web/alertActions.js +224 -0
- package/dist/helper/actions/web/cookieActions.d.ts +45 -0
- package/dist/helper/actions/web/cookieActions.js +186 -0
- package/dist/helper/actions/web/downloadActions.d.ts +40 -0
- package/dist/helper/actions/web/downloadActions.js +153 -0
- package/dist/helper/actions/web/elementReaderActions.d.ts +95 -0
- package/dist/helper/actions/web/elementReaderActions.js +326 -0
- package/dist/helper/actions/web/formActions.d.ts +122 -0
- package/dist/helper/actions/web/formActions.js +423 -0
- package/dist/helper/actions/web/iframeActions.d.ts +23 -0
- package/dist/helper/actions/web/iframeActions.js +108 -0
- package/dist/helper/actions/web/javascriptActions.d.ts +14 -0
- package/dist/helper/actions/web/javascriptActions.js +77 -0
- package/dist/helper/actions/web/keyboardActions.d.ts +35 -0
- package/dist/helper/actions/web/keyboardActions.js +118 -0
- package/dist/helper/actions/web/localStorageActions.d.ts +51 -0
- package/dist/helper/actions/web/localStorageActions.js +163 -0
- package/dist/helper/actions/web/mouseActions.d.ts +240 -0
- package/dist/helper/actions/web/mouseActions.js +609 -0
- package/dist/helper/actions/web/reportingActions.d.ts +34 -0
- package/dist/helper/actions/web/reportingActions.js +58 -0
- package/dist/helper/actions/web/screenshotActions.d.ts +34 -0
- package/dist/helper/actions/web/screenshotActions.js +151 -0
- package/dist/helper/actions/web/testDataActions.d.ts +21 -0
- package/dist/helper/actions/web/testDataActions.js +211 -0
- package/dist/helper/actions/web/validationActions.d.ts +547 -0
- package/dist/helper/actions/web/validationActions.js +1754 -0
- package/dist/helper/actions/web/waitActions.d.ts +191 -0
- package/dist/helper/actions/web/waitActions.js +589 -0
- package/dist/helper/actions/web/webNavigation.d.ts +104 -0
- package/dist/helper/actions/web/webNavigation.js +288 -0
- package/dist/helper/actions/webActions.d.ts +32 -0
- package/dist/helper/actions/webActions.js +48 -0
- package/dist/helper/actions/webStepDefs.d.ts +1 -0
- package/dist/helper/actions/webStepDefs.js +455 -0
- package/dist/helper/browsers/browserManager.d.ts +1 -0
- package/dist/helper/browsers/browserManager.js +56 -0
- package/dist/helper/bundle/defaultEntries.d.ts +6 -0
- package/dist/helper/bundle/defaultEntries.js +200 -0
- package/dist/helper/bundle/env.d.ts +1 -0
- package/dist/helper/bundle/env.js +157 -0
- package/dist/helper/bundle/vars.d.ts +9 -0
- package/dist/helper/bundle/vars.js +375 -0
- package/dist/helper/faker/customFaker.d.ts +55 -0
- package/dist/helper/faker/customFaker.js +45 -0
- package/dist/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
- package/dist/helper/faker/modules/dateTime.d.ts +18 -0
- package/dist/helper/faker/modules/dateTime.js +106 -0
- package/dist/helper/faker/modules/mobile.d.ts +4 -0
- package/dist/helper/faker/modules/mobile.js +59 -0
- package/dist/helper/faker/modules/nric.d.ts +32 -0
- package/dist/helper/faker/modules/nric.js +84 -0
- package/dist/helper/faker/modules/passport.d.ts +3 -0
- package/dist/helper/faker/modules/passport.js +36 -0
- package/dist/helper/faker/modules/person.d.ts +14 -0
- package/dist/helper/faker/modules/person.js +73 -0
- package/dist/helper/faker/modules/postcode.d.ts +6 -0
- package/dist/helper/faker/modules/postcode.js +47 -0
- package/dist/helper/fixtures/locAggregate.d.ts +7 -0
- package/dist/helper/fixtures/locAggregate.js +94 -0
- package/dist/helper/fixtures/logFixture.d.ts +8 -0
- package/dist/helper/fixtures/logFixture.js +56 -0
- package/dist/helper/fixtures/webFixture.d.ts +19 -0
- package/dist/helper/fixtures/webFixture.js +186 -0
- package/dist/helper/fixtures/webLocFixture.d.ts +2 -0
- package/dist/helper/fixtures/webLocFixture.js +144 -0
- package/dist/helper/report/allureStepLogger.d.ts +0 -0
- package/dist/helper/report/allureStepLogger.js +25 -0
- package/dist/helper/report/customiseReport.d.ts +1 -0
- package/dist/helper/report/customiseReport.js +55 -0
- package/dist/helper/report/init.d.ts +1 -0
- package/dist/helper/report/init.js +14 -0
- package/dist/helper/report/report.d.ts +1 -0
- package/dist/helper/report/report.js +102 -0
- package/dist/helper/util/dataLoader.d.ts +10 -0
- package/dist/helper/util/dataLoader.js +73 -0
- package/dist/helper/util/logger.d.ts +4 -0
- package/dist/helper/util/logger.js +61 -0
- package/dist/helper/util/session/sessionUtil.d.ts +26 -0
- package/dist/helper/util/session/sessionUtil.js +729 -0
- package/dist/helper/util/stepHelpers.d.ts +2 -0
- package/dist/helper/util/stepHelpers.js +16 -0
- package/dist/helper/util/test-data/dataLoader.d.ts +7 -0
- package/dist/helper/util/test-data/dataLoader.js +145 -0
- package/dist/helper/util/test-data/dataTest.d.ts +10 -0
- package/dist/helper/util/test-data/dataTest.js +216 -0
- package/dist/helper/util/totp/totpHelper.d.ts +38 -0
- package/dist/helper/util/totp/totpHelper.js +117 -0
- package/dist/helper/util/utilities/cryptoUtil.d.ts +2 -0
- package/dist/helper/util/utilities/cryptoUtil.js +53 -0
- package/dist/helper/util/utilities/schemaGeneratorUtil.d.ts +2 -0
- package/dist/helper/util/utilities/schemaGeneratorUtil.js +129 -0
- package/dist/helper/util/utils.d.ts +2 -0
- package/dist/helper/util/utils.js +22 -0
- package/dist/helper/wrapper/PlaywrightWrappers.d.ts +8 -0
- package/dist/helper/wrapper/PlaywrightWrappers.js +26 -0
- package/dist/helper/wrapper/assert.d.ts +9 -0
- package/dist/helper/wrapper/assert.js +23 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +57 -0
- package/dist/scripts/get-versions.d.ts +1 -0
- package/dist/scripts/get-versions.js +98 -0
- package/dist/scripts/posttest.d.ts +1 -0
- package/dist/scripts/posttest.js +29 -0
- package/dist/scripts/pretest.d.ts +1 -0
- package/dist/scripts/pretest.js +57 -0
- package/dist/scripts/util.d.ts +1 -0
- package/dist/scripts/util.js +376 -0
- package/package.json +68 -0
- package/src/exec/featureFileCache.ts +80 -0
- package/src/exec/featureFilePreProcess.ts +239 -0
- package/src/exec/preLoader.ts +72 -0
- package/src/exec/preProcessEntry.ts +59 -0
- package/src/exec/preProcess_old_todelete.ts +289 -0
- package/src/exec/runner.ts +241 -0
- package/src/exec/runnerCuke.js +90 -0
- package/src/exec/runner_orchestrator.ts +91 -0
- package/src/exec/sgGenerator.ts +373 -0
- package/src/global.ts +130 -0
- package/src/helper/actions/api/apiRequestActions.ts +362 -0
- package/src/helper/actions/api/apiValidationActions.ts +594 -0
- package/src/helper/actions/apiActions.ts +18 -0
- package/src/helper/actions/apiStepDefs.ts +80 -0
- package/src/helper/actions/comm/commonActions.ts +165 -0
- package/src/helper/actions/comm/utilityActions.ts +344 -0
- package/src/helper/actions/commActions.ts +18 -0
- package/src/helper/actions/commStepDefs.ts +72 -0
- package/src/helper/actions/stepGroupStepDefs.ts +17 -0
- package/src/helper/actions/web/alertActions.ts +179 -0
- package/src/helper/actions/web/cookieActions.ts +124 -0
- package/src/helper/actions/web/downloadActions.ts +129 -0
- package/src/helper/actions/web/elementReaderActions.ts +323 -0
- package/src/helper/actions/web/formActions.ts +469 -0
- package/src/helper/actions/web/iframeActions.ts +67 -0
- package/src/helper/actions/web/javascriptActions.ts +38 -0
- package/src/helper/actions/web/keyboardActions.ts +101 -0
- package/src/helper/actions/web/localStorageActions.ts +109 -0
- package/src/helper/actions/web/mouseActions.ts +864 -0
- package/src/helper/actions/web/reportingActions.ts +53 -0
- package/src/helper/actions/web/screenshotActions.ts +124 -0
- package/src/helper/actions/web/testDataActions.ts +162 -0
- package/src/helper/actions/web/validationActions.ts +2287 -0
- package/src/helper/actions/web/waitActions.ts +757 -0
- package/src/helper/actions/web/webNavigation.ts +313 -0
- package/src/helper/actions/webActions.ts +33 -0
- package/src/helper/actions/webStepDefs.ts +505 -0
- package/src/helper/browsers/browserManager.ts +23 -0
- package/src/helper/bundle/defaultEntries.ts +208 -0
- package/src/helper/bundle/env.ts +119 -0
- package/src/helper/bundle/vars.ts +368 -0
- package/src/helper/faker/customFaker.ts +107 -0
- package/src/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
- package/src/helper/faker/modules/dateTime.ts +121 -0
- package/src/helper/faker/modules/mobile.ts +58 -0
- package/src/helper/faker/modules/nric.ts +109 -0
- package/src/helper/faker/modules/passport.ts +34 -0
- package/src/helper/faker/modules/person.ts +93 -0
- package/src/helper/faker/modules/postcode.ts +57 -0
- package/src/helper/fixtures/locAggregate.ts +61 -0
- package/src/helper/fixtures/logFixture.ts +57 -0
- package/src/helper/fixtures/webFixture.ts +206 -0
- package/src/helper/fixtures/webLocFixture.ts +143 -0
- package/src/helper/report/allureStepLogger.ts +26 -0
- package/src/helper/report/customiseReport.ts +61 -0
- package/src/helper/report/init.ts +18 -0
- package/src/helper/report/report.ts +72 -0
- package/src/helper/util/dataLoader.ts +42 -0
- package/src/helper/util/logger.ts +32 -0
- package/src/helper/util/session/sessionUtil.ts +839 -0
- package/src/helper/util/stepHelpers.ts +14 -0
- package/src/helper/util/test-data/dataLoader.ts +108 -0
- package/src/helper/util/test-data/dataTest.ts +191 -0
- package/src/helper/util/test-data/registerUser.json +7 -0
- package/src/helper/util/totp/totpHelper.ts +102 -0
- package/src/helper/util/utilities/cryptoUtil.ts +53 -0
- package/src/helper/util/utilities/schemaGeneratorUtil.ts +143 -0
- package/src/helper/util/utils.ts +28 -0
- package/src/helper/wrapper/PlaywrightWrappers.ts +28 -0
- package/src/helper/wrapper/assert.ts +25 -0
- package/src/index.ts +17 -0
- package/src/scripts/get-versions.ts +68 -0
- package/src/scripts/posttest.ts +32 -0
- package/src/scripts/pretest.ts +48 -0
- package/src/scripts/util.ts +406 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file waitActions.ts
|
|
3
|
+
*
|
|
4
|
+
* Wait utilities for PlayQ web actions.
|
|
5
|
+
* Provides time-based waits, page load settling, element visibility/state
|
|
6
|
+
* waits, header/text waits, and URL waits with runner-aware step wrappers.
|
|
7
|
+
*
|
|
8
|
+
* Authors: PlayQ Team
|
|
9
|
+
* Version: v1.0.0
|
|
10
|
+
*/
|
|
11
|
+
import * as allure from "allure-js-commons";
|
|
12
|
+
import { Page, Locator, expect } from "@playwright/test";
|
|
13
|
+
import { vars, comm } from "../../../global";
|
|
14
|
+
import { webLocResolver } from "../../fixtures/webLocFixture";
|
|
15
|
+
import { processScreenshot } from "./screenshotActions";
|
|
16
|
+
import { attachLog } from "../comm/commonActions";
|
|
17
|
+
import { parseLooseJson } from '../../bundle/vars';
|
|
18
|
+
|
|
19
|
+
function isPlaywrightRunner() { return process.env.TEST_RUNNER === 'playwright'; }
|
|
20
|
+
const __allureAny_wait: any = allure as any;
|
|
21
|
+
if (typeof __allureAny_wait.step !== 'function') { __allureAny_wait.step = async (_n: string, f: any) => await f(); }
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Comm: Wait-In-Milli-Seconds -seconds: {param}
|
|
25
|
+
*
|
|
26
|
+
* Pauses execution for the given number of milliseconds.
|
|
27
|
+
* Delegates to `comm.waitInMilliSeconds`.
|
|
28
|
+
*
|
|
29
|
+
* @param ms Milliseconds to wait
|
|
30
|
+
*/
|
|
31
|
+
export async function wait(ms: number) {
|
|
32
|
+
return comm.waitInMilliSeconds(ms);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Web: Wait For Condition -timeout: {param}
|
|
37
|
+
*
|
|
38
|
+
* Polls a predicate until it returns true or times out.
|
|
39
|
+
*
|
|
40
|
+
* @param page Playwright Page instance
|
|
41
|
+
* @param predicate Async function returning a boolean
|
|
42
|
+
* @param options Optional JSON string or object ({ timeout, interval })
|
|
43
|
+
*/
|
|
44
|
+
export async function waitForCondition(page: Page, predicate: (page: Page) => Promise<boolean>, options?: string | Record<string, any>) {
|
|
45
|
+
const options_json = typeof options === 'string' ? vars.parseLooseJson(options) : options || {};
|
|
46
|
+
const { timeout = Number(vars.getConfigValue('testExecution.actionTimeout')) || 10000, interval = 250 } = options_json;
|
|
47
|
+
const stepName = `Web: Wait For Condition -timeout: ${timeout}`;
|
|
48
|
+
const start = Date.now();
|
|
49
|
+
async function loop() {
|
|
50
|
+
while (Date.now() - start < timeout) {
|
|
51
|
+
if (await predicate(page)) return true;
|
|
52
|
+
await comm.waitInMilliSeconds(interval);
|
|
53
|
+
}
|
|
54
|
+
throw new Error('Condition not met within timeout');
|
|
55
|
+
}
|
|
56
|
+
if (isPlaywrightRunner()) { await __allureAny_wait.step(stepName, loop); } else { await loop(); }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Waits for the page to fully load by checking multiple browser states:
|
|
61
|
+
* - `domcontentloaded`: Ensures DOM is parsed and ready.
|
|
62
|
+
* - `load`: Waits for all resources like images and scripts to load.
|
|
63
|
+
* - `requestIdleCallback`: Ensures the browser is idle before proceeding.
|
|
64
|
+
*
|
|
65
|
+
* This function is useful after navigation, form submission, or any page transition
|
|
66
|
+
* to ensure stable element interaction.
|
|
67
|
+
*
|
|
68
|
+
* @param page - The Playwright Page instance.
|
|
69
|
+
* @param actionTimeout - Optional timeout (in ms) to wait for each load state. Default: 10000.
|
|
70
|
+
*
|
|
71
|
+
*/
|
|
72
|
+
export async function waitForPageToLoad(
|
|
73
|
+
page: Page,
|
|
74
|
+
actionTimeout: number = 10000
|
|
75
|
+
): Promise<void> {
|
|
76
|
+
const wait = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
|
77
|
+
|
|
78
|
+
console.log("⏳ Waiting for DOMContentLoaded...");
|
|
79
|
+
try {
|
|
80
|
+
await page.waitForLoadState("domcontentloaded", { timeout: actionTimeout });
|
|
81
|
+
console.log("✅ DOMContentLoaded");
|
|
82
|
+
} catch {
|
|
83
|
+
console.warn("⚠️ DOMContentLoaded not detected within timeout");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log("🔄 Waiting for load event...");
|
|
87
|
+
try {
|
|
88
|
+
await page.waitForLoadState("load", { timeout: actionTimeout });
|
|
89
|
+
console.log("✅ Load event");
|
|
90
|
+
} catch {
|
|
91
|
+
console.warn("⚠️ Page load event not triggered within timeout");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log("🕓 Waiting for browser idle callback...");
|
|
95
|
+
try {
|
|
96
|
+
await page.evaluate(() => {
|
|
97
|
+
return new Promise((resolve) => {
|
|
98
|
+
window.requestIdleCallback(() => resolve(true));
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
console.log("✅ requestIdleCallback done");
|
|
102
|
+
} catch {
|
|
103
|
+
console.warn("⚠️ requestIdleCallback failed or delayed");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Waits for a given locator (element) to become enabled within the specified timeout.
|
|
109
|
+
* Useful before interacting with inputs, buttons, or other dynamic UI elements.
|
|
110
|
+
*
|
|
111
|
+
* @param locator - The Playwright Locator to wait for (e.g., input field, button).
|
|
112
|
+
* @param actionTimeout - Optional timeout (in ms). Default: 5000.
|
|
113
|
+
*
|
|
114
|
+
* @throws Error if the locator does not become enabled within the timeout.
|
|
115
|
+
*
|
|
116
|
+
*/
|
|
117
|
+
export async function waitForEnabled(
|
|
118
|
+
locator: Locator,
|
|
119
|
+
actionTimeout: number = 5000
|
|
120
|
+
): Promise<void> {
|
|
121
|
+
await expect(locator).toBeEnabled({ timeout: actionTimeout });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Web: Wait for displayed -field: {param} -options: {param}
|
|
126
|
+
*
|
|
127
|
+
* Waits for an element to become visible on the page.
|
|
128
|
+
*
|
|
129
|
+
* @param page - Playwright Page instance
|
|
130
|
+
* @param field - The label, id, name, or selector of the element to wait for
|
|
131
|
+
* @param options - Optional JSON string or object:
|
|
132
|
+
* - actionTimeout: [number] Optional timeout in milliseconds. Default: Configured timeout.
|
|
133
|
+
* - pattern: [string] Optional pattern to refine element search.
|
|
134
|
+
* - fieldType: [string] Type of field (e.g., input, button, etc.)
|
|
135
|
+
* - screenshot: [boolean] Capture screenshot after waiting. Default: false.
|
|
136
|
+
* - screenshotText: [string] Description for screenshot.
|
|
137
|
+
* - screenshotFullPage: [boolean] Full page screenshot. Default: true.
|
|
138
|
+
*/
|
|
139
|
+
export async function waitForDisplayed(page: Page, field: string | Locator, options?: string | Record<string, any>) {
|
|
140
|
+
const options_json = typeof options === "string" ? vars.parseLooseJson(options) : options || {};
|
|
141
|
+
const {
|
|
142
|
+
actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")) || 30000,
|
|
143
|
+
pattern,
|
|
144
|
+
fieldType,
|
|
145
|
+
screenshot = false,
|
|
146
|
+
screenshotText = "",
|
|
147
|
+
screenshotFullPage = true
|
|
148
|
+
} = options_json;
|
|
149
|
+
|
|
150
|
+
const stepName = `Web: Wait for displayed -field: ${String(field)} -options: ${JSON.stringify(options_json)}`;
|
|
151
|
+
async function run() {
|
|
152
|
+
if (!page) throw new Error("Page not initialized");
|
|
153
|
+
const target = typeof field === "string" ? await webLocResolver(fieldType, field, page, pattern, actionTimeout) : field;
|
|
154
|
+
try {
|
|
155
|
+
await (target as Locator).waitFor({ state: "visible", timeout: actionTimeout });
|
|
156
|
+
await attachLog(`✅ Element "${String(field)}" is now visible`, "text/plain", "Log");
|
|
157
|
+
} catch {
|
|
158
|
+
throw new Error(`❌ Element "${String(field)}" did not become visible within ${actionTimeout}ms`);
|
|
159
|
+
}
|
|
160
|
+
await processScreenshot(page, screenshot, screenshotText || `Waited for element to be displayed: ${String(field)}`, screenshotFullPage);
|
|
161
|
+
}
|
|
162
|
+
if (isPlaywrightRunner()) { await __allureAny_wait.step(stepName, run); } else { await run(); }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Web: Wait for disappear -field: {param} -options: {param}
|
|
167
|
+
*
|
|
168
|
+
* Waits for an element to disappear (become hidden or removed) from the page.
|
|
169
|
+
*
|
|
170
|
+
* @param page - Playwright Page instance
|
|
171
|
+
* @param field - The label, id, name, or selector of the element to wait for
|
|
172
|
+
* @param options - Optional JSON string or object:
|
|
173
|
+
* - actionTimeout: [number] Optional timeout in milliseconds. Default: Configured timeout.
|
|
174
|
+
* - pattern: [string] Optional pattern to refine element search.
|
|
175
|
+
* - fieldType: [string] Type of field (e.g., input, button, etc.)
|
|
176
|
+
* - screenshot: [boolean] Capture screenshot after waiting. Default: false.
|
|
177
|
+
* - screenshotText: [string] Description for screenshot.
|
|
178
|
+
* - screenshotFullPage: [boolean] Full page screenshot. Default: true.
|
|
179
|
+
*/
|
|
180
|
+
export async function waitForDisappear(page: Page, field: string | Locator, options?: string | Record<string, any>) {
|
|
181
|
+
const options_json = typeof options === "string" ? vars.parseLooseJson(options) : options || {};
|
|
182
|
+
const {
|
|
183
|
+
actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")) || 30000,
|
|
184
|
+
pattern,
|
|
185
|
+
fieldType,
|
|
186
|
+
screenshot = false,
|
|
187
|
+
screenshotText = "",
|
|
188
|
+
screenshotFullPage = true
|
|
189
|
+
} = options_json;
|
|
190
|
+
const stepName = `Web: Wait for disappear -field: ${String(field)} -options: ${JSON.stringify(options_json)}`;
|
|
191
|
+
async function run() {
|
|
192
|
+
if (!page) throw new Error("Page not initialized");
|
|
193
|
+
const target = typeof field === "string" ? await webLocResolver(fieldType, field, page, pattern, actionTimeout) : field;
|
|
194
|
+
try {
|
|
195
|
+
await (target as Locator).waitFor({ state: "hidden", timeout: actionTimeout });
|
|
196
|
+
await attachLog(`✅ Element "${String(field)}" has disappeared`, "text/plain", "Log");
|
|
197
|
+
} catch {
|
|
198
|
+
throw new Error(`❌ Element "${String(field)}" did not disappear within ${actionTimeout}ms`);
|
|
199
|
+
}
|
|
200
|
+
await processScreenshot(page, screenshot, screenshotText || `Waited for element to disappear: ${String(field)}`, screenshotFullPage);
|
|
201
|
+
}
|
|
202
|
+
if (isPlaywrightRunner()) { await __allureAny_wait.step(stepName, run); } else { await run(); }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Web: Wait for Text at Location -field: {param} -text: {param} -options: {param}
|
|
208
|
+
*
|
|
209
|
+
* Waits until the specified text appears at the given field/locator.
|
|
210
|
+
*
|
|
211
|
+
* @param page - Playwright Page instance
|
|
212
|
+
* @param field - The selector or Locator where the text should appear
|
|
213
|
+
* @param expectedText - The text to wait for
|
|
214
|
+
* @param options - Optional string or object:
|
|
215
|
+
* - actionTimeout: [number] Timeout in ms (default: 30000)
|
|
216
|
+
* - partialMatch: [boolean] If true, waits for substring match (default: false)
|
|
217
|
+
* - caseSensitive: [boolean] If true, match is case-sensitive (default: true)
|
|
218
|
+
* - screenshot: [boolean] Capture screenshot after waiting (default: false)
|
|
219
|
+
* - screenshotText: [string] Description for screenshot
|
|
220
|
+
* - screenshotFullPage: [boolean] Full page screenshot (default: true)
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* await waitForTextAtLocation(page, 'h1', 'Welcome', { actionTimeout: 10000, partialMatch: true });
|
|
224
|
+
*/
|
|
225
|
+
export async function waitForTextAtLocation(
|
|
226
|
+
page: Page,
|
|
227
|
+
field: string | Locator,
|
|
228
|
+
expectedText: string,
|
|
229
|
+
options?: string | Record<string, any>
|
|
230
|
+
) {
|
|
231
|
+
const options_json =
|
|
232
|
+
typeof options === "string" ? parseLooseJson(options) : options || {};
|
|
233
|
+
const {
|
|
234
|
+
actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")),
|
|
235
|
+
partialMatch = false,
|
|
236
|
+
ignoreCase = true,
|
|
237
|
+
screenshot = false,
|
|
238
|
+
screenshotText = "",
|
|
239
|
+
screenshotFullPage = true,
|
|
240
|
+
pattern,
|
|
241
|
+
} = options_json;
|
|
242
|
+
|
|
243
|
+
if (!page) throw new Error("Page not initialized");
|
|
244
|
+
|
|
245
|
+
if (isPlaywrightRunner()) {
|
|
246
|
+
await __allureAny_wait.step(
|
|
247
|
+
`Web: Wait for Text at Location -field: ${field} -text: ${expectedText} -options: ${JSON.stringify(
|
|
248
|
+
options_json
|
|
249
|
+
)}`,
|
|
250
|
+
async () => {
|
|
251
|
+
await doWaitForTextAtLocation();
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
} else {
|
|
255
|
+
await doWaitForTextAtLocation();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function doWaitForTextAtLocation() {
|
|
259
|
+
const target =
|
|
260
|
+
typeof field === "string"
|
|
261
|
+
? await webLocResolver("text", field, page, pattern, actionTimeout)
|
|
262
|
+
: field;
|
|
263
|
+
|
|
264
|
+
const start = Date.now();
|
|
265
|
+
let found = false;
|
|
266
|
+
let lastActual = "";
|
|
267
|
+
|
|
268
|
+
while (Date.now() - start < actionTimeout) {
|
|
269
|
+
const actualText = ((await target.innerText()) || "").trim();
|
|
270
|
+
lastActual = actualText;
|
|
271
|
+
let expected = expectedText;
|
|
272
|
+
let actual = actualText;
|
|
273
|
+
if (!ignoreCase) {
|
|
274
|
+
expected = expected.toLowerCase();
|
|
275
|
+
actual = actual.toLowerCase();
|
|
276
|
+
}
|
|
277
|
+
if (partialMatch ? actual.includes(expected) : actual === expected) {
|
|
278
|
+
found = true;
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
await new Promise((res) => setTimeout(res, 300));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!found) {
|
|
285
|
+
const msg = `❌ Text "${expectedText}" did not appear at location "${field}" within ${actionTimeout}ms. Last actual: "${lastActual}"`;
|
|
286
|
+
await attachLog(msg, "text/plain");
|
|
287
|
+
throw new Error(msg);
|
|
288
|
+
} else {
|
|
289
|
+
await attachLog(
|
|
290
|
+
`✅ Text "${expectedText}" appeared at location "${field}"`,
|
|
291
|
+
"text/plain"
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
await processScreenshot(
|
|
296
|
+
page,
|
|
297
|
+
screenshot,
|
|
298
|
+
screenshotText || `Waited for text at location: ${expectedText}`,
|
|
299
|
+
screenshotFullPage
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Web: Wait for Text to Disappear at Location -field: {param} -text: {param} -options: {param}
|
|
306
|
+
*
|
|
307
|
+
* Waits until the specified text disappears from the given field/locator.
|
|
308
|
+
*
|
|
309
|
+
* @param page - Playwright Page instance
|
|
310
|
+
* @param field - The selector or Locator where the text should disappear
|
|
311
|
+
* @param textToDisappear - The text to wait for disappearance
|
|
312
|
+
* @param options - Optional string or object:
|
|
313
|
+
* - actionTimeout: [number] Timeout in ms (default: 30000)
|
|
314
|
+
* - partialMatch: [boolean] If true, waits for substring match (default: false)
|
|
315
|
+
* - ignoreCase: [boolean] If true, match is case-insensitive (default: true)
|
|
316
|
+
* - screenshot: [boolean] Capture screenshot after waiting (default: false)
|
|
317
|
+
* - screenshotText: [string] Description for screenshot
|
|
318
|
+
* - screenshotFullPage: [boolean] Full page screenshot (default: true)
|
|
319
|
+
*/
|
|
320
|
+
export async function waitForTextToDisappearAtLocation(
|
|
321
|
+
page: Page,
|
|
322
|
+
field: string | Locator,
|
|
323
|
+
textToDisappear: string,
|
|
324
|
+
options?: string | Record<string, any>
|
|
325
|
+
) {
|
|
326
|
+
const options_json =
|
|
327
|
+
typeof options === "string" ? parseLooseJson(options) : options || {};
|
|
328
|
+
|
|
329
|
+
const {
|
|
330
|
+
actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")) || 30000,
|
|
331
|
+
partialMatch = true,
|
|
332
|
+
ignoreCase = true,
|
|
333
|
+
screenshot = false,
|
|
334
|
+
screenshotText = "",
|
|
335
|
+
screenshotFullPage = true,
|
|
336
|
+
} = options_json;
|
|
337
|
+
|
|
338
|
+
if (!page) throw new Error("Page not initialized");
|
|
339
|
+
|
|
340
|
+
let locator: Locator;
|
|
341
|
+
|
|
342
|
+
if (typeof field === "string") {
|
|
343
|
+
// ✅ Build regex safely
|
|
344
|
+
const escapedText = textToDisappear.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
345
|
+
|
|
346
|
+
const pattern = partialMatch
|
|
347
|
+
? `.*${escapedText}.*`
|
|
348
|
+
: `^${escapedText}$`;
|
|
349
|
+
|
|
350
|
+
const regex = new RegExp(pattern, ignoreCase ? "i" : undefined);
|
|
351
|
+
|
|
352
|
+
locator = page.getByText(regex);
|
|
353
|
+
} else {
|
|
354
|
+
locator = field;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
await locator.waitFor({
|
|
358
|
+
state: "hidden",
|
|
359
|
+
timeout: actionTimeout,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
await attachLog(
|
|
363
|
+
`✅ Text "${textToDisappear}" disappeared (partialMatch=${partialMatch}, ignoreCase=${ignoreCase})`,
|
|
364
|
+
"text/plain"
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
await processScreenshot(
|
|
368
|
+
page,
|
|
369
|
+
screenshot,
|
|
370
|
+
screenshotText || `Waited for text to disappear: ${textToDisappear}`,
|
|
371
|
+
screenshotFullPage
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Web: Wait for Selector -field: {param} -options: {param}
|
|
377
|
+
*
|
|
378
|
+
* Waits for a selector or locator to reach a specific state.
|
|
379
|
+
*
|
|
380
|
+
* @param page - Playwright Page instance
|
|
381
|
+
* @param field - The selector string or Locator to wait for
|
|
382
|
+
* @param options - Optional string or object:
|
|
383
|
+
* - fieldType: [string] Type of field (e.g., 'button', 'input') for pattern resolution
|
|
384
|
+
* - state: [string] 'attached' | 'detached' | 'visible' | 'hidden' (default: 'visible')
|
|
385
|
+
* - actionTimeout: [number] Timeout in ms (default: 30000)
|
|
386
|
+
* - pattern: [string] Optional pattern for locator resolution
|
|
387
|
+
* - screenshot: [boolean] Capture screenshot after waiting (default: false)
|
|
388
|
+
* - screenshotText: [string] Description for screenshot
|
|
389
|
+
* - screenshotFullPage: [boolean] Full page screenshot (default: true)
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* await waitForSelector(page, 'img[alt="~"]', { state: 'hidden', actionTimeout: 10000 });
|
|
393
|
+
*/
|
|
394
|
+
export async function waitForSelector(
|
|
395
|
+
page: Page,
|
|
396
|
+
field: string | Locator,
|
|
397
|
+
options?: string | Record<string, any>
|
|
398
|
+
) {
|
|
399
|
+
const options_json =
|
|
400
|
+
typeof options === "string" ? parseLooseJson(options) : options || {};
|
|
401
|
+
const {
|
|
402
|
+
fieldType,
|
|
403
|
+
state = "visible",
|
|
404
|
+
actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")) || 30000,
|
|
405
|
+
pattern,
|
|
406
|
+
screenshot = false,
|
|
407
|
+
screenshotText = "",
|
|
408
|
+
screenshotFullPage = true,
|
|
409
|
+
} = options_json;
|
|
410
|
+
|
|
411
|
+
if (!page) throw new Error("Page not initialized");
|
|
412
|
+
|
|
413
|
+
if (isPlaywrightRunner()) {
|
|
414
|
+
await __allureAny_wait.step(
|
|
415
|
+
`Web: Wait for Selector -field: ${field} -state: ${state} -options: ${JSON.stringify(options_json)}`,
|
|
416
|
+
async () => {
|
|
417
|
+
await doWaitForSelector();
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
} else {
|
|
421
|
+
await doWaitForSelector();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async function doWaitForSelector() {
|
|
425
|
+
if (typeof field === "string" && !fieldType) {
|
|
426
|
+
throw new Error(
|
|
427
|
+
`fieldType is required for string selectors. Received field="${field}"`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
let target: Locator;
|
|
432
|
+
|
|
433
|
+
if (typeof field === "string") {
|
|
434
|
+
if (state === "hidden" || state === "detached") {
|
|
435
|
+
if (fieldType === "text") {
|
|
436
|
+
target = page.getByText(field, { exact: false });
|
|
437
|
+
} else {
|
|
438
|
+
target = page.locator(`//*[normalize-space()='${field}']`);
|
|
439
|
+
}
|
|
440
|
+
} else {
|
|
441
|
+
target = await webLocResolver(
|
|
442
|
+
fieldType,
|
|
443
|
+
field,
|
|
444
|
+
page,
|
|
445
|
+
pattern,
|
|
446
|
+
actionTimeout
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
} else {
|
|
450
|
+
target = field;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
await target.waitFor({ state, timeout: actionTimeout });
|
|
454
|
+
|
|
455
|
+
await attachLog(
|
|
456
|
+
`✅ Selector "${field}" reached state "${state}".`,
|
|
457
|
+
"text/plain"
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
await processScreenshot(
|
|
461
|
+
page,
|
|
462
|
+
screenshot,
|
|
463
|
+
screenshotText || `Waited for selector: ${field} state: ${state}`,
|
|
464
|
+
screenshotFullPage
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Web: Wait for Header -header: {param} -text: {param} -options: {param}
|
|
473
|
+
*
|
|
474
|
+
* Waits until a specific header element contains the expected text.
|
|
475
|
+
* The header parameter should be a locator or will use pattern resolution.
|
|
476
|
+
*
|
|
477
|
+
* @param page - Playwright Page instance
|
|
478
|
+
* @param header - The locator of the header element (e.g., "h1", "xpath=//h1[@class='title']", or Locator object)
|
|
479
|
+
* @param headerText - The expected header text to wait for (e.g., "Welcome", "Dashboard")
|
|
480
|
+
* @param options - Optional string or object:
|
|
481
|
+
* - actionTimeout: [number] Timeout in ms (default: 30000)
|
|
482
|
+
* - partialMatch: [boolean] If true, waits for substring match (default: false)
|
|
483
|
+
* - ignoreCase: [boolean] If true, case-insensitive match (default: true)
|
|
484
|
+
* - pattern: [string] Optional pattern to refine element search
|
|
485
|
+
* - screenshot: [boolean] Capture screenshot after waiting (default: false)
|
|
486
|
+
* - screenshotText: [string] Description for screenshot
|
|
487
|
+
* - screenshotFullPage: [boolean] Full page screenshot (default: true)
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* await waitForHeader(page, 'h1', 'Welcome Back!', {
|
|
491
|
+
* partialMatch: true,
|
|
492
|
+
* screenshot: true
|
|
493
|
+
* });
|
|
494
|
+
*/
|
|
495
|
+
export async function waitForHeader(
|
|
496
|
+
page: Page,
|
|
497
|
+
header: string | Locator,
|
|
498
|
+
headerText: string,
|
|
499
|
+
options?: string | Record<string, any>
|
|
500
|
+
) {
|
|
501
|
+
const resolvedHeaderText = vars.replaceVariables(headerText);
|
|
502
|
+
const options_json =
|
|
503
|
+
typeof options === "string" ? parseLooseJson(options) : options || {};
|
|
504
|
+
|
|
505
|
+
const {
|
|
506
|
+
actionTimeout = Number(
|
|
507
|
+
vars.getConfigValue("testExecution.actionTimeout")
|
|
508
|
+
) || 30000,
|
|
509
|
+
partialMatch = false,
|
|
510
|
+
ignoreCase = true,
|
|
511
|
+
pattern,
|
|
512
|
+
screenshot = false,
|
|
513
|
+
screenshotText = "",
|
|
514
|
+
screenshotFullPage = true,
|
|
515
|
+
} = options_json;
|
|
516
|
+
|
|
517
|
+
if (!page) throw new Error("Page not initialized");
|
|
518
|
+
|
|
519
|
+
if (isPlaywrightRunner()) {
|
|
520
|
+
await __allureAny_wait.step(
|
|
521
|
+
`Web: Wait for Header -header: ${header} -text: ${resolvedHeaderText} -options: ${JSON.stringify(
|
|
522
|
+
options_json
|
|
523
|
+
)}`,
|
|
524
|
+
async () => {
|
|
525
|
+
await doWaitForHeader();
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
} else {
|
|
529
|
+
await doWaitForHeader();
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
async function doWaitForHeader() {
|
|
533
|
+
// Use webLocResolver for header locator resolution or direct Locator
|
|
534
|
+
const target =
|
|
535
|
+
typeof header === "string"
|
|
536
|
+
? await webLocResolver(
|
|
537
|
+
"header",
|
|
538
|
+
header,
|
|
539
|
+
page,
|
|
540
|
+
pattern,
|
|
541
|
+
actionTimeout
|
|
542
|
+
)
|
|
543
|
+
: header;
|
|
544
|
+
|
|
545
|
+
const start = Date.now();
|
|
546
|
+
let found = false;
|
|
547
|
+
let lastActualText = "";
|
|
548
|
+
|
|
549
|
+
while (Date.now() - start < actionTimeout) {
|
|
550
|
+
try {
|
|
551
|
+
// Check if header is visible and get its text
|
|
552
|
+
if (await target.isVisible()) {
|
|
553
|
+
const actualText = (await target.innerText()).trim();
|
|
554
|
+
lastActualText = actualText;
|
|
555
|
+
|
|
556
|
+
let expected = resolvedHeaderText;
|
|
557
|
+
let actual = actualText;
|
|
558
|
+
|
|
559
|
+
// Apply case sensitivity
|
|
560
|
+
if (ignoreCase) {
|
|
561
|
+
expected = expected.toLowerCase();
|
|
562
|
+
actual = actual.toLowerCase();
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Check for match
|
|
566
|
+
const isMatch = partialMatch
|
|
567
|
+
? actual.includes(expected)
|
|
568
|
+
: actual === expected;
|
|
569
|
+
|
|
570
|
+
if (isMatch) {
|
|
571
|
+
found = true;
|
|
572
|
+
await attachLog(
|
|
573
|
+
`✅ Header found: "${actualText}" matches expected "${resolvedHeaderText}"`,
|
|
574
|
+
"text/plain"
|
|
575
|
+
);
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Wait before next check
|
|
581
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
582
|
+
} catch (error) {
|
|
583
|
+
// Continue waiting if there's an error
|
|
584
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (!found) {
|
|
589
|
+
const msg = `❌ Header text "${resolvedHeaderText}" did not appear at locator "${header}" within ${actionTimeout}ms. Last seen: "${lastActualText}"`;
|
|
590
|
+
await attachLog(msg, "text/plain");
|
|
591
|
+
throw new Error(msg);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
await processScreenshot(
|
|
595
|
+
page,
|
|
596
|
+
screenshot,
|
|
597
|
+
screenshotText || `Waited for header: ${resolvedHeaderText}`,
|
|
598
|
+
screenshotFullPage
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Web: Wait for Input -field: {param} -state: {param} (enabled or disabled) -options: {param}
|
|
605
|
+
*
|
|
606
|
+
* Waits for an input field to become 'enabled' or 'disabled'.
|
|
607
|
+
*
|
|
608
|
+
* @param page - Playwright Page instance
|
|
609
|
+
* @param field - Locator or label of the input field
|
|
610
|
+
* @param state - Desired state: 'enabled' or 'disabled'
|
|
611
|
+
* @param options - Optional string or object:
|
|
612
|
+
* - actionTimeout: [number] Optional timeout in milliseconds for waiting. Default: from [config] or 30000.
|
|
613
|
+
* - pattern: [string] Optional pattern to refine element search.
|
|
614
|
+
* - screenshot: [boolean] Capture a screenshot. Default: true.
|
|
615
|
+
* - screenshotText: [string] Description for the screenshot.
|
|
616
|
+
* - screenshotFullPage: [boolean] Capture full page screenshot. Default: true.
|
|
617
|
+
* - smartIQ_refreshLoc: optional override for locator refresh key
|
|
618
|
+
*/
|
|
619
|
+
export async function waitForInputState(
|
|
620
|
+
page: Page,
|
|
621
|
+
field: string | Locator,
|
|
622
|
+
state: "enabled" | "disabled",
|
|
623
|
+
options?: string | Record<string, any>
|
|
624
|
+
) {
|
|
625
|
+
const options_json =
|
|
626
|
+
typeof options === "string" ? parseLooseJson(options) : options || {};
|
|
627
|
+
|
|
628
|
+
const {
|
|
629
|
+
actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")),
|
|
630
|
+
pattern,
|
|
631
|
+
screenshot = false,
|
|
632
|
+
screenshotText = "",
|
|
633
|
+
screenshotFullPage = true,
|
|
634
|
+
smartIQ_refreshLoc = "",
|
|
635
|
+
} = options_json;
|
|
636
|
+
|
|
637
|
+
if (isPlaywrightRunner()) {
|
|
638
|
+
await __allureAny_wait.step(
|
|
639
|
+
`Web: Wait for Input -field: ${field} -state: ${state} (enabled or disabled) -options: ${JSON.stringify(
|
|
640
|
+
options_json
|
|
641
|
+
)}`,
|
|
642
|
+
async () => {
|
|
643
|
+
await doWaitForInputState();
|
|
644
|
+
}
|
|
645
|
+
);
|
|
646
|
+
} else {
|
|
647
|
+
await doWaitForInputState();
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
async function doWaitForInputState() {
|
|
651
|
+
if (!page) throw new Error("Page not initialized");
|
|
652
|
+
|
|
653
|
+
const target =
|
|
654
|
+
typeof field === "string"
|
|
655
|
+
? await webLocResolver(
|
|
656
|
+
"input",
|
|
657
|
+
field,
|
|
658
|
+
page,
|
|
659
|
+
pattern,
|
|
660
|
+
actionTimeout,
|
|
661
|
+
smartIQ_refreshLoc
|
|
662
|
+
)
|
|
663
|
+
: field;
|
|
664
|
+
|
|
665
|
+
try {
|
|
666
|
+
if (state === "enabled") {
|
|
667
|
+
await expect(target).toBeEnabled({ timeout: actionTimeout });
|
|
668
|
+
} else if (state === "disabled") {
|
|
669
|
+
await expect(target).toBeDisabled({ timeout: actionTimeout });
|
|
670
|
+
} else {
|
|
671
|
+
throw new Error(
|
|
672
|
+
`Invalid state "${state}". Use "enabled" or "disabled".`
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
} catch (e) {
|
|
676
|
+
throw new Error(
|
|
677
|
+
`❌ Input "${field}" did not reach state "${state}" within ${actionTimeout}ms. ${e}`
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
await processScreenshot(
|
|
682
|
+
page,
|
|
683
|
+
screenshot,
|
|
684
|
+
screenshotText || `Waited for input state: ${state}`,
|
|
685
|
+
screenshotFullPage
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Web: Wait for URL -url: {param} -options: {param}
|
|
692
|
+
*
|
|
693
|
+
* Waits until the current page URL matches or contains the specified string or regex.
|
|
694
|
+
*
|
|
695
|
+
* @param url - The expected URL or substring/regex to match (e.g., "/dashboard", "https://example.com/page").
|
|
696
|
+
* @param options - Optional JSON string or object:
|
|
697
|
+
* - actionTimeout: [number] Timeout in ms to wait for URL. Default: 30000.
|
|
698
|
+
* - match: [string] "exact" | "contains" . Default: "contains".
|
|
699
|
+
* - assert: [boolean] If false, logs the failure but does not throw. Default: true.
|
|
700
|
+
* - screenshot: [boolean] If true, captures screenshot. Default: false.
|
|
701
|
+
* - screenshotText: [string] Custom screenshot label.
|
|
702
|
+
* - screenshotFullPage: [boolean] Full page screenshot. Default: true.
|
|
703
|
+
*/
|
|
704
|
+
export async function waitForUrl(
|
|
705
|
+
page: Page,
|
|
706
|
+
url: string,
|
|
707
|
+
options?: string | Record<string, any>
|
|
708
|
+
): Promise<void> {
|
|
709
|
+
const options_json =
|
|
710
|
+
typeof options === "string" ? parseLooseJson(options) : options || {};
|
|
711
|
+
const {
|
|
712
|
+
actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")),
|
|
713
|
+
match = "contains",
|
|
714
|
+
screenshot = false,
|
|
715
|
+
screenshotText,
|
|
716
|
+
screenshotFullPage = true,
|
|
717
|
+
} = options_json;
|
|
718
|
+
|
|
719
|
+
if (isPlaywrightRunner()) {
|
|
720
|
+
await __allureAny_wait.step(
|
|
721
|
+
`Web: Wait for URL -url: ${url} -options: ${JSON.stringify(
|
|
722
|
+
options_json
|
|
723
|
+
)}`,
|
|
724
|
+
async () => {
|
|
725
|
+
await doWaitForUrl();
|
|
726
|
+
}
|
|
727
|
+
);
|
|
728
|
+
} else {
|
|
729
|
+
await doWaitForUrl();
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
async function doWaitForUrl() {
|
|
733
|
+
try {
|
|
734
|
+
if (match === "exact") {
|
|
735
|
+
await page.waitForURL(url.toString(), { timeout: actionTimeout });
|
|
736
|
+
} else if (match === "contains") {
|
|
737
|
+
const cleanUrl = url.replace(/^\/|\/$/g, "");
|
|
738
|
+
const regexUrl = new RegExp(escapeRegExp(cleanUrl), "i");
|
|
739
|
+
await expect(page).toHaveURL(regexUrl, { timeout: actionTimeout });
|
|
740
|
+
}
|
|
741
|
+
} catch (error) {
|
|
742
|
+
throw new Error(`⚠️ waitForUrl failed: ${error.message}`);
|
|
743
|
+
}
|
|
744
|
+
await waitForPageToLoad(page);
|
|
745
|
+
await processScreenshot(
|
|
746
|
+
page,
|
|
747
|
+
screenshot,
|
|
748
|
+
screenshotText || "",
|
|
749
|
+
screenshotFullPage
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
function escapeRegExp(str: string): string {
|
|
756
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
757
|
+
}
|