Skip to content

feat(vitest-plugin): extract react-app testing helpers into vitest-plugin-react-app - #5286

Merged
odinr merged 14 commits into
feat/fusion-testingfrom
feat/vitest-plugin-react-app
Aug 13, 2026
Merged

feat(vitest-plugin): extract react-app testing helpers into vitest-plugin-react-app#5286
odinr merged 14 commits into
feat/fusion-testingfrom
feat/vitest-plugin-react-app

Conversation

@odinr

@odinr odinr commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Why is this change needed?
Supersedes #5285. That PR renamed @equinor/fusion-framework-react-app's src/testing to src/vitest to mirror the CLI's ffc app test naming. Building on that, it became clear the testing helpers don't belong inside the app package at all — they're test-only, add vitest-browser-react as a hard dependency of react-app, and duplicate resolution logic already owned by the CLI (app.manifest.ts/app.config.ts resolution). Extracting them into their own package removes that coupling and gives the helpers a home that can evolve independently of react-app's own release cadence.

What is the current behavior?

  • Testing helpers (renderAppHook, renderAppComponent, test-app.tsx/test.tsx, scope/*) live under packages/react/app/src/vitest, exported from @equinor/fusion-framework-react-app/vitest.
  • The CLI (@equinor/fusion-framework-cli) has its own ./vitest entry-point (app-test-vite-plugin.ts, resolve-app-test-env.ts) and a ffc app test command (test.command.ts) that wraps vitest with that plugin pre-registered.
  • useFrameworkModule's missing-module warning interpolates the wrong variable (${module} instead of ${name}).
  • @equinor/fusion-framework-module-context warns even when there's no initial context to resolve.
  • @equinor/fusion-framework-module-msal leaves a stray debug console.log in resolve-version.
  • @equinor/fusion-log's static logger unconditionally accesses process.env, which throws in Vitest Browser Mode (no process global).

What is the new behavior?

  • New package @equinor/fusion-framework-vitest-plugin-react-app (packages/vitest-plugin/react-app) hosts renderAppHook, renderAppComponent, testApp, and appTestVitePlugin — a Vite plugin resolving an app's manifest/config/module-configurator as virtual modules (the same resolution ffc app build/ffc app dev use), plus a /test entry-point exporting pre-seeded test/render fixtures once the plugin is registered.
  • @equinor/fusion-framework-react-app's ./vitest entry-point is removed entirely, with no compatibility shim; its README and docs point at the new package instead.
  • The ffc app test CLI command and @equinor/fusion-framework-cli's ./vitest entry-point are removed — appTestVitePlugin is registered directly in a project's own vitest.config.ts, so a dedicated CLI command/wrapper is unnecessary.
  • useFrameworkModule warns with the correct module name.
  • module-context no longer warns when there is no initial context to resolve.
  • module-msal no longer logs debug output during version resolution.
  • @equinor/fusion-log guards process.env access so it's safe in Vitest Browser Mode.
  • CI installs Playwright browsers for the new package's and react-app's Vitest Browser Mode tests.

What is the intended behavior or invariant?
Consumers testing a Fusion React app install @equinor/fusion-framework-vitest-plugin-react-app as a devDependency and either: (a) use renderAppHook/renderAppComponent/testApp directly with a hand-supplied env/configure, or (b) register appTestVitePlugin in vitest.config.ts and use the /test entry-point's test/render, which resolve env/configure automatically from the app's own manifest/config/module-configurator. The package has no runtime dependency on the CLI beyond reusing its manifest/config resolution.

Does this PR introduce a breaking change?
Yes.

  • @equinor/fusion-framework-react-app's ./vitest entry-point is removed with no compatibility shim. Migrate by installing @equinor/fusion-framework-vitest-plugin-react-app and importing renderAppHook/renderAppComponent/testApp from it instead.
  • The ffc app test CLI command and @equinor/fusion-framework-cli's ./vitest entry-point are removed. Migrate by registering appTestVitePlugin (@equinor/fusion-framework-vitest-plugin-react-app) directly in vitest.config.ts.

Impact assessment:

  • Breaking changes: Yes (see above)
  • Version bump: Major for @equinor/fusion-framework-react-app and @equinor/fusion-framework-cli (entry-point removal); Minor (initial release) for @equinor/fusion-framework-vitest-plugin-react-app; Patch for @equinor/fusion-framework-module-context, @equinor/fusion-framework-module-msal, @equinor/fusion-log
  • Consumer impact: Any consumer of @equinor/fusion-framework-react-app/vitest or ffc app test must migrate to the new package
  • Downstream impact: None outside packages/react/app and packages/cli consumers of the removed entry-points

Review guidance:
Focus on the new packages/vitest-plugin/react-app package — its README documents the full surface area. The CLI command/entry-point removal and the small bugfixes (useFrameworkModule, module-context, module-msal, fusion-log) are carried over unchanged from #5285.

Additional context
Supersedes #5285, which is closed in favor of this PR. Part of a larger split of an overloaded test/cookbooks branch into cli (#5284, merged) / this PR / cookbooks (upcoming).

Related issues
None

Checklist

  • Confirm completion of the self-review checklist
  • Confirm TSDoc captures intent for functions, hooks, components, classes, and named arrow functions
  • Confirm iterator blocks, decision gates, RxJS chains, and complex decisions explain why they exist
  • Confirm React logic and derived values are resolved before markup when applicable
  • Confirm README/docs are updated for user-facing changes
  • Confirm changes to target branch validation
    • Included files validated (pnpm build, pnpm test, pnpm exec biome check, pnpm exec fusion-lint lint, pnpm verify:agent-context)
    • No new linting warnings
    • Not a duplicate PR (check existing)
  • Confirm adherence to code of conduct

odinr added 2 commits August 12, 2026 21:21
- rename src/testing -> src/vitest, add test-app/scope fixture chain
  (test-app.tsx, test.tsx, scope/*) for rendering app components and
  hooks with a fully wired Fusion test environment
- fix(react): useFrameworkModule warns with the correct module name
- fix(module-context): stop warning when there's no initial context
  to resolve
- fix(module-msal): drop stray debug console.log in resolve-version
- fix(log): guard process.env access for Vitest Browser Mode
- chore: biome format fixes surfaced by pnpm check (unrelated pre-existing
  drift in cli/linting/event packages)
Move renderAppHook/renderAppComponent/testApp and the app-test Vite plugin out
of @equinor/fusion-framework-react-app's ./vitest entry-point and
@equinor/fusion-framework-cli's ./vitest entry-point into a new standalone
package, @equinor/fusion-framework-vitest-plugin-react-app, built on
vitest-browser-react instead of @testing-library/react.

- Remove the ffc app test CLI command and cli/src/lib/vitest (superseded by
  appTestVitePlugin registered directly in a project's vitest.config.ts).
- Add packages/vitest-plugin/react-app with README, appTestVitePlugin,
  renderAppHook, renderAppComponent, testApp, and a /test entry-point
  exporting pre-seeded test/render fixtures.
- Update react-app's README/docs and package.json to drop ./vitest and
  point at the new package instead.
- Fix stray console.log in msal's resolveVersion mismatch warning, and guard
  fusion-log's process.env access for environments without a Node process
  global (Vitest Browser Mode).
- Install Playwright browsers in CI for the new package's and react-app's
  Vitest Browser Mode tests.
- Add CODEMAP.md entry for the new package.

Changesets included for all affected packages.
@changeset-bot

changeset-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6ab2c32

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
@equinor/fusion-framework-cli Major
@equinor/fusion-framework-module-context Patch
@equinor/fusion-log Patch
@equinor/fusion-framework-module-msal Patch
@equinor/fusion-framework-react-app Major
@equinor/fusion-framework-react Patch
@equinor/fusion-framework-vitest-plugin-react-app Minor
@equinor/fusion-framework-cli-plugin-ai-base Major
@equinor/fusion-framework-cli-plugin-ai-chat Major
@equinor/fusion-framework-cli-plugin-ai-index Major
@equinor/fusion-framework-cli-plugin-copilot Major
@equinor/fusion-framework-cookbook-app-react-ag-grid Patch
@equinor/fusion-framework-cookbook-app-react-context-custom-error Patch
@equinor/fusion-framework-cookbook-app-react-context Patch
@equinor/fusion-framework-cookbook-app-react-feature-flag Patch
poc-portal Patch
portal-analytics Patch
portal Patch
@equinor/fusion-framework-dev-portal Patch
@equinor/fusion-framework Patch
@equinor/fusion-framework-module-analytics Patch
@equinor/fusion-framework-dev-server Patch
@equinor/fusion-framework-app Patch
@equinor/fusion-framework-vite-plugin-spa Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added 👾 React 💾 CLI fusion framework CLI 📚 documentation Improvements or additions to documentation 🚀 feature New feature or request 🚧 chore maintaines work, (update deps, workflos ...) 🛠️ utils packages related to utils 🧬 Modules labels Aug 13, 2026
@odinr
odinr requested a balanced review from Copilot August 13, 2026 07:14
…epends on it

pnpm exec at the repo root only resolves bins from root's own node_modules,
and playwright is a devDependency of react-app/vitest-plugin-react-app only,
not the workspace root - the previous 'pnpm exec playwright install' failed
with ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL / 'Command "playwright" not found'.
@odinr odinr self-assigned this Aug 13, 2026

Copilot AI 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.

Pull request overview

Extracts React app testing helpers into a dedicated Vitest plugin package, removes the superseded CLI testing interface, and includes supporting fixes.

Changes:

  • Adds browser-based render fixtures and app environment resolution.
  • Removes React app and CLI testing entry points.
  • Improves context telemetry, token stability, logging, documentation, and CI.

Reviewed changes

Copilot reviewed 60 out of 66 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
tsconfig.json Adds Vitest plugin path mapping.
pnpm-lock.yaml Updates workspace dependency graph.
packages/vitest-plugin/react-app/tsconfig.json Configures the new package build.
packages/vitest-plugin/react-app/src/virtual-modules.d.ts Declares plugin virtual modules.
packages/vitest-plugin/react-app/src/test.tsx Adds pre-seeded test fixture.
packages/vitest-plugin/react-app/src/test-app.tsx Defines app-scoped Vitest fixtures.
packages/vitest-plugin/react-app/src/scope/resolve-fusion.ts Resolves mocked framework instances.
packages/vitest-plugin/react-app/src/scope/resolve-app-scope.ts Resolves app test scopes.
packages/vitest-plugin/react-app/src/scope/index.ts Exports scope utilities.
packages/vitest-plugin/react-app/src/scope/default-app-env.ts Defines the default test environment.
packages/vitest-plugin/react-app/src/scope/create-app-scope-wrapper.tsx Creates React provider wrappers.
packages/vitest-plugin/react-app/src/resolve-app-test-env.ts Resolves app manifest and configuration.
packages/vitest-plugin/react-app/src/render.tsx Adds plugin-backed component rendering.
packages/vitest-plugin/react-app/src/render-app-hook.tsx Migrates hook rendering to browser mode.
packages/vitest-plugin/react-app/src/render-app-component.tsx Migrates component rendering to browser mode.
packages/vitest-plugin/react-app/src/index.ts Implements the Vite plugin.
packages/vitest-plugin/react-app/src/app-test.ts Defines the /test entry point.
packages/vitest-plugin/react-app/README.md Documents the new package.
packages/vitest-plugin/react-app/package.json Defines package exports and dependencies.
packages/utils/log/src/static.ts Guards browser access to process.env.
packages/react/framework/src/useFrameworkModule.ts Corrects the missing-module warning.
packages/react/app/vitest.config.ts Enables Playwright browser tests.
packages/react/app/src/testing/index.ts Removes the old testing barrel.
packages/react/app/src/msal/useToken.ts Stabilizes token acquisition dependencies.
packages/react/app/src/__tests__/useTrackFeature.test.tsx Migrates the render helper import.
packages/react/app/src/__tests__/useToken.test.tsx Migrates token tests to browser fixtures.
packages/react/app/src/__tests__/useHelpCenter.test.tsx Migrates asynchronous browser assertions.
packages/react/app/src/__tests__/useFeature.test.tsx Migrates feature tests to browser mode.
packages/react/app/src/__tests__/useCurrentContext.test.tsx Migrates context hook tests.
packages/react/app/src/__tests__/useCurrentBookmark.test.tsx Migrates bookmark hook tests.
packages/react/app/src/__tests__/useCurrentAccount.test.tsx Migrates account hook tests.
packages/react/app/src/__tests__/useAppSettings.test.tsx Migrates settings tests.
packages/react/app/src/__tests__/useAppSetting.test.tsx Migrates setting tests.
packages/react/app/src/__tests__/useAccessToken.test.tsx Migrates access-token tests.
packages/react/app/src/__tests__/testApp.test.tsx Tests the app fixture integration.
packages/react/app/src/__tests__/Apploader.test.tsx Migrates component tests to browser mode.
packages/react/app/README.md Redirects testing documentation.
packages/react/app/package.json Removes the testing export and updates test dependencies.
packages/react/app/docs/testing.md Removes obsolete testing documentation.
packages/modules/msal/src/versioning/resolve-version.ts Removes debug output.
packages/modules/context/tsconfig.json Adds the telemetry project reference.
packages/modules/context/src/utils/resolve-initial-context.ts Handles an absent initial context.
packages/modules/context/src/module.ts Adds context telemetry reporting.
packages/modules/context/src/ContextProvider.ts Removes context queue debug output.
packages/modules/context/src/__tests__/ContextModuleConfigurator.test.ts Tests empty and failed context resolution.
packages/modules/context/package.json Adds telemetry development metadata.
packages/cli/src/lib/vitest/tests/resolve-app-test-env.test.ts Removes obsolete CLI resolver tests.
packages/cli/src/lib/vitest/resolve-app-test-env.ts Removes CLI-owned environment resolution.
packages/cli/src/lib/vitest/index.ts Removes the CLI Vitest barrel.
packages/cli/src/cli/commands/app/test.command.ts Removes ffc app test.
packages/cli/src/cli/commands/app/index.ts Unregisters the test command.
packages/cli/src/bin/test-application.ts Removes the test runner wrapper.
packages/cli/src/bin/index.ts Removes the test runner export.
packages/cli/package.json Removes the CLI Vitest entry point.
CODEMAP.md Registers the new package.
.gitignore Ignores browser-test artifacts.
.github/workflows/pr.yml Installs Chromium for browser tests.
.changeset/vitest-plugin-react-app_initial-release.md Describes the new package release.
.changeset/react-app_render-app-hook-testing.md Documents hook-helper migration.
.changeset/react-app_render-app-component-testing.md Documents component-helper migration.
.changeset/react-app_fix-remaining-vitest-docs.md Records documentation cleanup.
.changeset/react_fix-usemodule-warning.md Records the warning fix.
.changeset/msal_remove-debug-log.md Records debug-log removal.
.changeset/module-context_fix-empty-context-warning.md Records empty-context handling.
.changeset/fusion-log_guard-process-env.md Records browser-safe logging.
.changeset/cli_app-test-command.md Removes the superseded CLI feature changeset.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (1)

packages/vitest-plugin/react-app/src/index.ts:36

  • The documentation now promises that the package root supplies the app-testing helpers, but this module exports only appTestVitePlugin; the README and changeset imports of renderAppHook, renderAppComponent, and testApp therefore fail. Add explicit exports for the plugin-free helper modules (and the documented resolver) without re-exporting app-test, whose virtual imports require plugin registration.

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

Comment thread packages/vitest-plugin/react-app/package.json
Comment thread packages/vitest-plugin/react-app/tsconfig.json Outdated
Comment thread packages/vitest-plugin/react-app/package.json
Comment thread packages/cli/package.json
Comment thread packages/modules/context/package.json
Comment thread packages/react/app/package.json Outdated
Comment thread packages/modules/context/src/module.ts
Comment thread packages/react/app/src/msal/useToken.ts
Comment thread packages/vitest-plugin/react-app/README.md Outdated
Comment thread packages/vitest-plugin/react-app/src/test-app.tsx Outdated
odinr added 10 commits August 13, 2026 09:52
The package uses vitest's expect/vi APIs at test-authoring time but only listed it as a devDependency, so consumers weren't told to install it themselves.
src/index.ts and src/resolve-app-test-env.ts import @equinor/fusion-imports (utils/imports), but the tsconfig referenced utils/observable, an unrelated package.
…ePlugin

The package's own resolution/virtual-module logic had no test coverage and no vitest.config.ts, so it wasn't even picked up as a project by the root Vitest run.
The removal of ffc app test, testApplication, the ./vitest entry-point, and resolveAppTestEnv from @equinor/fusion-framework-cli had no changeset.
The context module only reads telemetry defensively via an injected instance (never imports the package directly), matching the optional pattern already used by modules/msal.
…rding

Add the missing 'import { expect } from vitest' to the quick-start test snippet, and reword the fixture-sharing bullet to clarify only seeded defaults are shared, not fusion/app state between tests.
Match the README wording fix: testApp's JSDoc previously implied one shared mocked scope across tests, when each test actually gets fresh fusion/app instances and only the seeded defaults are shared.
vitest-browser-react was only used by the now-removed ./vitest entry-point; src/ has no remaining references to it, so it stays a devDependency only.
…solution

Adds coverage for the resolver-error and successful-resolution telemetry events raised by module.ts's postInitialize, alongside the existing console.warn-fallback test for when no telemetry module is registered.
Asserts acquireToken is not re-invoked when scopes are re-rendered with the same contents (a fresh array literal each time), but is re-invoked when the contents actually change.
@github-actions github-actions Bot added the 🐞 bug Something isn't working label Aug 13, 2026
@odinr
odinr requested a balanced review from Copilot August 13, 2026 08:00

Copilot AI 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.

Pull request overview

Copilot reviewed 64 out of 70 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (5)

packages/vitest-plugin/react-app/src/index.ts:36

  • The advertised root API is not actually exported: index.ts only exports appTestVitePlugin, so the documented imports of renderAppHook, renderAppComponent, testApp, and resolveAppTestEnv from the package root fail. Re-export these symbols from modules that do not import the virtual test modules.
    packages/react/app/vitest.config.ts:8
  • This project is also loaded by the root Vitest workspace, where process.cwd() is the repository root, so appTestVitePlugin() resolves the root package instead of packages/react/app. Pass the config directory explicitly so the /test fixtures always receive react-app's manifest/config regardless of the invocation directory.
    packages/react/app/src/msal/useToken.ts:41
  • This changes the public useToken behavior so equivalent scope arrays no longer reacquire tokens, but none of the react-app changesets mention this consumer-visible fix; the existing entries only cover the testing extraction and docs. Add a react-app changeset describing the stable-scope acquisition behavior so it appears in the release notes.
    packages/vitest-plugin/react-app/package.json:23
  • This typesVersions map omits the root "." declaration mapping used by the repository's other multi-entry packages (for example, packages/react/framework/package.json:37-43 and packages/cli/package.json:66-72). TypeScript resolution modes that consult typesVersions can consequently resolve /test but not the package-root declarations; add the root mapping.
    packages/vitest-plugin/react-app/README.md:75
  • The installation section does not install @vitest/browser-playwright or playwright, but the quick-start config imports both immediately; following the documented steps in a consumer app therefore leaves this example unresolved. Add the provider installation command before the config example (or use a provider already listed as required).

@odinr
odinr marked this pull request as ready for review August 13, 2026 10:45
@odinr
odinr requested a review from a team as a code owner August 13, 2026 10:45
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 76.7% 6020 / 7848
🔵 Statements 72.07% 9300 / 12904
🔵 Functions 62.13% 3129 / 5036
🔵 Branches 59.39% 3471 / 5844
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/modules/context/src/ContextProvider.ts 63.11% 48.36% 57.02% 72.59% 354, 388-397, 419-422, 429, 433, 439, 444, 536-537, 544-577, 617, 676-678, 740-741, 746-800, 820, 851, 879-882, 946, 951, 990-991, 1000-1003, 1029-354, 388-397, 545, 567-569, 585-586, 748-753, 759-797, 851-882, 946, 951, 990-992, 1000-1003, 1029-1040, 529-579, 559-582, 764-792, 991
packages/modules/context/src/module.ts 96.42% 75% 90% 100% 96, 166
packages/modules/context/src/utils/resolve-initial-context.ts 77.27% 25% 66.66% 91.66% 16-22, 19
packages/modules/msal/src/versioning/resolve-version.ts 96.07% 81.48% 100% 100% 35, 100-104
packages/react/app/src/msal/useToken.ts 100% 50% 100% 100%
packages/react/framework/src/useFrameworkModule.ts 100% 100% 100% 100%
packages/utils/log/src/static.ts 92% 71.42% 100% 93.33% 60, 60
packages/vitest-plugin/react-app/src/app-test.ts 100% 100% 100% 100%
packages/vitest-plugin/react-app/src/render.tsx 0% 0% 0% 0% 53-61
packages/vitest-plugin/react-app/src/resolve-app-test-env.ts 100% 87.5% 100% 100%
packages/vitest-plugin/react-app/src/test-app.tsx 70% 100% 71.42% 70% 65-69
packages/vitest-plugin/react-app/src/test.tsx 50% 100% 0% 50% 33
packages/vitest-plugin/react-app/src/scope/create-app-scope-wrapper.tsx 100% 100% 100% 100%
packages/vitest-plugin/react-app/src/scope/default-app-env.ts 100% 100% 100% 100%
packages/vitest-plugin/react-app/src/scope/index.ts 100% 100% 100% 100%
packages/vitest-plugin/react-app/src/scope/resolve-app-scope.ts 100% 75% 100% 100%
packages/vitest-plugin/react-app/src/scope/resolve-fusion.ts 100% 75% 100% 100%
Generated in workflow #15307 for commit 6ab2c32 by the Vitest Coverage Report Action

@odinr
odinr merged commit 10ae4cc into feat/fusion-testing Aug 13, 2026
7 checks passed
@odinr
odinr deleted the feat/vitest-plugin-react-app branch August 13, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐞 bug Something isn't working 🚧 chore maintaines work, (update deps, workflos ...) 💾 CLI fusion framework CLI 📚 documentation Improvements or additions to documentation 🚀 feature New feature or request 🧬 Modules 👾 React 🛠️ utils packages related to utils

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants