Skip to content

Add specs for experimental overlay internals - #655

Open
fpigeonjr wants to merge 2 commits into
masterfrom
gh-634-add-specs-for-experimental-overlay-internals
Open

Add specs for experimental overlay internals#655
fpigeonjr wants to merge 2 commits into
masterfrom
gh-634-add-specs-for-experimental-overlay-internals

Conversation

@fpigeonjr

Copy link
Copy Markdown
Contributor

Description

Adds unit specs for the CDK-style overlay positioning and scroll-strategy internals under src/ui-kit/experimental/patterns/layout/components/core/overlay/, closing the coverage gap called out in the parent epic (#576).

Coverage moved from at-or-near 0% to meaningfully covered for every targeted file:

File Before After (stmts)
connected-position-strategy.ts 0% 95.45%
overlay-ref.ts 0% 96.42%
global-position-strategy.ts 0% 100%
overlay-directives.ts 3.30% 93.47%
block-scroll-strategy.ts 0% 100%
close-scroll-strategy.ts 0% 100%
reposition-scroll-strategy.ts 0% 100%
scroll-dispatcher.ts 6.82% 97.72%

Repo-wide coverage improved from 53.56%/39.77%/50.31%/52.84% (stmts/branches/fns/lines) to 59.22%/44.33%/55.63%/58.68%. coverage-floor.json is intentionally not touched — raising the ratchet is a separate, deliberate coverage:bump commit per AGENTS.md.

Specs added (one file per source unit, colocated):

  • overlay-directives.spec.ts
  • overlay-ref.spec.ts
  • position/connected-position-strategy.spec.ts
  • position/global-position-strategy.spec.ts
  • scroll/block-scroll-strategy.spec.ts
  • scroll/close-scroll-strategy.spec.ts
  • scroll/reposition-scroll-strategy.spec.ts
  • scroll/scroll-dispatcher.spec.ts

Specs construct the units directly with fake collaborators and jsdom fixtures rather than through TestBed, matching these files' narrow public surface (apply()/dispose()/enable()/disable()/etc.) per the issue's guidance to favor testing through the public interface over reaching into private state.

Incidental bug fix: ScrollDispatcher.scrolled()'s throttled branch used the RxJS 5-style auditTime.call(observable, ms) form. Under RxJS 7 (this repo's version), that returns an operator function rather than an Observable, so calling .subscribe() on the result throws. Every current caller passes a 0ms delay, so the branch was effectively dead code and untested — which is also why it showed up as part of this coverage gap. Fixed by switching to observable.pipe(auditTime(ms)), and the throttled path is now covered by a spec (scroll-dispatcher.spec.ts, "applies auditTime debouncing when a positive delay is provided").

Motivation and Context

Closes #634

Type of Change (Select One and Apply Label)

  • Bug fix (non-breaking change which fixes an issue) → Apply bugfix label
  • New feature (non-breaking change which adds functionality) → Apply enhancement label
  • Breaking change (fix or feature that would cause existing functionality to change) → Apply breaking label
  • Documentation / configuration update → Apply maintenance label

How to Test

  1. npm ci && npm ci --prefix test-app
  2. cd test-app && npx vitest run --coverage --config vitest.config.mts — runs the full spec suite; expect Test Files 114 passed (114) / Tests 758 passed (758).
  3. npm run coverage:check (from repo root) — confirms the ratcheting coverage-floor gate still passes and has improved.
  4. npm run format:check / npm run lint:baseline / npm --prefix test-app run lint:baseline — confirm no new formatting or lint-warning regressions.

Expected result: All specs pass, per-file coverage for the 8 target files moves off their previous baselines (see table above), and the coverage-floor gate passes with all four metrics improved over the recorded floor.

Screenshots (if appropriate)

N/A — test/spec changes only, no UI impact.

Checklist

  • Branch name follows convention (e.g. gh-<number>-<slug>)
  • PR title starts with a verb in the imperative mood
  • I have self-reviewed my own code
  • format:check passes (npm run format:check)
  • lint passes (npm run lint)
  • build passes (cd test-app && npm run build)
  • Tests pass and coverage is reported (cd test-app && npm test)
  • If this change requires a documentation update, I have updated it accordingly
  • If there are dependent changes, they have been merged and published in downstream modules

Add unit specs for the CDK-style overlay positioning and scroll-strategy
internals under experimental/patterns/layout/components/core/overlay/,
raising coverage on files that were previously at or near 0%:

- connected-position-strategy.ts: 0% -> 95.45% stmts
- overlay-ref.ts: 0% -> 96.42% stmts
- global-position-strategy.ts: 0% -> 100% stmts
- overlay-directives.ts: 3.30% -> 93.47% stmts
- block-scroll-strategy.ts: 0% -> 100% stmts
- close-scroll-strategy.ts: 0% -> 100% stmts
- reposition-scroll-strategy.ts: 0% -> 100% stmts
- scroll-dispatcher.ts: 6.82% -> 97.72% stmts

