Skip to content

test(miner-extension): cover options.js pure helpers without a jsdom harness - #7118

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
luciferlive112116:fix/extension-options-pure-fn-tests-7008
Jul 17, 2026
Merged

test(miner-extension): cover options.js pure helpers without a jsdom harness#7118
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
luciferlive112116:fix/extension-options-pure-fn-tests-7008

Conversation

@luciferlive112116

Copy link
Copy Markdown
Contributor

Closes #7008

Summary

Scope

  • The PR title follows type(scope): short summary Conventional Commit format.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes — it is a test-only + README-note change scoped to apps/loopover-miner-extension/.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves — Closes #7008.

Validation

  • git diff --check — clean.
  • npm run typecheck — 0 errors (the root tsc config type-checks the new test/options.test.ts).
  • Extension suite: npm --workspace @loopover/miner-extension test — 31 tests pass (24 prior + 7 new) with vitest.config.ts coverage thresholds still met (options.js is not in coverage.include, so the new test adds behavior coverage without moving the gated numbers, mirroring content.js).
  • npm run miner-extension:lint (node --check on all scripts) and npm run miner-extension:typecheck pass; ESLint on the new test file is clean.

If any required check was skipped, explain why:

  • test:coverage, test:workers, build:mcp/test:mcp-pack, ui:openapi:check, ui:lint/ui:typecheck/ui:build, and npm audit are not applicable: this PR touches only apps/loopover-miner-extension/** (a test file plus a README note) — no src/**, no MCP/API/OpenAPI surface, no @loopover/ui files, and no dependency changes. apps/** is outside the Codecov codecov/patch scope, so there is no changed backend line/branch to cover; the extension's own vitest thresholds (verified above) are the relevant coverage signal.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests — N/A (none in this PR).
  • API/OpenAPI/MCP behavior is updated and tested where needed — N/A (none in this PR).
  • UI changes use live API data or real empty/error/loading states — N/A (no UI behavior change).
  • Visible UI changes include a UI Evidence section — N/A: this is a test-only + README-note change; options.js's runtime behavior and the extension UI are unchanged, so there is nothing visual to screenshot.
  • Public docs are updated where needed (the README deferred-coverage note); no changelog edited.

UI Evidence

Not applicable — no visible UI, frontend, or behavioral change. This PR adds a unit-test file and updates a README note only; options.js itself is unchanged, so there is no rendered state to capture.

Notes

  • The extension's vitest suite is not currently a CI-gated step (CI runs miner-extension:lint/:typecheck/:build); the new test file is nonetheless type-checked by the root typecheck job and passes locally with thresholds met, matching how content.test.ts already lives in this package.

…harness (JSONbored#7008)

options.js's pure, DOM-independent helpers had no test file. Add
test/options.test.ts using the same __LOOPOVER_MINER_EXTENSION_TEST__ import
hook that content.test.ts (JSONbored#6189) already proved out: importing options.js on a
non-mounted path (a null-returning document) exposes its internals without any
jsdom mount harness.

Covers parseWatchedRepos, parseRankedCandidatesJson (empty short-circuit, array
parse, non-array rejection, and the UTF-8 byte-size quota that guards
chrome.storage.local against silent over-quota failures), normalizeMinerUiUrl,
and the legacy discoveryIndexUrl purge. Update the README's deferred-coverage
note: content.js and options.js pure logic are now tested this way; only the
mounted options-page/content-script UI event handlers still need a real DOM
harness.

Closes JSONbored#7008
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 17, 2026
@loopover-orb

loopover-orb Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-17 22:12:57 UTC

2 files · 1 AI reviewer · no blockers · readiness 98/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
Test-only PR adding test/options.test.ts covering options.js's pure helpers (parseWatchedRepos, parseRankedCandidatesJson, normalizeMinerUiUrl, removeLegacyDiscoveryIndexUrl) via the same non-mounted-import trick already established for content.js in #6189, plus a README update reflecting the now-narrower deferred-coverage scope. The technique is sound: stubbing document.querySelector to return null and stubbing chrome/__LOOPOVER_MINER_EXTENSION_TEST__ globals lets the module take its unmounted branch and expose internals with no jsdom needed. Tests are well-targeted, hit both branches of nullish coalescing and quota boundary checks, and CI passed. This closes #7008 as claimed and is narrowly scoped to the extension's test suite and README.

Nits — 3 non-blocking
  • The oversized-payload test in options.test.ts uses "a".repeat(MAX_RANKED_CANDIDATES_JSON_BYTES + 1), which only exercises single-byte UTF-8 chars — consider adding a case with multi-byte characters to actually prove the TextEncoder byte-length (not char-length) claim in the comment.
  • README.md's new paragraph is dense; consider breaking the content.js vs options.js distinction into two sentences for readability.
  • Add a multi-byte-character test case to more directly validate the UTF-8 byte-size quota claim called out in both the PR description and the test comment.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #7008
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 179 registered-repo PR(s), 110 merged, 27 issue(s).
Contributor context ✅ Confirmed Gittensor contributor luciferlive112116; Gittensor profile; 179 PR(s), 27 issue(s).
Improvement ℹ️ Insufficient signal risk: clean · value: insufficient-signal · LLM: minor
Review context
  • Author: luciferlive112116
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 179 PR(s), 27 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/ desktop before /
before /
after /
after /
/ mobile before / (mobile)
before / (mobile)
after / (mobile)
after / (mobile)

Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb 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.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit 5e7f077 into JSONbored:main Jul 17, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extension README's test-coverage deferral note is stale; options.js pure functions can use content.js's proven technique

1 participant