@module-federation/bridge-react 2.3.2 → 2.4.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.
- package/dist/base.cjs.js +2 -2
- package/dist/base.es.js +2 -2
- package/dist/data-fetch-utils.cjs.js +1 -1
- package/dist/data-fetch-utils.es.js +2 -2
- package/dist/index.cjs.js +2 -2
- package/dist/index.es.js +2 -2
- package/dist/{lazy-load-component-plugin-CqxENGBE.mjs → lazy-load-component-plugin-Bf_HsMyF.mjs} +1 -1
- package/dist/{lazy-load-component-plugin-ZC6dhtcT.js → lazy-load-component-plugin-DZDwZ0Kz.js} +1 -1
- package/dist/lazy-load-component-plugin.cjs.js +2 -2
- package/dist/lazy-load-component-plugin.es.js +2 -2
- package/dist/{prefetch-CFKA0dZg.mjs → prefetch-ByDYONsx.mjs} +14 -7
- package/dist/{prefetch-8e8pqiSo.js → prefetch-DYFX9hl9.js} +14 -7
- package/package.json +9 -5
- package/.turbo/turbo-build.log +0 -85
- package/CHANGELOG.md +0 -833
- package/__tests__/bridge.spec.tsx +0 -160
- package/__tests__/createLazyComponent.spec.tsx +0 -209
- package/__tests__/prefetch.spec.ts +0 -156
- package/__tests__/router.spec.tsx +0 -82
- package/__tests__/setupTests.ts +0 -8
- package/__tests__/util.ts +0 -36
- package/jest.config.ts +0 -21
- package/src/base.ts +0 -50
- package/src/index.ts +0 -50
- package/src/lazy/AwaitDataFetch.tsx +0 -217
- package/src/lazy/constant.ts +0 -30
- package/src/lazy/createLazyComponent.tsx +0 -411
- package/src/lazy/data-fetch/cache.ts +0 -291
- package/src/lazy/data-fetch/call-data-fetch.ts +0 -13
- package/src/lazy/data-fetch/data-fetch-server-middleware.ts +0 -196
- package/src/lazy/data-fetch/index.ts +0 -16
- package/src/lazy/data-fetch/inject-data-fetch.ts +0 -109
- package/src/lazy/data-fetch/prefetch.ts +0 -112
- package/src/lazy/data-fetch/runtime-plugin.ts +0 -115
- package/src/lazy/index.ts +0 -35
- package/src/lazy/logger.ts +0 -6
- package/src/lazy/types.ts +0 -75
- package/src/lazy/utils.ts +0 -375
- package/src/lazy/wrapNoSSR.tsx +0 -10
- package/src/modern-app-env.d.ts +0 -2
- package/src/plugins/lazy-load-component-plugin.spec.ts +0 -21
- package/src/plugins/lazy-load-component-plugin.ts +0 -57
- package/src/provider/context.tsx +0 -4
- package/src/provider/plugin.ts +0 -22
- package/src/provider/versions/bridge-base.tsx +0 -153
- package/src/provider/versions/legacy.ts +0 -87
- package/src/provider/versions/v18.ts +0 -47
- package/src/provider/versions/v19.ts +0 -48
- package/src/remote/RemoteAppWrapper.tsx +0 -108
- package/src/remote/base-component/component.tsx +0 -2
- package/src/remote/base-component/create.tsx +0 -23
- package/src/remote/base-component/index.tsx +0 -10
- package/src/remote/createHelpers.tsx +0 -132
- package/src/remote/router-component/component.tsx +0 -104
- package/src/remote/router-component/create.tsx +0 -23
- package/src/remote/router-component/index.tsx +0 -10
- package/src/router/default.tsx +0 -73
- package/src/router/v5.tsx +0 -43
- package/src/router/v6.tsx +0 -74
- package/src/router/v7.tsx +0 -75
- package/src/types.ts +0 -147
- package/src/utils/index.ts +0 -44
- package/src/v18.ts +0 -9
- package/src/v19.ts +0 -9
- package/tsconfig.json +0 -42
- package/tsconfig.node.json +0 -11
- package/tsconfig.spec.json +0 -26
- package/vite.config.ts +0 -112
- package/vitest.config.ts +0 -27
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { createBridgeComponent, createRemoteAppComponent } from '../src';
|
|
3
|
-
import {
|
|
4
|
-
act,
|
|
5
|
-
fireEvent,
|
|
6
|
-
render,
|
|
7
|
-
screen,
|
|
8
|
-
waitFor,
|
|
9
|
-
} from '@testing-library/react';
|
|
10
|
-
import { createContainer, getHtml } from './util';
|
|
11
|
-
|
|
12
|
-
describe('bridge', () => {
|
|
13
|
-
let containerInfo: ReturnType<typeof createContainer>;
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
containerInfo = createContainer();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
containerInfo?.clean();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('createBridgeComponent life cycle', async () => {
|
|
23
|
-
function Component() {
|
|
24
|
-
return <div>life cycle render</div>;
|
|
25
|
-
}
|
|
26
|
-
const lifeCycle = createBridgeComponent({
|
|
27
|
-
rootComponent: Component,
|
|
28
|
-
})();
|
|
29
|
-
|
|
30
|
-
lifeCycle.render({
|
|
31
|
-
dom: containerInfo?.container,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
await waitFor(
|
|
35
|
-
() => {
|
|
36
|
-
expect(document.querySelector('#container')?.innerHTML).toContain(
|
|
37
|
-
'<div>life cycle render</div>',
|
|
38
|
-
);
|
|
39
|
-
},
|
|
40
|
-
{ timeout: 2000 },
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
lifeCycle.destroy({
|
|
44
|
-
dom: containerInfo?.container,
|
|
45
|
-
moduleName: 'test',
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
await waitFor(
|
|
49
|
-
() => {
|
|
50
|
-
expect(
|
|
51
|
-
(document.querySelector('#container')?.innerHTML || '').trim(),
|
|
52
|
-
).toBe('');
|
|
53
|
-
},
|
|
54
|
-
{ timeout: 2000 },
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('createRemoteAppComponent', async () => {
|
|
59
|
-
function Component({ props }: { props?: Record<string, any> }) {
|
|
60
|
-
return <div>life cycle render {props?.msg}</div>;
|
|
61
|
-
}
|
|
62
|
-
const BridgeComponent = createBridgeComponent({
|
|
63
|
-
rootComponent: Component,
|
|
64
|
-
});
|
|
65
|
-
const RemoteComponent = createRemoteAppComponent({
|
|
66
|
-
loader: async () => {
|
|
67
|
-
return {
|
|
68
|
-
default: BridgeComponent,
|
|
69
|
-
};
|
|
70
|
-
},
|
|
71
|
-
fallback: () => <div></div>,
|
|
72
|
-
loading: <div>loading</div>,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const { container } = render(
|
|
76
|
-
<RemoteComponent props={{ msg: 'hello world' }} />,
|
|
77
|
-
);
|
|
78
|
-
expect(getHtml(container)).toMatch('loading');
|
|
79
|
-
|
|
80
|
-
await waitFor(
|
|
81
|
-
() => {
|
|
82
|
-
expect(getHtml(container)).toMatch('life cycle render');
|
|
83
|
-
expect(getHtml(container)).toMatch('hello world');
|
|
84
|
-
},
|
|
85
|
-
{ timeout: 2000 },
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('createRemoteAppComponent and obtain ref property', async () => {
|
|
90
|
-
const ref = {
|
|
91
|
-
current: null,
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
function Component({ props }: { props?: Record<string, any> }) {
|
|
95
|
-
return <div>life cycle render {props?.msg}</div>;
|
|
96
|
-
}
|
|
97
|
-
const BridgeComponent = createBridgeComponent({
|
|
98
|
-
rootComponent: Component,
|
|
99
|
-
});
|
|
100
|
-
const RemoteComponent = createRemoteAppComponent({
|
|
101
|
-
loader: async () => {
|
|
102
|
-
return {
|
|
103
|
-
default: BridgeComponent,
|
|
104
|
-
};
|
|
105
|
-
},
|
|
106
|
-
fallback: () => <div></div>,
|
|
107
|
-
loading: <div>loading</div>,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const { container } = render(
|
|
111
|
-
<RemoteComponent ref={ref} props={{ msg: 'hello world' }} />,
|
|
112
|
-
);
|
|
113
|
-
expect(getHtml(container)).toMatch('loading');
|
|
114
|
-
|
|
115
|
-
await waitFor(
|
|
116
|
-
() => {
|
|
117
|
-
expect(getHtml(container)).toMatch('life cycle render');
|
|
118
|
-
expect(getHtml(container)).toMatch('hello world');
|
|
119
|
-
expect(ref.current).not.toBeNull();
|
|
120
|
-
},
|
|
121
|
-
{ timeout: 2000 },
|
|
122
|
-
);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('createRemoteAppComponent with custom createRoot prop', async () => {
|
|
126
|
-
const renderMock = jest.fn();
|
|
127
|
-
|
|
128
|
-
function Component({ props }: { props?: Record<string, any> }) {
|
|
129
|
-
return <div>life cycle render {props?.msg}</div>;
|
|
130
|
-
}
|
|
131
|
-
const BridgeComponent = createBridgeComponent({
|
|
132
|
-
rootComponent: Component,
|
|
133
|
-
createRoot: () => {
|
|
134
|
-
return {
|
|
135
|
-
render: renderMock,
|
|
136
|
-
unmount: jest.fn(),
|
|
137
|
-
};
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
const RemoteComponent = createRemoteAppComponent({
|
|
141
|
-
loader: async () => {
|
|
142
|
-
return {
|
|
143
|
-
default: BridgeComponent,
|
|
144
|
-
};
|
|
145
|
-
},
|
|
146
|
-
fallback: () => <div></div>,
|
|
147
|
-
loading: <div>loading</div>,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
const { container } = render(<RemoteComponent />);
|
|
151
|
-
expect(getHtml(container)).toMatch('loading');
|
|
152
|
-
|
|
153
|
-
await waitFor(
|
|
154
|
-
() => {
|
|
155
|
-
expect(renderMock).toHaveBeenCalledTimes(1);
|
|
156
|
-
},
|
|
157
|
-
{ timeout: 2000 },
|
|
158
|
-
);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import React, { Suspense } from 'react';
|
|
2
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
|
-
import {
|
|
4
|
-
createLazyComponent,
|
|
5
|
-
collectSSRAssets,
|
|
6
|
-
} from '../src/lazy/createLazyComponent';
|
|
7
|
-
import * as runtime from '@module-federation/runtime';
|
|
8
|
-
import * as utils from '../src/lazy/utils';
|
|
9
|
-
|
|
10
|
-
// Mocking dependencies
|
|
11
|
-
jest.mock('@module-federation/runtime');
|
|
12
|
-
jest.mock('../src/lazy/utils');
|
|
13
|
-
|
|
14
|
-
const mockGetInstance = runtime.getInstance as jest.Mock;
|
|
15
|
-
const mockGetLoadedRemoteInfos = utils.getLoadedRemoteInfos as jest.Mock;
|
|
16
|
-
const mockGetDataFetchMapKey = utils.getDataFetchMapKey as jest.Mock;
|
|
17
|
-
const mockFetchData = utils.fetchData as jest.Mock;
|
|
18
|
-
|
|
19
|
-
const MockComponent = () => <div>Mock Component</div>;
|
|
20
|
-
const LoadingComponent = () => <div>Loading...</div>;
|
|
21
|
-
const ErrorComponent = () => <div>Error!</div>;
|
|
22
|
-
|
|
23
|
-
describe('createLazyComponent', () => {
|
|
24
|
-
let mockInstance: any;
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
jest.clearAllMocks();
|
|
28
|
-
mockInstance = {
|
|
29
|
-
name: 'host-app',
|
|
30
|
-
options: { version: '1.0.0' },
|
|
31
|
-
getModuleInfo: jest.fn(),
|
|
32
|
-
};
|
|
33
|
-
mockGetInstance.mockReturnValue(mockInstance);
|
|
34
|
-
mockGetLoadedRemoteInfos.mockReturnValue({
|
|
35
|
-
name: 'remoteApp',
|
|
36
|
-
alias: 'remote',
|
|
37
|
-
expose: './Component',
|
|
38
|
-
version: '1.0.0',
|
|
39
|
-
snapshot: {
|
|
40
|
-
modules: [
|
|
41
|
-
{
|
|
42
|
-
modulePath: './Component',
|
|
43
|
-
assets: {
|
|
44
|
-
css: { sync: [], async: [] },
|
|
45
|
-
js: { sync: [], async: [] },
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
publicPath: 'http://localhost:3001/',
|
|
50
|
-
remoteEntry: 'remoteEntry.js',
|
|
51
|
-
},
|
|
52
|
-
entryGlobalName: 'remoteApp',
|
|
53
|
-
});
|
|
54
|
-
mockGetDataFetchMapKey.mockReturnValue('data-fetch-key');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should render loading component then the actual component', async () => {
|
|
58
|
-
const loader = jest.fn().mockResolvedValue({
|
|
59
|
-
default: MockComponent,
|
|
60
|
-
[Symbol.for('mf_module_id')]: 'remoteApp/Component',
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const LazyComponent = createLazyComponent({
|
|
64
|
-
loader,
|
|
65
|
-
instance: mockInstance,
|
|
66
|
-
loading: <LoadingComponent />,
|
|
67
|
-
fallback: <ErrorComponent />,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
render(
|
|
71
|
-
<Suspense fallback={<LoadingComponent />}>
|
|
72
|
-
<LazyComponent />
|
|
73
|
-
</Suspense>,
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
|
77
|
-
|
|
78
|
-
await waitFor(() => {
|
|
79
|
-
expect(screen.getByText('Mock Component')).toBeInTheDocument();
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should render fallback component on data fetch error', async () => {
|
|
84
|
-
mockFetchData.mockRejectedValue(new Error('Data fetch failed'));
|
|
85
|
-
const LazyComponentWithDataFetch = createLazyComponent({
|
|
86
|
-
loader: jest.fn().mockResolvedValue({
|
|
87
|
-
default: MockComponent,
|
|
88
|
-
[Symbol.for('mf_module_id')]: 'remoteApp/Component',
|
|
89
|
-
}),
|
|
90
|
-
instance: mockInstance,
|
|
91
|
-
loading: <LoadingComponent />,
|
|
92
|
-
fallback: <ErrorComponent />,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
render(<LazyComponentWithDataFetch />);
|
|
96
|
-
|
|
97
|
-
await waitFor(() => {
|
|
98
|
-
expect(screen.getByText('Error!')).toBeInTheDocument();
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should fetch data and pass it to the component', async () => {
|
|
103
|
-
const loader = jest.fn().mockResolvedValue({
|
|
104
|
-
default: (props: { mfData: any }) => (
|
|
105
|
-
<div>Data: {JSON.stringify(props.mfData)}</div>
|
|
106
|
-
),
|
|
107
|
-
[Symbol.for('mf_module_id')]: 'remoteApp/Component',
|
|
108
|
-
});
|
|
109
|
-
const mockData = { message: 'Hello' };
|
|
110
|
-
mockFetchData.mockResolvedValue(mockData);
|
|
111
|
-
|
|
112
|
-
const LazyComponent = createLazyComponent({
|
|
113
|
-
loader,
|
|
114
|
-
instance: mockInstance,
|
|
115
|
-
loading: <LoadingComponent />,
|
|
116
|
-
fallback: <ErrorComponent />,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
render(<LazyComponent />);
|
|
120
|
-
|
|
121
|
-
await waitFor(() => {
|
|
122
|
-
expect(
|
|
123
|
-
screen.getByText(`Data: ${JSON.stringify(mockData)}`),
|
|
124
|
-
).toBeInTheDocument();
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
describe('collectSSRAssets', () => {
|
|
130
|
-
let mockInstance: any;
|
|
131
|
-
|
|
132
|
-
beforeEach(() => {
|
|
133
|
-
jest.clearAllMocks();
|
|
134
|
-
mockInstance = {
|
|
135
|
-
name: 'host-app',
|
|
136
|
-
options: { version: '1.0.0' },
|
|
137
|
-
};
|
|
138
|
-
mockGetInstance.mockReturnValue(mockInstance);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('should return an empty array if instance is not available', () => {
|
|
142
|
-
const assets = collectSSRAssets({
|
|
143
|
-
id: 'test/expose',
|
|
144
|
-
instance: undefined as any,
|
|
145
|
-
});
|
|
146
|
-
expect(assets).toEqual([]);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should return an empty array if module info is not found', () => {
|
|
150
|
-
mockGetLoadedRemoteInfos.mockReturnValue(undefined);
|
|
151
|
-
const assets = collectSSRAssets({
|
|
152
|
-
id: 'test/expose',
|
|
153
|
-
instance: mockInstance,
|
|
154
|
-
});
|
|
155
|
-
expect(assets).toEqual([]);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should collect CSS and JS assets for SSR', () => {
|
|
159
|
-
mockGetLoadedRemoteInfos.mockReturnValue({
|
|
160
|
-
name: 'remoteApp',
|
|
161
|
-
expose: './Component',
|
|
162
|
-
snapshot: {
|
|
163
|
-
publicPath: 'http://localhost:3001/',
|
|
164
|
-
remoteEntry: 'remoteEntry.js',
|
|
165
|
-
modules: [
|
|
166
|
-
{
|
|
167
|
-
modulePath: './Component',
|
|
168
|
-
assets: {
|
|
169
|
-
css: { sync: ['main.css'], async: ['extra.css'] },
|
|
170
|
-
js: { sync: ['main.js'], async: [] },
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
],
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const assets = collectSSRAssets({
|
|
178
|
-
id: 'remoteApp/Component',
|
|
179
|
-
instance: mockInstance,
|
|
180
|
-
injectScript: true,
|
|
181
|
-
injectLink: true,
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
expect(assets).toHaveLength(4); // 2 links, 2 scripts
|
|
185
|
-
|
|
186
|
-
const links = assets.filter(
|
|
187
|
-
(asset) => (asset as React.ReactElement).type === 'link',
|
|
188
|
-
);
|
|
189
|
-
const scripts = assets.filter(
|
|
190
|
-
(asset) => (asset as React.ReactElement).type === 'script',
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
expect(links).toHaveLength(2);
|
|
194
|
-
expect((links[0] as React.ReactElement).props.href).toBe(
|
|
195
|
-
'http://localhost:3001/extra.css',
|
|
196
|
-
);
|
|
197
|
-
expect((links[1] as React.ReactElement).props.href).toBe(
|
|
198
|
-
'http://localhost:3001/main.css',
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
expect(scripts).toHaveLength(2);
|
|
202
|
-
expect((scripts[0] as React.ReactElement).props.src).toBe(
|
|
203
|
-
'http://localhost:3001/remoteEntry.js',
|
|
204
|
-
);
|
|
205
|
-
expect((scripts[1] as React.ReactElement).props.src).toBe(
|
|
206
|
-
'http://localhost:3001/main.js',
|
|
207
|
-
);
|
|
208
|
-
});
|
|
209
|
-
});
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { prefetch } from '../src/lazy/data-fetch/prefetch';
|
|
2
|
-
import * as utils from '../src/lazy/utils';
|
|
3
|
-
import logger from '../src/lazy/logger';
|
|
4
|
-
import helpers from '@module-federation/runtime/helpers';
|
|
5
|
-
|
|
6
|
-
// Mock dependencies
|
|
7
|
-
jest.mock('../src/lazy/logger');
|
|
8
|
-
jest.mock('../src/lazy/utils');
|
|
9
|
-
jest.mock('@module-federation/runtime/helpers', () => ({
|
|
10
|
-
default: {
|
|
11
|
-
utils: {
|
|
12
|
-
matchRemoteWithNameAndExpose: jest.fn(),
|
|
13
|
-
getRemoteInfo: jest.fn(),
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
utils: {
|
|
17
|
-
matchRemoteWithNameAndExpose: jest.fn(),
|
|
18
|
-
getRemoteInfo: jest.fn(),
|
|
19
|
-
},
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
describe('prefetch', () => {
|
|
23
|
-
let mockInstance: any;
|
|
24
|
-
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
jest.clearAllMocks();
|
|
27
|
-
mockInstance = {
|
|
28
|
-
name: 'host',
|
|
29
|
-
options: {
|
|
30
|
-
version: '1.0.0',
|
|
31
|
-
remotes: [
|
|
32
|
-
{
|
|
33
|
-
name: 'remote1',
|
|
34
|
-
alias: 'remote1_alias',
|
|
35
|
-
entry: 'http://localhost:3001/remoteEntry.js',
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
},
|
|
39
|
-
snapshotHandler: {
|
|
40
|
-
loadRemoteSnapshotInfo: jest.fn(),
|
|
41
|
-
},
|
|
42
|
-
remoteHandler: {
|
|
43
|
-
hooks: {
|
|
44
|
-
lifecycle: {
|
|
45
|
-
generatePreloadAssets: {
|
|
46
|
-
emit: jest.fn(),
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should log an error if id is not provided', async () => {
|
|
55
|
-
// @ts-ignore
|
|
56
|
-
await prefetch({ instance: mockInstance });
|
|
57
|
-
expect(logger.error).toHaveBeenCalledWith('id is required for prefetch!');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should log an error if instance is not provided', async () => {
|
|
61
|
-
// @ts-ignore
|
|
62
|
-
await prefetch({ id: 'remote1/component1' });
|
|
63
|
-
expect(logger.error).toHaveBeenCalledWith(
|
|
64
|
-
'instance is required for prefetch!',
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should log an error if remote is not found', async () => {
|
|
69
|
-
(helpers.utils.matchRemoteWithNameAndExpose as jest.Mock).mockReturnValue(
|
|
70
|
-
undefined,
|
|
71
|
-
);
|
|
72
|
-
await prefetch({ id: 'nonexistent/component', instance: mockInstance });
|
|
73
|
-
expect(logger.error).toHaveBeenCalledWith(
|
|
74
|
-
`Can not found 'nonexistent/component' in instance.options.remotes!`,
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('should successfully prefetch data and component resources', async () => {
|
|
79
|
-
const mockRemoteInfo = {
|
|
80
|
-
remote: { name: 'remote1', alias: 'remote1_alias' },
|
|
81
|
-
expose: './component1',
|
|
82
|
-
};
|
|
83
|
-
(helpers.utils.matchRemoteWithNameAndExpose as jest.Mock).mockReturnValue(
|
|
84
|
-
mockRemoteInfo,
|
|
85
|
-
);
|
|
86
|
-
(
|
|
87
|
-
mockInstance.snapshotHandler.loadRemoteSnapshotInfo as jest.Mock
|
|
88
|
-
).mockResolvedValue({
|
|
89
|
-
remoteSnapshot: {},
|
|
90
|
-
globalSnapshot: {},
|
|
91
|
-
});
|
|
92
|
-
(helpers.utils.getRemoteInfo as jest.Mock).mockReturnValue({});
|
|
93
|
-
|
|
94
|
-
const mockDataFetchFn = jest
|
|
95
|
-
.fn()
|
|
96
|
-
.mockResolvedValue({ data: 'prefetched data' });
|
|
97
|
-
const mockGetDataFetchGetter = jest.fn().mockResolvedValue(mockDataFetchFn);
|
|
98
|
-
const mockDataFetchMap = {
|
|
99
|
-
'remote1_alias@remote1/component1': [
|
|
100
|
-
[mockGetDataFetchGetter, 'GET', undefined],
|
|
101
|
-
],
|
|
102
|
-
};
|
|
103
|
-
(utils.getDataFetchMap as jest.Mock).mockReturnValue(mockDataFetchMap);
|
|
104
|
-
(utils.getDataFetchInfo as jest.Mock).mockReturnValue({
|
|
105
|
-
name: 'remote1',
|
|
106
|
-
alias: 'remote1_alias',
|
|
107
|
-
id: 'remote1/component1',
|
|
108
|
-
});
|
|
109
|
-
(utils.getDataFetchMapKey as jest.Mock).mockReturnValue(
|
|
110
|
-
'remote1_alias@remote1/component1',
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
await prefetch({
|
|
114
|
-
id: 'remote1/component1',
|
|
115
|
-
instance: mockInstance,
|
|
116
|
-
dataFetchParams: { some: 'param', isDowngrade: false } as any,
|
|
117
|
-
preloadComponentResource: true,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
expect(
|
|
121
|
-
mockInstance.remoteHandler.hooks.lifecycle.generatePreloadAssets.emit,
|
|
122
|
-
).toHaveBeenCalled();
|
|
123
|
-
|
|
124
|
-
expect(mockGetDataFetchGetter).toHaveBeenCalled();
|
|
125
|
-
await new Promise(process.nextTick);
|
|
126
|
-
expect(mockDataFetchFn).toHaveBeenCalledWith({
|
|
127
|
-
some: 'param',
|
|
128
|
-
_id: 'remote1_alias@remote1/component1',
|
|
129
|
-
isDowngrade: false,
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should handle cases where data fetch info is not available', async () => {
|
|
134
|
-
const mockRemoteInfo = {
|
|
135
|
-
remote: { name: 'remote1', alias: 'remote1_alias' },
|
|
136
|
-
expose: './component1',
|
|
137
|
-
};
|
|
138
|
-
(helpers.utils.matchRemoteWithNameAndExpose as jest.Mock).mockReturnValue(
|
|
139
|
-
mockRemoteInfo,
|
|
140
|
-
);
|
|
141
|
-
(
|
|
142
|
-
mockInstance.snapshotHandler.loadRemoteSnapshotInfo as jest.Mock
|
|
143
|
-
).mockResolvedValue({
|
|
144
|
-
remoteSnapshot: {},
|
|
145
|
-
globalSnapshot: {},
|
|
146
|
-
});
|
|
147
|
-
(utils.getDataFetchMap as jest.Mock).mockReturnValue(undefined);
|
|
148
|
-
|
|
149
|
-
await prefetch({
|
|
150
|
-
id: 'remote1/component1',
|
|
151
|
-
instance: mockInstance,
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
expect(utils.getDataFetchInfo).not.toHaveBeenCalled();
|
|
155
|
-
});
|
|
156
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
// Test file for router
|
|
2
|
-
import { render } from '@testing-library/react';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import {
|
|
5
|
-
Link,
|
|
6
|
-
Routes,
|
|
7
|
-
Route,
|
|
8
|
-
Outlet,
|
|
9
|
-
createBrowserRouter,
|
|
10
|
-
} from 'react-router-dom';
|
|
11
|
-
import { BrowserRouter, RouterProvider } from '../src/router/default';
|
|
12
|
-
import { RouterContext } from '../src/provider/context';
|
|
13
|
-
import { getHtml, getWindowImpl } from './util';
|
|
14
|
-
|
|
15
|
-
describe('react router proxy', () => {
|
|
16
|
-
it('BrowserRouter not wraper context', async () => {
|
|
17
|
-
let { container } = render(
|
|
18
|
-
<RouterContext.Provider value={{ basename: '/test' } as any}>
|
|
19
|
-
<BrowserRouter basename="/" window={getWindowImpl('/test', false)}>
|
|
20
|
-
<ul>
|
|
21
|
-
<li>
|
|
22
|
-
<Link to="/">Home</Link>
|
|
23
|
-
</li>
|
|
24
|
-
<li>
|
|
25
|
-
<Link to="/detail">Detail</Link>
|
|
26
|
-
</li>
|
|
27
|
-
</ul>
|
|
28
|
-
<Routes>
|
|
29
|
-
<Route path="/" Component={() => <div>home page</div>} />
|
|
30
|
-
<Route path="/detail" Component={() => <div>detail page</div>} />
|
|
31
|
-
</Routes>
|
|
32
|
-
</BrowserRouter>
|
|
33
|
-
</RouterContext.Provider>,
|
|
34
|
-
);
|
|
35
|
-
expect(getHtml(container)).toMatch('home page');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('RouterProvider', async () => {
|
|
39
|
-
function Layout() {
|
|
40
|
-
return (
|
|
41
|
-
<>
|
|
42
|
-
<ul>
|
|
43
|
-
<li>
|
|
44
|
-
<Link to="/">Home</Link>
|
|
45
|
-
</li>
|
|
46
|
-
<li>
|
|
47
|
-
<Link to="/detail">Detail</Link>
|
|
48
|
-
</li>
|
|
49
|
-
</ul>
|
|
50
|
-
<Outlet />
|
|
51
|
-
</>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
const router = createBrowserRouter(
|
|
55
|
-
[
|
|
56
|
-
{
|
|
57
|
-
path: '/',
|
|
58
|
-
element: <Layout />,
|
|
59
|
-
children: [
|
|
60
|
-
{
|
|
61
|
-
index: true,
|
|
62
|
-
element: <div>home page</div>,
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
path: '/detail',
|
|
66
|
-
element: <div>detail page</div>,
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
{
|
|
72
|
-
window: getWindowImpl('/test', false),
|
|
73
|
-
},
|
|
74
|
-
);
|
|
75
|
-
let { container } = render(
|
|
76
|
-
<RouterContext.Provider value={{ basename: '/test' } as any}>
|
|
77
|
-
<RouterProvider router={router} />
|
|
78
|
-
</RouterContext.Provider>,
|
|
79
|
-
);
|
|
80
|
-
expect(getHtml(container)).toMatch('home page');
|
|
81
|
-
});
|
|
82
|
-
});
|
package/__tests__/setupTests.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// In vitest, you can use the setupFiles option in your configuration file to import any necessary setup files for your tests.
|
|
2
|
-
// For example, if you want to use testing-library's custom matchers, you can import them in a setup file like this:
|
|
3
|
-
import '@testing-library/jest-dom';
|
|
4
|
-
|
|
5
|
-
// Fix TextEncoder/TextDecoder not defined in Node.js
|
|
6
|
-
import { TextEncoder, TextDecoder } from 'util';
|
|
7
|
-
global.TextEncoder = TextEncoder;
|
|
8
|
-
global.TextDecoder = TextDecoder as any;
|
package/__tests__/util.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { JSDOM } from 'jsdom';
|
|
2
|
-
import { prettyDOM } from '@testing-library/react';
|
|
3
|
-
|
|
4
|
-
export async function sleep(time: number) {
|
|
5
|
-
return new Promise((resolve) => {
|
|
6
|
-
setTimeout(() => {
|
|
7
|
-
resolve(null);
|
|
8
|
-
}, time);
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function createContainer() {
|
|
13
|
-
const container = document.createElement('div');
|
|
14
|
-
container.setAttribute('id', 'container');
|
|
15
|
-
document.body.appendChild(container);
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
clean: () => {
|
|
19
|
-
document.body.removeChild(container);
|
|
20
|
-
},
|
|
21
|
-
container,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function getWindowImpl(initialUrl: string, isHash = false): Window {
|
|
26
|
-
// Need to use our own custom DOM in order to get a working history
|
|
27
|
-
const dom = new JSDOM(`<!DOCTYPE html>`, { url: 'http://localhost/' });
|
|
28
|
-
dom.window.history.replaceState(null, '', (isHash ? '#' : '') + initialUrl);
|
|
29
|
-
return dom.window as unknown as Window;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function getHtml(container: HTMLElement) {
|
|
33
|
-
return prettyDOM(container, undefined, {
|
|
34
|
-
highlight: false,
|
|
35
|
-
});
|
|
36
|
-
}
|
package/jest.config.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
displayName: 'bridge-react',
|
|
3
|
-
preset: '../../../jest.preset.js',
|
|
4
|
-
transform: {
|
|
5
|
-
'^.+\\.[tj]sx?$': [
|
|
6
|
-
'ts-jest',
|
|
7
|
-
{
|
|
8
|
-
tsconfig: '<rootDir>/tsconfig.spec.json',
|
|
9
|
-
isolatedModules: true,
|
|
10
|
-
},
|
|
11
|
-
],
|
|
12
|
-
},
|
|
13
|
-
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
|
14
|
-
coverageDirectory: '../../../coverage/packages/bridge/bridge-react',
|
|
15
|
-
testEnvironment: 'jsdom',
|
|
16
|
-
setupFilesAfterEnv: ['<rootDir>/__tests__/setupTests.ts'],
|
|
17
|
-
testMatch: [
|
|
18
|
-
'<rootDir>/__tests__/**/*.spec.ts',
|
|
19
|
-
'<rootDir>/__tests__/**/*.spec.tsx',
|
|
20
|
-
],
|
|
21
|
-
};
|