@equinor/fusion-framework-app 13.0.0 → 14.0.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 (47) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +35 -65
  3. package/dist/esm/__tests__/mock/AppMockConfigurator.test.js +70 -0
  4. package/dist/esm/__tests__/mock/AppMockConfigurator.test.js.map +1 -0
  5. package/dist/esm/__tests__/mock/mock-app.test.js +86 -0
  6. package/dist/esm/__tests__/mock/mock-app.test.js.map +1 -0
  7. package/dist/esm/__tests__/mock/msal-hoisting.test.js +36 -0
  8. package/dist/esm/__tests__/mock/msal-hoisting.test.js.map +1 -0
  9. package/dist/esm/configure-modules.js +2 -42
  10. package/dist/esm/configure-modules.js.map +1 -1
  11. package/dist/esm/initialize-app-modules.js +65 -0
  12. package/dist/esm/initialize-app-modules.js.map +1 -0
  13. package/dist/esm/mock/AppMockConfigurator.js +183 -0
  14. package/dist/esm/mock/AppMockConfigurator.js.map +1 -0
  15. package/dist/esm/mock/enable-app-manifest-mock.js +49 -0
  16. package/dist/esm/mock/enable-app-manifest-mock.js.map +1 -0
  17. package/dist/esm/mock/index.js +21 -0
  18. package/dist/esm/mock/index.js.map +1 -0
  19. package/dist/esm/mock/mock-app-modules.js +82 -0
  20. package/dist/esm/mock/mock-app-modules.js.map +1 -0
  21. package/dist/esm/version.js +1 -1
  22. package/dist/esm/version.js.map +1 -1
  23. package/dist/tsconfig.tsbuildinfo +1 -1
  24. package/dist/types/__tests__/mock/AppMockConfigurator.test.d.ts +1 -0
  25. package/dist/types/__tests__/mock/mock-app.test.d.ts +1 -0
  26. package/dist/types/__tests__/mock/msal-hoisting.test.d.ts +1 -0
  27. package/dist/types/initialize-app-modules.d.ts +31 -0
  28. package/dist/types/mock/AppMockConfigurator.d.ts +142 -0
  29. package/dist/types/mock/enable-app-manifest-mock.d.ts +33 -0
  30. package/dist/types/mock/index.d.ts +20 -0
  31. package/dist/types/mock/mock-app-modules.d.ts +72 -0
  32. package/dist/types/version.d.ts +1 -1
  33. package/docs/bookmarks.md +18 -0
  34. package/docs/http-clients.md +71 -0
  35. package/docs/testing.md +105 -0
  36. package/package.json +22 -13
  37. package/src/__tests__/mock/AppMockConfigurator.test.ts +96 -0
  38. package/src/__tests__/mock/mock-app.test.ts +112 -0
  39. package/src/__tests__/mock/msal-hoisting.test.ts +54 -0
  40. package/src/configure-modules.ts +2 -52
  41. package/src/initialize-app-modules.ts +98 -0
  42. package/src/mock/AppMockConfigurator.ts +218 -0
  43. package/src/mock/enable-app-manifest-mock.ts +62 -0
  44. package/src/mock/index.ts +21 -0
  45. package/src/mock/mock-app-modules.ts +109 -0
  46. package/src/version.ts +1 -1
  47. package/vitest.config.ts +1 -1
