fix: use evaluateHandle to find Continue link in frames

page.$() and frame.$() can't find the <a> in LinkedIn's shadow DOM,
but frame.evaluateHandle with document.querySelectorAll can.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 11:00:46 -08:00
parent 1e67c930db
commit 5aed8eb404

View File

@@ -115,22 +115,25 @@ export async function apply(page, job, formFiller) {
let eaBtn = await page.waitForSelector(LINKEDIN_APPLY_BUTTON_SELECTOR, { timeout: 12000, state: 'attached' }).catch(() => null);
// Fallback: LinkedIn shows plain "Continue" when a draft exists (span > span > a)
// The <a> has href containing /apply/ — click it to resume the draft
// The <a> has href containing /apply/ — find it via evaluateHandle in each frame
// (page.$() may not pierce LinkedIn's specific shadow DOM setup)
if (!eaBtn) {
// page.$() pierces shadow DOM; also check via evaluate in each frame
let applyLink = await page.$(`a[href*="/apply/"]`);
if (!applyLink) {
// Search frames directly (shadow DOM may block page.$)
for (const frame of page.frames()) {
applyLink = await frame.$(`a[href*="/apply/"]`).catch(() => null);
if (applyLink) break;
}
}
if (applyLink) {
const text = await applyLink.evaluate(el => (el.innerText || '').trim()).catch(() => '');
if (/continue/i.test(text)) {
eaBtn = applyLink;
console.log(` Found "Continue" link (draft application)`);
for (const frame of page.frames()) {
const handle = await frame.evaluateHandle(() => {
const links = document.querySelectorAll('a[href*="/apply/"]');
for (const a of links) {
if (/continue/i.test((a.innerText || '').trim())) return a;
}
return null;
}).catch(() => null);
if (handle) {
const el = handle.asElement();
if (el) {
eaBtn = el;
console.log(` Found "Continue" link (draft application)`);
break;
}
await handle.dispose().catch(() => {});
}
}
}