Files
claw-apply/lib/apply/ashby.mjs
Matthew Jackson 0118254046 Poll for submission success instead of single check
After clicking submit, poll up to 4 times (2.5s + 3x2s = ~8.5s total)
for success text or form disappearance. Handles invisible reCAPTCHA
verification delay. Stops early on validation errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:11:50 -08:00

32 lines
1.3 KiB
JavaScript

/**
* ashby.mjs — Ashby ATS handler (extends generic)
*/
import { apply as genericApply } from './generic.mjs';
export const SUPPORTED_TYPES = ['ashby'];
export async function apply(page, job, formFiller) {
return genericApply(page, job, formFiller, {
transformUrl: (url) => url.includes('/application') ? url : url.replace(/\/?(\?|$)/, '/application$1'),
closedTexts: ['job not found', 'the job you requested was not found'],
formDetector: '#_systemfield_name',
applyButtonSelector: 'button:has-text("Apply for this Job"), a:has-text("Apply for this Job")',
submitSelector: 'button:has-text("Submit Application")',
verifySelector: '#_systemfield_name',
beforeSubmit: async (page, formFiller) => {
if (!formFiller.profile.resume_path) return;
// Ashby wraps resume upload in a custom component — find the actual file input
const fileInput = await page.$('#_systemfield_resume input[type="file"]') ||
await page.$('input[type="file"][name*="resume"]') ||
await page.$('input[type="file"]');
if (fileInput) {
const hasFile = await fileInput.evaluate(el => !!el.value);
if (!hasFile) {
await fileInput.setInputFiles(formFiller.profile.resume_path).catch(() => {});
await page.waitForTimeout(1500);
}
}
},
});
}