chore: selector audit, feed-filter test suite, release v1.17.0 #50

Merged
365DevNet merged 0 commits from refs/pull/50/head into main 2026-08-03 21:39:23 +02:00
365DevNet commented 2026-08-03 21:36:39 +02:00 (Migrated from codeberg.org)

Summary

Follow-up to #49, closing the two gaps that review surfaced: nothing detects a dead selector, and the DOM-facing code had no test coverage. Also cuts v1.17.0 and refreshes the site's manual-install download.

Selector audit

Run on any YouTube page:

__CW_AUDIT_SELECTORS__()

Prints a table of the selectors the extension depends on with a live match count, and warns on any that found nothing where they should. It cannot prove a selector is correct, only that it is still alive — but a renamed class currently produces no error whatsoever, which is precisely how the members-badge filter stayed broken through a release. Invalid selectors (e.g. :has() unsupported) are reported separately from dead ones, and entries that legitimately match nothing on a clean feed (promo shelves, ad slots) are marked optional so they never cry wolf.

The registry lives in defaults.js next to the selectors it audits, so adding a selector and forgetting to audit it is visible in one place.

Tests: 24 → 60

File Covers Needs jsdom
test/feed-text.test.js Age parsing EN/NL/DE/FR, view-count false-positives, badge-token mutual exclusivity, cut-off boundaries no
test/feed-dom.test.js Badge extraction, feed reachability, membership shelf rule, audit registry validity yes
test/shared-globals.test.js Every globalThis.FY_* a script depends on is actually exported no

Two of these earn their keep immediately:

  • the legacy-only badge selectors match nothing (why the filter died) pins the original regression against live markup, so it cannot silently return.
  • shared-globals catches renames in the FY_* contract. Those resolve at runtime with no import to typo-check them, so a mistake otherwise shows up as a TypeError in a user's browser. It caught a real mistake while I was writing it — FY_I18N comes from i18n.js, not defaults.js.

The DOM fixture is built from the live "Get more from memberships" markup. Writing it also exposed that my first draft had no video titles, which the audit test flagged — an unrepresentative fixture is worse than none.

Shared DOM surface (the refactor)

My scratch harnesses sliced source text out of content.js, and that broke once mid-session when I reformatted an array. Committing that brittleness would have made the tests a liability. So the selectors, badge tokens and relative-date parser moved into a documented "YouTube DOM surface" section in defaults.js — the repo's existing home for shared testable helpers (FY_MATCHES_COMMENT_FILTERS, FY_NORMALIZE_MEMBERS_FIRST_CHANNELS).

The filters, the tests and the audit now read the same values rather than three copies that drift apart. content.js keeps hoisted delegating wrappers, so no call sites changed and there is no TDZ risk; defaults.js already loads before content.js in all three content-script contexts per the manifest.

Notes for review

  • jsdom is the first devDependency, used only by feed-dom.test.js. The higher-value assertions are pure and need no browser environment.
  • node_modules/ was not in .gitignore — added before it could be committed. package-lock.json is now tracked for reproducible dev installs; say the word if you'd rather it weren't.
  • Version bumped to 1.17.0. Without it the rebuilt zip would ship as 1.16.0 while containing features 1.16.0 does not have — same version string, different contents. Minor bump matches the repo's convention (1.15.0 → 1.16.0 for SponsorBlock).
  • The audit function itself has not been run in a real browser — its registry is validated by tests, but the console output path needs one manual run.

Test plan

  • npm test — 60/60
  • node --check on all touched scripts
  • Zip verified: v1.17.0 manifest, 30 files, byte-identical to the store package, no test/, node_modules/, website/ or .DS_Store leakage
  • Load the unpacked extension and confirm the filters still behave after the defaults.js move
  • Run __CW_AUDIT_SELECTORS__() on a live home page and a watch page
  • Still outstanding from #49: spot-check the NL/DE/FR badge strings on a live page
