Skip to content

Commit bdfe1e3

Browse files
authored
fix: job alert toggle selector broken due to visually hidden inputs (#577)
LinkedIn uses inputs with width=0 and height=0 inside .artdeco-toggle components. The original fix in #534 targeted the input but failed to consider Playwright's visibility requirements and the DOM's getBoundingClientRect(). - Modifies isVisible to check parent visibility for visually hidden inputs - Adds label.artdeco-toggle__text and .artdeco-toggle to fallback selector - Primary path returns the toggle container so Playwright can click it - readJobsToggleState updated to recursively check for an inner input if a wrapper was passed
1 parent 8bc4023 commit bdfe1e3

File tree

1 file changed

+74
-15
lines changed

1 file changed

+74
-15
lines changed

packages/core/src/linkedinJobs.ts

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,7 +1554,30 @@ async function extractJobAlerts(
15541554
const isVisible = (element: Element): boolean => {
15551555
const htmlElement = element as HTMLElement;
15561556
const style = globalThis.window.getComputedStyle(htmlElement);
1557-
const rect = htmlElement.getBoundingClientRect();
1557+
let rect = htmlElement.getBoundingClientRect();
1558+
1559+
if (
1560+
htmlElement.tagName === "INPUT" &&
1561+
(htmlElement.getAttribute("type") === "checkbox" ||
1562+
htmlElement.getAttribute("role") === "switch")
1563+
) {
1564+
const toggleContainer = htmlElement.closest(
1565+
".artdeco-toggle, [class*='create-alert'], [class*='job-alert']",
1566+
);
1567+
if (toggleContainer) {
1568+
const containerStyle = globalThis.window.getComputedStyle(toggleContainer);
1569+
rect = toggleContainer.getBoundingClientRect();
1570+
if (
1571+
containerStyle.visibility !== "hidden" &&
1572+
containerStyle.display !== "none" &&
1573+
rect.width > 0 &&
1574+
rect.height > 0
1575+
) {
1576+
return true;
1577+
}
1578+
}
1579+
}
1580+
15581581
return (
15591582
style.visibility !== "hidden" &&
15601583
style.display !== "none" &&
@@ -1727,7 +1750,30 @@ async function markJobsButton(
17271750
const isVisible = (element: Element): boolean => {
17281751
const htmlElement = element as HTMLElement;
17291752
const style = globalThis.window.getComputedStyle(htmlElement);
1730-
const rect = htmlElement.getBoundingClientRect();
1753+
let rect = htmlElement.getBoundingClientRect();
1754+
1755+
if (
1756+
htmlElement.tagName === "INPUT" &&
1757+
(htmlElement.getAttribute("type") === "checkbox" ||
1758+
htmlElement.getAttribute("role") === "switch")
1759+
) {
1760+
const toggleContainer = htmlElement.closest(
1761+
".artdeco-toggle, [class*='create-alert'], [class*='job-alert']",
1762+
);
1763+
if (toggleContainer) {
1764+
const containerStyle = globalThis.window.getComputedStyle(toggleContainer);
1765+
rect = toggleContainer.getBoundingClientRect();
1766+
if (
1767+
containerStyle.visibility !== "hidden" &&
1768+
containerStyle.display !== "none" &&
1769+
rect.width > 0 &&
1770+
rect.height > 0
1771+
) {
1772+
return true;
1773+
}
1774+
}
1775+
}
1776+
17311777
return (
17321778
style.visibility !== "hidden" &&
17331779
style.display !== "none" &&
@@ -1757,19 +1803,22 @@ async function markJobsButton(
17571803
"input[role='switch'].artdeco-toggle__button",
17581804
);
17591805

1760-
if (artdecoToggle && isVisible(artdecoToggle)) {
1761-
artdecoToggle.setAttribute(
1762-
buttonAttributeName,
1763-
buttonMarkerValue,
1764-
);
1765-
return true;
1806+
if (artdecoToggle) {
1807+
const target = artdecoToggle.closest(".artdeco-toggle") ?? artdecoToggle;
1808+
if (isVisible(target)) {
1809+
target.setAttribute(
1810+
buttonAttributeName,
1811+
buttonMarkerValue,
1812+
);
1813+
return true;
1814+
}
17661815
}
17671816
}
17681817

17691818
const buttons = Array.from(
17701819
container.querySelectorAll(
17711820
buttonKind === "alert-toggle"
1772-
? "button, a[role='button'], div[role='button'], input[role='switch'], [role='switch'], [data-artdeco-toggle-button]"
1821+
? "button, a[role='button'], div[role='button'], input[role='switch'], [role='switch'], [data-artdeco-toggle-button], label.artdeco-toggle__text, label[for], .artdeco-toggle"
17731822
: "button, a[role='button']",
17741823
),
17751824
).filter((element) => isVisible(element));
@@ -1921,22 +1970,32 @@ async function readJobsToggleState(
19211970
const ariaPressed = normalize(htmlElement.getAttribute("aria-pressed"));
19221971
const ariaChecked = normalize(htmlElement.getAttribute("aria-checked"));
19231972

1973+
const inputChild = htmlElement.querySelector(
1974+
"input[type='checkbox'], input[role='switch']",
1975+
) as HTMLInputElement | null;
1976+
19241977
// For input/switch elements (Artdeco toggle), the checked property
19251978
// and aria-checked attribute are the most reliable state indicators.
19261979
const isSwitch =
19271980
htmlElement.tagName === "INPUT" ||
1928-
htmlElement.getAttribute("role") === "switch";
1981+
htmlElement.getAttribute("role") === "switch" ||
1982+
inputChild !== null;
1983+
1984+
const switchElement = inputChild ?? (htmlElement as HTMLInputElement);
19291985

19301986
if (isSwitch) {
1987+
const switchAriaChecked = normalize(
1988+
switchElement.getAttribute("aria-checked"),
1989+
);
19311990
if (
1932-
ariaChecked === "true" ||
1933-
(htmlElement as unknown as HTMLInputElement).checked === true
1991+
switchAriaChecked === "true" ||
1992+
switchElement.checked === true
19341993
) {
19351994
return true;
19361995
}
19371996
if (
1938-
ariaChecked === "false" ||
1939-
(htmlElement as unknown as HTMLInputElement).checked === false
1997+
switchAriaChecked === "false" ||
1998+
switchElement.checked === false
19401999
) {
19412000
return false;
19422001
}
@@ -1952,7 +2011,7 @@ async function readJobsToggleState(
19522011
// For input/switch elements, gather text from parent toggle container
19532012
// since inputs have no meaningful textContent.
19542013
if (isSwitch && !text.trim()) {
1955-
const toggleContainer = htmlElement.closest(
2014+
const toggleContainer = switchElement.closest(
19562015
".artdeco-toggle, [class*='create-alert'], [class*='job-alert']",
19572016
);
19582017
if (toggleContainer) {

0 commit comments

Comments
 (0)