Add captcha detection test coverage for webDetection - #2793
Conversation
Adds Jasmine unit tests and Playwright integration tests (plus fixture pages) for per-provider captcha detection via the existing webDetection framework. No source change — the detectors themselves are config in privacy-configuration; this proves the element + visibility matching and the auto-run -> fireEvent path behave correctly for captchas. Vendors covered: reCAPTCHA, hCaptcha, Cloudflare Turnstile (widget), the Cloudflare full-page interstitial, and a generic "other" fallback. Tests assert that a visible challenge matches, that hidden/invisible/absent ones do not, and crucially that there is no cross-vendor double counting. In particular the current Cloudflare interstitial embeds Turnstile via <div id="turnstile-wrapper" class="cf-turnstile">, so it must be attributed to the cloudflare detector only; the turnstile selector therefore excludes #turnstile-wrapper.
[Beta] Generated file diffTime updated: Tue, 23 Jun 2026 19:55:38 GMT |
|
This PR requires a manual review and approval from a member of one of the following teams:
|
The captcha fixture widened `visibility: 'visible'` to `string`, so passing `captcha.recaptcha`/`.hcaptcha`/`.turnstile` directly to matchInDOM failed tsc — the param expects the literal union "hidden" | "visible" | "any". Annotating the const as Record<string, MatchCondition> checks the literals against the schema type instead of widening them. Also reflow two over-long lines flagged by prettier.
Build Branch
Static preview entry points
QR codes (mobile preview)
Integration commandsnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", branch: "pr-releases/mark/captcha-detection-tests")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/mark/captcha-detection-tests
git -C submodules/content-scope-scripts checkout origin/pr-releases/mark/captcha-detection-testsPin to exact commitnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", revision: "2f46d2704f6c172924400846eacd446bfb557533")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/mark/captcha-detection-tests
git -C submodules/content-scope-scripts checkout 2f46d2704f6c172924400846eacd446bfb557533 |
There was a problem hiding this comment.
Stale comment
Injected PR Evaluation: Web Compatibility & Security
Reviewed diff
21aa1988…c53dc0a3— test-only changes: 6 HTML fixtures, unit tests inweb-detection.js, and integration tests inweb-detection.spec.js. No changes underinjected/src/(no production runtime, API shims, messaging, or security-sensitive paths).
Web Compatibility Assessment
File Severity Finding (all changed files) info No injected production code modified. Zero API surface, prototype, DOM-timing, or platform-runtime impact. injected/unit-test/web-detection.js(captcha vendor detectors)info Tests document intended read-only DOM matching: visibility: 'visible'gating, per-vendor selector isolation, and:not(#turnstile-wrapper)to prevent Cloudflare interstitial ↔ Turnstile double-counting. These are behavioral contracts, not runtime changes.injected/integration-test/web-detection.spec.js(CAPTCHA_DETECTORS)info Detector selectors/triggers are duplicated inline from privacy-configuration/features/web-detection.json. Drift between config and tests is a maintenance risk, not a shipped compat regression.injected/integration-test/test-pages/web-detection/pages/captcha-*.htmlinfo Static local fixtures with inline dimensions; no external script loads, viewport meta manipulation, or third-party embeds. Safe for test harness only. No warning or error-level web compatibility findings.
Security Assessment
File Severity Finding (all changed files) info No changes to captured-globals.js, message bridge,shouldExemptMethod(), wrapper utilities, or messaging transports.injected/integration-test/web-detection.spec.js(setupCaptchaTest)info Test harness injects captcha detector config and mocks webDetectionAutoRun/webEventresponses. Scoped to Playwright test pages; does not alter shipped feature gating.injected/integration-test/web-detection.spec.js(getWebEventNotifications)info Asserts outgoing webEventpayloads contain onlytype(and optionaldata). NonativeDataspread or new messaging surface introduced.Test HTML fixtures info No postMessage,eval, external fetches, or iframe sandbox changes.about:blank#recaptchain hidden fixture is inert.No warning, error, or critical security findings.
Risk Level
Low Risk — Adds unit and integration test coverage plus local HTML fixtures only; injected runtime, API overrides, and security boundaries are untouched.
Recommendations
- (info) Consider a shared test fixture module (or importing canonical detector snippets) so
CAPTCHA_DETECTORS, unit-testcaptchaobject, andprivacy-configurationselectors stay in sync — the comments already call this out.- (info) The visibility and cross-vendor isolation coverage is thorough and valuable; no additional compat/security blockers from this review.
Verification:
unit-test/web-detection.js— 135 specs, 0 failures.Sent by Cursor Automation: Web compat and sec
The lint chain's `prettier . --check` step flagged over-long detector lines in the new web-detection integration spec. The earlier tsc failure had stopped the chain before prettier ran, masking this. Reflow the affected lines.
There was a problem hiding this comment.
Stale comment
Injected PR Evaluation: Web Compatibility & Security
Reviewed diff
21aa198..985f38b(8 files, +336 lines). No changes underinjected/src/— this PR adds captcha-detection unit tests, Playwright integration tests, and static HTML fixtures only.
Web Compatibility Assessment
File Lines Severity Finding (entire diff) — info No injected runtime code, API overrides, DOM patches, or wrapper utilities are modified. There is no web-compatibility surface change for end users. injected/integration-test/web-detection.spec.js7–70 info CAPTCHA_DETECTORSduplicates selectors/triggers fromprivacy-configuration/features/web-detection.json(with WindowsconditionalChangesinlined). Selector drift vs shipped config is a test-maintenance risk, not a site-breakage risk.injected/unit-test/web-detection.js1197–1314 info Same selector duplication for matchInDOMfixtures. Good cross-vendor negative matrix and visibility gating coverage; keeps detection logic aligned with config intent.injected/integration-test/test-pages/web-detection/pages/captcha-*.htmlall info Static local fixtures with representative vendor markup (including Cloudflare interstitial #turnstile-wrapperexclusion). No viewport/meta manipulation or third-party script loading.No warnings or errors.
Security Assessment
File Lines Severity Finding (entire diff) — info No changes to captured-globals.js, message bridge, messaging transports,shouldExemptMethod(), orload()-time code. No new attack surface in production injection.injected/integration-test/web-detection.spec.js191–203 info setupCaptchaTestfollows existing harness patterns (ResultsCollector, mockedwebDetectionAutoRun/webEvent, fake timers). Config is constructed from local JSON; nonativeDataspread or origin-validation changes.Test HTML fixtures all info No external network requests, postMessage,eval, or user-data URL construction.data-sitekey="test"is inert fixture data.No warnings, errors, or critical findings.
Risk Level
Low Risk — test-only additions (Jasmine + Playwright + HTML fixtures) with zero injected production/runtime changes.
Recommendations
- (info) Add a comment or doc link in both test files pointing to the canonical
privacy-configuration/features/web-detection.jsoncaptcha group (and Windows conditional patch) so future selector edits stay synchronized.- (info) Optional gap: unit tests cover zero-size visibility for hCaptcha (
zeroSizeSelectors); integration tests coverdisplay:nonebut not zero-dimension widgets — consider a fixture if that path is important end-to-end.- (info) Integration config mirrors Windows
conditionalChangesonly; Apple/Android conditional patches for captcha are not exercised here (acceptable if intentional, but worth noting for platform parity).
Verification: Ran
jasmine --filter="captcha vendor"— 34 specs, 0 failures. No production bundle impact to evaluate.Sent by Cursor Automation: Web compat and sec
There was a problem hiding this comment.
Injected PR Evaluation: Web Compatibility & Security
Reviewed diff 21aa198..985f38b — 8 files, +336 lines. All changes are test fixtures and test code (unit + integration). No modifications to injected/src/, wrapper-utils.js, captured-globals.js, messaging transports, or platform entry points.
Verified locally: 34 captcha vendor unit specs pass; 7 captcha integration specs pass (Windows project).
Web Compatibility Assessment
| File | Lines | Severity | Finding |
|---|---|---|---|
| (entire diff) | — | info | No injected runtime code changes. Captcha detection behavior exercised here is config-driven (webDetection + remote privacy-configuration); this PR does not alter API shims, prototype patches, DOM mutations, or timing in production bundles. |
injected/integration-test/web-detection.spec.js |
13–70, 191–194 | info | CAPTCHA_DETECTORS duplicates selectors/triggers from privacy-configuration/features/web-detection.json (captcha group + Windows conditionalChanges). Drift between repos would cause tests to pass while production config diverges — a maintenance risk, not a site-breakage risk. |
injected/unit-test/web-detection.js |
1205–1248 | info | Same selector duplication in unit tests. Comments correctly document the sync requirement. |
injected/integration-test/test-pages/web-detection/pages/captcha-*.html |
all | info | Static local fixtures with hard-coded dimensions and no external script loads. They do not affect real-site compatibility. |
No findings at warning or error severity.
Security Assessment
| File | Lines | Severity | Finding |
|---|---|---|---|
| (entire diff) | — | info | Test harness only. setupCaptchaTest mutates in-memory config loaded via ResultsCollector; nothing ships to end users. |
captcha-recaptcha-hidden.html |
12 | info | iframe src="about:blank#recaptcha" is a local test stub — no network fetch, no postMessage surface. |
web-detection.spec.js |
209–219 | info | getWebEventNotifications() inspects mocked outgoing webEvent messages in the test collector. Does not change message-bridge trust boundaries or nativeData handling in production. |
No findings at warning, error, or critical severity.
Risk Level
Low Risk — Test-only additions (HTML fixtures, unit tests, integration tests) for existing captcha detection config; zero changes to injected runtime, API overrides, or security-sensitive infrastructure.
Recommendations
- (info) Consider extracting shared captcha detector definitions into a single test fixture imported by both
unit-test/web-detection.jsandintegration-test/web-detection.spec.jsto reduce triple-duplication withprivacy-configuration. - (info) When captcha selectors change in
privacy-configuration, require paired updates here (or a future cross-repo CI check) — comments already call this out; worth enforcing in the privacy-configuration PR checklist. - (info) Coverage is solid: per-vendor
fireEventtypes, Cloudflare-vs-Turnstile disambiguation (#turnstile-wrapperexclusion), visibility gating (display:none), zero-size, and negative controls. No additional compat/security tests required for this diff.
Verdict: Approve from a web-compatibility and security perspective.
Sent by Cursor Automation: Web compat and sec


What
Test coverage for per-provider captcha detection via the existing
webDetectionframework. The detectors themselves are config (see the paired privacy-configuration PR) — no source change here; this proves the element + visibility matching and the auto-run →fireEventpath behave correctly for captchas, and that providers don't cross-count.injected/unit-test/web-detection.js): per-vendor visible/hidden/absent matching for reCAPTCHA, hCaptcha, Cloudflare Turnstile, the Cloudflare interstitial, and a genericotherfallback, plus a full no-cross-counting matrix.injected/integration-test/web-detection.spec.js+ fixture pages): each vendor page fires exactly its owncaptcha_<vendor>webEvent and nothing else; clean and hidden pages fire nothing.Why the turnstile/cloudflare split matters
The current Cloudflare interstitial embeds Turnstile via
<div id="turnstile-wrapper" class="cf-turnstile">, so a naive.cf-turnstileselector would match both the standalone widget and the full-page gate. The tests pin the intended behaviour: the interstitial is attributed tocloudflareonly (the turnstile selector excludes#turnstile-wrapper), keeping the two surfaces separable.Validation
npm run test-unit(34 captcha specs green) andnpm run test-int(7 captcha integration tests green, headless Chromium).Part of the "visible captchas per million navigations" project; pairs with the privacy-configuration captcha PR.
Note
Low Risk
Changes are limited to tests and static fixture pages; no production webDetection or runtime behavior is modified in this diff.
Overview
Adds test-only coverage for per-provider captcha detection through the existing
webDetectionauto-run →fireEventpath. Production detector config lives in the paired privacy-configuration PR; this PR pins expected matching and event behavior.Unit tests extend
web-detection.jswith acaptcha vendor detectorssuite that mirrors config selectors: each of reCAPTCHA, hCaptcha, Turnstile, Cloudflare interstitial, and genericothermatches its fixture, fails cross-vendor double-counting, ignores clean pages, and gates on visible challenges (hidden/zero-size DOM does not match).Integration tests add six HTML fixture pages plus
CAPTCHA_DETECTORSandsetupCaptchaTestinweb-detection.spec.js. Each vendor page emits exactly onecaptcha_<vendor>webEvent; pages with no captcha ordisplay:nonereCAPTCHA emit none.The Turnstile vs Cloudflare split is explicitly tested: interstitial markup uses
#turnstile-wrapper.cf-turnstile, so Turnstile selectors exclude#turnstile-wrapperso the gate counts ascaptcha_cloudflareonly, notcaptcha_turnstile.Reviewed by Cursor Bugbot for commit 985f38b. Bugbot is set up for automated code reviews on this repo. Configure here.