Skip to content

JS coverage easy wins: geofence completo + panels restantes + scripts isolados (#168) - #169

Merged
rpgmem merged 4 commits into
mainfrom
claude/js-coverage-easy-wins
May 12, 2026
Merged

JS coverage easy wins: geofence completo + panels restantes + scripts isolados (#168)#169
rpgmem merged 4 commits into
mainfrom
claude/js-coverage-easy-wins

Conversation

@rpgmem

@rpgmem rpgmem commented May 12, 2026

Copy link
Copy Markdown
Owner

Closes #168.

Summary

Four sprints implementing the easy-testability JS coverage uplift from #168. Each commit is independently revertable.

Sprint Commit What
A fb153bd 37 tests for the rest of ffc-geofence-frontend.js — pure helpers, DOM methods, browser detection, location cache, blocked-message rendering, GPS fallback.
B 07e5af9 23 tests across the 3 dashboard panels left at 0% (reregistrations, profile read view, audience-join with mocked $.ajax).
C b107c81 25 tests across 5 small isolated IIFE scripts (dark-mode, user-capabilities, smtp-settings, webview-warning, already-submitted-notice).
D f10baaa JS_COVERAGE_FLOOR_LINES ratchets 7 → 15 to lock in the bigger baseline without firing on minor flux.

Coverage delta

Before (main) After (this PR)
Total tests 42 127 (+85)
Overall line coverage 8.67% 16.86%
ffc-geofence-frontend.js 39% 57%
ffc-user-dashboard-reregistrations.js 0% 75%
ffc-user-dashboard-profile.js 0% 40%
ffc-user-dashboard-audience-join.js 0% 56%
ffc-dark-mode.js 0% ~90%
ffc-user-capabilities.js 0% ~90%
ffc-smtp-settings.js 0% ~85%
ffc-webview-warning.js 0% ~60%
ffc-already-submitted-notice.js 0% ~65%
JS_COVERAGE_FLOOR_LINES 7 15

Notes

  • Profile panel at 40% — below the 60-80% target. Its render builds 6+ sections (read view, password form, preferences, notifications, LGPD); this PR covers the read view and core actions only. Deeper coverage of the action-handler flows warrants its own focused PR when those flows surface bugs.
  • $(document).ready(cb) deferral — jQuery 4 defers ready callbacks to a microtask even when document.readyState === 'complete'. Tests for scripts using that pattern await one tick via await new Promise((r) => setTimeout(r, 0)) after loadScript.
  • UA override patternObject.defineProperty(navigator, 'userAgent', { configurable: true }) works in jsdom; tests restore the original UA in beforeEach to avoid cross-test bleed.

Test plan

  • npm run test:js127 / 127 OK (was 42).
  • npm run test:js:coverage — line coverage 16.86%, gate (floor 15) passes.
  • npm run lint:js — clean (9 pre-existing unused-vars warnings unchanged).
  • vendor/bin/phpunit — runs unchanged (no PHP touched).

What's deferred to future PRs

  • ffc-frontend.js (500 LOC, hub), ffc-frontend-helpers.js (656 LOC), ffc-core.js (300 LOC) — extract-pure-helpers-then-test, larger sprint of its own.
  • ffc-csv-download.js, ffc-reregistration-frontend.js — large critical-path files.
  • ffc-admin.js + admin pages — separate sprint.
  • ffc-audience.js (1470 LOC) — skipped per [Skipped] Sprint J — split ffc-audience.js (won't do, see body) #167.
  • Profile panel deep coverage — separate sprint when needed.

https://claude.ai/code/session_01HiExaniSqvNBLpVTszCLNx


Generated by Claude Code

claude added 4 commits May 12, 2026 12:10
…A of #168)

Adds 37 tests for `window.FFCGeofence` methods left at 0% after #160's
initial pass that covered only `validateDateTime` + `pickHideMode`.

Coverage of `ffc-geofence-frontend.js` jumps:
  - Lines:     39.26% → 56.94%
  - Functions: 25.92% → 81.48%
  - Branches:  73.33% → 82.22%

What's covered now:
  - `getString` — i18n lookup with three fallback layers (key missing,
    strings object missing, config missing entirely).
  - `formatDate` / `formatTime` — zero-padding edge cases for single-
    digit month/day/hour/minute.
  - `escapeHtml` — proves HTML entity encoding on the dangerous chars
    (script tag injection attempt → encoded).
  - `calculateDistance` / `deg2rad` — Haversine math: identity case,
    real-world São Paulo→Rio (~360 km), symmetry, and angle conversion
    for 0°/180°/-90°.
  - `isSafari` — UA matching across iPhone, desktop Safari, iPad-as-
    desktop (`maxTouchPoints > 1` + Macintosh UA), Chrome, Firefox.
  - `getLocationCache` / `setLocationCache` — round-trip, missing key
    returns null, expired TTL clears the entry, malformed JSON yields
    null defensively.
  - `handleBlocked` — three branches (`hide`, `message`, default) plus
    XSS-prevention assertion (escapes raw HTML before injecting).
  - `showAdminBypassMessages` — generic vs datetime-only vs both-flags
    paths.
  - `showForm` / `resetForm` — class toggling + cleanup of injected
    blocked messages.
  - `showLoadingMessage` / `updateLoadingMessage` / `hideLoadingMessage`
    — spinner appended, text rewritten without losing spinner, full
    removal on hide.
  - `applyGpsFallback` — allow vs block branches (shows form vs
    handleBlocked).

Test infrastructure unchanged — uses the same `loadScript` + real
jQuery setup from #163. Each test starts with a fresh `#ffc-form-1`
fixture and clears `localStorage`.

Per-file `ffc-geofence-frontend.js` coverage report (`% Lines`):
  39.26 → 56.94 (Δ +17.7 points). Overall JS coverage: 8.67% → 9.93%.
Floor in `lint.yml` ratchets after sprints B and C land in this PR.

https://claude.ai/code/session_01HiExaniSqvNBLpVTszCLNx
23 new tests for the 3 dashboard panels left at 0% after #163 S4.

  - dashboard-reregistrations.test.js (6 tests) — empty state, Active/
    Completed section split, past-row class, edit-button visibility
    (gated by `can_submit`), download-ficha link (gated by
    `can_download` AND `magic_link`), auth_code as <code> vs dash.

  - dashboard-profile.test.js (9 tests) — read view rendering: profile
    container, logout link visibility (gated by `ffcDashboard.logoutUrl`),
    phone/department/organization labels + values, notes block (gated
    by non-empty `notes`), audience-group chips and the "Leave all
    groups" button (gated by group count), Edit Profile / Change
    Password buttons, audience-join section placeholder, panel state
    storage.

  - dashboard-audience-join.test.js (8 tests) — `$.ajax` is mocked so
    we drive the load() → render path deterministically: empty parents
    array empties section, heading + description render, Join button
    (non-member) vs Leave button (member), disabled-Join when
    joined_count >= max_groups, nested parent accordion, error branch
    empties the section, no-op when section is missing.

Per-file coverage:
  - ffc-user-dashboard-reregistrations.js: 0% → 74.66% lines.
  - ffc-user-dashboard-profile.js:         0% → 40.21% lines.
  - ffc-user-dashboard-audience-join.js:   0% → 56.25% lines.

Profile is below the 60-80% target because its render builds 6+
sections (read view, password form, preferences toggles, notifications
settings, LGPD export buttons); this commit covers the read view and
core actions only. The form-submission / password-change / preferences-
save handlers each open their own panels of behaviour that warrant
dedicated test files when those flows surface bugs.

Overall JS coverage: 9.93% → 13.27%.
Floor ratchet deferred to Sprint D's commit so all of A+B+C
contribute to a single bump.

https://claude.ai/code/session_01HiExaniSqvNBLpVTszCLNx
25 new tests across 3 files for the small IIFE-only scripts in
`assets/js/` that had no test coverage.

  - tiny-scripts.test.js (11 tests) — combined file for the truly
    tiny scripts:
      • ffc-dark-mode.js (4 tests): off/undefined no-ops, mode=on
        adds class, mode=auto follows matchMedia + responds to
        change events.
      • ffc-user-capabilities.js (4 tests): Grant all / Revoke all
        / Grant certificates only / Grant appointments only — each
        verifies that only the targeted name prefix is toggled.
      • ffc-smtp-settings.js (3 tests): smtp_mode=custom reveals
        #smtp-options, disable_all_emails disables every SMTP
        input, default page-load leaves inputs enabled.

  - webview-warning.test.js (8 tests) — UA detection, banner
    rendering, dismiss flow. Covers plain desktop UA, Android
    WebView, Instagram in-app, Facebook in-app (FBAN marker),
    pre-dismissed session, the dismiss button → banner removal +
    sessionStorage flag, anchor placement above .ffc-form-wrapper,
    no-anchor no-op.

  - already-submitted-notice.test.js (6 tests) — localStorage form-
    ID list driving the notice. Covers not-in-list no-render,
    in-list render, session-dismissed no-render, dismiss → flag
    + removal, missing form no-op, malformed JSON resilience.

Test infrastructure additions:
  - `await new Promise((r) => setTimeout(r, 0))` after `loadScript`
    for scripts that wire handlers inside `$(document).ready(cb)` —
    jQuery 4 defers the callback to a microtask even when the
    document is already complete in the jsdom environment.
  - UA override via `Object.defineProperty(navigator, 'userAgent',
    { configurable: true })` is restored in `beforeEach`.

Coverage delta on the affected files (`% Lines`):
  - ffc-dark-mode.js:                0 → ~90.
  - ffc-user-capabilities.js:        0 → ~90.
  - ffc-smtp-settings.js:            0 → ~85.
  - ffc-webview-warning.js:          0 → ~60.
  - ffc-already-submitted-notice.js: 0 → ~65.

Overall JS coverage: 13.27% → 16.86%.

Floor ratchet ships in the next commit so the bump reflects the
combined gain of A + B + C.

https://claude.ai/code/session_01HiExaniSqvNBLpVTszCLNx
…#168)

Sprints A+B+C of #168 added 60+ new tests covering:
  - geofence-frontend pure helpers + DOM methods (Sprint A)
  - 3 remaining dashboard panels (Sprint B)
  - 5 small isolated scripts (Sprint C)

Overall line coverage went from 8.67% to 16.86% (a ~94% relative
increase). The floor moves from 7 → 15, preserving the ~1.8% buffer
the previous ratchets used.

The buffer pattern still applies: PRs that touch tested code without
adding coverage may drop the number slightly without firing the gate;
PRs that genuinely improve coverage should bump the floor in the
same commit (see the running comment in `lint.yml`).

https://claude.ai/code/session_01HiExaniSqvNBLpVTszCLNx
@rpgmem
rpgmem marked this pull request as ready for review May 12, 2026 14:13
@rpgmem
rpgmem merged commit 845351a into main May 12, 2026
16 checks passed
@rpgmem
rpgmem deleted the claude/js-coverage-easy-wins branch May 12, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Coverage] Easy-testability sprints (A: geofence completo + B: panels restantes + C: small isolated scripts)

2 participants