From fdb0224226d55417af74e0fe0afc75b2add06897 Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Fri, 6 Mar 2026 15:02:35 -0800 Subject: [PATCH] Fix date inputs and dismiss date picker/sub-form popups - Start date fields now return mm/dd/yyyy format instead of "Immediately" - Cancel any open sub-forms or date pickers before filling (handles stacked popups with double-cancel check) Co-Authored-By: Claude Opus 4.6 --- lib/apply/easy_apply.mjs | 15 ++++++++++----- lib/form_filler.mjs | 10 ++++++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/apply/easy_apply.mjs b/lib/apply/easy_apply.mjs index 16b3b04..4473e93 100644 --- a/lib/apply/easy_apply.mjs +++ b/lib/apply/easy_apply.mjs @@ -189,14 +189,19 @@ export async function apply(page, job, formFiller) { const debugInfo = await getModalDebugInfo(page, MODAL); console.log(` [step ${step}] progress=${progress} heading="${debugInfo.heading}" buttons=${JSON.stringify(debugInfo.buttons)}${debugInfo.errors.length ? ' errors=' + JSON.stringify(debugInfo.errors) : ''}`); - // LinkedIn sometimes opens an "Add education/experience" sub-form with Save/Cancel buttons. - // These block the main Next button. Dismiss them before filling. - const saveBtn = await findModalButton(page, MODAL, { ariaLabels: [], exactTexts: ['Save'] }); + // LinkedIn sometimes opens sub-forms (education, experience, date pickers) with Cancel/Save. + // Dismiss them before filling to avoid filling sub-form fields. const cancelBtn = await findModalButton(page, MODAL, { ariaLabels: [], exactTexts: ['Cancel'] }); - if (saveBtn && cancelBtn) { - console.log(` [step ${step}] sub-form detected (Save/Cancel) — cancelling`); + if (cancelBtn) { + console.log(` [step ${step}] sub-form/picker detected — cancelling`); await cancelBtn.click({ timeout: APPLY_CLICK_TIMEOUT }).catch(() => {}); await page.waitForTimeout(CLICK_WAIT); + // Check if another Cancel is still open (e.g. date picker behind education form) + const cancelBtn2 = await findModalButton(page, MODAL, { ariaLabels: [], exactTexts: ['Cancel'] }); + if (cancelBtn2) { + await cancelBtn2.click({ timeout: APPLY_CLICK_TIMEOUT }).catch(() => {}); + await page.waitForTimeout(CLICK_WAIT); + } } // Fill form fields — page.$() in form_filler pierces shadow DOM diff --git a/lib/form_filler.mjs b/lib/form_filler.mjs index 9b33952..da5319d 100644 --- a/lib/form_filler.mjs +++ b/lib/form_filler.mjs @@ -198,8 +198,14 @@ export class FormFiller { if (l.includes('salary') || l.includes('compensation') || l.includes('expected pay')) return String(p.desired_salary || ''); if (l.includes('minimum') && l.includes('salary')) return String(Math.round((p.desired_salary || DEFAULT_DESIRED_SALARY) * MINIMUM_SALARY_FACTOR)); - // Dates - if (l.includes('start date') || l.includes('when can you start') || l.includes('available to start')) return 'Immediately'; + // Dates — some fields expect mm/dd/yyyy format, others accept text + if (l.includes('start date') || l.includes('when can you start') || l.includes('available to start') || l.includes('earliest date') || l.includes('date available')) { + const now = new Date(); + const mm = String(now.getMonth() + 1).padStart(2, '0'); + const dd = String(now.getDate()).padStart(2, '0'); + const yyyy = now.getFullYear(); + return `${mm}/${dd}/${yyyy}`; + } if (l.includes('notice period')) return '2 weeks'; // Education