@equinor/fusion-framework-vitest-plugin-react-app 0.2.0-next.0

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 (78) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/LICENSE +21 -0
  3. package/README.md +349 -0
  4. package/dist/esm/app-test.js +9 -0
  5. package/dist/esm/app-test.js.map +1 -0
  6. package/dist/esm/define-project.js +68 -0
  7. package/dist/esm/define-project.js.map +1 -0
  8. package/dist/esm/index.js +99 -0
  9. package/dist/esm/index.js.map +1 -0
  10. package/dist/esm/render-app-component.js +52 -0
  11. package/dist/esm/render-app-component.js.map +1 -0
  12. package/dist/esm/render-app-hook.js +63 -0
  13. package/dist/esm/render-app-hook.js.map +1 -0
  14. package/dist/esm/render.js +49 -0
  15. package/dist/esm/render.js.map +1 -0
  16. package/dist/esm/resolve-app-test-env.js +85 -0
  17. package/dist/esm/resolve-app-test-env.js.map +1 -0
  18. package/dist/esm/scope/create-app-scope-wrapper.js +15 -0
  19. package/dist/esm/scope/create-app-scope-wrapper.js.map +1 -0
  20. package/dist/esm/scope/default-app-env.js +12 -0
  21. package/dist/esm/scope/default-app-env.js.map +1 -0
  22. package/dist/esm/scope/index.js +5 -0
  23. package/dist/esm/scope/index.js.map +1 -0
  24. package/dist/esm/scope/resolve-app-scope.js +21 -0
  25. package/dist/esm/scope/resolve-app-scope.js.map +1 -0
  26. package/dist/esm/scope/resolve-fusion.js +18 -0
  27. package/dist/esm/scope/resolve-fusion.js.map +1 -0
  28. package/dist/esm/test-app.js +59 -0
  29. package/dist/esm/test-app.js.map +1 -0
  30. package/dist/esm/test.js +33 -0
  31. package/dist/esm/test.js.map +1 -0
  32. package/dist/esm/version.js +3 -0
  33. package/dist/esm/version.js.map +1 -0
  34. package/dist/tsconfig.tsbuildinfo +1 -0
  35. package/dist/types/app-test.d.ts +6 -0
  36. package/dist/types/define-project.d.ts +41 -0
  37. package/dist/types/index.d.ts +45 -0
  38. package/dist/types/render-app-component.d.ts +86 -0
  39. package/dist/types/render-app-hook.d.ts +99 -0
  40. package/dist/types/render.d.ts +37 -0
  41. package/dist/types/resolve-app-test-env.d.ts +56 -0
  42. package/dist/types/scope/create-app-scope-wrapper.d.ts +14 -0
  43. package/dist/types/scope/default-app-env.d.ts +5 -0
  44. package/dist/types/scope/index.d.ts +4 -0
  45. package/dist/types/scope/resolve-app-scope.d.ts +31 -0
  46. package/dist/types/scope/resolve-fusion.d.ts +13 -0
  47. package/dist/types/test-app.d.ts +68 -0
  48. package/dist/types/test.d.ts +66 -0
  49. package/dist/types/version.d.ts +1 -0
  50. package/docs/advanced.md +140 -0
  51. package/docs/configuration.md +109 -0
  52. package/docs/getting-started.md +66 -0
  53. package/docs/migrating-an-existing-app.md +197 -0
  54. package/docs/module-mocks.md +120 -0
  55. package/docs/overview.md +49 -0
  56. package/docs/troubleshooting.md +64 -0
  57. package/docs/why-browser-mode.md +113 -0
  58. package/package.json +87 -0
  59. package/src/__tests__/app-test-vite-plugin.test.ts +109 -0
  60. package/src/__tests__/resolve-app-test-env.test.ts +83 -0
  61. package/src/app-test.ts +18 -0
  62. package/src/define-project.ts +84 -0
  63. package/src/index.ts +124 -0
  64. package/src/render-app-component.tsx +116 -0
  65. package/src/render-app-hook.tsx +135 -0
  66. package/src/render.tsx +64 -0
  67. package/src/resolve-app-test-env.ts +132 -0
  68. package/src/scope/create-app-scope-wrapper.tsx +26 -0
  69. package/src/scope/default-app-env.ts +13 -0
  70. package/src/scope/index.ts +4 -0
  71. package/src/scope/resolve-app-scope.ts +46 -0
  72. package/src/scope/resolve-fusion.ts +29 -0
  73. package/src/test-app.tsx +72 -0
  74. package/src/test.tsx +35 -0
  75. package/src/version.ts +2 -0
  76. package/src/virtual-modules.d.ts +12 -0
  77. package/tsconfig.json +24 -0
  78. package/vitest.config.ts +10 -0
