@equinor/fusion-framework-react-app 14.0.3-next.0 → 14.0.3

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 (54) hide show
  1. package/CHANGELOG.md +2 -10
  2. package/README.md +2 -9
  3. package/dist/esm/create-component.js +1 -1
  4. package/dist/esm/msal/useToken.js +3 -12
  5. package/dist/esm/msal/useToken.js.map +1 -1
  6. package/dist/esm/version.js +1 -1
  7. package/dist/esm/version.js.map +1 -1
  8. package/dist/tsconfig.tsbuildinfo +1 -1
  9. package/dist/types/create-component.d.ts +1 -1
  10. package/dist/types/version.d.ts +1 -1
  11. package/docs/bookmark.md +0 -7
  12. package/docs/context.md +1 -3
  13. package/docs/framework.md +2 -2
  14. package/docs/msal.md +3 -3
  15. package/package.json +25 -77
  16. package/src/__tests__/useStateSyncEvents.test.ts +11 -12
  17. package/src/create-component.tsx +1 -1
  18. package/src/msal/useToken.ts +3 -14
  19. package/src/version.ts +1 -1
  20. package/tsconfig.json +0 -6
  21. package/vitest.config.ts +8 -2
  22. package/dist/esm/ag-grid/community.js +0 -12
  23. package/dist/esm/ag-grid/community.js.map +0 -1
  24. package/dist/esm/ag-grid/enterprise.js +0 -12
  25. package/dist/esm/ag-grid/enterprise.js.map +0 -1
  26. package/dist/esm/ag-grid/react.js +0 -12
  27. package/dist/esm/ag-grid/react.js.map +0 -1
  28. package/dist/esm/ag-grid/testing.js +0 -19
  29. package/dist/esm/ag-grid/testing.js.map +0 -1
  30. package/dist/esm/ag-grid/theme.js +0 -13
  31. package/dist/esm/ag-grid/theme.js.map +0 -1
  32. package/dist/types/ag-grid/community.d.ts +0 -11
  33. package/dist/types/ag-grid/enterprise.d.ts +0 -11
  34. package/dist/types/ag-grid/react.d.ts +0 -11
  35. package/dist/types/ag-grid/testing.d.ts +0 -18
  36. package/dist/types/ag-grid/theme.d.ts +0 -13
  37. package/src/__tests__/Apploader.test.tsx +0 -51
  38. package/src/__tests__/fixtures/apploader-child-script.ts +0 -9
  39. package/src/__tests__/testApp.test.tsx +0 -76
  40. package/src/__tests__/useAccessToken.test.tsx +0 -51
  41. package/src/__tests__/useAppSetting.test.tsx +0 -133
  42. package/src/__tests__/useAppSettings.test.tsx +0 -147
  43. package/src/__tests__/useCurrentAccount.test.tsx +0 -32
  44. package/src/__tests__/useCurrentBookmark.test.tsx +0 -108
  45. package/src/__tests__/useCurrentContext.test.tsx +0 -72
  46. package/src/__tests__/useFeature.test.tsx +0 -104
  47. package/src/__tests__/useHelpCenter.test.tsx +0 -64
  48. package/src/__tests__/useToken.test.tsx +0 -71
  49. package/src/__tests__/useTrackFeature.test.tsx +0 -83
  50. package/src/ag-grid/community.ts +0 -11
  51. package/src/ag-grid/enterprise.ts +0 -11
  52. package/src/ag-grid/react.ts +0 -11
  53. package/src/ag-grid/testing.ts +0 -19
  54. package/src/ag-grid/theme.ts +0 -17
