@equinor/fusion-framework-vitest-plugin-react-app 1.0.0-next.6 → 1.0.1
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.
- package/dist/esm/index.js +9 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/resolve-app-test-env.js +8 -2
- package/dist/esm/resolve-app-test-env.js.map +1 -1
- package/dist/esm/scope/resolve-fusion.js +22 -24
- package/dist/esm/scope/resolve-fusion.js.map +1 -1
- package/dist/esm/test-app.js +5 -8
- package/dist/esm/test-app.js.map +1 -1
- package/dist/esm/test.js +2 -1
- package/dist/esm/test.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +4 -3
- package/dist/types/resolve-app-test-env.d.ts +3 -1
- package/dist/types/scope/resolve-fusion.d.ts +6 -7
- package/dist/types/test-app.d.ts +12 -11
- package/dist/types/test.d.ts +20 -9
- package/dist/types/version.d.ts +1 -1
- package/package.json +17 -19
- package/CHANGELOG.md +0 -196
- package/docs/advanced.md +0 -209
- package/docs/configuration.md +0 -112
- package/docs/getting-started.md +0 -66
- package/docs/migrating-an-existing-app.md +0 -202
- package/docs/module-mocks.md +0 -120
- package/docs/overview.md +0 -49
- package/docs/troubleshooting.md +0 -67
- package/docs/why-browser-mode.md +0 -128
- package/src/__tests__/app-test-vite-plugin.test.ts +0 -109
- package/src/__tests__/merge-env-config.test.ts +0 -67
- package/src/__tests__/resolve-app-test-env.test.ts +0 -83
- package/src/app-test.ts +0 -19
- package/src/define-project.ts +0 -91
- package/src/index.ts +0 -124
- package/src/merge-env-config.ts +0 -58
- package/src/render-app-component.tsx +0 -116
- package/src/render-app-hook.tsx +0 -135
- package/src/render.tsx +0 -64
- package/src/resolve-app-test-env.ts +0 -132
- package/src/scope/create-app-scope-wrapper.tsx +0 -26
- package/src/scope/default-app-env.ts +0 -13
- package/src/scope/index.ts +0 -4
- package/src/scope/resolve-app-scope.ts +0 -46
- package/src/scope/resolve-fusion.ts +0 -74
- package/src/test-app.tsx +0 -148
- package/src/test.tsx +0 -42
- package/src/version.ts +0 -2
- package/src/virtual-modules.d.ts +0 -12
- package/tsconfig.json +0 -26
- package/vitest.config.ts +0 -10
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { FileNotFoundError } from '@equinor/fusion-imports';
|
|
2
|
-
import type { AppManifest } from '@equinor/fusion-framework-module-app';
|
|
3
|
-
import type { RuntimeEnv } from '@equinor/fusion-framework-cli';
|
|
4
|
-
import {
|
|
5
|
-
createAppManifestFromPackage,
|
|
6
|
-
loadAppManifest,
|
|
7
|
-
loadAppConfig,
|
|
8
|
-
mergeAppManifests,
|
|
9
|
-
ApiAppConfigSchema,
|
|
10
|
-
type AppManifestFn,
|
|
11
|
-
type AppConfigFn,
|
|
12
|
-
type ApiAppConfig,
|
|
13
|
-
} from '@equinor/fusion-framework-cli/app';
|
|
14
|
-
import { resolvePackage } from '@equinor/fusion-framework-cli/utils';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The application manifest and config resolved for a test run.
|
|
18
|
-
*/
|
|
19
|
-
export type AppTestEnv = {
|
|
20
|
-
manifest: AppManifest;
|
|
21
|
-
config: ApiAppConfig;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Options for {@link resolveAppTestEnv}.
|
|
26
|
-
*/
|
|
27
|
-
export type ResolveAppTestEnvOptions = {
|
|
28
|
-
/** Directory to resolve the package, manifest, and config from. Defaults to `process.cwd()`. */
|
|
29
|
-
entrypoint?: string;
|
|
30
|
-
/**
|
|
31
|
-
* An explicit manifest file to load instead of the default `app.manifest(.*)?` lookup, or a
|
|
32
|
-
* manifest function (same shape as `defineAppManifest`'s argument) applied directly.
|
|
33
|
-
*/
|
|
34
|
-
manifest?: string | AppManifestFn;
|
|
35
|
-
/**
|
|
36
|
-
* An explicit config file to load instead of the default `app.config(.*)?` lookup, or a
|
|
37
|
-
* config function (same shape as `defineAppConfig`'s argument) applied directly.
|
|
38
|
-
*/
|
|
39
|
-
config?: string | AppConfigFn;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Resolves an application's manifest and config using the same pipeline `ffc app build`/
|
|
44
|
-
* `ffc app dev` use: a base manifest generated from `package.json`, merged with a local
|
|
45
|
-
* `app.manifest.ts` if one exists; and `app.config.ts` for endpoints/environment, falling
|
|
46
|
-
* back to an empty config if none exists.
|
|
47
|
-
*
|
|
48
|
-
* @remarks
|
|
49
|
-
* Intended to seed `@equinor/fusion-framework-vitest-plugin-react-app/test`'s `testApp` `appEnv` fixture, so
|
|
50
|
-
* a test suite exercises the application's real manifest/config instead of a hand-maintained
|
|
51
|
-
* duplicate. Anything a specific test still needs faked (a missing endpoint, a different
|
|
52
|
-
* `appKey`) can be layered on top with `testApp.extend('appEnv', ...)` or a per-test
|
|
53
|
-
* `test.override('appEnv', ...)`.
|
|
54
|
-
*
|
|
55
|
-
* @param options - Resolution options; `entrypoint` defaults to the current working directory.
|
|
56
|
-
* @returns The resolved application manifest and config.
|
|
57
|
-
* @throws If no `package.json` can be found from `entrypoint` upward, or an explicitly requested
|
|
58
|
-
* `manifest`/`config` file does not exist.
|
|
59
|
-
* @example
|
|
60
|
-
* ```ts
|
|
61
|
-
* import { resolveAppTestEnv } from '@equinor/fusion-framework-vitest-plugin-react-app';
|
|
62
|
-
* import { testApp } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
|
|
63
|
-
* import { configure } from '../config';
|
|
64
|
-
*
|
|
65
|
-
* const test = testApp
|
|
66
|
-
* .extend('appEnv', { injected: true }, () => resolveAppTestEnv())
|
|
67
|
-
* .extend('configureApp', { injected: true }, () => configure);
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
export const resolveAppTestEnv = async (
|
|
71
|
-
options?: ResolveAppTestEnvOptions,
|
|
72
|
-
): Promise<AppTestEnv> => {
|
|
73
|
-
const pkg = await resolvePackage({ cwd: options?.entrypoint });
|
|
74
|
-
const env: RuntimeEnv = { command: 'build', mode: 'test', root: pkg.root, environment: 'test' };
|
|
75
|
-
|
|
76
|
-
const baseManifest = createAppManifestFromPackage(env, pkg.packageJson);
|
|
77
|
-
const [manifest, config] = await Promise.all([
|
|
78
|
-
resolveManifest(env, baseManifest, options?.manifest),
|
|
79
|
-
resolveConfig(env, options?.config),
|
|
80
|
-
]);
|
|
81
|
-
|
|
82
|
-
return { manifest, config };
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Loads `app.manifest(.*)?` (or applies an inline {@link AppManifestFn}), falling back to the
|
|
87
|
-
* package-derived manifest when none exists — mirrors `ffc app build`'s own fallback so a test
|
|
88
|
-
* env matches a real build with zero manifest file.
|
|
89
|
-
*/
|
|
90
|
-
const resolveManifest = async (
|
|
91
|
-
env: RuntimeEnv,
|
|
92
|
-
base: AppManifest,
|
|
93
|
-
manifest?: string | AppManifestFn,
|
|
94
|
-
): Promise<AppManifest> => {
|
|
95
|
-
// an inline function is applied directly, the same way a loaded `app.manifest.ts`'s default export would be
|
|
96
|
-
if (typeof manifest === 'function') {
|
|
97
|
-
const result = await manifest(env, { base });
|
|
98
|
-
return mergeAppManifests(base, result ?? {});
|
|
99
|
-
}
|
|
100
|
-
try {
|
|
101
|
-
return (await loadAppManifest(env, { base, file: manifest })).manifest;
|
|
102
|
-
} catch (err) {
|
|
103
|
-
// an explicitly requested manifest that's missing is a real error; only the default lookup falls back
|
|
104
|
-
if (err instanceof FileNotFoundError && !manifest) return base;
|
|
105
|
-
throw err;
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Loads `app.config(.*)?` (or applies an inline {@link AppConfigFn}), falling back to an empty
|
|
111
|
-
* config when none exists — mirrors `ffc app build`'s own fallback so a test env matches a real
|
|
112
|
-
* build with zero config file.
|
|
113
|
-
*/
|
|
114
|
-
const resolveConfig = async (
|
|
115
|
-
env: RuntimeEnv,
|
|
116
|
-
config?: string | AppConfigFn,
|
|
117
|
-
): Promise<ApiAppConfig> => {
|
|
118
|
-
// an inline function is applied directly, the same way a loaded `app.config.ts`'s default export would be
|
|
119
|
-
if (typeof config === 'function') {
|
|
120
|
-
const result = await config(env, { base: { environment: {} } });
|
|
121
|
-
return ApiAppConfigSchema.parse(result ?? { environment: {} });
|
|
122
|
-
}
|
|
123
|
-
try {
|
|
124
|
-
return (await loadAppConfig(env, { file: config })).config;
|
|
125
|
-
} catch (err) {
|
|
126
|
-
// an explicitly requested config that's missing is a real error; only the default lookup falls back
|
|
127
|
-
if (err instanceof FileNotFoundError && !config) return { environment: {} };
|
|
128
|
-
throw err;
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export default resolveAppTestEnv;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
import { FrameworkProvider } from '@equinor/fusion-framework-react';
|
|
4
|
-
import { ModuleProvider } from '@equinor/fusion-framework-react-module';
|
|
5
|
-
import type { AnyModule } from '@equinor/fusion-framework-module';
|
|
6
|
-
|
|
7
|
-
import type { AppScope } from './resolve-app-scope';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The provider nesting `createComponent` uses in production, for wrapping a component or
|
|
11
|
-
* hook under test in its resolved {@link AppScope}.
|
|
12
|
-
*
|
|
13
|
-
* @template TModules - Module descriptors beyond the default set.
|
|
14
|
-
* @param scope - The resolved parent Fusion instance and application module scope.
|
|
15
|
-
* @returns A wrapper component nesting a `FrameworkProvider` around a `ModuleProvider`.
|
|
16
|
-
*/
|
|
17
|
-
export function createAppScopeWrapper<TModules extends Array<AnyModule> | unknown = unknown>({
|
|
18
|
-
framework,
|
|
19
|
-
app,
|
|
20
|
-
}: AppScope<TModules>): (props: { children: ReactNode }) => ReactElement {
|
|
21
|
-
return ({ children }: { children: ReactNode }) => (
|
|
22
|
-
<FrameworkProvider value={framework}>
|
|
23
|
-
<ModuleProvider value={app}>{children}</ModuleProvider>
|
|
24
|
-
</FrameworkProvider>
|
|
25
|
-
);
|
|
26
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { AppEnv } from '@equinor/fusion-framework-app';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The application environment used when a test does not care about its own app identity.
|
|
5
|
-
*/
|
|
6
|
-
export const defaultAppEnv: AppEnv = {
|
|
7
|
-
manifest: {
|
|
8
|
-
appKey: 'test-app',
|
|
9
|
-
displayName: 'Test App',
|
|
10
|
-
description: 'A test application',
|
|
11
|
-
type: 'standalone',
|
|
12
|
-
},
|
|
13
|
-
};
|
package/src/scope/index.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { mockAppModules } from '@equinor/fusion-framework-app/mock';
|
|
2
|
-
import type { AppMockConfigureFn } from '@equinor/fusion-framework-app/mock';
|
|
3
|
-
import type { AppEnv, AppModulesInstance } from '@equinor/fusion-framework-app';
|
|
4
|
-
import type { Fusion } from '@equinor/fusion-framework';
|
|
5
|
-
import type { AnyModule } from '@equinor/fusion-framework-module';
|
|
6
|
-
|
|
7
|
-
import { resolveFusion } from './resolve-fusion';
|
|
8
|
-
import { defaultAppEnv } from './default-app-env';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* The parent Fusion instance and resolved application module scope shared by every
|
|
12
|
-
* `packages/react/app` testing helper.
|
|
13
|
-
*
|
|
14
|
-
* @template TModules - Module descriptors beyond the default set.
|
|
15
|
-
*/
|
|
16
|
-
export interface AppScope<TModules extends Array<AnyModule> | unknown = unknown> {
|
|
17
|
-
/** The parent Fusion instance the application scope was resolved against. */
|
|
18
|
-
framework: Fusion;
|
|
19
|
-
/** The resolved application module instance. */
|
|
20
|
-
app: AppModulesInstance<TModules>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Resolves the parent Fusion instance and application module scope shared by every
|
|
25
|
-
* `packages/react/app` testing helper.
|
|
26
|
-
*
|
|
27
|
-
* @template TModules - Module descriptors beyond the default set.
|
|
28
|
-
* @template TEnv - The application environment descriptor.
|
|
29
|
-
* @param options - A `configure` callback and `env` for {@link mockAppModules}, plus an
|
|
30
|
-
* already-built `fusion` instance to reuse instead of a fresh one.
|
|
31
|
-
* @returns The resolved {@link AppScope}.
|
|
32
|
-
*/
|
|
33
|
-
export async function resolveAppScope<
|
|
34
|
-
TModules extends Array<AnyModule> | unknown = unknown,
|
|
35
|
-
TEnv extends AppEnv = AppEnv,
|
|
36
|
-
>(options?: {
|
|
37
|
-
configure?: AppMockConfigureFn<TModules, TEnv>;
|
|
38
|
-
env?: TEnv;
|
|
39
|
-
fusion?: Fusion;
|
|
40
|
-
}): Promise<AppScope<TModules>> {
|
|
41
|
-
const { configure, env, fusion: providedFusion } = options ?? {};
|
|
42
|
-
const resolvedEnv = env ?? (defaultAppEnv as TEnv);
|
|
43
|
-
const framework = await resolveFusion({ env: resolvedEnv, fusion: providedFusion });
|
|
44
|
-
const app = await mockAppModules(configure, resolvedEnv, framework);
|
|
45
|
-
return { framework, app };
|
|
46
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { AppEnv } from '@equinor/fusion-framework-app';
|
|
2
|
-
import type { Fusion } from '@equinor/fusion-framework';
|
|
3
|
-
import {
|
|
4
|
-
mockFramework,
|
|
5
|
-
type FrameworkMockConfigureFn,
|
|
6
|
-
type FrameworkMockConfigurator,
|
|
7
|
-
} from '@equinor/fusion-framework/mock';
|
|
8
|
-
import { enableAppManifestMock } from '@equinor/fusion-framework-app/mock';
|
|
9
|
-
import type { AppModule } from '@equinor/fusion-framework-module-app';
|
|
10
|
-
import { enableNavigation, createHistory } from '@equinor/fusion-framework-module-navigation';
|
|
11
|
-
import type { NavigationModule } from '@equinor/fusion-framework-module-navigation';
|
|
12
|
-
|
|
13
|
-
import { defaultAppEnv } from './default-app-env';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Enables the feature-flag mock only when `@equinor/fusion-framework-module-feature-flag` — an
|
|
17
|
-
* optional peer dependency — is actually installed, so apps that don't use feature flags aren't
|
|
18
|
-
* forced to install a module they never reference.
|
|
19
|
-
*/
|
|
20
|
-
async function enableFeatureFlagMockIfAvailable(
|
|
21
|
-
configurator: FrameworkMockConfigurator<[AppModule, NavigationModule]>,
|
|
22
|
-
): Promise<void> {
|
|
23
|
-
try {
|
|
24
|
-
const { enableFeatureFlagMock } = await import(
|
|
25
|
-
'@equinor/fusion-framework-module-feature-flag/mock'
|
|
26
|
-
);
|
|
27
|
-
enableFeatureFlagMock(configurator);
|
|
28
|
-
} catch (error) {
|
|
29
|
-
// re-throw anything other than the optional peer being missing, so a real
|
|
30
|
-
// registration failure isn't silently swallowed
|
|
31
|
-
if (
|
|
32
|
-
error instanceof Error &&
|
|
33
|
-
(error.message.includes('Cannot find module') || error.message.includes('MODULE_NOT_FOUND'))
|
|
34
|
-
) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Resolves the parent Fusion instance backing an application module scope, building a
|
|
43
|
-
* fresh {@link mockFramework} instance with this app's own manifest served when none is
|
|
44
|
-
* given.
|
|
45
|
-
*
|
|
46
|
-
* @template TEnv - The application environment descriptor.
|
|
47
|
-
* @param options - `env` seeds the built-in app manifest mock; navigation defaults to in-memory
|
|
48
|
-
* history, so tests don't leak URL/history state between runs. Feature flags default to the
|
|
49
|
-
* in-memory feature-flag mock, with none enabled, when the optional
|
|
50
|
-
* `@equinor/fusion-framework-module-feature-flag` peer dependency is installed. `configure`
|
|
51
|
-
* runs afterwards on the same configurator — e.g. call `enableNavigation` or
|
|
52
|
-
* `enableFeatureFlagMock` again to override either, or register extra modules and service
|
|
53
|
-
* discovery entries. `fusion`, an already-built parent instance, is reused as-is and skips
|
|
54
|
-
* `configure` entirely.
|
|
55
|
-
* @returns The given `fusion`, or a fresh mocked parent Fusion instance.
|
|
56
|
-
*/
|
|
57
|
-
export async function resolveFusion<TEnv extends AppEnv = AppEnv>(options?: {
|
|
58
|
-
env?: TEnv;
|
|
59
|
-
fusion?: Fusion;
|
|
60
|
-
configure?: FrameworkMockConfigureFn<[AppModule, NavigationModule]>;
|
|
61
|
-
}): Promise<Fusion> {
|
|
62
|
-
const { env, fusion, configure } = options ?? {};
|
|
63
|
-
return (
|
|
64
|
-
fusion ??
|
|
65
|
-
mockFramework<[AppModule, NavigationModule]>(async (configurator) => {
|
|
66
|
-
enableAppManifestMock(configurator, env ?? (defaultAppEnv as TEnv));
|
|
67
|
-
enableNavigation(configurator, {
|
|
68
|
-
configure: (config) => config.setHistory(createHistory('memory')),
|
|
69
|
-
});
|
|
70
|
-
await enableFeatureFlagMockIfAvailable(configurator);
|
|
71
|
-
await configure?.(configurator);
|
|
72
|
-
})
|
|
73
|
-
);
|
|
74
|
-
}
|
package/src/test-app.tsx
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
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
|
-
import type { AppModule } from '@equinor/fusion-framework-module-app';
|
|
10
|
-
import type { NavigationModule } from '@equinor/fusion-framework-module-navigation';
|
|
11
|
-
import type { FrameworkMockConfigureFn } from '@equinor/fusion-framework/mock';
|
|
12
|
-
|
|
13
|
-
import { defaultAppEnv, resolveFusion, createAppScopeWrapper } from './scope';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* `vitest`'s `test`, extended with an application module scope fixture.
|
|
17
|
-
*
|
|
18
|
-
* @remarks
|
|
19
|
-
* An alternative to {@link renderAppComponent}/{@link renderAppHook} for a test file whose
|
|
20
|
-
* cases share seeded fixture defaults: `appEnv`/`configureApp` become suite-level concerns,
|
|
21
|
-
* overridden once per file (or per `describe` block) with `testApp.extend(...)`, rather than
|
|
22
|
-
* an options object repeated on every call. `fusion`/`app` are still instantiated fresh per
|
|
23
|
-
* test — only the seeded defaults are shared, not state between tests. They also resolve
|
|
24
|
-
* lazily: a test that only destructures `app` never pays for rendering anything, and one
|
|
25
|
-
* that only destructures `render`/`renderHook` gets the same fixture wiring automatically.
|
|
26
|
-
*
|
|
27
|
-
* Both entry points stay supported: reach for `renderAppComponent`/`renderAppHook` for a
|
|
28
|
-
* one-off test whose configuration is not shared by the rest of the file; reach for
|
|
29
|
-
* `testApp` when several cases in a file share one set of seeded fixture defaults.
|
|
30
|
-
*
|
|
31
|
-
* @remarks `configureApp`/`configureFusion` default to `undefined` here
|
|
32
|
-
* Unlike `@equinor/fusion-framework-vitest-plugin-react-app/test`'s `test`, this `testApp` does
|
|
33
|
-
* not resolve the app's real `src/config.ts` — it requires `appTestVitePlugin`'s Vite virtual
|
|
34
|
-
* modules to load that file as live code, which `testApp` (no Vite dependency) cannot do. Extend
|
|
35
|
-
* `test` from `/test` instead when a suite needs to compose with the app's real configuration.
|
|
36
|
-
*
|
|
37
|
-
* @remarks Overriding `fusion` bypasses `configureFusion`
|
|
38
|
-
* `fusion` and `configureFusion` are not independent: `fusion`'s default resolver is what
|
|
39
|
-
* calls `configureFusion`. `.override('fusion', ...)` replaces that resolver outright, so a
|
|
40
|
-
* `configureFusion` override on the same test/suite is silently never called. Use
|
|
41
|
-
* `configureFusion` to extend the base framework mock; use `fusion` only to replace it
|
|
42
|
-
* entirely (e.g. with a fully custom or non-mocked instance).
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```tsx
|
|
46
|
-
* testApp('resolves current context', async ({ app, render }) => {
|
|
47
|
-
* const screen = await render(<App />);
|
|
48
|
-
* expect(app.context).toBeDefined();
|
|
49
|
-
* });
|
|
50
|
-
* ```
|
|
51
|
-
*
|
|
52
|
-
* @example Seed a module for every test in a suite
|
|
53
|
-
* ```tsx
|
|
54
|
-
* describe('with a seeded context module', () => {
|
|
55
|
-
* const test = testApp.extend(
|
|
56
|
-
* 'configureApp',
|
|
57
|
-
* { injected: true },
|
|
58
|
-
* (): AppMockConfigureFn =>
|
|
59
|
-
* (configurator) =>
|
|
60
|
-
* enableContextMock(configurator, (mock) => mock.setCurrentContext(projectA)),
|
|
61
|
-
* );
|
|
62
|
-
*
|
|
63
|
-
* test('starts on the seeded context', async ({ render }) => {
|
|
64
|
-
* const screen = await render(<App />);
|
|
65
|
-
* await expect.element(screen.getByText(projectA.title)).toBeVisible();
|
|
66
|
-
* });
|
|
67
|
-
* });
|
|
68
|
-
* ```
|
|
69
|
-
*
|
|
70
|
-
* @example Type `app`'s registered modules for consumers
|
|
71
|
-
* ```tsx
|
|
72
|
-
* // `configureApp`'s `TModules` generic only types that callback's own `configurator` parameter.
|
|
73
|
-
* // `app`'s type was already fixed (to `unknown`) when the base `testApp` chain defined it, so a
|
|
74
|
-
* // later `configureApp` override does not retroactively change what `app` is typed as. Re-extend
|
|
75
|
-
* // `app` too, with the same `TModules`, to get a typed `app.navigation` in tests.
|
|
76
|
-
* const test = testApp
|
|
77
|
-
* .extend(
|
|
78
|
-
* 'configureApp',
|
|
79
|
-
* { injected: true },
|
|
80
|
-
* ({ configureApp }): AppMockConfigureFn<[NavigationModule]> =>
|
|
81
|
-
* async (configurator, args) => {
|
|
82
|
-
* await configureApp?.(configurator, args);
|
|
83
|
-
* enableNavigation(configurator, '/app');
|
|
84
|
-
* },
|
|
85
|
-
* )
|
|
86
|
-
* .extend('app', ({ configureApp, appEnv, fusion }) =>
|
|
87
|
-
* mockAppModules<[NavigationModule], AppEnv>(configureApp, appEnv as AppEnv, fusion),
|
|
88
|
-
* );
|
|
89
|
-
*
|
|
90
|
-
* test('exposes the navigation module', async ({ app }) => {
|
|
91
|
-
* expect(app.navigation).toBeDefined();
|
|
92
|
-
* });
|
|
93
|
-
* ```
|
|
94
|
-
*
|
|
95
|
-
* @example Extend the parent framework mock with an application module
|
|
96
|
-
* ```tsx
|
|
97
|
-
* const test = testApp.extend(
|
|
98
|
-
* 'configureFusion',
|
|
99
|
-
* { injected: true },
|
|
100
|
-
* (): FrameworkMockConfigureFn<[AppModule, NavigationModule]> =>
|
|
101
|
-
* (configurator) => {
|
|
102
|
-
* // seed a specific flag rather than merely enabling the mock — that's already the
|
|
103
|
-
* // default when the optional feature-flag peer dependency is installed
|
|
104
|
-
* enableFeatureFlagMock(configurator, (mock) => mock.addFeature({ key: 'new-search', enabled: true }));
|
|
105
|
-
* configurator.serviceDiscovery.addServices([
|
|
106
|
-
* { key: 'people', uri: baseUrl('people') },
|
|
107
|
-
* { key: 'context', uri: baseUrl('context') },
|
|
108
|
-
* ]);
|
|
109
|
-
* },
|
|
110
|
-
* );
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
export const testApp = baseTest
|
|
114
|
-
.extend('appEnv', { injected: true }, defaultAppEnv)
|
|
115
|
-
// `test.extend`'s plain-`value` overload rejects function types (ambiguous with the
|
|
116
|
-
// resolver-`fn` overload), so a function-typed fixture default must go through `fn` instead.
|
|
117
|
-
.extend('configureApp', { injected: true }, () => undefined as AppMockConfigureFn | undefined)
|
|
118
|
-
// Runs after the built-in app manifest/navigation/feature-flag setup, so a test can register
|
|
119
|
-
// extra framework modules, service discovery entries, or call `enableNavigation`/
|
|
120
|
-
// `enableFeatureFlagMock` again to override either, without reimplementing the base setup.
|
|
121
|
-
.extend(
|
|
122
|
-
'configureFusion',
|
|
123
|
-
{ injected: true },
|
|
124
|
-
() => undefined as FrameworkMockConfigureFn<[AppModule, NavigationModule]> | undefined,
|
|
125
|
-
)
|
|
126
|
-
// IMPORTANT: `.override('fusion', ...)` replaces this resolver entirely, so `configureFusion`
|
|
127
|
-
// is never called — reach for `configureFusion` to extend the base mock, `fusion` only to
|
|
128
|
-
// replace it outright (e.g. with a fully custom or non-mocked instance).
|
|
129
|
-
.extend('fusion', async ({ appEnv, configureFusion }) =>
|
|
130
|
-
resolveFusion({ env: appEnv, configure: configureFusion }),
|
|
131
|
-
)
|
|
132
|
-
.extend('app', async ({ configureApp, appEnv, fusion }) =>
|
|
133
|
-
mockAppModules<unknown, AppEnv>(configureApp, appEnv as AppEnv, fusion),
|
|
134
|
-
)
|
|
135
|
-
.extend('render', ({ fusion, app }) => {
|
|
136
|
-
const wrapper = createAppScopeWrapper({ framework: fusion, app });
|
|
137
|
-
return (ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>) =>
|
|
138
|
-
render(ui, { ...options, wrapper });
|
|
139
|
-
})
|
|
140
|
-
.extend('renderHook', ({ fusion, app }) => {
|
|
141
|
-
const wrapper = createAppScopeWrapper({ framework: fusion, app });
|
|
142
|
-
return <Result, Props = undefined>(
|
|
143
|
-
cb: (initialProps?: Props) => Result,
|
|
144
|
-
options?: Omit<RenderHookOptions<Props>, 'wrapper'>,
|
|
145
|
-
) => renderHook(cb, { ...options, wrapper });
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
export default testApp;
|
package/src/test.tsx
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
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 as configureApp } 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('configureApp', ...)` or
|
|
18
|
-
* a per-case `test.override('appEnv', ...)` layers on top of the resolved values.
|
|
19
|
-
*
|
|
20
|
-
* @remarks `.override('configureApp', ...)` replaces the app's real `configure`
|
|
21
|
-
* This fixture's default value *is* the app's real `src/config.ts` `configure` export.
|
|
22
|
-
* `.override('configureApp', ...)` replaces that default outright, so an override that doesn't
|
|
23
|
-
* itself call the real `configure(configurator, args)` skips the app's production module setup
|
|
24
|
-
* entirely, rather than composing with it. See [Advanced usage](../docs/advanced.md) for the
|
|
25
|
-
* compose-safely pattern.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```tsx
|
|
29
|
-
* import { test } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
|
|
30
|
-
* import { App } from '../App';
|
|
31
|
-
*
|
|
32
|
-
* test('renders the app', async ({ render }) => {
|
|
33
|
-
* const screen = await render(<App />);
|
|
34
|
-
* await expect.element(screen.getByRole('heading')).toBeVisible();
|
|
35
|
-
* });
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export const test = baseTestApp
|
|
39
|
-
.extend('appEnv', { injected: true }, { manifest, config })
|
|
40
|
-
.extend('configureApp', { injected: true }, () => configureApp);
|
|
41
|
-
|
|
42
|
-
export default test;
|
package/src/version.ts
DELETED
package/src/virtual-modules.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
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": "../../modules/navigation" },
|
|
19
|
-
{ "path": "../../modules/feature-flag" },
|
|
20
|
-
{ "path": "../../react/framework" },
|
|
21
|
-
{ "path": "../../react/modules/module" },
|
|
22
|
-
{ "path": "../../utils/imports" }
|
|
23
|
-
],
|
|
24
|
-
"include": ["src/**/*"],
|
|
25
|
-
"exclude": ["node_modules", "dist", "src/__tests__/**/*"]
|
|
26
|
-
}
|
package/vitest.config.ts
DELETED