@@ -0,0 +1,29 @@
1
+ import type { AppEnv } from '@equinor/fusion-framework-app';
2
+ import type { Fusion } from '@equinor/fusion-framework';
3
+ import { mockFramework } from '@equinor/fusion-framework/mock';
4
+ import { enableAppManifestMock } from '@equinor/fusion-framework-app/mock';
5
+ import type { AppModule } from '@equinor/fusion-framework-module-app';
6
+
7
+ import { defaultAppEnv } from './default-app-env';
8
+
9
+ /**
10
+ * Resolves the parent Fusion instance backing an application module scope, building a
11
+ * fresh {@link mockFramework} instance with this app's own manifest served when none is
12
+ * given.
13
+ *
14
+ * @template TEnv - The application environment descriptor.
15
+ * @param env - The application environment; defaults to {@link defaultAppEnv}.
16
+ * @param fusion - An already-built parent Fusion instance to reuse instead.
17
+ * @returns The given `fusion`, or a fresh mocked parent Fusion instance.
18
+ */
19
+ export async function resolveFusion<TEnv extends AppEnv = AppEnv>(
20
+ env?: TEnv,
21
+ fusion?: Fusion,
22
+ ): Promise<Fusion> {
23
+ return (
24
+ fusion ??
25
+ mockFramework<[AppModule]>((configurator) =>
26
+ enableAppManifestMock(configurator, env ?? (defaultAppEnv as TEnv)),
27
+ )
28
+ );
29
+ }
@@ -0,0 +1,72 @@
1
+ import type { ReactElement } from 'react';
2
+ import { test as baseTest } from 'vitest';
3
+ import { render, renderHook } from 'vitest-browser-react';
4
+ import type { RenderOptions, RenderHookOptions } from 'vitest-browser-react';
5
+
6
+ import { mockAppModules } from '@equinor/fusion-framework-app/mock';
7
+ import type { AppMockConfigureFn } from '@equinor/fusion-framework-app/mock';
8
+ import type { AppEnv } from '@equinor/fusion-framework-app';
9
+
10
+ import { defaultAppEnv, resolveFusion, createAppScopeWrapper } from './scope';
11
+
12
+ /**
13
+ * `vitest`'s `test`, extended with an application module scope fixture.
14
+ *
15
+ * @remarks
16
+ * An alternative to {@link renderAppComponent}/{@link renderAppHook} for a test file whose
17
+ * cases share seeded fixture defaults: `env`/`configure` become suite-level concerns,
18
+ * overridden once per file (or per `describe` block) with `testApp.extend(...)`, rather than
19
+ * an options object repeated on every call. `fusion`/`app` are still instantiated fresh per
20
+ * test — only the seeded defaults are shared, not state between tests. They also resolve
21
+ * lazily: a test that only destructures `app` never pays for rendering anything, and one
22
+ * that only destructures `render`/`renderHook` gets the same fixture wiring automatically.
23
+ *
24
+ * Both entry points stay supported: reach for `renderAppComponent`/`renderAppHook` for a
25
+ * one-off test whose configuration is not shared by the rest of the file; reach for
26
+ * `testApp` when several cases in a file share one set of seeded fixture defaults.
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * testApp('resolves current context', async ({ app, render }) => {
31
+ * const screen = await render(<App />);
32
+ * expect(app.context).toBeDefined();
33
+ * });
34
+ * ```
35
+ *
36
+ * @example Seed a module for every test in a suite
37
+ * ```tsx
38
+ * describe('with a seeded context module', () => {
39
+ * const test = testApp.extend('configure', { injected: true }, () =>
40
+ * (configurator) => enableContextMock(configurator, (mock) => mock.setCurrentContext(projectA)),
41
+ * );
42
+ *
43
+ * test('starts on the seeded context', async ({ render }) => {
44
+ * const screen = await render(<App />);
45
+ * await expect.element(screen.getByText(projectA.title)).toBeVisible();
46
+ * });
47
+ * });
48
+ * ```
49
+ */
50
+ export const testApp = baseTest
51
+ .extend('env', { injected: true }, defaultAppEnv)
52
+ // `test.extend`'s plain-`value` overload rejects function types (ambiguous with the
53
+ // resolver-`fn` overload), so a function-typed fixture default must go through `fn` instead.
54
+ .extend('configure', { injected: true }, () => undefined as AppMockConfigureFn | undefined)
55
+ .extend('fusion', async ({ env }) => resolveFusion(env))
56
+ .extend('app', async ({ configure, env, fusion }) =>
57
+ mockAppModules<unknown, AppEnv>(configure, env as AppEnv, fusion),
58
+ )
59
+ .extend('render', ({ fusion, app }) => {
60
+ const wrapper = createAppScopeWrapper({ framework: fusion, app });
61
+ return (ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>) =>
62
+ render(ui, { ...options, wrapper });
63
+ })
64
+ .extend('renderHook', ({ fusion, app }) => {
65
+ const wrapper = createAppScopeWrapper({ framework: fusion, app });
66
+ return <Result, Props = undefined>(
67
+ cb: (initialProps?: Props) => Result,
68
+ options?: Omit<RenderHookOptions<Props>, 'wrapper'>,
69
+ ) => renderHook(cb, { ...options, wrapper });
70
+ });
71
+
72
+ export default testApp;
package/src/test.tsx ADDED
@@ -0,0 +1,35 @@
1
+ import { testApp as baseTestApp } from './test-app';
2
+
3
+ // resolved at test-time by `appTestVitePlugin` (@equinor/fusion-framework-vitest-plugin-react-app);
4
+ // see virtual-modules.d.ts for the ambient module declarations
5
+ import { manifest, config } from 'virtual:fusion-app-test-env';
6
+ import { configure } from 'virtual:fusion-app-test-configure';
7
+
8
+ /**
9
+ * `vitest`'s `test`, pre-seeded with the application's own manifest, config, and
10
+ * module-configurator, resolved the same way `ffc app build`/`ffc app dev` resolve them.
11
+ *
12
+ * @remarks
13
+ * Requires `appTestVitePlugin` (`@equinor/fusion-framework-vitest-plugin-react-app`) registered in
14
+ * your `vitest.config.ts` `plugins`, which serves the virtual modules backing this fixture.
15
+ * Running the same test file without the plugin registered fails to resolve those imports.
16
+ *
17
+ * Per-test mocking still works exactly like the base `testApp`: `.extend('configure', ...)` or
18
+ * a per-case `test.override('env', ...)` layers on top of the resolved values.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * import { test } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
23
+ * import { App } from '../App';
24
+ *
25
+ * test('renders the app', async ({ render }) => {
26
+ * const screen = await render(<App />);
27
+ * await expect.element(screen.getByRole('heading')).toBeVisible();
28
+ * });
29
+ * ```
30
+ */
31
+ export const test = baseTestApp
32
+ .extend('env', { injected: true }, { manifest, config })
33
+ .extend('configure', { injected: true }, () => configure);
34
+
35
+ export default test;
package/src/version.ts ADDED
@@ -0,0 +1,2 @@
1
+ // Generated by genversion.
2
+ export const version = '0.2.0-next.0';
@@ -0,0 +1,12 @@
1
+ declare module 'virtual:fusion-app-test-env' {
2
+ import type { AppEnv } from '@equinor/fusion-framework-app';
3
+
4
+ export const manifest: AppEnv['manifest'];
5
+ export const config: AppEnv['config'];
6
+ }
7
+
8
+ declare module 'virtual:fusion-app-test-configure' {
9
+ import type { AppMockConfigureFn } from '@equinor/fusion-framework-app/mock';
10
+
11
+ export const configure: AppMockConfigureFn | undefined;
12
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx",
5
+ "outDir": "dist/esm",
6
+ "rootDir": "src",
7
+ "declarationDir": "./dist/types",
8
+ "paths": {
9
+ "*": ["./*"]
10
+ }
11
+ },
12
+ "references": [
13
+ { "path": "../../cli" },
14
+ { "path": "../../framework" },
15
+ { "path": "../../app" },
16
+ { "path": "../../modules/module" },
17
+ { "path": "../../modules/app" },
18
+ { "path": "../../react/framework" },
19
+ { "path": "../../react/modules/module" },
20
+ { "path": "../../utils/imports" }
21
+ ],
22
+ "include": ["src/**/*"],
23
+ "exclude": ["node_modules", "dist", "src/__tests__/**/*"]
24
+ }
@@ -0,0 +1,10 @@
1
+ import { defineProject } from 'vitest/config';
2
+
3
+ import { name, version } from './package.json' with { type: 'json' };
4
+
5
+ export default defineProject({
6
+ test: {
7
+ include: ['src/__tests__/**/*.test.ts'],
8
+ name: `${name}@${version}`,
9
+ },
10
+ });