aboutsummaryrefslogtreecommitdiff
path: root/playwright-js/lib
diff options
context:
space:
mode:
Diffstat (limited to 'playwright-js/lib')
-rw-r--r--playwright-js/lib/helpers.js54
1 files changed, 35 insertions, 19 deletions
diff --git a/playwright-js/lib/helpers.js b/playwright-js/lib/helpers.js
index 0920d68..42aeedd 100644
--- a/playwright-js/lib/helpers.js
+++ b/playwright-js/lib/helpers.js
@@ -82,30 +82,45 @@ async function createPage(context, options = {}) {
}
/**
- * Smart wait for page to be ready
+ * Smart wait for page to be ready.
+ *
+ * Readiness defaults to the 'load' event. Pass `options.waitForSelector` with an
+ * app-specific landmark (a heading, a role=main region, known text) to wait on
+ * something the app actually rendered — that's the most reliable readiness signal
+ * and the one to prefer. `networkidle` is intentionally NOT the default: Playwright
+ * discourages it for readiness, since a page can be interactive long before the
+ * network goes quiet (and may never go quiet with polling or analytics). Callers
+ * can still pass `waitUntil: 'networkidle'` explicitly if they really need it.
* @param {Object} page - Playwright page
- * @param {Object} options - Wait options
+ * @param {Object} options - Wait options (waitUntil, timeout, waitForSelector)
*/
async function waitForPageReady(page, options = {}) {
const waitOptions = {
- waitUntil: options.waitUntil || 'networkidle',
+ waitUntil: options.waitUntil || 'load',
timeout: options.timeout || 30000
};
-
+
+ // Prefer waiting on a caller-supplied landmark selector when given; it's a
+ // far stronger readiness signal than any load-state event.
+ if (options.waitForSelector) {
+ try {
+ await page.waitForSelector(options.waitForSelector, {
+ state: 'visible',
+ timeout: waitOptions.timeout
+ });
+ return;
+ } catch (e) {
+ console.warn(`Landmark "${options.waitForSelector}" not visible in time, falling back to load state...`);
+ }
+ }
+
try {
- await page.waitForLoadState(waitOptions.waitUntil, {
- timeout: waitOptions.timeout
+ await page.waitForLoadState(waitOptions.waitUntil, {
+ timeout: waitOptions.timeout
});
} catch (e) {
console.warn('Page load timeout, continuing...');
}
-
- // Additional wait for dynamic content if selector provided
- if (options.waitForSelector) {
- await page.waitForSelector(options.waitForSelector, {
- timeout: options.timeout
- });
- }
}
/**
@@ -215,10 +230,11 @@ async function authenticate(page, credentials, selectors = {}) {
await safeType(page, finalSelectors.password, credentials.password);
await safeClick(page, finalSelectors.submit);
- // Wait for navigation or success indicator
+ // Wait for a post-login landmark to become visible (preferred), or for a
+ // navigation to settle. networkidle is avoided here as a readiness signal.
await Promise.race([
- page.waitForNavigation({ waitUntil: 'networkidle' }),
- page.waitForSelector(selectors.successIndicator || '.dashboard, .user-menu, .logout', { timeout: 10000 })
+ page.waitForSelector(selectors.successIndicator || '.dashboard, .user-menu, .logout', { state: 'visible', timeout: 10000 }),
+ page.waitForNavigation({ waitUntil: 'load' })
]).catch(() => {
console.log('Login might have completed without navigation');
});
@@ -383,7 +399,7 @@ async function detectDevServers(customPorts = []) {
const detectedServers = [];
- console.log('🔍 Checking for running dev servers...');
+ console.log('[scan] Checking for running dev servers...');
for (const port of allPorts) {
try {
@@ -397,7 +413,7 @@ async function detectDevServers(customPorts = []) {
}, (res) => {
if (res.statusCode < 500) {
detectedServers.push(`http://localhost:${port}`);
- console.log(` ✅ Found server on port ${port}`);
+ console.log(` [ok] Found server on port ${port}`);
}
resolve();
});
@@ -416,7 +432,7 @@ async function detectDevServers(customPorts = []) {
}
if (detectedServers.length === 0) {
- console.log(' ❌ No dev servers detected');
+ console.log(' [none] No dev servers detected');
}
return detectedServers;