Skip to content

feat(react-app): vitest render/test-app fixtures under src/vitest - #5285

Closed
odinr wants to merge 1 commit into
feat/fusion-testingfrom
feat/react-app-vitest-fixtures
Closed

feat(react-app): vitest render/test-app fixtures under src/vitest#5285
odinr wants to merge 1 commit into
feat/fusion-testingfrom
feat/react-app-vitest-fixtures

Conversation

@odinr

@odinr odinr commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Why is this change needed?
@equinor/fusion-framework-react-app's testing utilities lived under src/testing, disconnected from the CLI's new ffc app test command (@equinor/fusion-framework-cli/vitest, added in #5284, now merged). This PR renames the testing surface to src/vitest and adds a full fixture chain (test-app.tsx, test.tsx, scope/*) for rendering app components and hooks against a fully wired Fusion test environment, matching the CLI's naming convention.

What is the current behavior?

  • Testing helpers live at packages/react/app/src/testing/* with only render-app-component.tsx and render-app-hook.tsx.
  • useFrameworkModule's missing-module warning interpolates the wrong variable (${module} instead of ${name}), so the warning message is always broken.
  • @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?

  • src/testing renamed to src/vitest, with a new test-app.tsx/test.tsx/scope/* fixture chain providing a ready-to-use Fusion test environment (scope wrapper, default app env, fusion resolver).
  • 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.

What is the intended behavior or invariant?
Consumers importing app-testing utilities should do so from @equinor/fusion-framework-react-app/vitest, mirroring @equinor/fusion-framework-cli/vitest. The fixture chain assumes it's only used in a Vitest environment (browser or node).

Does this PR introduce a breaking change?
Yes — @equinor/fusion-framework-react-app's src/testing export path is renamed to src/vitest. Consumers importing from the old testing subpath must update to vitest.

Impact assessment:

  • Breaking changes: Yes (import path rename)
  • Version bump: Minor for @equinor/fusion-framework-react-app (new subpath + fixtures), Patch for @equinor/fusion-framework-react, @equinor/fusion-framework-module-context
  • Consumer impact: Update imports from @equinor/fusion-framework-react-app/testing to @equinor/fusion-framework-react-app/vitest
  • Downstream impact: None outside packages/react/app consumers

Review guidance:
Focus on the new src/vitest/scope/* fixture chain and test-app.tsx/test.tsx — these are the new surface area. The other fixes (useFrameworkModule, module-context, module-msal, fusion-log) are small, isolated bugfixes bundled in because they were needed for the new fixtures to pass cleanly.

Additional context
Part of a larger split of an overloaded test/cookbooks branch into cli (#5284, merged) / react-app-vitest (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:packages, pnpm exec vitest run, pnpm check, pnpm exec fusion-lint lint)
    • No new linting warnings
    • Not a duplicate PR (check existing)
  • Confirm adherence to code of conduct

@odinr
odinr requested a review from a team as a code owner August 12, 2026 19:19
@changeset-bot

changeset-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1fb0357

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

This PR includes changesets to release 11 packages
Name Type
@equinor/fusion-framework-module-context Patch
@equinor/fusion-framework-react-app Minor
@equinor/fusion-framework-react Patch
@equinor/fusion-framework-dev-portal Patch
@equinor/fusion-framework Patch
@equinor/fusion-framework-module-analytics Patch
portal-analytics Patch
poc-portal Patch
@equinor/fusion-framework-cli Patch
@equinor/fusion-framework-app Patch
portal 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 🐞 bug Something isn't working 👾 React 💾 CLI fusion framework CLI 📚 documentation Improvements or additions to documentation 🚀 feature New feature or request 🛠️ utils packages related to utils 🧬 Modules labels Aug 12, 2026
- 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)
@odinr
odinr force-pushed the feat/react-app-vitest-fixtures branch from 7be6827 to 1fb0357 Compare August 12, 2026 19:21
@github-actions github-actions Bot removed 🐞 bug Something isn't working 💾 CLI fusion framework CLI labels Aug 12, 2026
@odinr
odinr requested a balanced review from Copilot August 12, 2026 19:23

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

Adds Vitest Browser Mode fixtures for rendering React apps and hooks in a fully configured Fusion test scope, aligned with ffc app test.

Changes:

  • Renames the testing subpath to /vitest and adds app-aware fixtures.
  • Migrates package tests to Playwright-backed browser rendering.
  • Includes supporting context, logging, MSAL, and warning fixes.

Reviewed changes

Copilot reviewed 41 out of 44 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
pnpm-lock.yaml Resolves browser-testing dependencies.
packages/utils/log/src/static.ts Guards browser access to process.env.
packages/react/framework/src/useFrameworkModule.ts Corrects missing-module warning text.
packages/react/app/vitest.config.ts Enables Playwright browser tests.
packages/react/app/src/vitest/virtual-modules.d.ts Types CLI-provided virtual modules.
packages/react/app/src/vitest/test.tsx Adds CLI-seeded test fixture.
packages/react/app/src/vitest/test-app.tsx Adds base Fusion app fixture chain.
packages/react/app/src/vitest/scope/resolve-fusion.ts Resolves mocked parent frameworks.
packages/react/app/src/vitest/scope/resolve-app-scope.ts Resolves app module scopes.
packages/react/app/src/vitest/scope/index.ts Exports scope utilities.
packages/react/app/src/vitest/scope/default-app-env.ts Defines the default test environment.
packages/react/app/src/vitest/scope/create-app-scope-wrapper.tsx Creates the provider wrapper.
packages/react/app/src/vitest/render.tsx Adds CLI-seeded component rendering.
packages/react/app/src/vitest/render-app-hook.tsx Migrates hook rendering to browser mode.
packages/react/app/src/vitest/render-app-component.tsx Migrates component rendering to browser mode.
packages/react/app/src/vitest/index.ts Defines the /vitest public surface.
packages/react/app/src/testing/index.ts Removes the old testing barrel.
packages/react/app/src/msal/useToken.ts Stabilizes token request dependencies.
packages/react/app/src/__tests__/useTrackFeature.test.tsx Migrates helper import.
packages/react/app/src/__tests__/useToken.test.tsx Adapts token tests to browser mode.
packages/react/app/src/__tests__/useHelpCenter.test.tsx Uses Vitest polling.
packages/react/app/src/__tests__/useFeature.test.tsx Migrates feature tests.
packages/react/app/src/__tests__/useCurrentContext.test.tsx Migrates context tests.
packages/react/app/src/__tests__/useCurrentBookmark.test.tsx Migrates bookmark tests.
packages/react/app/src/__tests__/useCurrentAccount.test.tsx Updates fixture import.
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 Adapts access-token tests.
packages/react/app/src/__tests__/Apploader.test.tsx Migrates component tests.
packages/react/app/README.md Renames the testing entry point.
packages/react/app/package.json Exports /vitest and adds browser dependencies.
packages/react/app/docs/testing.md Updates testing API documentation.
packages/modules/msal/src/versioning/resolve-version.ts Removes debug output.
packages/modules/context/tsconfig.json References the telemetry package.
packages/modules/context/src/utils/resolve-initial-context.ts Handles an absent initial context.
packages/modules/context/src/module.ts Adds telemetry for context initialization.
packages/modules/context/src/ContextProvider.ts Removes queue debug output.
packages/modules/context/src/__tests__/ContextModuleConfigurator.test.ts Covers empty initial context behavior.
packages/modules/context/package.json Adds telemetry development dependency.
.gitignore Ignores browser-test artifacts.
.changeset/react-app_render-app-hook-testing.md Updates hook-helper release notes.
.changeset/react-app_render-app-component-testing.md Updates component-helper release notes.
.changeset/react_fix-usemodule-warning.md Records the warning fix.
.changeset/module-context_fix-empty-context-warning.md Records the context fix.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (1)

packages/react/app/docs/testing.md:147

  • This guide still documents @testing-library/react options, return values, imports, and waitFor, although the implementation and peer dependency were switched to vitest-browser-react. As written, the examples require an undeclared package and do not describe the public API actually returned; migrate the guide consistently to the browser renderer.
Options are the same shape as `renderAppHook`'s — `configure`, `env`, `fusion` — plus any
other `@testing-library/react` `render` option. The result carries the usual `render` return
values (`getByText`, `container`, `unmount`, ...) plus `fusion` — nested rather than spread
directly onto the result, so `@testing-library/react`'s own return shape stays free to evolve
without ever colliding with it. `fusion.app` is the same application module instance the

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

Comment on lines +12 to +13
export { test } from './test';
export { render } from './render';
Comment on lines +68 to +70
"./vitest": {
"types": "./dist/types/vitest/index.d.ts",
"import": "./dist/esm/vitest/index.js"
Comment on lines +50 to +52
// `process` is unavailable in real browser environments (e.g. Vitest Browser Mode)
const env = typeof process !== 'undefined' ? process.env : undefined;
const envLogLevel = env?.FUSION_LOG_LEVEL;
export function createAppScopeWrapper<TModules extends Array<AnyModule> | unknown = unknown>({
framework,
app,
}: AppScope<TModules>) {
// `req` is typically a fresh object literal each render; key the effect on its
// scopes' content instead of identity, so it doesn't re-run (and reset `pending`
// to `true` forever) every time the caller re-renders.
const scopesKey = req.scopes.join(',');
Comment on lines +17 to 19
The result also carries a nested `app` object (`app.modules`, `app.fusion`) — the same instances the hook rendered against, for driving a module the hook itself doesn't return — nested rather than spread directly onto the result so `@testing-library/react`'s own return shape stays free to evolve without ever colliding with it.

Requires `@testing-library/react` (added as an optional peer dependency).
Comment on lines 16 to +25
`renderAppComponent` wraps `@testing-library/react`'s `render` with the same `FrameworkProvider` + `ModuleProvider` nesting `renderAppHook` uses, backed by `mockFramework` and `mockAppModules` (`@equinor/fusion-framework-app/mock`), so tests can render a real component tree without hand-wiring those mocks.

The result also carries a nested `app` object (`app.modules`, `app.fusion`) — nested rather than spread directly onto the result so `@testing-library/react`'s own return shape stays free to evolve without ever colliding with it — so a test can drive a module directly after the initial render and assert the component re-renders, instead of hand-wiring `mockAppModules`/`ModuleProvider` itself to reach the same instance:

```tsx
const { getByText, app } = await renderAppComponent<[ContextModule]>(<App />, {
configure: (configurator) => enableContextMock(configurator, (mock) => mock.setCurrentContext(projectA)),
});
await act(() => app.modules.context.setCurrentContextByIdAsync(projectB.id));
await waitFor(() => expect(getByText(/project-b/)).toBeInTheDocument());
Comment on lines +64 to +66
Any other `renderHook` option (e.g. `initialProps`) is forwarded as-is. The result carries the
usual `renderHook` return values (`result`, `rerender`, `unmount`) plus `modules` and `fusion` —
the same instances the hook rendered against — for driving a module the hook itself doesn't return.
Comment on lines 177 to 180
```tsx
import { renderAppHook } from '@equinor/fusion-framework-react-app/testing';
import { renderAppHook } from '@equinor/fusion-framework-react-app/vitest';
import { waitFor } from '@testing-library/react';
import { useAccessToken } from '@equinor/fusion-framework-react-app/msal';
| `/framework` | `useFramework`, `useCurrentUser`, `useFrameworkHttpClient` |
| `/widget` | Widget entry-point |
| `/testing` | `renderAppHook`, `renderAppComponent` — pre-wrapped `renderHook`/`render` for testing app-scoped hooks and components |
| `/vitest` | `renderAppHook`, `renderAppComponent` — pre-wrapped `renderHook`/`render` for testing app-scoped hooks and components |
@odinr

odinr commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

Closing in favor of a new PR — the direction changed after this was opened: instead of renaming src/testing to src/vitest inside @equinor/fusion-framework-react-app, the testing helpers (renderAppHook, renderAppComponent, testApp) and the app-test Vite plugin now live in a new standalone package, @equinor/fusion-framework-vitest-plugin-react-app, built on vitest-browser-react. This also removes the ffc app test CLI command added in #5284, since appTestVitePlugin registers directly in a project's vitest.config.ts instead.

Superseded by a new PR from feat/vitest-plugin-react-app (same base).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📚 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