fix: cover letter silent drop, submit verification, autocomplete scoping
- Text inputs matched to cover letter now report as unknown if required, instead of silently leaving the field empty - Submit click now verifies modal closed before reporting success; returns 'incomplete' with actionable log if modal stays open - selectAutocomplete scoped to container (modal) to avoid clicking wrong dropdowns from the underlying page Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -207,7 +207,20 @@ export async function apply(page, job, formFiller) {
|
||||
console.log(` [step ${step}] clicking Submit`);
|
||||
await submitBtn.click({ timeout: APPLY_CLICK_TIMEOUT }).catch(() => {});
|
||||
await page.waitForTimeout(SUBMIT_WAIT);
|
||||
return { status: 'submitted', meta };
|
||||
|
||||
// Verify modal closed or success message appeared
|
||||
const modalGone = !(await page.$(MODAL));
|
||||
const successVisible = await page.$('[class*="success"], [class*="confirmation"], [aria-label*="applied"]').catch(() => null);
|
||||
if (modalGone || successVisible) {
|
||||
console.log(` ✅ Submit confirmed — modal closed`);
|
||||
return { status: 'submitted', meta };
|
||||
}
|
||||
|
||||
// Modal still open — submit may have failed
|
||||
console.log(` [step ${step}] ⚠️ Modal still open after Submit click`);
|
||||
console.log(` Action: submit may have failed due to validation or network error`);
|
||||
await dismissModal(page, MODAL);
|
||||
return { status: 'incomplete', meta };
|
||||
}
|
||||
|
||||
// Stuck detection — progress hasn't changed and we've been through a few steps
|
||||
|
||||
@@ -148,12 +148,17 @@ export class FormFiller {
|
||||
* Waits for the dropdown to appear, then clicks the first option.
|
||||
* Scoped to the input's nearest container to avoid clicking wrong dropdowns.
|
||||
*/
|
||||
async selectAutocomplete(page, inp) {
|
||||
// Wait for dropdown to appear near the input
|
||||
const option = await page.waitForSelector(
|
||||
'[role="option"], [role="listbox"] li, ul[class*="autocomplete"] li',
|
||||
{ timeout: AUTOCOMPLETE_TIMEOUT, state: 'visible' }
|
||||
).catch(() => null);
|
||||
async selectAutocomplete(page, container) {
|
||||
// Wait for dropdown to appear — scope to container (modal) to avoid clicking wrong dropdowns
|
||||
const selectors = '[role="option"], [role="listbox"] li, ul[class*="autocomplete"] li';
|
||||
const option = await container.waitForSelector(selectors, {
|
||||
timeout: AUTOCOMPLETE_TIMEOUT, state: 'visible',
|
||||
}).catch(() => {
|
||||
// Fallback to page-level if container doesn't support waitForSelector (e.g. ElementHandle)
|
||||
return page.waitForSelector(selectors, {
|
||||
timeout: AUTOCOMPLETE_TIMEOUT, state: 'visible',
|
||||
}).catch(() => null);
|
||||
});
|
||||
if (option) {
|
||||
await option.click().catch(() => {});
|
||||
await page.waitForTimeout(AUTOCOMPLETE_WAIT);
|
||||
@@ -198,9 +203,10 @@ export class FormFiller {
|
||||
// Handle city/location autocomplete dropdowns
|
||||
const ll = lbl.toLowerCase();
|
||||
if (ll.includes('city') || ll.includes('location') || ll.includes('located')) {
|
||||
await this.selectAutocomplete(page, inp);
|
||||
await this.selectAutocomplete(page, container);
|
||||
}
|
||||
} else if (!answer) {
|
||||
} else {
|
||||
// No answer, or answer is cover letter (too long for a text input) — check if required
|
||||
if (await this.isRequired(inp)) unknown.push(lbl);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user