@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.
- package/CHANGELOG.md +2 -10
- package/README.md +2 -9
- package/dist/esm/create-component.js +1 -1
- package/dist/esm/msal/useToken.js +3 -12
- package/dist/esm/msal/useToken.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/create-component.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/docs/bookmark.md +0 -7
- package/docs/context.md +1 -3
- package/docs/framework.md +2 -2
- package/docs/msal.md +3 -3
- package/package.json +25 -77
- package/src/__tests__/useStateSyncEvents.test.ts +11 -12
- package/src/create-component.tsx +1 -1
- package/src/msal/useToken.ts +3 -14
- package/src/version.ts +1 -1
- package/tsconfig.json +0 -6
- package/vitest.config.ts +8 -2
- package/dist/esm/ag-grid/community.js +0 -12
- package/dist/esm/ag-grid/community.js.map +0 -1
- package/dist/esm/ag-grid/enterprise.js +0 -12
- package/dist/esm/ag-grid/enterprise.js.map +0 -1
- package/dist/esm/ag-grid/react.js +0 -12
- package/dist/esm/ag-grid/react.js.map +0 -1
- package/dist/esm/ag-grid/testing.js +0 -19
- package/dist/esm/ag-grid/testing.js.map +0 -1
- package/dist/esm/ag-grid/theme.js +0 -13
- package/dist/esm/ag-grid/theme.js.map +0 -1
- package/dist/types/ag-grid/community.d.ts +0 -11
- package/dist/types/ag-grid/enterprise.d.ts +0 -11
- package/dist/types/ag-grid/react.d.ts +0 -11
- package/dist/types/ag-grid/testing.d.ts +0 -18
- package/dist/types/ag-grid/theme.d.ts +0 -13
- package/src/__tests__/Apploader.test.tsx +0 -51
- package/src/__tests__/fixtures/apploader-child-script.ts +0 -9
- package/src/__tests__/testApp.test.tsx +0 -76
- package/src/__tests__/useAccessToken.test.tsx +0 -51
- package/src/__tests__/useAppSetting.test.tsx +0 -133
- package/src/__tests__/useAppSettings.test.tsx +0 -147
- package/src/__tests__/useCurrentAccount.test.tsx +0 -32
- package/src/__tests__/useCurrentBookmark.test.tsx +0 -108
- package/src/__tests__/useCurrentContext.test.tsx +0 -72
- package/src/__tests__/useFeature.test.tsx +0 -104
- package/src/__tests__/useHelpCenter.test.tsx +0 -64
- package/src/__tests__/useToken.test.tsx +0 -71
- package/src/__tests__/useTrackFeature.test.tsx +0 -83
- package/src/ag-grid/community.ts +0 -11
- package/src/ag-grid/enterprise.ts +0 -11
- package/src/ag-grid/react.ts +0 -11
- package/src/ag-grid/testing.ts +0 -19
- package/src/ag-grid/theme.ts +0 -17
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { describe, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
|
|
4
|
-
import type { ContextItem } from '@equinor/fusion-framework-module-context';
|
|
5
|
-
import { useCurrentContext } from '@equinor/fusion-framework-react-app/context';
|
|
6
|
-
import { useFramework } from '@equinor/fusion-framework-react';
|
|
7
|
-
import { createHistory, enableNavigation } from '@equinor/fusion-framework-module-navigation';
|
|
8
|
-
import type { NavigationModule } from '@equinor/fusion-framework-module-navigation';
|
|
9
|
-
|
|
10
|
-
import { testApp } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
|
|
11
|
-
|
|
12
|
-
const projectA: ContextItem = {
|
|
13
|
-
id: 'ctx-a',
|
|
14
|
-
title: 'Project A',
|
|
15
|
-
type: { id: 'ProjectMaster' },
|
|
16
|
-
value: {},
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const Greeting = () => <p>hello</p>;
|
|
20
|
-
|
|
21
|
-
const CurrentContext = () => {
|
|
22
|
-
const { currentContext } = useCurrentContext();
|
|
23
|
-
return <p>{currentContext?.title ?? 'none'}</p>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
describe('testApp', () => {
|
|
27
|
-
testApp(
|
|
28
|
-
'resolves a fusion/app scope and renders through the public /vitest entry point',
|
|
29
|
-
async ({ render, fusion, app }) => {
|
|
30
|
-
const screen = await render(<Greeting />);
|
|
31
|
-
await expect.element(screen.getByText('hello')).toBeVisible();
|
|
32
|
-
expect(fusion).toBeDefined();
|
|
33
|
-
expect(app).toBeDefined();
|
|
34
|
-
},
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
describe('with a seeded context module', () => {
|
|
38
|
-
const test = testApp.extend(
|
|
39
|
-
'configureApp',
|
|
40
|
-
{ injected: true },
|
|
41
|
-
() => (configurator) =>
|
|
42
|
-
enableContextMock(configurator, (mock) => mock.setCurrentContext(projectA)),
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
test('starts on the seeded context', async ({ render }) => {
|
|
46
|
-
const screen = await render(<CurrentContext />);
|
|
47
|
-
await expect.element(screen.getByText(projectA.title as string)).toBeVisible();
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('with a configured parent framework', () => {
|
|
52
|
-
const NavigationLocation = () => {
|
|
53
|
-
const { navigation } = useFramework<[NavigationModule]>().modules;
|
|
54
|
-
return <p>{navigation.history.location.pathname}</p>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// pushed on the history instance itself, before it's handed to the framework configurator,
|
|
58
|
-
// so a passing assertion also proves `configureFusion` ran ahead of framework initialization
|
|
59
|
-
const history = createHistory('memory');
|
|
60
|
-
history.push('/configured-by-configure-fusion');
|
|
61
|
-
|
|
62
|
-
const test = testApp.extend(
|
|
63
|
-
'configureFusion',
|
|
64
|
-
{ injected: true },
|
|
65
|
-
() => (configurator) =>
|
|
66
|
-
enableNavigation(configurator, { configure: (config) => config.setHistory(history) }),
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
test('resolves the fusion instance with the configured navigation history', async ({
|
|
70
|
-
render,
|
|
71
|
-
}) => {
|
|
72
|
-
const screen = await render(<NavigationLocation />);
|
|
73
|
-
await expect.element(screen.getByText('/configured-by-configure-fusion')).toBeVisible();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { mockFramework } from '@equinor/fusion-framework/mock';
|
|
4
|
-
|
|
5
|
-
import { useAccessToken } from '../msal/useAccessToken';
|
|
6
|
-
import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
|
|
7
|
-
|
|
8
|
-
describe('useAccessToken', () => {
|
|
9
|
-
it('resolves an access token from the app scope’s real, mock-backed auth module', async () => {
|
|
10
|
-
// `renderAppHook` runs the real msal module against an in-process mock client,
|
|
11
|
-
// so `auth` behaves exactly as it would with a signed-in user in production.
|
|
12
|
-
const { result, unmount } = await renderAppHook(() =>
|
|
13
|
-
useAccessToken({ scopes: ['User.Read'] }),
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
// `renderAppHook` awaits the render, and the mock resolves near-instantly,
|
|
17
|
-
// so the pending state may have already settled by the time we can observe it
|
|
18
|
-
await vi.waitFor(() => expect(result.current.pending).toBe(false));
|
|
19
|
-
|
|
20
|
-
expect(result.current.error).toBeNull();
|
|
21
|
-
// a structurally valid JWT has three dot-separated segments
|
|
22
|
-
expect(result.current.token?.split('.')).toHaveLength(3);
|
|
23
|
-
|
|
24
|
-
// unmount before the next test's environment tears down, so no acquisition
|
|
25
|
-
// effect can flush a state update against an already-destroyed `window`
|
|
26
|
-
await unmount();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('surfaces an acquisition error instead of throwing', async () => {
|
|
30
|
-
const fusion = await mockFramework();
|
|
31
|
-
// persistent, not `-Once`: the app module hoists via a version-compat proxy that
|
|
32
|
-
// may call through before the hook's own effect does, consuming a one-shot mock
|
|
33
|
-
vi.spyOn(fusion.modules.auth, 'acquireToken').mockRejectedValue(
|
|
34
|
-
new Error('acquisition failed'),
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const { result, unmount } = await renderAppHook(
|
|
38
|
-
() => useAccessToken({ scopes: ['User.Read'] }),
|
|
39
|
-
{
|
|
40
|
-
fusion,
|
|
41
|
-
},
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
await vi.waitFor(() => expect(result.current.pending).toBe(false));
|
|
45
|
-
|
|
46
|
-
expect(result.current.token).toBeUndefined();
|
|
47
|
-
expect(result.current.error).toBeInstanceOf(Error);
|
|
48
|
-
|
|
49
|
-
await unmount();
|
|
50
|
-
});
|
|
51
|
-
});
|
|
@@ -1,133 +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 { AppModule } from '@equinor/fusion-framework-module-app';
|
|
7
|
-
import { createRouterMiddleware } from '@equinor/fusion-framework-module-http/mock';
|
|
8
|
-
|
|
9
|
-
import { useAppSetting } from '../settings/useAppSetting';
|
|
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
|
-
/**
|
|
22
|
-
* Boots a parent framework whose `apps` client serves per-user settings from an
|
|
23
|
-
* in-memory store, so `useAppSetting` exercises the real fetch/update round-trip
|
|
24
|
-
* instead of a stubbed provider.
|
|
25
|
-
*
|
|
26
|
-
* @param initial - The settings the store starts seeded with.
|
|
27
|
-
* @param putResponse - Overrides the response a PUT request resolves to, to simulate a failed update.
|
|
28
|
-
*/
|
|
29
|
-
const mockSettingsFusion = async (
|
|
30
|
-
initial: Record<string, unknown> = {},
|
|
31
|
-
putResponse?: () => Response,
|
|
32
|
-
) => {
|
|
33
|
-
const store: Record<string, unknown> = { ...initial };
|
|
34
|
-
const fusion = await mockFramework<[AppModule]>((configurator) => {
|
|
35
|
-
configurator.http.addMiddleware(
|
|
36
|
-
createRouterMiddleware('https://apps.fusion.test', (router) => {
|
|
37
|
-
router.get('/persons/me/apps/:appKey/settings', () => Response.json(store));
|
|
38
|
-
router.put('/persons/me/apps/:appKey/settings', async ({ request }) => {
|
|
39
|
-
// a caller-supplied response simulates a failed persistence request
|
|
40
|
-
if (putResponse) return putResponse();
|
|
41
|
-
// the PUT body replaces the seeded keys it targets, leaving the rest of the store untouched
|
|
42
|
-
Object.assign(store, await request.json());
|
|
43
|
-
return Response.json(store);
|
|
44
|
-
});
|
|
45
|
-
}),
|
|
46
|
-
);
|
|
47
|
-
enableAppManifestMock(configurator, env);
|
|
48
|
-
});
|
|
49
|
-
fusion.modules.app.setCurrentApp(env.manifest.appKey);
|
|
50
|
-
return fusion;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
describe('useAppSetting', () => {
|
|
54
|
-
it('resolves the persisted value for a single setting key', async () => {
|
|
55
|
-
const fusion = await mockSettingsFusion({ theme: 'dark' });
|
|
56
|
-
|
|
57
|
-
const { result } = await renderAppHook(
|
|
58
|
-
() => useAppSetting<{ theme: string }, 'theme'>('theme'),
|
|
59
|
-
{ env, fusion },
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
await vi.waitFor(() => expect(result.current[0]).toBe('dark'));
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('falls back to the default value until the persisted settings resolve', async () => {
|
|
66
|
-
const fusion = await mockSettingsFusion({ theme: 'dark' });
|
|
67
|
-
|
|
68
|
-
const { result } = await renderAppHook(
|
|
69
|
-
() => useAppSetting<{ theme: string }, 'theme'>('theme', 'light'),
|
|
70
|
-
{ env, fusion },
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
expect(result.current[0]).toBe('light');
|
|
74
|
-
await vi.waitFor(() => expect(result.current[0]).toBe('dark'));
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('persists an updated value and notifies onUpdated', async () => {
|
|
78
|
-
const fusion = await mockSettingsFusion({ theme: 'dark' });
|
|
79
|
-
const onUpdated = vi.fn();
|
|
80
|
-
|
|
81
|
-
const { result } = await renderAppHook(
|
|
82
|
-
() => useAppSetting<{ theme: string }, 'theme'>('theme', undefined, { onUpdated }),
|
|
83
|
-
{ env, fusion },
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
await vi.waitFor(() => expect(result.current[0]).toBe('dark'));
|
|
87
|
-
|
|
88
|
-
act(() => {
|
|
89
|
-
result.current[1]('light');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
await vi.waitFor(() => expect(result.current[0]).toBe('light'));
|
|
93
|
-
await vi.waitFor(() => expect(onUpdated).toHaveBeenCalled());
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('resolves the next value from the previous one when given an updater function', async () => {
|
|
97
|
-
const fusion = await mockSettingsFusion({ count: 1 });
|
|
98
|
-
|
|
99
|
-
const { result } = await renderAppHook(
|
|
100
|
-
() => useAppSetting<{ count: number }, 'count'>('count'),
|
|
101
|
-
{ env, fusion },
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
await vi.waitFor(() => expect(result.current[0]).toBe(1));
|
|
105
|
-
|
|
106
|
-
act(() => {
|
|
107
|
-
result.current[1]((current) => (current ?? 0) + 1);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
await vi.waitFor(() => expect(result.current[0]).toBe(2));
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('surfaces a persistence failure through onError instead of throwing', async () => {
|
|
114
|
-
const fusion = await mockSettingsFusion(
|
|
115
|
-
{ theme: 'dark' },
|
|
116
|
-
() => new Response(null, { status: 500 }),
|
|
117
|
-
);
|
|
118
|
-
const onError = vi.fn();
|
|
119
|
-
|
|
120
|
-
const { result } = await renderAppHook(
|
|
121
|
-
() => useAppSetting<{ theme: string }, 'theme'>('theme', undefined, { onError }),
|
|
122
|
-
{ env, fusion },
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
await vi.waitFor(() => expect(result.current[0]).toBe('dark'));
|
|
126
|
-
|
|
127
|
-
act(() => {
|
|
128
|
-
result.current[1]('light');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
await vi.waitFor(() => expect(onError).toHaveBeenCalledWith(expect.any(Error)));
|
|
132
|
-
});
|
|
133
|
-
});
|
|
@@ -1,147 +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 { AppModule } from '@equinor/fusion-framework-module-app';
|
|
7
|
-
import { createRouterMiddleware } from '@equinor/fusion-framework-module-http/mock';
|
|
8
|
-
|
|
9
|
-
import { useAppSettings } from '../settings/useAppSettings';
|
|
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
|
-
/**
|
|
22
|
-
* Boots a parent framework whose `apps` client serves per-user settings from an
|
|
23
|
-
* in-memory store, so `useAppSettings` exercises the real fetch/update round-trip
|
|
24
|
-
* instead of a stubbed provider.
|
|
25
|
-
*
|
|
26
|
-
* @param initial - The settings the store starts seeded with.
|
|
27
|
-
* @param putResponse - Overrides the response a PUT request resolves to, to simulate a failed update.
|
|
28
|
-
*/
|
|
29
|
-
const mockSettingsFusion = async (
|
|
30
|
-
initial: Record<string, unknown> = {},
|
|
31
|
-
putResponse?: () => Response,
|
|
32
|
-
) => {
|
|
33
|
-
const store: Record<string, unknown> = { ...initial };
|
|
34
|
-
const fusion = await mockFramework<[AppModule]>((configurator) => {
|
|
35
|
-
configurator.http.addMiddleware(
|
|
36
|
-
createRouterMiddleware('https://apps.fusion.test', (router) => {
|
|
37
|
-
router.get('/persons/me/apps/:appKey/settings', () => Response.json(store));
|
|
38
|
-
router.put('/persons/me/apps/:appKey/settings', async ({ request }) => {
|
|
39
|
-
// a caller-supplied response simulates a failed persistence request
|
|
40
|
-
if (putResponse) return putResponse();
|
|
41
|
-
// the PUT body replaces the seeded keys it targets, leaving the rest of the store untouched
|
|
42
|
-
Object.assign(store, await request.json());
|
|
43
|
-
return Response.json(store);
|
|
44
|
-
});
|
|
45
|
-
}),
|
|
46
|
-
);
|
|
47
|
-
enableAppManifestMock(configurator, env);
|
|
48
|
-
});
|
|
49
|
-
fusion.modules.app.setCurrentApp(env.manifest.appKey);
|
|
50
|
-
return fusion;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
interface TestSettings extends Record<string, unknown> {
|
|
54
|
-
theme: string;
|
|
55
|
-
layout: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
describe('useAppSettings', () => {
|
|
59
|
-
it('resolves the full persisted settings object', async () => {
|
|
60
|
-
const fusion = await mockSettingsFusion({ theme: 'dark', layout: 'grid' });
|
|
61
|
-
|
|
62
|
-
const { result } = await renderAppHook(() => useAppSettings<TestSettings>(), { env, fusion });
|
|
63
|
-
|
|
64
|
-
await vi.waitFor(() =>
|
|
65
|
-
expect(result.current[0]).toMatchObject({ theme: 'dark', layout: 'grid' }),
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('falls back to the default value until the persisted settings resolve', async () => {
|
|
70
|
-
const fusion = await mockSettingsFusion({ theme: 'dark', layout: 'grid' });
|
|
71
|
-
|
|
72
|
-
const { result } = await renderAppHook(
|
|
73
|
-
() => useAppSettings<TestSettings>({ theme: 'light', layout: 'list' }),
|
|
74
|
-
{ env, fusion },
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
expect(result.current[0]).toMatchObject({ theme: 'light', layout: 'list' });
|
|
78
|
-
await vi.waitFor(() =>
|
|
79
|
-
expect(result.current[0]).toMatchObject({ theme: 'dark', layout: 'grid' }),
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('persists an updated settings object and notifies onUpdated', async () => {
|
|
84
|
-
const fusion = await mockSettingsFusion({ theme: 'dark', layout: 'grid' });
|
|
85
|
-
const onUpdated = vi.fn();
|
|
86
|
-
|
|
87
|
-
const { result } = await renderAppHook(
|
|
88
|
-
() => useAppSettings<TestSettings>(undefined, { onUpdated }),
|
|
89
|
-
{ env, fusion },
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
await vi.waitFor(() =>
|
|
93
|
-
expect(result.current[0]).toMatchObject({ theme: 'dark', layout: 'grid' }),
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
act(() => {
|
|
97
|
-
result.current[1]({ theme: 'light', layout: 'grid' });
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
await vi.waitFor(() =>
|
|
101
|
-
expect(result.current[0]).toMatchObject({ theme: 'light', layout: 'grid' }),
|
|
102
|
-
);
|
|
103
|
-
await vi.waitFor(() => expect(onUpdated).toHaveBeenCalled());
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('resolves the next settings object from the previous one when given an updater function', async () => {
|
|
107
|
-
const fusion = await mockSettingsFusion({ theme: 'dark', layout: 'grid' });
|
|
108
|
-
|
|
109
|
-
const { result } = await renderAppHook(() => useAppSettings<TestSettings>(), { env, fusion });
|
|
110
|
-
|
|
111
|
-
await vi.waitFor(() =>
|
|
112
|
-
expect(result.current[0]).toMatchObject({ theme: 'dark', layout: 'grid' }),
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
act(() => {
|
|
116
|
-
// `current` is typed as possibly undefined even though it's already resolved by this point
|
|
117
|
-
result.current[1]((current) => ({ theme: current?.theme ?? 'dark', layout: 'list' }));
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
await vi.waitFor(() =>
|
|
121
|
-
expect(result.current[0]).toMatchObject({ theme: 'dark', layout: 'list' }),
|
|
122
|
-
);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('surfaces a persistence failure through onError instead of throwing', async () => {
|
|
126
|
-
const fusion = await mockSettingsFusion(
|
|
127
|
-
{ theme: 'dark', layout: 'grid' },
|
|
128
|
-
() => new Response(null, { status: 500 }),
|
|
129
|
-
);
|
|
130
|
-
const onError = vi.fn();
|
|
131
|
-
|
|
132
|
-
const { result } = await renderAppHook(
|
|
133
|
-
() => useAppSettings<TestSettings>(undefined, { onError }),
|
|
134
|
-
{ env, fusion },
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
await vi.waitFor(() =>
|
|
138
|
-
expect(result.current[0]).toMatchObject({ theme: 'dark', layout: 'grid' }),
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
act(() => {
|
|
142
|
-
result.current[1]({ theme: 'light', layout: 'grid' });
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
await vi.waitFor(() => expect(onError).toHaveBeenCalledWith(expect.any(Error)));
|
|
146
|
-
});
|
|
147
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { useCurrentAccount } from '../msal/useCurrentAccount';
|
|
4
|
-
import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
|
|
5
|
-
|
|
6
|
-
describe('useCurrentAccount', () => {
|
|
7
|
-
it('returns the default mock user signed in by the app scope’s auth module', async () => {
|
|
8
|
-
const { result } = await renderAppHook(() => useCurrentAccount());
|
|
9
|
-
|
|
10
|
-
expect(result.current).toMatchObject({
|
|
11
|
-
name: 'Test User',
|
|
12
|
-
username: 'test.user@equinor.com',
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('returns the account configured through the msal mock builder', async () => {
|
|
17
|
-
const { result } = await renderAppHook(() => useCurrentAccount(), {
|
|
18
|
-
configure: (configurator) =>
|
|
19
|
-
configurator.msal.setAccount({ name: 'Ada Lovelace', username: 'ada@equinor.com' }),
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
expect(result.current).toMatchObject({ name: 'Ada Lovelace', username: 'ada@equinor.com' });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('returns undefined when no account is signed in', async () => {
|
|
26
|
-
const { result } = await renderAppHook(() => useCurrentAccount(), {
|
|
27
|
-
configure: (configurator) => configurator.msal.setAccount(null),
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
expect(result.current).toBeUndefined();
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,108 +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 { AppMockConfigureFn } from '@equinor/fusion-framework-app/mock';
|
|
6
|
-
import type { AppModule } from '@equinor/fusion-framework-module-app';
|
|
7
|
-
import { enableBookmarkMock } from '@equinor/fusion-framework-module-bookmark/mock';
|
|
8
|
-
import type { Bookmark, BookmarkModule } from '@equinor/fusion-framework-module-bookmark';
|
|
9
|
-
|
|
10
|
-
import { useCurrentBookmark } from '../bookmark/useCurrentBookmark';
|
|
11
|
-
import { renderAppHook } from '@equinor/fusion-framework-vitest-plugin-react-app/test';
|
|
12
|
-
import { useAppModules } from '../useAppModules';
|
|
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
|
-
/** A fully-formed seeded bookmark, so tests only override what they care about. */
|
|
24
|
-
const createBookmark = (overrides: Partial<Bookmark> = {}): Bookmark => ({
|
|
25
|
-
id: 'bookmark-1',
|
|
26
|
-
name: 'My Bookmark',
|
|
27
|
-
appKey: 'test-app',
|
|
28
|
-
created: new Date('2024-01-01T00:00:00.000Z'),
|
|
29
|
-
createdBy: { id: 'seed-user', name: 'Seed User' },
|
|
30
|
-
...overrides,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('useCurrentBookmark', () => {
|
|
34
|
-
it('returns the app-scoped current bookmark once it belongs to the active app', async () => {
|
|
35
|
-
const bookmark = createBookmark();
|
|
36
|
-
const fusion = await mockFramework<[AppModule]>((configurator) =>
|
|
37
|
-
enableAppManifestMock(configurator, env),
|
|
38
|
-
);
|
|
39
|
-
fusion.modules.app.setCurrentApp(env.manifest.appKey);
|
|
40
|
-
|
|
41
|
-
const configure: AppMockConfigureFn<[BookmarkModule]> = (configurator) =>
|
|
42
|
-
enableBookmarkMock(configurator, (builder) => {
|
|
43
|
-
builder.setBookmarks([bookmark]);
|
|
44
|
-
builder.setCurrentBookmark(bookmark.id);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const { result } = await renderAppHook(() => useCurrentBookmark(), { env, fusion, configure });
|
|
48
|
-
|
|
49
|
-
await vi.waitFor(() =>
|
|
50
|
-
expect(result.current.currentBookmark).toMatchObject({ id: bookmark.id }),
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('hides the current bookmark once it belongs to a different app', async () => {
|
|
55
|
-
const bookmark = createBookmark({ appKey: 'some-other-app' });
|
|
56
|
-
const fusion = await mockFramework<[AppModule]>((configurator) =>
|
|
57
|
-
enableAppManifestMock(configurator, env),
|
|
58
|
-
);
|
|
59
|
-
fusion.modules.app.setCurrentApp(env.manifest.appKey);
|
|
60
|
-
|
|
61
|
-
const configure: AppMockConfigureFn<[BookmarkModule]> = (configurator) =>
|
|
62
|
-
enableBookmarkMock(configurator, (builder) => {
|
|
63
|
-
builder.setBookmarks([bookmark]);
|
|
64
|
-
builder.setCurrentBookmark(bookmark.id);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const { result } = await renderAppHook(
|
|
68
|
-
() => ({
|
|
69
|
-
bookmark: useCurrentBookmark(),
|
|
70
|
-
// unfiltered provider state, so we can tell the seeded bookmark actually
|
|
71
|
-
// resolved rather than the filter trivially matching a still-pending value
|
|
72
|
-
provider: useAppModules<[BookmarkModule]>().bookmark,
|
|
73
|
-
}),
|
|
74
|
-
{ env, fusion, configure },
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
await vi.waitFor(() =>
|
|
78
|
-
expect(result.current.provider.currentBookmark).toMatchObject({ id: bookmark.id }),
|
|
79
|
-
);
|
|
80
|
-
expect(result.current.bookmark.currentBookmark).toBeNull();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('falls back to the framework-scoped bookmark provider, warning about the deprecation', async () => {
|
|
84
|
-
const bookmark = createBookmark();
|
|
85
|
-
const fusion = await mockFramework<[AppModule, BookmarkModule]>((configurator) => {
|
|
86
|
-
enableAppManifestMock(configurator, env);
|
|
87
|
-
enableBookmarkMock(configurator, (builder) => {
|
|
88
|
-
builder.setBookmarks([bookmark]);
|
|
89
|
-
builder.setCurrentBookmark(bookmark.id);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
fusion.modules.app.setCurrentApp(env.manifest.appKey);
|
|
93
|
-
|
|
94
|
-
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
95
|
-
|
|
96
|
-
const { result } = await renderAppHook(() => useCurrentBookmark(), { env, fusion });
|
|
97
|
-
|
|
98
|
-
await vi.waitFor(() =>
|
|
99
|
-
expect(result.current.currentBookmark).toMatchObject({ id: bookmark.id }),
|
|
100
|
-
);
|
|
101
|
-
expect(warnSpy).toHaveBeenCalledWith(
|
|
102
|
-
'@deprecation',
|
|
103
|
-
expect.stringContaining('has not enabled bookmarks'),
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
warnSpy.mockRestore();
|
|
107
|
-
});
|
|
108
|
-
});
|
|
@@ -1,72 +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 { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
|
|
9
|
-
import type { ContextItem, ContextModule } from '@equinor/fusion-framework-module-context';
|
|
10
|
-
|
|
11
|
-
import { useCurrentContext } from '../context/useCurrentContext';
|
|
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
|
-
const project: ContextItem = {
|
|
24
|
-
id: 'ctx-1',
|
|
25
|
-
title: 'My project',
|
|
26
|
-
type: { id: 'ProjectMaster' },
|
|
27
|
-
value: {},
|
|
28
|
-
};
|
|
29
|
-
const facility: ContextItem = {
|
|
30
|
-
id: 'ctx-2',
|
|
31
|
-
title: 'My facility',
|
|
32
|
-
type: { id: 'Facility' },
|
|
33
|
-
value: {},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
describe('useCurrentContext', () => {
|
|
37
|
-
it('resolves the context item selected on startup from the app-scoped context module', async () => {
|
|
38
|
-
const fusion = await mockFramework<[AppModule]>((configurator) =>
|
|
39
|
-
enableAppManifestMock(configurator, env),
|
|
40
|
-
);
|
|
41
|
-
const configure: AppMockConfigureFn<[ContextModule]> = (configurator) =>
|
|
42
|
-
enableContextMock(configurator, (mock) => {
|
|
43
|
-
mock.setCurrentContext(project);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const { result } = await renderAppHook(() => useCurrentContext(), { env, fusion, configure });
|
|
47
|
-
|
|
48
|
-
await vi.waitFor(() => expect(result.current.currentContext).toMatchObject({ id: project.id }));
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('switches the current context when setCurrentContext is called with another seeded item', async () => {
|
|
52
|
-
const fusion = await mockFramework<[AppModule]>((configurator) =>
|
|
53
|
-
enableAppManifestMock(configurator, env),
|
|
54
|
-
);
|
|
55
|
-
const configure: AppMockConfigureFn<[ContextModule]> = (configurator) =>
|
|
56
|
-
enableContextMock(configurator, (mock) => {
|
|
57
|
-
mock.setCurrentContext(project);
|
|
58
|
-
mock.addContext(facility);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
const { result } = await renderAppHook(() => useCurrentContext(), { env, fusion, configure });
|
|
62
|
-
await vi.waitFor(() => expect(result.current.currentContext).toMatchObject({ id: project.id }));
|
|
63
|
-
|
|
64
|
-
await act(async () => {
|
|
65
|
-
await result.current.setCurrentContext(facility.id);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
await vi.waitFor(() =>
|
|
69
|
-
expect(result.current.currentContext).toMatchObject({ id: facility.id }),
|
|
70
|
-
);
|
|
71
|
-
});
|
|
72
|
-
});
|