diff --git a/lib/apply/easy_apply.mjs b/lib/apply/easy_apply.mjs index f3e19e6..531f928 100644 --- a/lib/apply/easy_apply.mjs +++ b/lib/apply/easy_apply.mjs @@ -48,13 +48,29 @@ export async function apply(page, job, formFiller) { let lastProgress = '-1'; for (let step = 0; step < LINKEDIN_MAX_MODAL_STEPS; step++) { const modalStillOpen = await page.$(LINKEDIN_EASY_APPLY_MODAL_SELECTOR); - if (!modalStillOpen) return { status: 'submitted', meta }; + if (!modalStillOpen) { + console.log(` ✅ Modal closed — submitted`); + return { status: 'submitted', meta }; + } const progress = await page.$eval('[role="progressbar"]', el => el.getAttribute('aria-valuenow') || el.getAttribute('value') || String(el.style?.width || step) ).catch(() => String(step)); + // Snapshot all buttons visible in modal for debugging + const modalButtons = await page.evaluate((sel) => { + const modal = document.querySelector(sel); + if (!modal) return []; + return Array.from(modal.querySelectorAll('button, [role="button"]')).map(b => ({ + text: b.textContent?.trim().slice(0, 40), + aria: b.getAttribute('aria-label'), + disabled: b.disabled, + })).filter(b => b.text || b.aria); + }, LINKEDIN_EASY_APPLY_MODAL_SELECTOR).catch(() => []); + console.log(` [step ${step}] progress=${progress} buttons=${JSON.stringify(modalButtons)}`); + const unknowns = await formFiller.fill(page, formFiller.profile.resume_path); + if (unknowns.length > 0) console.log(` [step ${step}] unknown fields: ${JSON.stringify(unknowns.map(u => u.label))}`); if (unknowns[0]?.honeypot) { await page.click(LINKEDIN_DISMISS_SELECTOR, { timeout: DISMISS_TIMEOUT }).catch(() => {}); @@ -70,18 +86,21 @@ export async function apply(page, job, formFiller) { const hasSubmit = await page.$(LINKEDIN_SUBMIT_SELECTOR); if (hasSubmit) { + console.log(` [step ${step}] clicking Submit`); await page.click(LINKEDIN_SUBMIT_SELECTOR, { timeout: APPLY_CLICK_TIMEOUT }); await page.waitForTimeout(SUBMIT_WAIT); return { status: 'submitted', meta }; } if (progress === lastProgress && step > 2) { + console.log(` [step ${step}] stuck — progress unchanged at ${progress}`); await page.click(LINKEDIN_DISMISS_SELECTOR, { timeout: DISMISS_TIMEOUT }).catch(() => {}); return { status: 'stuck', meta }; } const hasNext = await page.$(LINKEDIN_NEXT_SELECTOR); if (hasNext) { + console.log(` [step ${step}] clicking Next`); await page.click(LINKEDIN_NEXT_SELECTOR, { timeout: APPLY_CLICK_TIMEOUT }).catch(() => {}); await page.waitForTimeout(CLICK_WAIT); lastProgress = progress; @@ -90,12 +109,14 @@ export async function apply(page, job, formFiller) { const hasReview = await page.$(LINKEDIN_REVIEW_SELECTOR); if (hasReview) { + console.log(` [step ${step}] clicking Review`); await page.click(LINKEDIN_REVIEW_SELECTOR, { timeout: APPLY_CLICK_TIMEOUT }).catch(() => {}); await page.waitForTimeout(CLICK_WAIT); lastProgress = progress; continue; } + console.log(` [step ${step}] no Next/Review/Submit found — breaking`); break; }