## Summary Follow-up to #49, closing the two gaps that review surfaced: **nothing detects a dead selector**, and **the DOM-facing code had no test coverage**. Also cuts v1.17.0 and refreshes the site's manual-install download. ## Selector audit Run on any YouTube page: ```js __CW_AUDIT_SELECTORS__() ``` Prints a table of the selectors the extension depends on with a live match count, and warns on any that found nothing where they should. It **cannot prove a selector is correct**, only that it is still alive — but a renamed class currently produces no error whatsoever, which is precisely how the members-badge filter stayed broken through a release. Invalid selectors (e.g. `:has()` unsupported) are reported separately from dead ones, and entries that legitimately match nothing on a clean feed (promo shelves, ad slots) are marked optional so they never cry wolf. The registry lives in `defaults.js` next to the selectors it audits, so adding a selector and forgetting to audit it is visible in one place. ## Tests: 24 → 60 | File | Covers | Needs jsdom | |---|---|---| | `test/feed-text.test.js` | Age parsing EN/NL/DE/FR, view-count false-positives, badge-token mutual exclusivity, cut-off boundaries | no | | `test/feed-dom.test.js` | Badge extraction, feed reachability, membership shelf rule, audit registry validity | yes | | `test/shared-globals.test.js` | Every `globalThis.FY_*` a script depends on is actually exported | no | Two of these earn their keep immediately: - **`the legacy-only badge selectors match nothing (why the filter died)`** pins the original regression against live markup, so it cannot silently return. - **`shared-globals`** catches renames in the `FY_*` contract. Those resolve at runtime with no import to typo-check them, so a mistake otherwise shows up as a TypeError in a user's browser. It caught a real mistake while I was writing it — `FY_I18N` comes from `i18n.js`, not `defaults.js`. The DOM fixture is built from the live "Get more from memberships" markup. Writing it also exposed that my first draft had no video titles, which the audit test flagged — an unrepresentative fixture is worse than none. ## Shared DOM surface (the refactor) My scratch harnesses sliced source text out of `content.js`, and that broke once mid-session when I reformatted an array. Committing that brittleness would have made the tests a liability. So the selectors, badge tokens and relative-date parser moved into a documented **"YouTube DOM surface"** section in `defaults.js` — the repo's existing home for shared testable helpers (`FY_MATCHES_COMMENT_FILTERS`, `FY_NORMALIZE_MEMBERS_FIRST_CHANNELS`). The filters, the tests and the audit now read the *same values* rather than three copies that drift apart. `content.js` keeps hoisted delegating wrappers, so **no call sites changed and there is no TDZ risk**; `defaults.js` already loads before `content.js` in all three content-script contexts per the manifest. ## Notes for review - **`jsdom` is the first devDependency**, used only by `feed-dom.test.js`. The higher-value assertions are pure and need no browser environment. - **`node_modules/` was not in `.gitignore`** — added before it could be committed. `package-lock.json` is now tracked for reproducible dev installs; say the word if you'd rather it weren't. - **Version bumped to 1.17.0.** Without it the rebuilt zip would ship as 1.16.0 while containing features 1.16.0 does not have — same version string, different contents. Minor bump matches the repo's convention (1.15.0 → 1.16.0 for SponsorBlock). - **The audit function itself has not been run in a real browser** — its registry is validated by tests, but the console output path needs one manual run. ## Test plan - [x] `npm test` — 60/60 - [x] `node --check` on all touched scripts - [x] Zip verified: v1.17.0 manifest, 30 files, byte-identical to the store package, no `test/`, `node_modules/`, `website/` or `.DS_Store` leakage - [ ] Load the unpacked extension and confirm the filters still behave after the `defaults.js` move - [ ] Run `__CW_AUDIT_SELECTORS__()` on a live home page and a watch page - [ ] Still outstanding from #49: spot-check the NL/DE/FR badge strings on a live page
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
365DevNet/CleanWatch!50
No description provided.