diff --git a/lib/apply/easy_apply.mjs b/lib/apply/easy_apply.mjs index 33d7fa2..114e6a3 100644 --- a/lib/apply/easy_apply.mjs +++ b/lib/apply/easy_apply.mjs @@ -164,7 +164,6 @@ export async function apply(page, job, formFiller) { // Step through modal let lastProgress = '-1'; - let lastHeading = ''; let samePageCount = 0; for (let step = 0; step < LINKEDIN_MAX_MODAL_STEPS; step++) { const modalStillOpen = await page.$(MODAL); @@ -173,10 +172,10 @@ export async function apply(page, job, formFiller) { return { status: 'submitted', meta }; } - // Read progress bar — use page.$() + evaluate on the handle - const progressEl = await page.$(`${MODAL} [role="progressbar"]`); + // Read progress bar — LinkedIn uses element (no explicit role="progressbar") + const progressEl = await page.$(`${MODAL} progress, ${MODAL} [role="progressbar"]`); const progress = progressEl - ? await progressEl.evaluate(el => el.getAttribute('aria-valuenow') || el.getAttribute('value') || el.style?.width || '').catch(() => '') + ? await progressEl.evaluate(el => el.getAttribute('aria-valuenow') || el.value?.toString() || el.getAttribute('value') || el.style?.width || '').catch(() => '') : ''; // Debug snapshot using ElementHandle operations (shadow DOM safe) @@ -229,14 +228,18 @@ export async function apply(page, job, formFiller) { if (nextBtn) { console.log(` [step ${step}] clicking Next`); await nextBtn.click({ timeout: APPLY_CLICK_TIMEOUT }).catch(() => {}); - await page.waitForTimeout(CLICK_WAIT); - // Detect if we're stuck — same heading+progress means page didn't advance - const curHeading = debugInfo.heading; - if (curHeading === lastHeading && progress === lastProgress) { + // Detect if we're stuck — wait for content to change after clicking Next + await page.waitForTimeout(CLICK_WAIT); + const newProgress = await (async () => { + const el = await page.$(`${MODAL} progress, ${MODAL} [role="progressbar"]`); + return el ? await el.evaluate(e => e.getAttribute('aria-valuenow') || e.value?.toString() || '').catch(() => '') : ''; + })(); + + if (newProgress === progress) { samePageCount++; - if (samePageCount >= 2) { - console.log(` [step ${step}] stuck — clicked Next but page didn't advance (${samePageCount} times)`); + if (samePageCount >= 3) { + console.log(` [step ${step}] stuck — clicked Next ${samePageCount} times but progress unchanged at ${progress}`); console.log(` Action: a required field may be unfilled. Check select dropdowns still at "Select an option"`); await dismissModal(page, MODAL); return { status: 'stuck', meta }; @@ -244,8 +247,7 @@ export async function apply(page, job, formFiller) { } else { samePageCount = 0; } - lastProgress = progress; - lastHeading = curHeading; + lastProgress = newProgress; continue; } @@ -259,7 +261,6 @@ export async function apply(page, job, formFiller) { await reviewBtn.click({ timeout: APPLY_CLICK_TIMEOUT }).catch(() => {}); await page.waitForTimeout(CLICK_WAIT); lastProgress = progress; - lastHeading = debugInfo.heading; samePageCount = 0; continue; }