Also fixes a latent bug in ScrollDispatcher.scrolled(): the throttled
branch used the RxJS 5-style auditTime.call(observable, ms) form, which
under RxJS 7 returns an operator function rather than an Observable and
throws on subscribe(). Every current caller passes a 0ms delay, so the
branch was effectively dead code and untested. Switched to
observable.pipe(auditTime(ms)) so the throttled path actually works and
is now covered by a spec.

Specs construct the units directly (fake collaborators, jsdom fixtures)
rather than through TestBed, matching these files' narrow public
surface (apply()/dispose()/enable()/disable() etc.) per the issue's
guidance.

Closes #634
@fpigeonjr fpigeonjr added the maintenance Repo maintenance / tooling label Aug 28, 2026
@fpigeonjr fpigeonjr self-assigned this Aug 28, 2026
@fpigeonjr
fpigeonjr requested a lite review from Copilot August 28, 2026 16:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds unit specs for the experimental CDK-style overlay internals (positioning + scroll strategies) under src/ui-kit/experimental/patterns/layout/components/core/overlay/, and includes a small RxJS-7 compatibility fix in ScrollDispatcher.scrolled().

Changes:

  • Adds 8 new colocated spec files covering overlay directives, overlay ref behavior, position strategies, and scroll strategies/dispatcher.
  • Fixes ScrollDispatcher.scrolled() throttling path to use observable.pipe(auditTime(ms)) instead of the RxJS-5-style auditTime.call(...).
  • Improves coverage for the targeted overlay internals without modifying coverage-floor.json (per repo ratchet guidance).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/ui-kit/experimental/patterns/layout/components/core/overlay/scroll/scroll-dispatcher.ts RxJS 7-safe auditTime usage for throttled scrolled notifications.
src/ui-kit/experimental/patterns/layout/components/core/overlay/scroll/scroll-dispatcher.spec.ts New unit coverage for ScrollDispatcher registration, global listener lifecycle, and throttling behavior.
src/ui-kit/experimental/patterns/layout/components/core/overlay/scroll/reposition-scroll-strategy.spec.ts New unit coverage for reposition strategy attach/enable/disable semantics and throttle passthrough.
src/ui-kit/experimental/patterns/layout/components/core/overlay/scroll/close-scroll-strategy.spec.ts New unit coverage for close-on-scroll behavior and subscription lifecycle.
src/ui-kit/experimental/patterns/layout/components/core/overlay/scroll/block-scroll-strategy.spec.ts New unit coverage for scroll blocking and style restoration behavior.
src/ui-kit/experimental/patterns/layout/components/core/overlay/position/global-position-strategy.spec.ts New unit coverage for fluent setters, wrapper behavior, and disposal.
src/ui-kit/experimental/patterns/layout/components/core/overlay/position/connected-position-strategy.spec.ts New unit coverage for preferred/fallback positioning, direction handling, offsets, and position change emissions.
src/ui-kit/experimental/patterns/layout/components/core/overlay/overlay-ref.spec.ts New unit coverage for attach/detach/dispose flows, sizing/positioning updates, and backdrop behaviors.
src/ui-kit/experimental/patterns/layout/components/core/overlay/overlay-directives.spec.ts New unit coverage for OverlayOrigin and ConnectedOverlayDirective configuration and open/close behavior.
Suppressed comments (2)

src/ui-kit/experimental/patterns/layout/components/core/overlay/scroll/scroll-dispatcher.spec.ts:92

  • This test creates multiple scrolled() subscriptions but doesn't unsubscribe them, which can leave global listeners running and affect subsequent tests. Unsubscribe both subscriptions at the end of the test.
    it("shares a single global listener across multiple subscriptions", () => {
      const dispatcher = new ScrollDispatcher(ngZone, createFakePlatform());
      dispatcher.scrolled(0, vi.fn());
      dispatcher.scrolled(0, vi.fn());

src/ui-kit/experimental/patterns/layout/components/core/overlay/scroll/scroll-dispatcher.spec.ts:117

  • This test leaves the registered Scrollable subscription (and the dispatcher's global listeners) active after the assertion. Add explicit cleanup after the expectation so this test doesn't leak listeners/state into later tests.
    it("keeps the global listener alive while a Scrollable is still registered", () => {
      const dispatcher = new ScrollDispatcher(ngZone, createFakePlatform());
      const scrollable = createFakeScrollable();
      dispatcher.register(scrollable as unknown as Scrollable);


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

- block-scroll-strategy.spec.ts: delete the document.body scrollHeight/
  scrollWidth own-property overrides in afterEach so they don't leak into
  later tests (afterEach only restored HTMLElement.prototype descriptors).
- scroll-dispatcher.spec.ts: capture and unsubscribe every Subscription
  returned by scrolled() so global scroll/resize listeners don't leak
  across tests; replace the real setTimeout wait in the auditTime
  debouncing test with Vitest fake timers for determinism.
- overlay-ref.spec.ts: wrap the detachBackdrop() transitionend test in
  fake timers and flush the pending 500ms fallback setTimeout so no
  timer is left running after the test.
@fpigeonjr
fpigeonjr marked this pull request as ready for review August 28, 2026 18:11
@fpigeonjr
fpigeonjr requested a review from a team as a code owner August 28, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Repo maintenance / tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add specs for experimental overlay internals

3 participants