Skip to content

Commit 02e4edf

Browse files
mcherifclaude
andcommitted
Fix Greenhouse employment history and school combobox form filling
Employment history: - Fill ALL work_history entries including [0], overwriting the pre-rendered block that fill_form incorrectly populated with current_company - Exclude inputs inside [role="combobox"] from label matching to prevent react-select inner search inputs from being misidentified as year fields - Re-evaluate year field indices after month dropdown interactions (DOM shifts during open/close invalidated pre-computed indices) - Add "Current role" checkbox support for entries with to="present" - Extract _fill_one_entry and _check_current_role helpers to reduce duplication School combobox: - Add 0.4s wait before activeElement check so the dropdown has time to focus its inner search input - Preserve outer combobox aria-controls when inner input has none, preventing unscoped option search that selected "0 - Not Applicable" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e396d05 commit 02e4edf

2 files changed

Lines changed: 329 additions & 197 deletions

File tree

utils/form_filler.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,26 +1950,34 @@ def _query_opts(listbox_id: str) -> str:
19501950
is_input = field.get("tag", "input") == "input"
19511951
if not opts and is_input:
19521952
await el.fill(value)
1953-
await asyncio.sleep(0.5)
1953+
await asyncio.sleep(1.0)
19541954
aria_controls = await el.get_attribute("aria-controls") or ""
19551955
opts = await page.evaluate(_query_opts(aria_controls), aria_controls)
19561956

19571957
# Some comboboxes are div/button wrappers (is_input=False) that reveal an
19581958
# inner <input> search field when opened (e.g. Greenhouse school selector).
1959-
# After clicking, focus moves to that inner input — use document.activeElement
1960-
# rather than a broad visible-input scan to avoid typing into unrelated fields.
1961-
if not opts and not is_input:
1959+
# Always type the search value into the inner input — the initial unfiltered
1960+
# option list (if any appeared) may not contain the target; typing triggers
1961+
# server-side filtering. Use document.activeElement for a stable reference.
1962+
if not is_input:
1963+
await asyncio.sleep(0.4) # wait for dropdown to fully open and focus inner input
19621964
try:
19631965
active = await page.evaluate(
19641966
"() => { const a = document.activeElement; "
1965-
"return a ? {tag: a.tagName.toLowerCase(), itype: (a.type||'').toLowerCase()} : {}; }"
1967+
"return a ? {tag: a.tagName.toLowerCase(), "
1968+
"itype: (a.type||'').toLowerCase(), id: a.id || ''} : {}; }"
19661969
)
19671970
if active.get("tag") == "input" and active.get("itype", "text") in ("text", "search", ""):
1968-
el = page.locator(":focus")
1971+
# Prefer a stable ID-based locator so repeated fills in the
1972+
# fallback loop don't drift to a different focused element.
1973+
inner_id = active.get("id", "")
1974+
el = page.locator(f"[id='{inner_id}']").first if inner_id else page.locator(":focus")
19691975
is_input = True
19701976
await el.fill(value)
1971-
await asyncio.sleep(0.5)
1972-
aria_controls = await el.get_attribute("aria-controls") or ""
1977+
await asyncio.sleep(2.0) # school lookups are server-side and slow
1978+
# The inner input may not carry aria-controls; preserve the outer's value.
1979+
inner_aria = await el.get_attribute("aria-controls") or ""
1980+
aria_controls = inner_aria or aria_controls
19731981
opts = await page.evaluate(_query_opts(aria_controls), aria_controls)
19741982
except Exception:
19751983
pass
@@ -2001,7 +2009,7 @@ def _query_opts(listbox_id: str) -> str:
20012009
continue
20022010
seen.add(term)
20032011
await el.fill(term)
2004-
await asyncio.sleep(0.5)
2012+
await asyncio.sleep(1.2) # school/location lookups can be slow
20052013
aria_controls = await el.get_attribute("aria-controls") or ""
20062014
opts = await page.evaluate(_query_opts(aria_controls), aria_controls)
20072015
if opts:

0 commit comments

Comments
 (0)