@equinor/fusion-framework-vitest-plugin-react-app 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/esm/index.js +9 -4
  2. package/dist/esm/index.js.map +1 -1
  3. package/dist/esm/resolve-app-test-env.js +8 -2
  4. package/dist/esm/resolve-app-test-env.js.map +1 -1
  5. package/dist/esm/scope/resolve-fusion.js +22 -24
  6. package/dist/esm/scope/resolve-fusion.js.map +1 -1
  7. package/dist/esm/test-app.js +5 -8
  8. package/dist/esm/test-app.js.map +1 -1
  9. package/dist/esm/test.js +2 -1
  10. package/dist/esm/test.js.map +1 -1
  11. package/dist/esm/version.js +1 -1
  12. package/dist/tsconfig.tsbuildinfo +1 -1
  13. package/dist/types/index.d.ts +4 -3
  14. package/dist/types/resolve-app-test-env.d.ts +3 -1
  15. package/dist/types/scope/resolve-fusion.d.ts +6 -7
  16. package/dist/types/test-app.d.ts +12 -11
  17. package/dist/types/test.d.ts +20 -9
  18. package/dist/types/version.d.ts +1 -1
  19. package/package.json +17 -19
  20. package/CHANGELOG.md +0 -81
  21. package/docs/advanced.md +0 -209
  22. package/docs/configuration.md +0 -112
  23. package/docs/getting-started.md +0 -66
  24. package/docs/migrating-an-existing-app.md +0 -202
  25. package/docs/module-mocks.md +0 -120
  26. package/docs/overview.md +0 -49
  27. package/docs/troubleshooting.md +0 -67
  28. package/docs/why-browser-mode.md +0 -128
  29. package/src/__tests__/app-test-vite-plugin.test.ts +0 -109
  30. package/src/__tests__/merge-env-config.test.ts +0 -67
  31. package/src/__tests__/resolve-app-test-env.test.ts +0 -83
  32. package/src/app-test.ts +0 -19
  33. package/src/define-project.ts +0 -91
  34. package/src/index.ts +0 -124
  35. package/src/merge-env-config.ts +0 -58
  36. package/src/render-app-component.tsx +0 -116
  37. package/src/render-app-hook.tsx +0 -135
  38. package/src/render.tsx +0 -64
  39. package/src/resolve-app-test-env.ts +0 -132
  40. package/src/scope/create-app-scope-wrapper.tsx +0 -26
  41. package/src/scope/default-app-env.ts +0 -13
  42. package/src/scope/index.ts +0 -4
  43. package/src/scope/resolve-app-scope.ts +0 -46
  44. package/src/scope/resolve-fusion.ts +0 -74
  45. package/src/test-app.tsx +0 -148
  46. package/src/test.tsx +0 -42
  47. package/src/version.ts +0 -2
  48. package/src/virtual-modules.d.ts +0 -12
  49. package/tsconfig.json +0 -26
  50. package/vitest.config.ts +0 -10