@@ -0,0 +1,62 @@
1
+ import type { FrameworkMockConfigurator } from '@equinor/fusion-framework/mock';
2
+ import { AppConfig, enableAppModule, type AppModule } from '@equinor/fusion-framework-module-app';
3
+ import { MockAppClient } from '@equinor/fusion-framework-module-app/mock';
4
+ import type { ConfigEnvironment } from '@equinor/fusion-framework-module-app';
5
+
6
+ import type { AppEnv } from '../types.js';
7
+
8
+ /**
9
+ * Enables the `app` module on a parent framework configurator, wrapping its
10
+ * client in a {@link MockAppClient} so this app's manifest and config resolve
11
+ * locally.
12
+ *
13
+ * @remarks
14
+ * The underlying http client is still resolved the same way `AppConfigurator`
15
+ * resolves it (a pre-configured client, falling back to service discovery), so
16
+ * a caller pointing `serviceDiscovery` at something else — e.g. a real local
17
+ * mock server — is honored for every request `MockAppClient` doesn't answer
18
+ * itself. {@link mockAppModules} uses this to wire its zero-config default
19
+ * parent; call it directly when building a custom parent (via
20
+ * {@link mockFramework}) that also needs this app's own manifest servable.
21
+ *
22
+ * @param configurator - The parent framework's mock configurator, with `app` in its module set.
23
+ * @param env - The application environment whose manifest (and optional config) should be served.
24
+ * @param assetUri - Overrides the base URI a loaded app's script is imported from.
25
+ * @template TEnv - The application environment descriptor.
26
+ *
27
+ * @example Custom service discovery, same manifest resolution
28
+ * ```typescript
29
+ * const fusion = await mockFramework<[AppModule]>((configurator) => {
30
+ * configurator.serviceDiscovery.setBaseUri('http://localhost:9999');
31
+ * enableAppManifestMock(configurator, env);
32
+ * });
33
+ * const modules = await mockAppModules(undefined, env, fusion);
34
+ * ```
35
+ */
36
+ export function enableAppManifestMock<TEnv extends AppEnv>(
37
+ configurator: FrameworkMockConfigurator<[AppModule]>,
38
+ env: TEnv,
39
+ assetUri?: string,
40
+ ): void {
41
+ enableAppModule(configurator, (builder) => {
42
+ // only override the default asset base when the caller supplies one; an
43
+ // explicit empty string is meaningful (selects a root-relative script path)
44
+ if (assetUri !== undefined) {
45
+ builder.setAssetUri(assetUri);
46
+ }
47
+ builder.setClient(async ({ requireInstance }) => {
48
+ const http = await requireInstance('http');
49
+ const client = http.hasClient('apps')
50
+ ? http.createClient('apps')
51
+ : await (await requireInstance('serviceDiscovery')).createClient('apps');
52
+ // fall back to a trivial config so `App.initialize()` can resolve without a caller-supplied one
53
+ return new MockAppClient(
54
+ client,
55
+ env.manifest,
56
+ env.config ?? new AppConfig<ConfigEnvironment>({ environment: {} }),
57
+ );
58
+ });
59
+ });
60
+ }
61
+
62
+ export default enableAppManifestMock;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Zero-configuration application module pipelines for tests.
3
+ *
4
+ * @remarks
5
+ * Lets a test initialize an application's real module pipeline — real
6
+ * `event`/`http`/`msal` modules, real configuration pipeline, real lifecycle —
7
+ * while the boundaries that reach outside the process are substituted with the
8
+ * same deterministic fakes {@link https://www.npmjs.com/package/@equinor/fusion-framework | @equinor/fusion-framework}'s
9
+ * own `/mock` entry point uses. No credentials, no network access and no
10
+ * running parent portal are required.
11
+ *
12
+ * This entry point is test-runner agnostic: it contains no dependency on
13
+ * Vitest or any other test framework, so the same helpers work under any
14
+ * runner.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+
19
+ export { mockAppModules, type AppMockConfigureFn } from './mock-app-modules.js';
20
+ export { AppMockConfigurator } from './AppMockConfigurator.js';
21
+ export { enableAppManifestMock } from './enable-app-manifest-mock.js';
@@ -0,0 +1,109 @@
1
+ import type { Fusion } from '@equinor/fusion-framework';
2
+ import { mockFramework } from '@equinor/fusion-framework/mock';
3
+
4
+ import type { AnyModule } from '@equinor/fusion-framework-module';
5
+ import type { AppModule } from '@equinor/fusion-framework-module-app';
6
+
7
+ import { initializeAppModules } from '../initialize-app-modules.js';
8
+ import type { AppEnv, AppModulesInstance } from '../types.js';
9
+
10
+ import { AppMockConfigurator } from './AppMockConfigurator.js';
11
+ import { enableAppManifestMock } from './enable-app-manifest-mock.js';
12
+
13
+ /**
14
+ * Configuration callback for {@link mockAppModules}.
15
+ */
16
+ export type AppMockConfigureFn<
17
+ TModules extends Array<AnyModule> | unknown = unknown,
18
+ TEnv extends AppEnv = AppEnv,
19
+ > = (
20
+ configurator: AppMockConfigurator<TModules, Fusion['modules'], TEnv>,
21
+ args: { fusion: Fusion; env: TEnv },
22
+ ) => void | Promise<void>;
23
+
24
+ /**
25
+ * Runs an application's module pipeline with no real credentials required,
26
+ * from either the parent framework or the app's own `http`/`msal`
27
+ * registrations.
28
+ *
29
+ * @remarks
30
+ * The real `AppConfigurator` pipeline is run — the real module set, the real
31
+ * configuration pipeline and the real lifecycle. Only the boundaries that
32
+ * would need credentials are substituted by default; the `http` module is
33
+ * the real `HttpClientConfigurator`, so a registered client only avoids the
34
+ * network for requests a middleware short-circuits with a response — a
35
+ * client with no matching middleware, or a middleware that calls `next`,
36
+ * still reaches the real network. A test exercises the wiring an
37
+ * application actually depends on rather than a reimplementation of it.
38
+ *
39
+ * The configurator passed to `cb` is an {@link AppMockConfigurator}, which *is*
40
+ * an `AppConfigurator`. `useFrameworkServiceClient`, `configureHttpClient` and
41
+ * any callback written for a real app work against it unchanged.
42
+ *
43
+ * `fusion` defaults to a fresh {@link mockFramework} instance with a real `app`
44
+ * module already enabled and this app's own manifest served at whatever URI
45
+ * service discovery resolves `'apps'` to, so a test needs no parent Fusion
46
+ * instance of its own — but an already-mocked (or real) instance can be passed
47
+ * to compose with other framework-level setup. To point the parent's service
48
+ * discovery at something else (e.g. a real local mock server) while keeping
49
+ * the manifest served consistently, build that `fusion` with
50
+ * {@link mockFramework} and call {@link enableAppManifestMock} yourself,
51
+ * after customizing `serviceDiscovery`.
52
+ *
53
+ * @template TModules - Module descriptors beyond the default set. Supply this
54
+ * when a test registers application modules, so they are typed on the result.
55
+ * @template TEnv - The application environment descriptor.
56
+ * @param cb - Configuration callback invoked before module initialization, or `undefined` to skip it.
57
+ * @param env - The application environment (manifest, config, basename).
58
+ * @param fusion - The parent Fusion instance; defaults to a fresh {@link mockFramework} instance.
59
+ * @returns The initialized application module instance.
60
+ *
61
+ * @example Zero configuration
62
+ * ```typescript
63
+ * const manifest = { appKey: 'my-app', displayName: 'My App', description: 'My app', type: 'standalone' } as const;
64
+ * const modules = await mockAppModules(undefined, { manifest });
65
+ * ```
66
+ *
67
+ * @example Register a client answered by the app's own mocked HTTP module
68
+ * ```typescript
69
+ * const manifest = { appKey: 'my-app', displayName: 'My App', description: 'My app', type: 'standalone' } as const;
70
+ * const modules = await mockAppModules(
71
+ * (configurator) => {
72
+ * configurator.useFrameworkServiceClient('portal-api');
73
+ * configurator.http.addMiddleware(async (uri, init, next) =>
74
+ * uri === 'https://portal-api.fusion.test/items' ? Response.json([{ id: 1 }]) : next(uri, init),
75
+ * );
76
+ * },
77
+ * { manifest },
78
+ * );
79
+ *
80
+ * const items = await modules.http.createClient('portal-api').json('/items');
81
+ * ```
82
+ */
83
+ export async function mockAppModules<
84
+ TModules extends Array<AnyModule> | unknown = unknown,
85
+ TEnv extends AppEnv = AppEnv,
86
+ >(
87
+ cb: AppMockConfigureFn<TModules, TEnv> | undefined,
88
+ env: TEnv,
89
+ fusion?: Fusion,
90
+ ): Promise<AppModulesInstance<TModules>> {
91
+ // `await` is illegal in a parameter default, so an omitted fusion is resolved here instead.
92
+ // The default parent also carries a real `app` module, serving this app's own manifest at
93
+ // whatever URI service discovery is currently configured to resolve `'apps'` to, so a test
94
+ // exercises the same portal wiring a real parent framework would provide.
95
+ const resolvedFusion: Fusion =
96
+ fusion ??
97
+ (await mockFramework<[AppModule]>((configurator) => enableAppManifestMock(configurator, env)));
98
+ const configurator = new AppMockConfigurator<TModules, Fusion['modules'], TEnv>(env);
99
+ // Cast is safe: `initializeAppModules` returns the exact module instance produced by
100
+ // `configurator`, which was constructed with this same `TModules`. TypeScript widens
101
+ // `TModules` to its constraint (`AnyModule[]`) when inferring through the generic
102
+ // `TConfigurator` parameter, so the assignment needs an explicit assertion here.
103
+ return initializeAppModules(configurator, cb, {
104
+ fusion: resolvedFusion,
105
+ env,
106
+ }) as Promise<AppModulesInstance<TModules>>;
107
+ }
108
+
109
+ export default mockAppModules;
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '13.0.0';
2
+ export const version = '14.0.0-next.0';
package/vitest.config.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defineProject } from 'vitest/config';
2
2
 
3
- import { name, version } from './package.json';
3
+ import { name, version } from './package.json' with { type: 'json' };
4
4
 
5
5
  export default defineProject({
6
6
  test: {