@@ -4798,6 +4798,52 @@ test('CAPTCHA preflight ignores hidden dialogs while ambiguous all-tree reads fa
47984798 );
47994799 });
48004800 }
4801+ const visibilityOverrideNodes = [
4802+ captchaEl('div', { 'data-test-visibility': 'hidden' }, [
4803+ captchaEl('div', {
4804+ role: 'dialog',
4805+ innerText: 'Security verification',
4806+ 'data-test-visibility': 'visible',
4807+ }, [
4808+ captchaEl('div', {
4809+ class: 'g-recaptcha',
4810+ 'data-sitekey': 'VISIBILITY_OVERRIDE_KEY',
4811+ 'data-test-visibility': 'visible',
4812+ }),
4813+ captchaEl('iframe', {
4814+ src: 'https://www.google.com/recaptcha/api2/anchor?k=VISIBILITY_OVERRIDE_KEY',
4815+ 'data-test-visibility': 'visible',
4816+ }),
4817+ ]),
4818+ ]),
4819+ ];
4820+ await withCaptchaFakePage(build, visibilityOverrideNodes, async () => {
4821+ assert.equal(
4822+ gate.detectChallengeDialogInPage()?.label,
4823+ 'Security verification',
4824+ `${build}: visible descendant under visibility-hidden ancestor was suppressed`,
4825+ );
4826+ const runtime = await import(pathToFileURL(
4827+ path.join(ROOT, `src/${build}/src/agent/captcha-frame-runtime.js`),
4828+ ).href);
4829+ const detected = runtime.detectCaptchaCandidatesInPage({
4830+ window: {
4831+ location: globalThis.location,
4832+ innerWidth: globalThis.innerWidth,
4833+ innerHeight: globalThis.innerHeight,
4834+ getComputedStyle: globalThis.getComputedStyle,
4835+ },
4836+ document: globalThis.document,
4837+ });
4838+ const candidate = detected.candidates.find(
4839+ entry => entry.websiteKey === 'VISIBILITY_OVERRIDE_KEY',
4840+ );
4841+ assert.equal(
4842+ candidate?.visible,
4843+ true,
4844+ `${build}: visible CAPTCHA widget under visibility-hidden ancestor was demoted`,
4845+ );
4846+ });
48014847 await withCaptchaFakePage(build, [
48024848 captchaEl('div', { role: 'dialog', innerText: 'Verify you are a human' }),
48034849 ], async () => {
@@ -52681,7 +52727,7 @@ async function withCaptchaFakePage(build, nodes, callback) {
5268152727 globalThis.innerHeight = 720;
5268252728 globalThis.getComputedStyle = (element) => ({
5268352729 display: element.hidden ? 'none' : 'block',
52684- visibility: 'visible',
52730+ visibility: element.getAttribute?.('data-test-visibility') || 'visible',
5268552731 opacity: '1',
5268652732 });
5268752733 // The detector reaches for the extension API by name; give each build the
0 commit comments