diff --git a/lib/apply/ashby.mjs b/lib/apply/ashby.mjs index d50226c..a24b7b3 100644 --- a/lib/apply/ashby.mjs +++ b/lib/apply/ashby.mjs @@ -28,26 +28,24 @@ export async function apply(page, job, formFiller) { } // Ashby uses button-style Yes/No for questions (not radios/fieldsets). - // Find question labels and click the appropriate button. + // Find .ashby-application-form-field-entry containers with Yes/No buttons. const buttonQuestions = await page.evaluate(() => { + const entries = document.querySelectorAll('.ashby-application-form-field-entry'); const questions = []; - // Find containers with question text + Yes/No buttons - const allBtns = Array.from(document.querySelectorAll('button[type="submit"]')); - const yesNoBtns = allBtns.filter(b => b.innerText.trim() === 'Yes' || b.innerText.trim() === 'No'); - const seen = new Set(); - for (const btn of yesNoBtns) { - const container = btn.parentElement?.parentElement; - if (!container || seen.has(container)) continue; - seen.add(container); - const label = container.innerText.replace(/Yes\s*No/g, '').trim(); - if (label) questions.push({ label, containerIdx: questions.length }); + for (const entry of entries) { + const btns = entry.querySelectorAll('button'); + const btnTexts = Array.from(btns).map(b => b.innerText.trim()); + if (btnTexts.includes('Yes') && btnTexts.includes('No')) { + const label = entry.innerText.replace(/Yes/g, '').replace(/No/g, '').trim(); + questions.push(label); + } } return questions; }); const p = formFiller.profile; - for (const q of buttonQuestions) { - const ll = q.label.toLowerCase(); + for (const label of buttonQuestions) { + const ll = label.toLowerCase(); let answer = null; if (ll.includes('authorized') || ll.includes('legally') || ll.includes('eligible') || ll.includes('right to work')) { answer = p.work_authorization?.authorized ? 'Yes' : 'No'; @@ -57,22 +55,13 @@ export async function apply(page, job, formFiller) { answer = 'Yes'; } if (answer) { - // Click the matching button - find by text within the question's container - const clicked = await page.evaluate((label, answer) => { - const allBtns = Array.from(document.querySelectorAll('button[type="submit"]')); - const containers = new Set(); - for (const btn of allBtns) { - const c = btn.parentElement?.parentElement; - if (!c) continue; - const cText = c.innerText.replace(/Yes\s*No/g, '').trim(); - if (cText === label) { - const target = Array.from(c.querySelectorAll('button')).find(b => b.innerText.trim() === answer); - if (target) { target.click(); return true; } - } - } - return false; - }, q.label, answer); - if (clicked) await page.waitForTimeout(300); + // Use Playwright locator for reliable clicking + const entry = page.locator('.ashby-application-form-field-entry', { hasText: label.substring(0, 40) }); + const btn = entry.locator(`button:has-text("${answer}")`).first(); + if (await btn.count() > 0) { + await btn.click().catch(() => {}); + await page.waitForTimeout(300); + } } } },