Fix Ashby Yes/No button detection using field-entry containers
Use .ashby-application-form-field-entry class to find question containers, then Playwright locators for reliable button clicking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,26 +28,24 @@ export async function apply(page, job, formFiller) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ashby uses button-style Yes/No for questions (not radios/fieldsets).
|
// 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 buttonQuestions = await page.evaluate(() => {
|
||||||
|
const entries = document.querySelectorAll('.ashby-application-form-field-entry');
|
||||||
const questions = [];
|
const questions = [];
|
||||||
// Find containers with question text + Yes/No buttons
|
for (const entry of entries) {
|
||||||
const allBtns = Array.from(document.querySelectorAll('button[type="submit"]'));
|
const btns = entry.querySelectorAll('button');
|
||||||
const yesNoBtns = allBtns.filter(b => b.innerText.trim() === 'Yes' || b.innerText.trim() === 'No');
|
const btnTexts = Array.from(btns).map(b => b.innerText.trim());
|
||||||
const seen = new Set();
|
if (btnTexts.includes('Yes') && btnTexts.includes('No')) {
|
||||||
for (const btn of yesNoBtns) {
|
const label = entry.innerText.replace(/Yes/g, '').replace(/No/g, '').trim();
|
||||||
const container = btn.parentElement?.parentElement;
|
questions.push(label);
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
return questions;
|
return questions;
|
||||||
});
|
});
|
||||||
|
|
||||||
const p = formFiller.profile;
|
const p = formFiller.profile;
|
||||||
for (const q of buttonQuestions) {
|
for (const label of buttonQuestions) {
|
||||||
const ll = q.label.toLowerCase();
|
const ll = label.toLowerCase();
|
||||||
let answer = null;
|
let answer = null;
|
||||||
if (ll.includes('authorized') || ll.includes('legally') || ll.includes('eligible') || ll.includes('right to work')) {
|
if (ll.includes('authorized') || ll.includes('legally') || ll.includes('eligible') || ll.includes('right to work')) {
|
||||||
answer = p.work_authorization?.authorized ? 'Yes' : 'No';
|
answer = p.work_authorization?.authorized ? 'Yes' : 'No';
|
||||||
@@ -57,22 +55,13 @@ export async function apply(page, job, formFiller) {
|
|||||||
answer = 'Yes';
|
answer = 'Yes';
|
||||||
}
|
}
|
||||||
if (answer) {
|
if (answer) {
|
||||||
// Click the matching button - find by text within the question's container
|
// Use Playwright locator for reliable clicking
|
||||||
const clicked = await page.evaluate((label, answer) => {
|
const entry = page.locator('.ashby-application-form-field-entry', { hasText: label.substring(0, 40) });
|
||||||
const allBtns = Array.from(document.querySelectorAll('button[type="submit"]'));
|
const btn = entry.locator(`button:has-text("${answer}")`).first();
|
||||||
const containers = new Set();
|
if (await btn.count() > 0) {
|
||||||
for (const btn of allBtns) {
|
await btn.click().catch(() => {});
|
||||||
const c = btn.parentElement?.parentElement;
|
await page.waitForTimeout(300);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user