@@ -1,112 +0,0 @@
1
- # Configure Fusion React app tests
2
-
3
- The package exposes three entry points with different responsibilities:
4
-
5
- | Import | Responsibility |
6
- | --- | --- |
7
- | `@equinor/fusion-framework-vitest-plugin-react-app/config` | Build a browser-ready Vitest project with `defineProject` |
8
- | `@equinor/fusion-framework-vitest-plugin-react-app/test` | Resolve the app's files and provide `test` and `render` fixtures |
9
- | `@equinor/fusion-framework-vitest-plugin-react-app` | Configure the Vite plugin manually or render with explicit `env`, `configure`, and `fusion` options |
10
-
11
- ## `defineProject` defaults
12
-
13
- ```ts
14
- import { defineProject } from '@equinor/fusion-framework-vitest-plugin-react-app/config';
15
-
16
- export default defineProject();
17
- ```
18
-
19
- The default project registers `appTestVitePlugin()` and configures:
20
-
21
- - test files under `src/**/*.{test,spec}.{ts,tsx}`
22
- - Vitest Browser Mode enabled
23
- - the Playwright provider with one Chromium instance
24
- - headless browser execution
25
- - a `1024x768` default viewport, matching a typical low-resolution Citrix session rather than
26
- Vitest's own mobile-sized default
27
- - Vite warmup for `src/**/*.{ts,tsx}` to discover lazy imports before tests run
28
-
29
- ## Merge ordinary Vitest options
30
-
31
- Pass an object to deep-merge it with the defaults through Vite's `mergeConfig`:
32
-
33
- ```ts
34
- import { defineProject } from '@equinor/fusion-framework-vitest-plugin-react-app/config';
35
- import { name, version } from './package.json' with { type: 'json' };
36
-
37
- export default defineProject({
38
- test: {
39
- name: `${name}@${version}`,
40
- // opt into a wider viewport for an app that only needs to support desktop
41
- browser: { viewport: { width: 1920, height: 1080 } },
42
- },
43
- });
44
- ```
45
-
46
- These are standard Vitest and Vite options. Use the official Vitest configuration reference
47
- for runner behavior rather than looking for Fusion-specific equivalents.
48
-
49
- ## Replace defaults deliberately
50
-
51
- Pass a function only when a deep merge cannot express the change. The function's return value
52
- replaces the defaults outright, so preserve every default the project still needs:
53
-
54
- ```ts
55
- import { defineProject } from '@equinor/fusion-framework-vitest-plugin-react-app/config';
56
-
57
- export default defineProject((defaults) => ({
58
- ...defaults,
59
- test: {
60
- ...defaults.test,
61
- include: ['tests/browser/**/*.test.tsx'],
62
- },
63
- }));
64
- ```
65
-
66
- When test files move outside `src`, update both `test.include` and `server.warmup.clientFiles`
67
- if those tests load lazy application modules.
68
-
69
- ## Resolve non-standard app files
70
-
71
- Use `appTestVitePlugin` directly when the app manifest, app configuration, or module
72
- configurator does not use Fusion's normal file conventions:
73
-
74
- ```ts
75
- import { playwright } from '@vitest/browser-playwright';
76
- import { appTestVitePlugin } from '@equinor/fusion-framework-vitest-plugin-react-app';
77
- import { defineProject } from 'vitest/config';
78
-
79
- export default defineProject({
80
- plugins: [
81
- appTestVitePlugin({
82
- manifest: './config/app.manifest.ts',
83
- config: './config/app.config.ts',
84
- configure: './config/modules.ts',
85
- }),
86
- ],
87
- test: {
88
- browser: {
89
- enabled: true,
90
- provider: playwright(),
91
- headless: true,
92
- instances: [{ browser: 'chromium' }],
93
- },
94
- },
95
- server: { warmup: { clientFiles: ['src/**/*.{ts,tsx}', '!src/**/*.d.ts'] } },
96
- });
97
- ```
98
-
99
- `entrypoint`, `manifest`, and `config` use the same resolution pipeline as `ffc app build`
100
- and `ffc app dev`. `configure` must identify a real source file because the plugin re-exports
101
- its live application code into the test bundle. Explicit files that do not exist throw
102
- `FileNotFoundError`; convention-based lookups fall back to defaults.
103
-
104
- ## Choose fixtures or explicit render options
105
-
106
- Use `/test` when the app's own files should resolve automatically. Use `renderAppHook`,
107
- `renderAppComponent`, or `testApp` from the root entry point when the test should pass `env`,
108
- `configure`, or a parent `fusion` instance explicitly.
109
-
110
- - [`test` and app rendering](getting-started.md)
111
- - [Detailed rendering and fixture APIs](../README.md#renderapphook)
112
- - [Troubleshooting configuration](troubleshooting.md)
@@ -1,66 +0,0 @@
1
- # Test a Fusion React app with Vitest
2
-
3
- Use `@equinor/fusion-framework-vitest-plugin-react-app` to render an existing Fusion React
4
- app in Vitest Browser Mode. The test runs in Chromium with a fresh framework and application
5
- module scope, a deterministic signed-in `Test User`, and no running portal or real credentials.
6
-
7
- ## Install
8
-
9
- ```sh
10
- pnpm add -D vitest playwright @vitest/browser-playwright vitest-browser-react \
11
- @equinor/fusion-framework-vitest-plugin-react-app
12
- pnpm exec playwright install chromium
13
- ```
14
-
15
- React, React DOM, RxJS, and Vite are peer dependencies that a Fusion React app normally
16
- already provides.
17
-
18
- ## Configure Vitest
19
-
20
- Create `vitest.config.ts` at the app project root:
21
-
22
- ```ts
23
- import { defineProject } from '@equinor/fusion-framework-vitest-plugin-react-app/config';
24
-
25
- export default defineProject();
26
- ```
27
-
28
- `defineProject` registers `appTestVitePlugin`, enables headless Chromium through Playwright,
29
- includes `src/**/*.{test,spec}.{ts,tsx}`, and warms application source files so lazy route
30
- imports do not reload the browser during a test.
31
-
32
- ## Write the first app test
33
-
34
- ```tsx
35
- import { expect } from 'vitest';
36
- import { test } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
37
- import { App } from './App';
38
-
39
- test('renders the app', async ({ render }) => {
40
- const screen = await render(<App />);
41
- await expect.element(screen.getByRole('heading')).toBeVisible();
42
- });
43
- ```
44
-
45
- The `/test` entry point resolves the app's manifest, `app.config.ts`, and module configurator
46
- through the registered Vite plugin. Always await `render`, `renderHook`,
47
- `renderAppComponent`, and `renderAppHook`; Fusion module initialization completes before the
48
- first render.
49
-
50
- ## Run
51
-
52
- ```sh
53
- pnpm exec vitest
54
- pnpm exec vitest run
55
- ```
56
-
57
- The first command watches for changes. The second performs one run for CI. A successful run
58
- reports one passing test and requires no portal, credentials, or backend service.
59
-
60
- ## Next steps
61
-
62
- - [Configure the test project and app-file resolution](configuration.md)
63
- - [Resolve common setup, browser, and network failures](troubleshooting.md)
64
- - [Seed Fusion module dependencies](module-mocks.md)
65
- - [Choose between app, framework, module, and HTTP test layers](../../../framework/docs/testing-choosing-a-layer.md)
66
- - [Seed authentication, context, service discovery, and HTTP](../README.md#overview)
@@ -1,202 +0,0 @@
1
- # Migrate an existing app to Fusion Vitest
2
-
3
- Use this guide to move existing application tests to
4
- `@equinor/fusion-framework-vitest-plugin-react-app`. It covers suites built with
5
- `@testing-library/react`, `jsdom` or `happy-dom`, hand-written Fusion hook mocks, and mock HTTP
6
- servers such as MirageJS, MSW, or Nock.
7
-
8
- You can migrate one test at a time. A mixed suite is a valid final state.
9
-
10
- ## Choose which tests to migrate
11
-
12
- Start with tests that read from the application module scope through
13
- `useAppModule`, `useAccessToken`, `useCurrentContext`, `useCurrentBookmark`, `useFeature`, or a
14
- route that uses several Fusion modules. The plugin can replace their hand-written hook mocks
15
- with the real module pipeline and supported `enable*Mock` configuration.
16
-
17
- Keep pure functions, presentational components, and hooks with no Fusion dependency on their
18
- current runner when that is simpler. A test can also use the real Fusion module setup without
19
- Browser Mode by providing its own renderer. See
20
- [Why Browser Mode is the default](why-browser-mode.md#choose-a-different-runtime).
21
-
22
- ## What changes, concretely
23
-
24
- | Existing pattern | Replace with |
25
- | --- | --- |
26
- | `@testing-library/react`'s `render`/`renderHook`/`waitFor`/`act`, on `jsdom` or `happy-dom` | `vitest-browser-react`'s `render`/`renderHook` and `vitest`'s `waitFor`/`act`, on real Chromium (Vitest Browser Mode) |
27
- | `vi.mock('@equinor/fusion-framework-react/hooks', ...)`, `vi.mock('.../feature-flag', ...)`, and similar hand-rolled Fusion hook mocks | The owning module's `enable*Mock` from its own `/mock` entry point. See [Module mocks](module-mocks.md) |
28
- | A hand-written mock HTTP server (MirageJS, `msw/node`, `nock`) answering every backend call | `configurator.http.addMiddleware(...)` with a hand-written `HttpMiddleware`, or `createRouterMiddleware` for several routes under one base URI. See [HTTP testing](../../../modules/http/docs/testing.md) |
29
- | A hand-rolled test wrapper composing a router, context providers, and error boundaries around every render | `test.extend(...)` fixtures stacked on the base `render`/`configureApp` fixtures. See [Compose a router and a domain fixture](#compose-a-router-and-a-domain-fixture) below |
30
- | Synchronous assertions (`expect(screen.getByText(...))`) | Browser locators and `await expect.element(screen.getByText(...)).toBeVisible()` |
31
-
32
- ## Step 1: install Browser Mode dependencies
33
-
34
- ```sh
35
- pnpm add -D vitest playwright @vitest/browser-playwright vitest-browser-react \
36
- @equinor/fusion-framework-vitest-plugin-react-app
37
- pnpm exec playwright install chromium
38
- ```
39
-
40
- Remove `@testing-library/react`, `@testing-library/dom`, `@testing-library/user-event`, and
41
- whichever `jsdom`/`happy-dom` package the app installed once every test that used them has
42
- migrated. Keep them if part of the suite intentionally stays on the old renderer.
43
-
44
- Replace the app's `vitest.config.ts` with the plugin's project config:
45
-
46
- ```ts
47
- import { defineProject } from '@equinor/fusion-framework-vitest-plugin-react-app/config';
48
-
49
- export default defineProject();
50
- ```
51
-
52
- `defineProject` registers `appTestVitePlugin`, enables headless Chromium, includes
53
- `src/**/*.{test,spec}.{ts,tsx}`, and warms application source so lazy route imports don't reload
54
- the browser mid-test. See [Configuration](configuration.md) for overriding any of that.
55
-
56
- ## Step 2: replace hand-rolled Fusion hook mocks
57
-
58
- The `/test` entry point initializes the real module pipeline. This removes most `vi.mock`
59
- implementations for hooks such as `useCurrentUser`, `useFeature`, and `useHttpClient`. The
60
- default setup includes a signed-in `Test User` and initialized feature-flag, context, and
61
- bookmark modules:
62
-
63
- ```diff
64
- -vi.mock('@equinor/fusion-framework-react/hooks', async (importOriginal) => ({
65
- - ...(await importOriginal()),
66
- - useCurrentUser: vi.fn(() => undefined),
67
- -}));
68
- -vi.mock('@equinor/fusion-framework-react-app/feature-flag', () => ({
69
- - useFeature: vi.fn(() => ({})),
70
- -}));
71
- +import { enableFeatureFlagMock } from '@equinor/fusion-framework-module-feature-flag/mock';
72
- +import { test as baseTest } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
73
- +
74
- +export const test = baseTest.extend('configureApp', ({ configureApp }) => (configurator, args) => {
75
- + configureApp?.(configurator, args);
76
- + configurator.msal.setAccount(null); // was: useCurrentUser returning undefined
77
- + enableFeatureFlagMock(configurator, (mock) => mock.addFeature({ key: 'new-search', enabled: true }));
78
- +});
79
- ```
80
-
81
- Each Fusion module owns its own mock entry point: `enableMsalMock`/`configurator.msal`,
82
- `enableFeatureFlagMock`, `enableContextMock`, `enableBookmarkMock`, and more. See
83
- [Module mocks](module-mocks.md) for the full list and each one's defaults. A hook or a small
84
- piece of app config with no Fusion dependency (for example, reading `environment` from the
85
- app's own manifest) stays a plain `vi.mock`.
86
-
87
- Some suites override `useModuleCurrentContext` directly and change its return value with
88
- `vi.spyOn`. Replace the initial value with `enableContextMock`. To change context after render,
89
- call the real module:
90
- `await fusion.app.context.setCurrentContextByIdAsync(otherProject.id)`. See the first
91
- [`renderAppComponent`](../README.md#renderappcomponent) example.
92
-
93
- ## Step 3: port the mock HTTP server
94
-
95
- Use `createRouterMiddleware` for a mock server that handles several routes under one base URL:
96
-
97
- ```diff
98
- -import { createServer } from 'miragejs';
99
- -
100
- -export function createTestServer() {
101
- - return createServer({
102
- - routes() {
103
- - this.get('/activities/:id', (schema, request) => ({ id: request.params.id, ... }));
104
- - this.post('/activities', (schema, request) => ({ ... }));
105
- - },
106
- - });
107
- -}
108
- +import { createRouterMiddleware } from '@equinor/fusion-framework-module-http/mock';
109
- +
110
- +export const activityRoutes = createRouterMiddleware('https://cpr-api.example.com', (router) => {
111
- + router.get('/activities/:id', ({ params }) => Response.json({ id: params.id /* ... */ }));
112
- + router.post('/activities', async ({ request }) => Response.json({ /* ... */ }));
113
- +});
114
- ```
115
-
116
- Register the result with `configurator.http.addMiddleware(activityRoutes)` inside a `configureApp`
117
- fixture (see step 4). Port one route file at a time. Each ported file is independently testable.
118
- An unported route can fall through to the real network, so keep the old interceptor
119
- for tests that have not migrated yet or add a final fail-closed middleware; do not rely on a
120
- missing route to fail by itself. If the backend has an OpenAPI document, prefer
121
- `createOpenApiMockMiddleware` (`@equinor/fusion-framework-module-http/mock`) over hand-written
122
- routes; see [HTTP testing](../../../modules/http/docs/testing.md).
123
-
124
- If `useHttpClient` currently returns a plain `fetch` wrapper, remove that hook mock as well. The
125
- real client reaches middleware registered with `configurator.http.addMiddleware`. Register the
126
- router for the base URI used by the real client.
127
-
128
- ## Compose a router and a domain fixture
129
-
130
- Use a `render` extension for JSX wrappers such as routers and app-owned React providers. Use a
131
- `configureApp` extension for Fusion module state. Stack both extensions when a test needs both:
132
-
133
- ```tsx
134
- import type { ReactElement } from 'react';
135
- import { test as baseTest } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
136
- import { Router } from '@equinor/fusion-framework-react-router';
137
- import type { RouteObject } from '@equinor/fusion-framework-react-router';
138
- import { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
139
-
140
- // Every route matches, so the element under test stays mounted.
141
- const testWithRouter = baseTest.extend('render', () => (ui: ReactElement) => {
142
- const routes: RouteObject[] = [{ path: '*', Component: () => ui }];
143
- return baseTest.render(<Router routes={routes} />);
144
- });
145
-
146
- // The domain fixture uses the same shape as any other `configureApp` extension.
147
- export const test = testWithRouter.extend('configureApp', ({ configureApp }) => (configurator, args) => {
148
- configureApp?.(configurator, args);
149
- enableContextMock(configurator, (mock) => mock.setCurrentContext(projectA));
150
- });
151
- ```
152
-
153
- A test importing this `test` gets both the router wrapper and seeded Fusion context.
154
-
155
- Keep app-owned React providers, such as authorization, schema, or snackbar providers, in the
156
- `render` extension. Move only Fusion module state to `configureApp` and `enable*Mock`.
157
-
158
- ## Step 4: update renders and assertions
159
-
160
- Every render/hook helper is `async`, and most assertion helpers from `vitest-browser-react`
161
- resolve against the real browser rather than synchronously:
162
-
163
- ```diff
164
- -const { findByTestId } = render(<WrappedProcessPage {...props} />);
165
- -await findByTestId('customization-panel');
166
- +const { getByTestId } = await render(<WrappedProcessPage {...props} />);
167
- +await expect.element(getByTestId('customization-panel')).toBeVisible();
168
- ```
169
-
170
- `fireEvent`-style interactions become element method calls (`await screen.getByRole('button', {
171
- name: 'Activate' }).click()`), and `act`/`waitFor` come from `vitest` rather than
172
- `@testing-library/react`. See the [Vitest Browser Mode](https://vitest.dev/guide/browser/) and
173
- [mocking](https://vitest.dev/guide/mocking) guides for the general-purpose parts of this that
174
- aren't Fusion-specific.
175
-
176
- ## Step 5: reassess DOM-emulation-only workarounds
177
-
178
- Review polyfills and component replacements that may only exist for `jsdom` or `happy-dom`.
179
- Remove one workaround at a time and run the affected tests against the real component.
180
-
181
- A common one: a no-op `window.ResizeObserver` stub carried over from `jsdom`/`happy-dom` setup.
182
- Real Chromium doesn't need the stub, but leaving it in place silently breaks any component that
183
- measures itself through `ResizeObserver` before rendering — for example a virtualized popover
184
- list. Remove the stub rather than porting it.
185
-
186
- Do not remove unrelated suppressions automatically. AG Grid license messages, Lit dev-mode
187
- warnings, network behavior, and app-specific test doubles may still apply in Browser Mode.
188
-
189
- ## Migrate incrementally
190
-
191
- Nothing requires migrating a whole app in one pass. A common order: pick one page or route-level
192
- test that already hand-mocks several Fusion hooks, migrate it end to end (steps 1-4 above),
193
- confirm it's green, then migrate the next. Leave tests with no Fusion dependency on their
194
- current renderer for as long as that remains the cheaper option.
195
-
196
- ## Related documentation
197
-
198
- - [Choose a Fusion testing layer](../../../framework/docs/testing-choosing-a-layer.md)
199
- - [Module mocks](module-mocks.md)
200
- - [HTTP testing](../../../modules/http/docs/testing.md)
201
- - [Advanced usage](advanced.md): composing fixtures and explicit render options
202
- - [Troubleshooting](troubleshooting.md)
@@ -1,120 +0,0 @@
1
- # Mock Fusion dependencies in app tests
2
-
3
- Use module-owned `/mock` entry points to seed deterministic Fusion state while retaining each
4
- module's real configurator, provider, validation, and lifecycle. Import only the boundary the
5
- app test needs; the React app test fixture already composes the normal framework and app
6
- module scopes.
7
-
8
- | App dependency | Import path | Primary API |
9
- | --- | --- | --- |
10
- | Analytics | `@equinor/fusion-framework-module-analytics/mock` | `MockAnalyticsAdapter` |
11
- | App manifests and config | `@equinor/fusion-framework-module-app/mock` | `MockAppClient` |
12
- | Browser authentication | `@equinor/fusion-framework-module-msal/mock` | `enableMsalMock`, `MsalMockClient`, `createMockToken` |
13
- | Node authentication with Azure Identity | `@equinor/fusion-framework-module-azure-identity/mock` | `enableAuthMock`, `MockAuthProvider` |
14
- | Node authentication with MSAL | `@equinor/fusion-framework-module-msal-node/mock` | `enableAuthMock`, `MockAuthProvider` |
15
- | Bookmarks | `@equinor/fusion-framework-module-bookmark/mock` | `enableBookmarkMock`, `BookmarkMockConfigurator` |
16
- | Context | `@equinor/fusion-framework-module-context/mock` | `enableContextMock`, `ContextMockConfigurator` |
17
- | Context fixture generation | `@equinor/fusion-framework-module-context/mock/fixtures` | `createContextItemFactory`, `createContextItems` |
18
- | Feature flags | `@equinor/fusion-framework-module-feature-flag/mock` | `enableFeatureFlagMock`, `FeatureFlagMockConfigurator` |
19
- | HTTP routes and OpenAPI responses | `@equinor/fusion-framework-module-http/mock` | `createRouterMiddleware`, `createOpenApiMockMiddleware` |
20
- | Service discovery | `@equinor/fusion-framework-module-service-discovery/mock` | `enableServiceDiscoveryMock`, `ServiceDiscoveryMockConfigurator` |
21
- | Telemetry | `@equinor/fusion-framework-module-telemetry/mock` | `enableTelemetryMock`, `MockTelemetryAdapter` |
22
-
23
- The event module has no mock entry point. `waitForEvent` and `watchEvents` from
24
- `@equinor/fusion-framework-module-event/utils` observe the real event provider initialized by
25
- the app test fixture.
26
-
27
- ## Authentication
28
-
29
- App tests start with a deterministic signed-in `Test User`. Set a named account or `null`
30
- through `configurator.msal.setAccount(...)` before rendering. The real MSAL provider still
31
- runs its initialization, account, token, and logout behavior against the in-process client.
32
-
33
- See [MSAL testing](../../../modules/msal/docs/testing.md) for signed-out startup, login flows,
34
- deterministic JWTs, and individual client spies.
35
-
36
- ## App manifest and configuration
37
-
38
- The `/test` entry point automatically resolves the current app's manifest, `app.config.ts`,
39
- and module configurator. Use `enableAppManifestMock` when a custom parent framework must serve
40
- those values, or `mockAppModules` for app module testing without React.
41
-
42
- See [Application module testing](../../../app/docs/testing.md).
43
-
44
- ## Context
45
-
46
- Use `enableContextMock` for known domain state without a context API or HTTP setup. The pool
47
- starts empty; `setCurrentContext` seeds and selects one item, while `setContexts` only makes
48
- items resolvable. Use HTTP middleware instead when the context service and transport pipeline
49
- are part of the test.
50
-
51
- See [Context testing](../../../modules/context/README.md#testing) for defaults, related-context
52
- behavior, and deterministic fixture generators.
53
-
54
- ## Service discovery and HTTP
55
-
56
- Use `enableServiceDiscoveryMock` to resolve services from an in-memory registry. Use
57
- `configurator.http.addMiddleware` to answer a few explicit requests through the app's real
58
- named clients. Use `createOpenApiMockMiddleware` when an OpenAPI document describes many
59
- operations.
60
-
61
- - [Service discovery testing](../../../modules/service-discovery/docs/testing.md)
62
- - [HTTP testing](../../../modules/http/docs/testing.md)
63
- - [OpenAPI mock](../../../utils/openapi-mock/README.md)
64
-
65
- An HTTP middleware handles only requests for which it returns a `Response`. Calling
66
- `next(uri, init)` delegates to the next middleware and eventually the real network.
67
-
68
- ## Events, analytics, and telemetry
69
-
70
- - Observe the real event provider with `waitForEvent` or `watchEvents` from
71
- `@equinor/fusion-framework-module-event/utils`.
72
- - Register `MockAnalyticsAdapter` to record analytics without exporting them.
73
- - Use `enableTelemetryMock` and assert through `MockTelemetryAdapter.getItems` or
74
- `waitForItem`.
75
-
76
- - [Event testing utilities](../../../modules/event/docs/testing.md)
77
- - [Analytics testing](../../../modules/analytics/docs/testing.md)
78
- - [Telemetry testing](../../../modules/telemetry/README.md#testing)
79
-
80
- ## Seed several app dependencies
81
-
82
- Compose the app's real configuration with the module mocks required by the scenario:
83
-
84
- ```tsx
85
- import { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
86
- import { enableFeatureFlagMock } from '@equinor/fusion-framework-module-feature-flag/mock';
87
- import { test as baseTest } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
88
-
89
- const project = {
90
- id: 'project-a',
91
- title: 'Project A',
92
- type: { id: 'ProjectMaster' },
93
- value: {},
94
- };
95
-
96
- export const test = baseTest.extend('configureApp', ({ configureApp }) => (configurator, args) => {
97
- configureApp?.(configurator, args);
98
- configurator.msal.setAccount({ name: 'Ada Lovelace' });
99
- enableContextMock(configurator, (mock) => mock.setCurrentContext(project));
100
- enableFeatureFlagMock(configurator, (mock) => {
101
- mock.addFeature({ key: 'new-search', enabled: true });
102
- });
103
- });
104
- ```
105
-
106
- The fixture declarations are reusable, while every test still receives fresh framework and
107
- app module instances.
108
-
109
- ## Choose direct module mocks or HTTP
110
-
111
- - Use a module mock for known domain state such as one current context, one account, or a set
112
- of feature flags.
113
- - Use `configurator.http.addMiddleware` when the test must exercise the module's production
114
- service-discovery, HTTP-client, and response-handling pipeline.
115
- - Use `createOpenApiMockMiddleware` when an OpenAPI document describes many operations.
116
- - Use Vitest `vi.fn`, `vi.spyOn`, or `vi.mock` for individual JavaScript calls rather than a
117
- Fusion-specific wrapper.
118
-
119
- See each owning package README or `docs/testing.md` for its defaults, builder methods, and
120
- failure behavior.
package/docs/overview.md DELETED
@@ -1,49 +0,0 @@
1
- # Test Fusion React apps
2
-
3
- Fusion Framework uses Vitest for application tests. Vitest shares Vite's module and
4
- configuration model, runs components in a real browser, and owns the test runner, assertions,
5
- fixtures, spies, coverage, and editor integration. Fusion provides only the application scope
6
- and deterministic platform boundaries needed to test production behavior.
7
-
8
- Use `@equinor/fusion-framework-vitest-plugin-react-app` when a React hook, component, route,
9
- or complete app consumes Fusion modules. The package resolves app files, initializes the real
10
- framework and app provider nesting, and substitutes supported external clients without
11
- introducing a second testing language.
12
-
13
- ## Choose the subject
14
-
15
- | Subject | Start with | What the test proves |
16
- | --- | --- | --- |
17
- | Pure function or framework-independent hook | Standard Vitest | Local behavior without a Fusion runtime |
18
- | Hook that consumes Fusion app modules | `renderAppHook` | Hook behavior inside an initialized app scope |
19
- | Component that consumes Fusion app modules | `/test` `render` fixture or `renderAppComponent` | Rendered behavior with real providers |
20
- | Route or complete application | `/test` `test` and `render` | App configuration, navigation, loaders, and module lifecycle together |
21
- | Framework or module integration without React | Package `/mock` entry points | Production provider behavior with external boundaries substituted |
22
-
23
- Prefer the smallest layer containing the behavior under assertion. A component test should
24
- not recreate a portal, while an app lifecycle test should not replace every Fusion hook with
25
- a JavaScript module mock.
26
-
27
- ## Start here
28
-
29
- Follow [Getting started](getting-started.md) to install the browser dependencies, configure
30
- Vitest, and run one deterministic app test without credentials, a portal, or backend services.
31
-
32
- ## Continue by task
33
-
34
- - [Configure Vitest defaults and non-standard app files](configuration.md)
35
- - [Compose fixtures and explicit render options](advanced.md)
36
- - [Seed Fusion module dependencies](module-mocks.md)
37
- - [Troubleshoot browser, app-resolution, and network failures](troubleshooting.md)
38
- - [Understand the Browser Mode default or choose another renderer](why-browser-mode.md)
39
- - [Migrate an existing app from Testing Library and DOM emulation](migrating-an-existing-app.md)
40
- - [Choose between app, framework, module, and HTTP testing](../../../framework/docs/testing-choosing-a-layer.md)
41
-
42
- Use the official Vitest documentation for generic runner concepts:
43
-
44
- - [Why Vitest](https://vitest.dev/guide/why)
45
- - [Writing tests](https://vitest.dev/guide/learn/writing-tests)
46
- - [Browser Mode](https://vitest.dev/guide/browser/)
47
- - [Test context and fixtures](https://vitest.dev/guide/test-context)
48
- - [Configuration](https://vitest.dev/config/)
49
- - [Mocking](https://vitest.dev/guide/mocking)
@@ -1,67 +0,0 @@
1
- # Troubleshoot Fusion React app tests
2
-
3
- Use this guide when a Fusion app test fails before the assertion, loads real services, cannot
4
- resolve the app, or behaves differently in Vitest Browser Mode.
5
-
6
- ## Common symptoms
7
-
8
- | Symptom | Likely cause | Resolution |
9
- | --- | --- | --- |
10
- | Chromium executable is missing | Playwright installed without its browser binary | Run `pnpm exec playwright install chromium` |
11
- | The `/test` import cannot resolve Fusion virtual modules | `appTestVitePlugin` is not registered in this Vitest project | Export `defineProject()` from the package's `/config` entry point or register `appTestVitePlugin()` manually |
12
- | `FileNotFoundError` names a manifest, config, or configurator | An explicit plugin path does not exist | Correct the path relative to the Vitest project root; explicit paths fail instead of falling back |
13
- | The app's module configuration is not applied | No conventional `src/config.ts(x|js)` file was found | Pass `configure` to `appTestVitePlugin` or override the `configure` fixture |
14
- | A render result is a Promise or assertions run before initialization | A Fusion render helper was not awaited | Await `render`, `renderHook`, `renderAppComponent`, or `renderAppHook` |
15
- | A request reaches a live backend or fails with a network error | No HTTP middleware answered it | Add a matching `configurator.http.addMiddleware`; unmatched requests eventually reach the real network |
16
- | A lazy route import reloads the browser during a test | Source warmup no longer covers the lazy module | Keep `server.warmup.clientFiles` aligned with application source and route locations |
17
- | No tests are found | Tests are outside the default `src/**/*.{test,spec}.{ts,tsx}` pattern | Override `test.include` in `defineProject` |
18
- | The app starts signed in unexpectedly | The MSAL mock defaults to `Test User` | Set `configurator.msal.setAccount(null)` before rendering |
19
- | State configured in one test is missing in another | Framework and app fixtures are test-scoped | Seed the required state per test or publish reusable fixture declarations with `test.extend` |
20
- | `vi.spyOn` fails on an imported module in Browser Mode | Native ESM module namespace objects are sealed | Use `vi.mock('./module.js', { spy: true })` as documented by Vitest Browser Mode |
21
- | A `<Router>` route with a catch-all or parameterized `path` never renders; every query on it times out | The navigation module's current location does not match that path yet | Push the target location through the navigation module (`app.modules.navigation.push(path)`) before rendering, not after |
22
- | A virtualized list or popover (for example an EDS `Autocomplete` built on `@tanstack/react-virtual`) never renders its rows | `window.ResizeObserver` was stubbed as a no-op in test setup | Remove the stub; real Chromium's `ResizeObserver` is required for virtualized layout to measure correctly |
23
- | `test.each` runs but a fixture in its per-case callback is `undefined` | `test.each` does not forward `test.extend` fixture context to each case | Use Vitest's `test.for` instead, which does receive fixture context |
24
-
25
- ## Verify the project wiring
26
-
27
- Start with the smallest configuration:
28
-
29
- ```ts
30
- import { defineProject } from '@equinor/fusion-framework-vitest-plugin-react-app/config';
31
-
32
- export default defineProject();
33
- ```
34
-
35
- Then verify the fixture itself before testing application behavior:
36
-
37
- ```tsx
38
- import { expect } from 'vitest';
39
- import { test } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
40
-
41
- test('initializes a Fusion app scope', async ({ app, render }) => {
42
- expect(app.auth.account?.name).toBe('Test User');
43
- const screen = await render(<div>ready</div>);
44
- await expect.element(screen.getByText('ready')).toBeVisible();
45
- });
46
- ```
47
-
48
- If this test fails, fix project or app-file resolution before adding module-specific data.
49
-
50
- ## Keep tests offline
51
-
52
- Fusion mocks replace known external boundaries, but an HTTP middleware is an ordered chain.
53
- Returning `next(uri, init)` delegates to the next middleware and eventually `fetch`. A test
54
- that must never use the network should register middleware for every expected request and
55
- fail deliberately on unexpected requests.
56
-
57
- Use `createOpenApiMockMiddleware` from
58
- `@equinor/fusion-framework-module-http/mock` when an OpenAPI document describes many routes.
59
- Use `vi.fn` around a middleware when the test also needs call assertions.
60
-
61
- ## Related references
62
-
63
- - [Getting started](getting-started.md)
64
- - [Configuration and app-file resolution](configuration.md)
65
- - [Choose a Fusion testing layer](../../../framework/docs/testing-choosing-a-layer.md)
66
- - [HTTP middleware testing](../../../modules/http/docs/testing.md)
67
- - [Vitest Browser Mode limitations](https://vitest.dev/guide/browser/#limitations)