@@ -1,104 +0,0 @@
1
- import { act } from 'react';
2
- import { describe, expect, it, vi } from 'vitest';
3
-
4
- import { mockFramework } from '@equinor/fusion-framework/mock';
5
- import { enableAppManifestMock } from '@equinor/fusion-framework-app/mock';
6
- import type { AppMockConfigureFn } from '@equinor/fusion-framework-app/mock';
7
- import type { AppModule } from '@equinor/fusion-framework-module-app';
8
- import { enableFeatureFlagMock } from '@equinor/fusion-framework-module-feature-flag/mock';
9
- import type { FeatureFlagModule } from '@equinor/fusion-framework-module-feature-flag';
10
-
11
- import { useFeature } from '../feature-flag/useFeature';
12
- import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
13
-
14
- const env = {
15
- manifest: {
16
- appKey: 'test-app',
17
- displayName: 'Test App',
18
- description: 'A test application',
19
- type: 'standalone' as const,
20
- },
21
- };
22
-
23
- describe('useFeature', () => {
24
- it('resolves a flag seeded on the app scope when the framework has no feature-flag module', async () => {
25
- const fusion = await mockFramework<[AppModule]>((configurator) =>
26
- enableAppManifestMock(configurator, env),
27
- );
28
- const configure: AppMockConfigureFn<[FeatureFlagModule]> = (configurator) => {
29
- enableFeatureFlagMock(configurator, (mock) => {
30
- mock.addFeature({ key: 'dark-mode', enabled: true });
31
- });
32
- };
33
-
34
- const { result } = await renderAppHook(() => useFeature('dark-mode'), {
35
- env,
36
- fusion,
37
- configure,
38
- });
39
-
40
- await vi.waitFor(() => expect(result.current.feature?.enabled).toBe(true));
41
- });
42
-
43
- it('lets an app-scoped flag override a framework-scoped flag with the same key', async () => {
44
- const fusion = await mockFramework<[AppModule, FeatureFlagModule]>((configurator) => {
45
- enableAppManifestMock(configurator, env);
46
- enableFeatureFlagMock(configurator, (mock) => {
47
- mock.addFeature({ key: 'dark-mode', enabled: false });
48
- });
49
- });
50
- const configure: AppMockConfigureFn<[FeatureFlagModule]> = (configurator) => {
51
- enableFeatureFlagMock(configurator, (mock) => {
52
- mock.addFeature({ key: 'dark-mode', enabled: true });
53
- });
54
- };
55
-
56
- const { result } = await renderAppHook(() => useFeature('dark-mode'), {
57
- env,
58
- fusion,
59
- configure,
60
- });
61
-
62
- await vi.waitFor(() => expect(result.current.feature?.enabled).toBe(true));
63
- });
64
-
65
- it('exposes a framework-only flag through the merged stream when the app has not seeded it', async () => {
66
- const fusion = await mockFramework<[AppModule, FeatureFlagModule]>((configurator) => {
67
- enableAppManifestMock(configurator, env);
68
- enableFeatureFlagMock(configurator, (mock) => {
69
- mock.addFeature({ key: 'framework-only', enabled: true });
70
- });
71
- });
72
- const configure: AppMockConfigureFn<[FeatureFlagModule]> = (configurator) => {
73
- enableFeatureFlagMock(configurator);
74
- };
75
-
76
- const { result } = await renderAppHook(() => useFeature('framework-only'), {
77
- env,
78
- fusion,
79
- configure,
80
- });
81
-
82
- await vi.waitFor(() => expect(result.current.feature?.enabled).toBe(true));
83
- });
84
-
85
- it('inverts the current value when toggleFeature is called without an explicit value', async () => {
86
- const fusion = await mockFramework<[AppModule]>((configurator) =>
87
- enableAppManifestMock(configurator, env),
88
- );
89
- const configure: AppMockConfigureFn<[FeatureFlagModule]> = (configurator) => {
90
- enableFeatureFlagMock(configurator, (mock) => {
91
- mock.addFeature({ key: 'my-flag', enabled: false });
92
- });
93
- };
94
-
95
- const { result } = await renderAppHook(() => useFeature('my-flag'), { env, fusion, configure });
96
- await vi.waitFor(() => expect(result.current.feature?.enabled).toBe(false));
97
-
98
- act(() => {
99
- result.current.toggleFeature();
100
- });
101
-
102
- await vi.waitFor(() => expect(result.current.feature?.enabled).toBe(true));
103
- });
104
- });
@@ -1,64 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
-
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 useAppModule from '../useAppModule';
8
- import { useHelpCenter } from '../help-center/useHelpCenter';
9
- import { EVENT_NAME } from '../help-center/event-name.js';
10
- import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
11
-
12
- const env = {
13
- manifest: {
14
- appKey: 'test-app',
15
- displayName: 'Test App',
16
- description: 'A test application',
17
- type: 'standalone' as const,
18
- },
19
- };
20
-
21
- describe('useHelpCenter', () => {
22
- it('dispatches the expected page and detail for every help-center action', async () => {
23
- const fusion = await mockFramework<[AppModule]>((configurator) =>
24
- enableAppManifestMock(configurator, env),
25
- );
26
-
27
- const { result } = await renderAppHook(
28
- () => ({ helpCenter: useHelpCenter(), eventModule: useAppModule('event') }),
29
- { env, fusion },
30
- );
31
-
32
- const received: Array<{ page: string } & Record<string, unknown>> = [];
33
- result.current.eventModule.addEventListener(EVENT_NAME, (event) => {
34
- received.push(event.detail as { page: string } & Record<string, unknown>);
35
- });
36
-
37
- result.current.helpCenter.openHelp();
38
- await vi.waitFor(() => expect(received).toHaveLength(1));
39
-
40
- result.current.helpCenter.openArticle('my-article');
41
- await vi.waitFor(() => expect(received).toHaveLength(2));
42
-
43
- result.current.helpCenter.openFaqs();
44
- await vi.waitFor(() => expect(received).toHaveLength(3));
45
-
46
- result.current.helpCenter.openSearch('my search');
47
- await vi.waitFor(() => expect(received).toHaveLength(4));
48
-
49
- result.current.helpCenter.openGovernance();
50
- await vi.waitFor(() => expect(received).toHaveLength(5));
51
-
52
- result.current.helpCenter.openReleaseNotes();
53
- await vi.waitFor(() => expect(received).toHaveLength(6));
54
-
55
- expect(received).toEqual([
56
- { page: 'home' },
57
- { page: 'article', articleId: 'my-article' },
58
- { page: 'faqs' },
59
- { page: 'search', search: 'my search' },
60
- { page: 'governance' },
61
- { page: 'release-notes' },
62
- ]);
63
- });
64
- });
@@ -1,71 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
-
3
- import { mockFramework } from '@equinor/fusion-framework/mock';
4
-
5
- import { useToken } from '../msal/useToken';
6
- import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
7
-
8
- describe('useToken', () => {
9
- it('resolves a full AuthenticationResult from the app scope’s real, mock-backed auth module', async () => {
10
- const { result, unmount } = await renderAppHook(() => useToken({ scopes: ['User.Read'] }));
11
-
12
- // `renderAppHook` awaits the render, and the mock resolves near-instantly,
13
- // so the pending state may have already settled by the time we can observe it
14
- await vi.waitFor(() => expect(result.current.pending).toBe(false));
15
-
16
- expect(result.current.error).toBeNull();
17
- expect(result.current.token?.scopes).toEqual(['User.Read']);
18
- // a structurally valid JWT has three dot-separated segments
19
- expect(result.current.token?.accessToken.split('.')).toHaveLength(3);
20
- expect(result.current.token?.account).toMatchObject({ username: 'test.user@equinor.com' });
21
-
22
- // unmount before the next test's environment tears down, so no acquisition
23
- // effect can flush a state update against an already-destroyed `window`
24
- await unmount();
25
- });
26
-
27
- it('surfaces an acquisition error instead of throwing', async () => {
28
- const fusion = await mockFramework();
29
- // persistent, not `-Once`: the app module hoists via a version-compat proxy that
30
- // may call through before the hook's own effect does, consuming a one-shot mock
31
- vi.spyOn(fusion.modules.auth, 'acquireToken').mockRejectedValue(
32
- new Error('acquisition failed'),
33
- );
34
-
35
- const { result, unmount } = await renderAppHook(() => useToken({ scopes: ['User.Read'] }), {
36
- fusion,
37
- });
38
-
39
- await vi.waitFor(() => expect(result.current.pending).toBe(false));
40
-
41
- expect(result.current.token).toBeUndefined();
42
- expect(result.current.error).toBeInstanceOf(Error);
43
-
44
- await unmount();
45
- });
46
-
47
- it('only re-acquires the token when the scopes\u2019 contents change, not on every re-render', async () => {
48
- const fusion = await mockFramework();
49
- const acquireToken = vi.spyOn(fusion.modules.auth, 'acquireToken');
50
-
51
- const { result, rerender, unmount } = await renderAppHook((props) => useToken(props), {
52
- initialProps: { scopes: ['User.Read'] },
53
- fusion,
54
- });
55
-
56
- await vi.waitFor(() => expect(result.current.pending).toBe(false));
57
- expect(acquireToken).toHaveBeenCalledTimes(1);
58
-
59
- // a fresh array literal with the same contents must not trigger a re-acquisition
60
- await rerender({ scopes: ['User.Read'] });
61
- await vi.waitFor(() => expect(result.current.pending).toBe(false));
62
- expect(acquireToken).toHaveBeenCalledTimes(1);
63
-
64
- // changed scope contents must trigger a second acquisition
65
- await rerender({ scopes: ['User.Read', 'Mail.Read'] });
66
- await vi.waitFor(() => expect(result.current.pending).toBe(false));
67
- expect(acquireToken).toHaveBeenCalledTimes(2);
68
-
69
- await unmount();
70
- });
71
- });
@@ -1,83 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
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
- import { enableAnalytics, type AnalyticsModule } from '@equinor/fusion-framework-module-analytics';
7
- import { MockAnalyticsAdapter } from '@equinor/fusion-framework-module-analytics/mock';
8
- import type { MockTelemetryAdapter } from '@equinor/fusion-framework-module-telemetry/mock';
9
-
10
- import { useTrackFeature } from '../analytics/useTrackFeature';
11
- import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
12
-
13
- const env = {
14
- manifest: {
15
- appKey: 'test-app',
16
- displayName: 'Test App',
17
- description: 'A test application',
18
- type: 'standalone' as const,
19
- },
20
- };
21
-
22
- describe('useTrackFeature', () => {
23
- it('tracks an app-feature analytics event carrying the current app’s key, leaving telemetry untouched', async () => {
24
- const recorder = new MockAnalyticsAdapter();
25
-
26
- const fusion = await mockFramework<[AppModule, AnalyticsModule]>((configurator) => {
27
- enableAppManifestMock(configurator, env);
28
- enableAnalytics(configurator, (builder) => {
29
- builder.setAdapter('mock', async () => recorder);
30
- });
31
- });
32
- fusion.modules.app.setCurrentApp('test-app');
33
-
34
- const { result } = await renderAppHook(() => useTrackFeature(), { env, fusion });
35
- result.current('button-click', { section: 'header' });
36
-
37
- // analytics is the only channel a successful call should reach
38
- expect(recorder.getAnalytics()).toMatchObject([
39
- {
40
- name: 'app-feature',
41
- value: { feature: 'button-click', data: { section: 'header' } },
42
- attributes: { appKey: 'test-app', context: undefined },
43
- },
44
- ]);
45
- // the framework logs its own telemetry regardless; the fallback diagnostic
46
- // specifically must not fire when analytics was reached successfully
47
- const telemetry = fusion.modules.telemetry.getAdapter('mock') as MockTelemetryAdapter;
48
- expect(telemetry.getItems('AnalyticsProviderNotFound')).toHaveLength(0);
49
- });
50
-
51
- it('includes the current context alongside the app key', async () => {
52
- const recorder = new MockAnalyticsAdapter();
53
- const project = { id: 'ctx-1', title: 'My project', type: { id: 'ProjectMaster' }, value: {} };
54
-
55
- const fusion = await mockFramework<[AppModule, AnalyticsModule]>((configurator) => {
56
- enableAppManifestMock(configurator, env);
57
- enableAnalytics(configurator, (builder) => {
58
- builder.setAdapter('mock', async () => recorder);
59
- });
60
- configurator.context.setCurrentContext(project);
61
- });
62
-
63
- const { result } = await renderAppHook(() => useTrackFeature(), { env, fusion });
64
- result.current('button-click');
65
-
66
- const [event] = recorder.getAnalytics('app-feature');
67
- expect(event.attributes?.context).toMatchObject({ id: project.id, type: 'ProjectMaster' });
68
- });
69
-
70
- it('reports to telemetry instead of throwing when no analytics provider is registered', async () => {
71
- const fusion = await mockFramework<[AppModule]>((configurator) => {
72
- enableAppManifestMock(configurator, env);
73
- });
74
-
75
- const { result } = await renderAppHook(() => useTrackFeature(), { env, fusion });
76
-
77
- // the missing-analytics diagnostic is a telemetry concern, not an analytics one —
78
- // it must not throw and must not fabricate an analytics event of its own
79
- expect(() => result.current('button-click')).not.toThrow();
80
- const telemetry = fusion.modules.telemetry.getAdapter('mock') as MockTelemetryAdapter;
81
- expect(telemetry.getItems('AnalyticsProviderNotFound')).toHaveLength(1);
82
- });
83
- });
@@ -1,11 +0,0 @@
1
- /**
2
- * AG Grid community-tier sub-path entry-point.
3
- *
4
- * @remarks
5
- * Re-exports every public symbol from
6
- * `@equinor/fusion-framework-react-ag-grid/community` so the application
7
- * resolves a single shared copy of `ag-grid-community`.
8
- *
9
- * @packageDocumentation
10
- */
11
- export * from '@equinor/fusion-framework-react-ag-grid/community';
@@ -1,11 +0,0 @@
1
- /**
2
- * AG Grid enterprise-tier sub-path entry-point.
3
- *
4
- * @remarks
5
- * Re-exports every public symbol from
6
- * `@equinor/fusion-framework-react-ag-grid/enterprise` so the application
7
- * resolves a single shared copy of `ag-grid-enterprise`.
8
- *
9
- * @packageDocumentation
10
- */
11
- export * from '@equinor/fusion-framework-react-ag-grid/enterprise';
@@ -1,11 +0,0 @@
1
- /**
2
- * AG Grid React component sub-path entry-point.
3
- *
4
- * @remarks
5
- * Re-exports the AG Grid React bindings from
6
- * `@equinor/fusion-framework-react-ag-grid/react`, including the
7
- * `AgGridReact` component, `enableAgGrid`, and their associated types.
8
- *
9
- * @packageDocumentation
10
- */
11
- export * from '@equinor/fusion-framework-react-ag-grid/react';
@@ -1,19 +0,0 @@
1
- /**
2
- * AG Grid test helpers sub-path entry-point.
3
- *
4
- * @remarks
5
- * Re-exports the AG Grid test helpers from
6
- * `@equinor/fusion-framework-module-ag-grid/testing`. Import from test setup
7
- * files only — these helpers patch global state and are not meant for
8
- * application runtime code.
9
- *
10
- * @packageDocumentation
11
- */
12
-
13
- /**
14
- * Silences AG Grid Enterprise's unlicensed "License Key Not Found" banner on
15
- * `console.error` so it doesn't bury real failures in test output.
16
- *
17
- * @returns A function that restores the original `console.error`.
18
- */
19
- export { suppressAgGridLicenseBanner } from '@equinor/fusion-framework-module-ag-grid/testing';
@@ -1,17 +0,0 @@
1
- /**
2
- * AG Grid theme sub-path entry-point.
3
- *
4
- * @remarks
5
- * Re-exports the Fusion AG Grid theme utilities from
6
- * `@equinor/fusion-framework-module-ag-grid/themes`, together with the
7
- * application-scoped {@link useTheme} hook.
8
- *
9
- * @packageDocumentation
10
- */
11
- export {
12
- fusionTheme,
13
- createThemeFromTheme,
14
- createTheme,
15
- } from '@equinor/fusion-framework-module-ag-grid/themes';
16
- export type { Theme } from '@equinor/fusion-framework-module-ag-grid/themes';
17
- export { useTheme } from './useTheme';