Skip to content

Add captcha detection test coverage for webDetection - #2793

Merged
mark-szabo merged 3 commits into
mainfrom
mark/captcha-detection-tests
Jun 26, 2026
Merged

Add captcha detection test coverage for webDetection#2793
mark-szabo merged 3 commits into
mainfrom
mark/captcha-detection-tests

Conversation

@mark-szabo

@mark-szabo mark-szabo commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

What

Test coverage for per-provider captcha detection via the existing webDetection framework. 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 → fireEvent path behave correctly for captchas, and that providers don't cross-count.

  • Unit tests (injected/unit-test/web-detection.js): per-vendor visible/hidden/absent matching for reCAPTCHA, hCaptcha, Cloudflare Turnstile, the Cloudflare interstitial, and a generic other fallback, plus a full no-cross-counting matrix.
  • Integration tests (injected/integration-test/web-detection.spec.js + fixture pages): each vendor page fires exactly its own captcha_<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-turnstile selector would match both the standalone widget and the full-page gate. The tests pin the intended behaviour: the interstitial is attributed to cloudflare only (the turnstile selector excludes #turnstile-wrapper), keeping the two surfaces separable.

Validation

npm run test-unit (34 captcha specs green) and npm 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 webDetection auto-run → fireEvent path. Production detector config lives in the paired privacy-configuration PR; this PR pins expected matching and event behavior.

Unit tests extend web-detection.js with a captcha vendor detectors suite that mirrors config selectors: each of reCAPTCHA, hCaptcha, Turnstile, Cloudflare interstitial, and generic other matches 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_DETECTORS and setupCaptchaTest in web-detection.spec.js. Each vendor page emits exactly one captcha_<vendor> webEvent; pages with no captcha or display:none reCAPTCHA emit none.

The Turnstile vs Cloudflare split is explicitly tested: interstitial markup uses #turnstile-wrapper.cf-turnstile, so Turnstile selectors exclude #turnstile-wrapper so the gate counts as captcha_cloudflare only, not captcha_turnstile.

Reviewed by Cursor Bugbot for commit 985f38b. Bugbot is set up for automated code reviews on this repo. Configure here.

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.
@github-actions github-actions Bot added the semver-patch Bug fix / internal — no release needed label Jun 23, 2026
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

[Beta] Generated file diff

Time updated: Tue, 23 Jun 2026 19:55:38 GMT

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Cursor review was not successful.

This PR requires a manual review and approval from a member of one of the following teams:

  • @duckduckgo/content-scope-scripts-owners
  • @duckduckgo/apple-devs
  • @duckduckgo/android-devs
  • @duckduckgo/team-windows-development
  • @duckduckgo/extension-owners
  • @duckduckgo/config-aor
  • @duckduckgo/breakage-aor
  • @duckduckgo/breakage

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.
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Build Branch

Branch pr-releases/mark/captcha-detection-tests
Commit 2f46d2704f
Updated June 23, 2026 at 7:38:16 PM UTC

Static preview entry points

QR codes (mobile preview)
Entry point QR code
Docs QR for docs preview
Static pages QR for static pages preview
Integration pages QR for integration pages preview

Integration commands

npm (Android / Extension):

npm i github:duckduckgo/content-scope-scripts#pr-releases/mark/captcha-detection-tests

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-tests
Pin to exact commit

npm (Android / Extension):

npm i github:duckduckgo/content-scope-scripts#2f46d2704f6c172924400846eacd446bfb557533

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

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Injected PR Evaluation: Web Compatibility & Security

Reviewed diff 21aa1988…c53dc0a3test-only changes: 6 HTML fixtures, unit tests in web-detection.js, and integration tests in web-detection.spec.js. No changes under injected/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-*.html info 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 / webEvent responses. Scoped to Playwright test pages; does not alter shipped feature gating.
injected/integration-test/web-detection.spec.js (getWebEventNotifications) info Asserts outgoing webEvent payloads contain only type (and optional data). No nativeData spread or new messaging surface introduced.
Test HTML fixtures info No postMessage, eval, external fetches, or iframe sandbox changes. about:blank#recaptcha in 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

  1. (info) Consider a shared test fixture module (or importing canonical detector snippets) so CAPTCHA_DETECTORS, unit-test captcha object, and privacy-configuration selectors stay in sync — the comments already call this out.
  2. (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.

Open in Web View Automation 

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.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Injected PR Evaluation: Web Compatibility & Security

Reviewed diff 21aa198..985f38b (8 files, +336 lines). No changes under injected/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.js 7–70 info CAPTCHA_DETECTORS duplicates selectors/triggers from privacy-configuration/features/web-detection.json (with Windows conditionalChanges inlined). Selector drift vs shipped config is a test-maintenance risk, not a site-breakage risk.
injected/unit-test/web-detection.js 1197–1314 info Same selector duplication for matchInDOM fixtures. 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-*.html all info Static local fixtures with representative vendor markup (including Cloudflare interstitial #turnstile-wrapper exclusion). 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(), or load()-time code. No new attack surface in production injection.
injected/integration-test/web-detection.spec.js 191–203 info setupCaptchaTest follows existing harness patterns (ResultsCollector, mocked webDetectionAutoRun/webEvent, fake timers). Config is constructed from local JSON; no nativeData spread 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

  1. (info) Add a comment or doc link in both test files pointing to the canonical privacy-configuration/features/web-detection.json captcha group (and Windows conditional patch) so future selector edits stay synchronized.
  2. (info) Optional gap: unit tests cover zero-size visibility for hCaptcha (zeroSizeSelectors); integration tests cover display:none but not zero-dimension widgets — consider a fixture if that path is important end-to-end.
  3. (info) Integration config mirrors Windows conditionalChanges only; 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.

Open in Web View Automation 

Sent by Cursor Automation: Web compat and sec

@mark-szabo
mark-szabo marked this pull request as ready for review June 23, 2026 19:54
@mark-szabo
mark-szabo requested a review from GuiltyDolphin June 23, 2026 19:54

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  1. (info) Consider extracting shared captcha detector definitions into a single test fixture imported by both unit-test/web-detection.js and integration-test/web-detection.spec.js to reduce triple-duplication with privacy-configuration.
  2. (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.
  3. (info) Coverage is solid: per-vendor fireEvent types, Cloudflare-vs-Turnstile disambiguation (#turnstile-wrapper exclusion), 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.

Open in Web View Automation 

Sent by Cursor Automation: Web compat and sec

@mark-szabo
mark-szabo enabled auto-merge June 26, 2026 08:43
@mark-szabo
mark-szabo added this pull request to the merge queue Jun 26, 2026
Merged via the queue into main with commit 81adc91 Jun 26, 2026
50 of 51 checks passed
@mark-szabo
mark-szabo deleted the mark/captcha-detection-tests branch June 26, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

semver-patch Bug fix / internal — no release needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants