Skip to content

feat: generic per-test scope hooks in itBase#7

Closed
Lojhan wants to merge 19 commits into
mainfrom
feat/generic-test-scope-hooks
Closed

feat: generic per-test scope hooks in itBase#7
Lojhan wants to merge 19 commits into
mainfrom
feat/generic-test-scope-hooks

Conversation

@Lojhan
Copy link
Copy Markdown
Owner

@Lojhan Lojhan commented Apr 6, 2026

Summary

This PR introduces a generic per-test scope lifecycle in Poku so plugin state can be isolated safely, even when tests run concurrently inside the same describe block.

Instead of relying on module-level globals that can leak between tests, Poku now exposes a neutral scope hook contract that any plugin can register and use. Core remains plugin-agnostic.

Why we are building this

Today, tests can already execute concurrently in the same file when multiple it/test calls are registered synchronously.
When plugin internals use shared process-level state (for example module-level Set/Map registries), one test can accidentally mutate or clean up resources owned by another test.

This creates:

  • cross-test leakage
  • flaky behavior
  • cleanup races
  • hard-to-debug failures under concurrency

We need a first-class per-test state boundary in the runner lifecycle, not only ad-hoc cleanup patterns in each plugin.

What this feature adds

  1. Generic scope hook contract in core test execution
  • Added in src/modules/helpers/it/core.ts
  • Core checks for a globally-registered scope provider and, if present, executes test callbacks through it.
  • If no provider is registered, behavior is unchanged.
  1. Neutral, plugin-agnostic integration point
  • Hook key is generic and owned by Poku naming:
    • Symbol.for(@pokujs/poku.test-scope-hooks)
  1. Concurrency and isolation verification
  • Added unit test coverage in test/unit/scope-hooks.test.ts
  • Confirms:
    • fallback path works with no hooks
    • concurrent runs receive independent stores
    • store identity remains stable across async boundaries

Design goals achieved

  • Core remains framework/plugin agnostic
  • Backward compatible (no hooks => old behavior)
  • Safe under concurrent test execution
  • Extensible contract plugins can adopt incrementally

What plugins can build from this

With this scope lifecycle, plugins can safely implement per-test resource ownership without global leaks, including:

  • DOM framework adapters (mounted roots/fixtures per test)
  • mock/spy registries with guaranteed scoped restore
  • process/service lifecycle managers with scoped teardown
  • DB transaction/session scopes per test
  • request/tenant context propagation via AsyncLocalStorage
  • scoped event/log capture and metrics buffers

In short: plugins can now implement reliable per-test state machines that are race-safe by default.

Backward compatibility

  • No breaking API changes for test authors
  • Existing plugins that do not register scope hooks continue to run unchanged
  • Hook registration is optional and additive

Validation

  • Focused unit test run for scope hooks passes:
    • test/unit/scope-hooks.test.ts

Risks and mitigations

Risk:

  • Incorrect plugin hook implementation could mis-handle cleanup order.

Mitigation:

  • Core contract is minimal and explicit
  • Test coverage verifies isolation behavior
  • Fallback execution path remains intact when hooks are absent

Follow-up work

  • Adopt this generic scope contract in framework plugins (React, Vue, Angular) for mounted resource tracking
  • Add helper utilities in shared packages to reduce plugin boilerplate when implementing scoped stores
  • Expand integration tests for mixed plugin scenarios under concurrent executionContinued with AutopilotPrepared a complete, ready-to-paste PR description covering the feature purpose, motivation, architecture, plugin extensibility, compatibility, validation, risks, and follow-up roadmap.

@Lojhan Lojhan force-pushed the feat/generic-test-scope-hooks branch from a6847d5 to 0c76696 Compare April 6, 2026 10:38
@Lojhan
Copy link
Copy Markdown
Owner Author

Lojhan commented Apr 6, 2026

An usage exaple is here:
pokujs/dom#14

@github-actions github-actions Bot added the Stale label Apr 21, 2026
@github-actions
Copy link
Copy Markdown

This PR has been closed due to inactivity for 15 days. You are welcome to reopen it if you want to continue the development or request it to be reopened by a maintainer 🤝

@github-actions github-actions Bot closed this Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants