repluggable-core 1.302.65 → 1.302.67
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/__tests__/spec-setup.js +3 -0
- package/dist/es/{API.d.ts → src/API.d.ts} +46 -8
- package/dist/es/src/API.d.ts.map +1 -0
- package/dist/es/src/API.js +3 -0
- package/dist/es/src/API.js.map +1 -0
- package/dist/es/src/IterableWeakMap.d.ts +20 -0
- package/dist/es/src/IterableWeakMap.d.ts.map +1 -0
- package/dist/es/src/IterableWeakMap.js +92 -0
- package/dist/es/src/IterableWeakMap.js.map +1 -0
- package/dist/es/src/__internal.d.ts.map +1 -0
- package/dist/es/src/__internal.js +5 -0
- package/dist/es/src/__internal.js.map +1 -0
- package/dist/es/src/appHost.d.ts +7 -0
- package/dist/es/src/appHost.d.ts.map +1 -0
- package/dist/es/src/appHost.js +898 -0
- package/dist/es/src/appHost.js.map +1 -0
- package/dist/es/src/appHostServices.d.ts +12 -0
- package/dist/es/src/appHostServices.d.ts.map +1 -0
- package/dist/es/src/appHostServices.js +25 -0
- package/dist/es/src/appHostServices.js.map +1 -0
- package/dist/es/src/appHostUtils.d.ts +4 -0
- package/dist/es/src/appHostUtils.d.ts.map +1 -0
- package/dist/es/src/appHostUtils.js +8 -0
- package/dist/es/src/appHostUtils.js.map +1 -0
- package/dist/es/src/extensionSlot.d.ts +8 -0
- package/dist/es/src/extensionSlot.d.ts.map +1 -0
- package/dist/es/src/extensionSlot.js +59 -0
- package/dist/es/src/extensionSlot.js.map +1 -0
- package/dist/es/src/hot.d.ts +14 -0
- package/dist/es/src/hot.d.ts.map +1 -0
- package/dist/es/src/hot.js +52 -0
- package/dist/es/src/hot.js.map +1 -0
- package/dist/es/src/index.d.ts +11 -0
- package/dist/es/src/index.d.ts.map +1 -0
- package/dist/es/src/index.js +10 -0
- package/dist/es/src/index.js.map +1 -0
- package/dist/es/src/installedShellsState.d.ts +19 -0
- package/dist/es/src/installedShellsState.d.ts.map +1 -0
- package/dist/es/src/installedShellsState.js +30 -0
- package/dist/es/src/installedShellsState.js.map +1 -0
- package/dist/es/src/interceptAnyObject.d.ts +7 -0
- package/dist/es/src/interceptAnyObject.d.ts.map +1 -0
- package/dist/es/src/interceptAnyObject.js +21 -0
- package/dist/es/src/interceptAnyObject.js.map +1 -0
- package/dist/es/src/invokeSlotCallbacks.d.ts +3 -0
- package/dist/es/src/invokeSlotCallbacks.d.ts.map +1 -0
- package/dist/es/src/invokeSlotCallbacks.js +20 -0
- package/dist/es/src/invokeSlotCallbacks.js.map +1 -0
- package/dist/es/src/loggers.d.ts +4 -0
- package/dist/es/src/loggers.d.ts.map +1 -0
- package/dist/es/src/loggers.js +100 -0
- package/dist/es/src/loggers.js.map +1 -0
- package/dist/es/src/monitorAPI.d.ts +3 -0
- package/dist/es/src/monitorAPI.d.ts.map +1 -0
- package/dist/es/src/monitorAPI.js +53 -0
- package/dist/es/src/monitorAPI.js.map +1 -0
- package/dist/es/src/repluggableAppDebug/index.d.ts +2 -0
- package/dist/es/src/repluggableAppDebug/index.d.ts.map +1 -0
- package/dist/es/src/repluggableAppDebug/index.js +2 -0
- package/dist/es/src/repluggableAppDebug/index.js.map +1 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.d.ts +15 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.d.ts.map +1 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.js +94 -0
- package/dist/es/src/repluggableAppDebug/performanceDebugInfo.js.map +1 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts +24 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js +132 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -0
- package/dist/es/src/tarjanGraph.d.ts +27 -0
- package/dist/es/src/tarjanGraph.d.ts.map +1 -0
- package/dist/es/src/tarjanGraph.js +94 -0
- package/dist/es/src/tarjanGraph.js.map +1 -0
- package/dist/es/src/throttledStore.d.ts +32 -0
- package/dist/es/src/throttledStore.d.ts.map +1 -0
- package/dist/es/src/throttledStore.js +240 -0
- package/dist/es/src/throttledStore.js.map +1 -0
- package/dist/es/test/IterableWeakMap.spec.d.ts +2 -0
- package/dist/es/test/IterableWeakMap.spec.d.ts.map +1 -0
- package/dist/es/test/IterableWeakMap.spec.js +218 -0
- package/dist/es/test/IterableWeakMap.spec.js.map +1 -0
- package/dist/es/test/appHost.mock.d.ts +4 -0
- package/dist/es/test/appHost.mock.d.ts.map +1 -0
- package/dist/es/test/appHost.mock.js +54 -0
- package/dist/es/test/appHost.mock.js.map +1 -0
- package/dist/es/test/appHost.spec.d.ts +2 -0
- package/dist/es/test/appHost.spec.d.ts.map +1 -0
- package/dist/es/test/appHost.spec.js +1451 -0
- package/dist/es/test/appHost.spec.js.map +1 -0
- package/dist/es/test/installedShellsState.spec.d.ts +2 -0
- package/dist/es/test/installedShellsState.spec.d.ts.map +1 -0
- package/dist/es/test/installedShellsState.spec.js +28 -0
- package/dist/es/test/installedShellsState.spec.js.map +1 -0
- package/dist/es/test/interceptAnyObject.spec.d.ts +2 -0
- package/dist/es/test/interceptAnyObject.spec.d.ts.map +1 -0
- package/dist/es/test/interceptAnyObject.spec.js +166 -0
- package/dist/es/test/interceptAnyObject.spec.js.map +1 -0
- package/dist/es/test/loggers.spec.d.ts +2 -0
- package/dist/es/test/loggers.spec.d.ts.map +1 -0
- package/dist/es/test/loggers.spec.js +218 -0
- package/dist/es/test/loggers.spec.js.map +1 -0
- package/dist/es/test/repluggableAppDebug.spec.d.ts +2 -0
- package/dist/es/test/repluggableAppDebug.spec.d.ts.map +1 -0
- package/dist/es/test/repluggableAppDebug.spec.js +107 -0
- package/dist/es/test/repluggableAppDebug.spec.js.map +1 -0
- package/dist/es/test/testKit.spec.d.ts +2 -0
- package/dist/es/test/testKit.spec.d.ts.map +1 -0
- package/dist/es/test/testKit.spec.js +129 -0
- package/dist/es/test/testKit.spec.js.map +1 -0
- package/dist/es/testKit/emptyLoggerOptions.d.ts +3 -0
- package/dist/es/testKit/emptyLoggerOptions.d.ts.map +1 -0
- package/dist/es/testKit/emptyLoggerOptions.js +15 -0
- package/dist/es/testKit/emptyLoggerOptions.js.map +1 -0
- package/dist/es/testKit/index.d.ts +27 -0
- package/dist/es/testKit/index.d.ts.map +1 -0
- package/dist/es/testKit/index.js +132 -0
- package/dist/es/testKit/index.js.map +1 -0
- package/dist/es/testKit/mockPackage.d.ts +23 -0
- package/dist/es/testKit/mockPackage.d.ts.map +1 -0
- package/dist/es/testKit/mockPackage.js +95 -0
- package/dist/es/testKit/mockPackage.js.map +1 -0
- package/dist/es/testKit/withConsoleErrors.d.ts +2 -0
- package/dist/es/testKit/withConsoleErrors.d.ts.map +1 -0
- package/dist/es/testKit/withConsoleErrors.js +12 -0
- package/dist/es/testKit/withConsoleErrors.js.map +1 -0
- package/dist/es/testKit/withThrowOnError.d.ts +3 -0
- package/dist/es/testKit/withThrowOnError.d.ts.map +1 -0
- package/dist/es/testKit/withThrowOnError.js +27 -0
- package/dist/es/testKit/withThrowOnError.js.map +1 -0
- package/dist/src/API.d.ts +46 -8
- package/dist/src/API.d.ts.map +1 -1
- package/dist/src/API.js +4 -0
- package/dist/src/API.js.map +1 -1
- package/dist/src/IterableWeakMap.d.ts +20 -0
- package/dist/src/IterableWeakMap.d.ts.map +1 -0
- package/dist/src/IterableWeakMap.js +96 -0
- package/dist/src/IterableWeakMap.js.map +1 -0
- package/dist/src/__internal.d.ts.map +1 -1
- package/dist/src/__internal.js +1 -1
- package/dist/src/__internal.js.map +1 -1
- package/dist/src/appHost.d.ts +7 -0
- package/dist/src/appHost.d.ts.map +1 -0
- package/dist/src/appHost.js +906 -0
- package/dist/src/appHost.js.map +1 -0
- package/dist/src/appHostServices.d.ts +12 -0
- package/dist/src/appHostServices.d.ts.map +1 -0
- package/dist/src/appHostServices.js +29 -0
- package/dist/src/appHostServices.js.map +1 -0
- package/dist/src/appHostUtils.d.ts +4 -0
- package/dist/src/appHostUtils.d.ts.map +1 -0
- package/dist/src/appHostUtils.js +16 -0
- package/dist/src/appHostUtils.js.map +1 -0
- package/dist/src/extensionSlot.d.ts +8 -0
- package/dist/src/extensionSlot.d.ts.map +1 -0
- package/dist/src/extensionSlot.js +67 -0
- package/dist/src/extensionSlot.js.map +1 -0
- package/dist/src/hot.d.ts +14 -0
- package/dist/src/hot.d.ts.map +1 -0
- package/dist/src/hot.js +56 -0
- package/dist/src/hot.js.map +1 -0
- package/dist/src/index.d.ts +10 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +22 -15
- package/dist/src/index.js.map +1 -1
- package/dist/src/installedShellsState.d.ts +19 -0
- package/dist/src/installedShellsState.d.ts.map +1 -0
- package/dist/src/installedShellsState.js +38 -0
- package/dist/src/installedShellsState.js.map +1 -0
- package/dist/src/interceptAnyObject.d.ts +7 -0
- package/dist/src/interceptAnyObject.d.ts.map +1 -0
- package/dist/src/interceptAnyObject.js +28 -0
- package/dist/src/interceptAnyObject.js.map +1 -0
- package/dist/src/invokeSlotCallbacks.d.ts +3 -0
- package/dist/src/invokeSlotCallbacks.d.ts.map +1 -0
- package/dist/src/invokeSlotCallbacks.js +24 -0
- package/dist/src/invokeSlotCallbacks.js.map +1 -0
- package/dist/src/loggers.d.ts +4 -0
- package/dist/src/loggers.d.ts.map +1 -0
- package/dist/src/loggers.js +104 -0
- package/dist/src/loggers.js.map +1 -0
- package/dist/src/monitorAPI.d.ts +3 -0
- package/dist/src/monitorAPI.d.ts.map +1 -0
- package/dist/src/monitorAPI.js +57 -0
- package/dist/src/monitorAPI.js.map +1 -0
- package/dist/src/repluggableAppDebug/index.d.ts +2 -0
- package/dist/src/repluggableAppDebug/index.d.ts.map +1 -0
- package/dist/src/repluggableAppDebug/index.js +6 -0
- package/dist/src/repluggableAppDebug/index.js.map +1 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.d.ts +15 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.d.ts.map +1 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.js +101 -0
- package/dist/src/repluggableAppDebug/performanceDebugInfo.js.map +1 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts +24 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js +139 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -0
- package/dist/src/tarjanGraph.d.ts +27 -0
- package/dist/src/tarjanGraph.d.ts.map +1 -0
- package/dist/src/tarjanGraph.js +100 -0
- package/dist/src/tarjanGraph.js.map +1 -0
- package/dist/src/throttledStore.d.ts +32 -0
- package/dist/src/throttledStore.d.ts.map +1 -0
- package/dist/src/throttledStore.js +249 -0
- package/dist/src/throttledStore.js.map +1 -0
- package/dist/test/IterableWeakMap.spec.d.ts +2 -0
- package/dist/test/IterableWeakMap.spec.d.ts.map +1 -0
- package/dist/test/IterableWeakMap.spec.js +220 -0
- package/dist/test/IterableWeakMap.spec.js.map +1 -0
- package/dist/test/appHost.mock.d.ts +4 -0
- package/dist/test/appHost.mock.d.ts.map +1 -0
- package/dist/test/appHost.mock.js +59 -0
- package/dist/test/appHost.mock.js.map +1 -0
- package/dist/test/appHost.spec.d.ts +2 -0
- package/dist/test/appHost.spec.d.ts.map +1 -0
- package/dist/test/appHost.spec.js +1456 -0
- package/dist/test/appHost.spec.js.map +1 -0
- package/dist/test/installedShellsState.spec.d.ts +2 -0
- package/dist/test/installedShellsState.spec.d.ts.map +1 -0
- package/dist/test/installedShellsState.spec.js +30 -0
- package/dist/test/installedShellsState.spec.js.map +1 -0
- package/dist/test/interceptAnyObject.spec.d.ts +2 -0
- package/dist/test/interceptAnyObject.spec.d.ts.map +1 -0
- package/dist/test/interceptAnyObject.spec.js +171 -0
- package/dist/test/interceptAnyObject.spec.js.map +1 -0
- package/dist/test/loggers.spec.d.ts +2 -0
- package/dist/test/loggers.spec.d.ts.map +1 -0
- package/dist/test/loggers.spec.js +220 -0
- package/dist/test/loggers.spec.js.map +1 -0
- package/dist/test/repluggableAppDebug.spec.d.ts +2 -0
- package/dist/test/repluggableAppDebug.spec.d.ts.map +1 -0
- package/dist/test/repluggableAppDebug.spec.js +109 -0
- package/dist/test/repluggableAppDebug.spec.js.map +1 -0
- package/dist/test/testKit.spec.d.ts +2 -0
- package/dist/test/testKit.spec.d.ts.map +1 -0
- package/dist/test/testKit.spec.js +134 -0
- package/dist/test/testKit.spec.js.map +1 -0
- package/dist/testKit/emptyLoggerOptions.d.ts +3 -0
- package/dist/testKit/emptyLoggerOptions.d.ts.map +1 -0
- package/dist/testKit/emptyLoggerOptions.js +18 -0
- package/dist/testKit/emptyLoggerOptions.js.map +1 -0
- package/dist/testKit/index.d.ts +27 -0
- package/dist/testKit/index.d.ts.map +1 -0
- package/dist/testKit/index.js +160 -0
- package/dist/testKit/index.js.map +1 -0
- package/dist/testKit/mockPackage.d.ts +23 -0
- package/dist/testKit/mockPackage.d.ts.map +1 -0
- package/dist/testKit/mockPackage.js +101 -0
- package/dist/testKit/mockPackage.js.map +1 -0
- package/dist/testKit/withConsoleErrors.d.ts +2 -0
- package/dist/testKit/withConsoleErrors.d.ts.map +1 -0
- package/dist/testKit/withConsoleErrors.js +16 -0
- package/dist/testKit/withConsoleErrors.js.map +1 -0
- package/dist/testKit/withThrowOnError.d.ts +3 -0
- package/dist/testKit/withThrowOnError.d.ts.map +1 -0
- package/dist/testKit/withThrowOnError.js +31 -0
- package/dist/testKit/withThrowOnError.js.map +1 -0
- package/jest.config.js +16 -0
- package/package.json +21 -3
- package/src/API.ts +47 -9
- package/src/IterableWeakMap.ts +123 -0
- package/src/__internal.ts +1 -1
- package/src/appHost.ts +1222 -0
- package/src/appHostServices.ts +42 -0
- package/src/appHostUtils.ts +11 -0
- package/src/extensionSlot.ts +96 -0
- package/src/hot.ts +53 -0
- package/src/index.ts +42 -2
- package/src/installedShellsState.ts +54 -0
- package/src/interceptAnyObject.ts +39 -0
- package/src/invokeSlotCallbacks.ts +20 -0
- package/src/loggers.ts +112 -0
- package/src/monitorAPI.ts +71 -0
- package/src/repluggableAppDebug/debug.d.ts +37 -0
- package/src/repluggableAppDebug/index.ts +1 -0
- package/src/repluggableAppDebug/performanceDebugInfo.ts +96 -0
- package/src/repluggableAppDebug/repluggableAppDebug.ts +192 -0
- package/src/tarjanGraph.ts +96 -0
- package/src/throttledStore.ts +355 -0
- package/test/IterableWeakMap.spec.ts +280 -0
- package/test/appHost.mock.ts +58 -0
- package/test/appHost.spec.ts +1765 -0
- package/test/installedShellsState.spec.ts +39 -0
- package/test/interceptAnyObject.spec.ts +217 -0
- package/test/loggers.spec.ts +288 -0
- package/test/repluggableAppDebug.spec.ts +118 -0
- package/test/testKit.spec.tsx +153 -0
- package/testKit/emptyLoggerOptions.ts +16 -0
- package/testKit/index.ts +170 -0
- package/testKit/mockPackage.ts +110 -0
- package/testKit/package.json +3 -0
- package/testKit/withConsoleErrors.ts +12 -0
- package/testKit/withThrowOnError.ts +34 -0
- package/tsconfig.json +9 -2
- package/dist/es/API.d.ts.map +0 -1
- package/dist/es/API.js +0 -2
- package/dist/es/API.js.map +0 -1
- package/dist/es/__internal.d.ts.map +0 -1
- package/dist/es/__internal.js +0 -5
- package/dist/es/__internal.js.map +0 -1
- package/dist/es/index.d.ts +0 -3
- package/dist/es/index.d.ts.map +0 -1
- package/dist/es/index.js +0 -2
- package/dist/es/index.js.map +0 -1
- /package/dist/es/{__internal.d.ts → src/__internal.d.ts} +0 -0
|
@@ -0,0 +1,1451 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import _ from 'lodash';
|
|
11
|
+
import { createAppHost, mainViewSlotKey, makeLazyEntryPoint, stateSlotKey } from '../src/appHost';
|
|
12
|
+
import { addMockShell, asyncLoadMockPackage, dependsOnMockPackageEntryPoint, emptyLoggerOptions, MockAPI, mockPackage, mockPackageWithPublicAPI, mockPackageWithSlot, MockPublicAPI, mockShellInitialState, mockShellStateKey, MockSlot } from '../testKit';
|
|
13
|
+
import { AppHostAPI, AppHostServicesEntryPointName } from '../src/appHostServices';
|
|
14
|
+
import { ConsoleHostLogger } from '../src/loggers';
|
|
15
|
+
import { createCircularEntryPoints, createDirectCircularEntryPoints } from './appHost.mock';
|
|
16
|
+
const testHostOptions = {
|
|
17
|
+
monitoring: { disableMonitoring: true }
|
|
18
|
+
};
|
|
19
|
+
const createHostWithDependantPackages = (DependencyAPI) => {
|
|
20
|
+
const MockAPI2 = { name: 'Mock-API-2' };
|
|
21
|
+
const dependentPackage = [
|
|
22
|
+
{
|
|
23
|
+
name: 'DEPENDENT_MOCK_ENTRY_POINT_1',
|
|
24
|
+
getDependencyAPIs() {
|
|
25
|
+
return [DependencyAPI];
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'DEPENDENT_MOCK_ENTRY_POINT_2',
|
|
30
|
+
getDependencyAPIs() {
|
|
31
|
+
return [DependencyAPI];
|
|
32
|
+
},
|
|
33
|
+
declareAPIs() {
|
|
34
|
+
return [MockAPI2];
|
|
35
|
+
},
|
|
36
|
+
attach(shell) {
|
|
37
|
+
shell.contributeAPI(MockAPI2, () => ({}));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
const deeplyDependentPackage = [
|
|
42
|
+
{
|
|
43
|
+
name: 'DEPENDENT_MOCK_ENTRY_POINT_3',
|
|
44
|
+
getDependencyAPIs() {
|
|
45
|
+
return [MockAPI2];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
let getHelperShell = () => {
|
|
50
|
+
throw new Error();
|
|
51
|
+
};
|
|
52
|
+
const helperEntryPoint = {
|
|
53
|
+
name: 'TEST_HELPER',
|
|
54
|
+
declareAPIs() {
|
|
55
|
+
return [DependencyAPI];
|
|
56
|
+
},
|
|
57
|
+
attach(shell) {
|
|
58
|
+
getHelperShell = () => shell;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
host: createAppHost([dependentPackage, deeplyDependentPackage, helperEntryPoint], testHostOptions),
|
|
63
|
+
dependentPackage,
|
|
64
|
+
deeplyDependentPackage,
|
|
65
|
+
helperShell: getHelperShell()
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
describe('App Host', () => {
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
spyOn(ConsoleHostLogger, 'log');
|
|
71
|
+
});
|
|
72
|
+
it('should create an app host', () => {
|
|
73
|
+
const host = createAppHost([], testHostOptions);
|
|
74
|
+
expect(host).toBeInstanceOf(Object);
|
|
75
|
+
});
|
|
76
|
+
describe('AppHost Options', () => {
|
|
77
|
+
it('should use ConsoleHostLogger by default', () => {
|
|
78
|
+
const host = createAppHost([], testHostOptions);
|
|
79
|
+
expect(host.log).toBe(ConsoleHostLogger);
|
|
80
|
+
});
|
|
81
|
+
it('should use custom host logger if specified', () => {
|
|
82
|
+
const logger = {
|
|
83
|
+
log() { },
|
|
84
|
+
spanRoot() {
|
|
85
|
+
return {
|
|
86
|
+
end() { }
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
spanChild() {
|
|
90
|
+
return {
|
|
91
|
+
end() { }
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const options = {
|
|
96
|
+
logger,
|
|
97
|
+
monitoring: {}
|
|
98
|
+
};
|
|
99
|
+
const host = createAppHost([], options);
|
|
100
|
+
expect(host.log).toBe(logger);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('Packages Installation', () => {
|
|
104
|
+
it('should NOT throw on circular dependency if check is disabled in host options', () => {
|
|
105
|
+
const circularPackages = createDirectCircularEntryPoints();
|
|
106
|
+
const hostOptionsWithDisabledCircularCheck = {
|
|
107
|
+
monitoring: {},
|
|
108
|
+
disableCheckCircularDependencies: true
|
|
109
|
+
};
|
|
110
|
+
expect(() => createAppHost(circularPackages, hostOptionsWithDisabledCircularCheck)).not.toThrow();
|
|
111
|
+
});
|
|
112
|
+
it('should throw on direct circular API dependency (private keys)', () => {
|
|
113
|
+
const circularPackages = createDirectCircularEntryPoints();
|
|
114
|
+
expect(() => createAppHost(circularPackages, testHostOptions)).toThrowError();
|
|
115
|
+
});
|
|
116
|
+
it('should throw on direct circular API dependency (public keys)', () => {
|
|
117
|
+
const circularPackages = createDirectCircularEntryPoints(true);
|
|
118
|
+
expect(() => createAppHost(circularPackages, testHostOptions)).toThrowError();
|
|
119
|
+
});
|
|
120
|
+
it('should throw on circular API dependency (private keys)', () => {
|
|
121
|
+
const circularPackages = createCircularEntryPoints();
|
|
122
|
+
expect(() => createAppHost(circularPackages, testHostOptions)).toThrowError();
|
|
123
|
+
});
|
|
124
|
+
it('should throw on circular API dependency (public keys)', () => {
|
|
125
|
+
const circularPackages = createCircularEntryPoints(true);
|
|
126
|
+
expect(() => createAppHost(circularPackages, testHostOptions)).toThrowError();
|
|
127
|
+
});
|
|
128
|
+
it('should throw when dynamically adding a shell with circular dependency', () => {
|
|
129
|
+
const circularPackages = createCircularEntryPoints(true);
|
|
130
|
+
const nonCircular = circularPackages.slice(0, 3);
|
|
131
|
+
const circularEP = _.last(circularPackages);
|
|
132
|
+
const host = createAppHost(nonCircular, testHostOptions);
|
|
133
|
+
expect(() => host.addShells([circularEP])).toThrow();
|
|
134
|
+
});
|
|
135
|
+
it('should install initial packages', () => {
|
|
136
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
137
|
+
expect(host.hasShell(mockPackage.name)).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
it('should install packages after initial installations', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
140
|
+
const host = createAppHost([], testHostOptions);
|
|
141
|
+
expect(host.hasShell(mockPackage.name)).toBe(false);
|
|
142
|
+
yield host.addShells([mockPackage]);
|
|
143
|
+
expect(host.hasShell(mockPackage.name)).toBe(true);
|
|
144
|
+
}));
|
|
145
|
+
it('should uninstall shell', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
146
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
147
|
+
yield host.removeShells([mockPackage.name]);
|
|
148
|
+
expect(host.hasShell(mockPackage.name)).toBe(false);
|
|
149
|
+
}));
|
|
150
|
+
it('should not install multiple shells with the same name', () => {
|
|
151
|
+
expect(() => createAppHost([mockPackage, _.pick(mockPackage, 'name')], testHostOptions)).toThrow();
|
|
152
|
+
});
|
|
153
|
+
it('should install lazy shells', () => {
|
|
154
|
+
const lazyEntryPoint = makeLazyEntryPoint(mockPackage.name, () => __awaiter(void 0, void 0, void 0, function* () { return mockPackage; }));
|
|
155
|
+
const host = createAppHost([lazyEntryPoint], testHostOptions);
|
|
156
|
+
expect(host.hasShell(lazyEntryPoint.name)).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
describe('EntryPoint lifecycle state', () => {
|
|
160
|
+
const takeEntryPointStateSnapshot = (shell) => {
|
|
161
|
+
return {
|
|
162
|
+
canUseStore: shell.canUseStore(),
|
|
163
|
+
canUseAPIs: shell.canUseAPIs(),
|
|
164
|
+
wasInitializationCompleted: shell.wasInitializationCompleted()
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
it('should be incomplete during appHost initialization', () => {
|
|
168
|
+
let stateInAttach;
|
|
169
|
+
let stateInExtend;
|
|
170
|
+
const entryPoint = {
|
|
171
|
+
name: 'TEST_EP',
|
|
172
|
+
attach(shell) {
|
|
173
|
+
stateInAttach = takeEntryPointStateSnapshot(shell);
|
|
174
|
+
},
|
|
175
|
+
extend(shell) {
|
|
176
|
+
stateInExtend = takeEntryPointStateSnapshot(shell);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
createAppHost([entryPoint], testHostOptions);
|
|
180
|
+
expect(stateInAttach).toMatchObject({
|
|
181
|
+
wasInitializationCompleted: false,
|
|
182
|
+
canUseAPIs: false,
|
|
183
|
+
canUseStore: false
|
|
184
|
+
});
|
|
185
|
+
expect(stateInExtend).toMatchObject({
|
|
186
|
+
wasInitializationCompleted: false,
|
|
187
|
+
canUseAPIs: true,
|
|
188
|
+
canUseStore: true
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
it('should be complete after appHost initialization', () => {
|
|
192
|
+
let shell;
|
|
193
|
+
const entryPoint = {
|
|
194
|
+
name: 'TEST_EP',
|
|
195
|
+
attach(_shell) {
|
|
196
|
+
shell = _shell;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
createAppHost([entryPoint], testHostOptions);
|
|
200
|
+
const stateAfter = shell && takeEntryPointStateSnapshot(shell);
|
|
201
|
+
expect(stateAfter).toMatchObject({
|
|
202
|
+
wasInitializationCompleted: true,
|
|
203
|
+
canUseAPIs: true,
|
|
204
|
+
canUseStore: true
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
it('should be incomplete during lifecycle of added entry point', () => {
|
|
208
|
+
let stateInAttach;
|
|
209
|
+
let stateInExtend;
|
|
210
|
+
const host = createAppHost([], testHostOptions);
|
|
211
|
+
addMockShell(host, {
|
|
212
|
+
attach(shell) {
|
|
213
|
+
stateInAttach = takeEntryPointStateSnapshot(shell);
|
|
214
|
+
},
|
|
215
|
+
extend(shell) {
|
|
216
|
+
stateInExtend = takeEntryPointStateSnapshot(shell);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
expect(stateInAttach).toMatchObject({
|
|
220
|
+
wasInitializationCompleted: false,
|
|
221
|
+
canUseAPIs: false,
|
|
222
|
+
canUseStore: false
|
|
223
|
+
});
|
|
224
|
+
expect(stateInExtend).toMatchObject({
|
|
225
|
+
wasInitializationCompleted: false,
|
|
226
|
+
canUseAPIs: true,
|
|
227
|
+
canUseStore: true
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
it('should be complete after lifecycle of added entry point', () => {
|
|
231
|
+
const host = createAppHost([], testHostOptions);
|
|
232
|
+
const shell = addMockShell(host);
|
|
233
|
+
const stateAfter = takeEntryPointStateSnapshot(shell);
|
|
234
|
+
expect(stateAfter).toMatchObject({
|
|
235
|
+
wasInitializationCompleted: true,
|
|
236
|
+
canUseAPIs: true,
|
|
237
|
+
canUseStore: true
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
it('should be incomplete during execution of late initializer', () => {
|
|
241
|
+
let state;
|
|
242
|
+
const host = createAppHost([], testHostOptions);
|
|
243
|
+
const shell = addMockShell(host);
|
|
244
|
+
expect(shell.wasInitializationCompleted()).toBe(true);
|
|
245
|
+
shell.runLateInitializer(() => {
|
|
246
|
+
state = takeEntryPointStateSnapshot(shell);
|
|
247
|
+
});
|
|
248
|
+
expect(state).toMatchObject({
|
|
249
|
+
canUseStore: true,
|
|
250
|
+
canUseAPIs: true,
|
|
251
|
+
wasInitializationCompleted: false
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
it('should be complete after execution of late initializer', () => {
|
|
255
|
+
const host = createAppHost([], testHostOptions);
|
|
256
|
+
const shell = addMockShell(host);
|
|
257
|
+
expect(shell.wasInitializationCompleted()).toBe(true);
|
|
258
|
+
shell.runLateInitializer(() => { });
|
|
259
|
+
const stateAfter = takeEntryPointStateSnapshot(shell);
|
|
260
|
+
expect(stateAfter).toMatchObject({
|
|
261
|
+
canUseStore: true,
|
|
262
|
+
canUseAPIs: true,
|
|
263
|
+
wasInitializationCompleted: true
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
it('should be complete after execution of late initializer that throws', () => {
|
|
267
|
+
const host = createAppHost([], testHostOptions);
|
|
268
|
+
const shell = addMockShell(host);
|
|
269
|
+
expect(shell.wasInitializationCompleted()).toBe(true);
|
|
270
|
+
expect(() => {
|
|
271
|
+
shell.runLateInitializer(() => {
|
|
272
|
+
throw new Error('TEST-ERROR');
|
|
273
|
+
});
|
|
274
|
+
}).toThrow('TEST-ERROR');
|
|
275
|
+
const stateAfter = takeEntryPointStateSnapshot(shell);
|
|
276
|
+
expect(stateAfter).toMatchObject({
|
|
277
|
+
canUseStore: true,
|
|
278
|
+
canUseAPIs: true,
|
|
279
|
+
wasInitializationCompleted: true
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
_.forEach([
|
|
284
|
+
{
|
|
285
|
+
testCase: 'private API keys',
|
|
286
|
+
dependencyAPI: MockAPI,
|
|
287
|
+
providerPackage: mockPackage
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
testCase: 'public API keys',
|
|
291
|
+
dependencyAPI: { name: MockPublicAPI.name, public: true },
|
|
292
|
+
providerPackage: mockPackageWithPublicAPI
|
|
293
|
+
}
|
|
294
|
+
], ({ testCase, dependencyAPI, providerPackage }) => {
|
|
295
|
+
describe(`Dependency entry point installation (${testCase})`, () => {
|
|
296
|
+
it('should not install dependent entry point until dependency is installed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
297
|
+
const { host, dependentPackage } = createHostWithDependantPackages(dependencyAPI);
|
|
298
|
+
expect(host.hasShell(dependentPackage[0].name)).toBe(false);
|
|
299
|
+
yield host.addShells([providerPackage]);
|
|
300
|
+
expect(host.hasShell(dependentPackage[0].name)).toBe(true);
|
|
301
|
+
}));
|
|
302
|
+
it('should install all dependent entry points chain when dependencies are installed from entry point', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
303
|
+
const { host, dependentPackage, deeplyDependentPackage } = createHostWithDependantPackages(dependencyAPI);
|
|
304
|
+
expect(host.hasShell(dependentPackage[0].name)).toBe(false);
|
|
305
|
+
expect(host.hasShell(dependentPackage[1].name)).toBe(false);
|
|
306
|
+
expect(host.hasShell(deeplyDependentPackage[0].name)).toBe(false);
|
|
307
|
+
yield host.addShells([providerPackage]);
|
|
308
|
+
expect(host.hasShell(dependentPackage[0].name)).toBe(true);
|
|
309
|
+
expect(host.hasShell(dependentPackage[1].name)).toBe(true);
|
|
310
|
+
expect(host.hasShell(deeplyDependentPackage[0].name)).toBe(true);
|
|
311
|
+
}));
|
|
312
|
+
it('should install all dependent entry points chain when dependencies are installed outside of entry point', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
313
|
+
const { host, dependentPackage, deeplyDependentPackage, helperShell } = createHostWithDependantPackages(dependencyAPI);
|
|
314
|
+
expect(host.hasShell(dependentPackage[0].name)).toBe(false);
|
|
315
|
+
expect(host.hasShell(dependentPackage[1].name)).toBe(false);
|
|
316
|
+
expect(host.hasShell(deeplyDependentPackage[0].name)).toBe(false);
|
|
317
|
+
helperShell.contributeAPI(dependencyAPI, () => ({
|
|
318
|
+
stubTrue: () => true,
|
|
319
|
+
getNewObject: () => ({})
|
|
320
|
+
}));
|
|
321
|
+
expect(host.hasShell(dependentPackage[0].name)).toBe(true);
|
|
322
|
+
expect(host.hasShell(dependentPackage[1].name)).toBe(true);
|
|
323
|
+
expect(host.hasShell(deeplyDependentPackage[0].name)).toBe(true);
|
|
324
|
+
}));
|
|
325
|
+
it('should uninstall all dependent entry points chain when dependencies are uninstalled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
326
|
+
const { host, dependentPackage, deeplyDependentPackage } = createHostWithDependantPackages(dependencyAPI);
|
|
327
|
+
yield host.addShells([providerPackage]);
|
|
328
|
+
yield host.removeShells([providerPackage.name]);
|
|
329
|
+
expect(host.hasShell(dependentPackage[0].name)).toBe(false);
|
|
330
|
+
expect(host.hasShell(dependentPackage[1].name)).toBe(false);
|
|
331
|
+
expect(host.hasShell(deeplyDependentPackage[0].name)).toBe(false);
|
|
332
|
+
}));
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
describe('Host extension slots', () => {
|
|
336
|
+
describe('hasSlot', () => {
|
|
337
|
+
it('should return false for hasSlot if the slot is not defined on the host', () => {
|
|
338
|
+
const host = createAppHost([], testHostOptions);
|
|
339
|
+
expect(host.hasSlot(MockSlot)).toBeFalsy();
|
|
340
|
+
});
|
|
341
|
+
it('should return true for hasSlot if the slot is defined on the host', () => {
|
|
342
|
+
const host = createAppHost([mockPackageWithSlot], testHostOptions);
|
|
343
|
+
expect(host.hasSlot(MockSlot)).toBeTruthy();
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
it('should have a state extension slot', () => {
|
|
347
|
+
const host = createAppHost([], testHostOptions);
|
|
348
|
+
expect(host.getSlot(stateSlotKey)).toBeTruthy();
|
|
349
|
+
});
|
|
350
|
+
it('should have a main view extension slot', () => {
|
|
351
|
+
const host = createAppHost([], testHostOptions);
|
|
352
|
+
expect(host.getSlot(mainViewSlotKey)).toBeTruthy();
|
|
353
|
+
});
|
|
354
|
+
it('should retrieve all slot keys', () => {
|
|
355
|
+
const sortSlotKeys = (slotKeys) => _.sortBy(slotKeys, 'name');
|
|
356
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
357
|
+
const actual = sortSlotKeys(host.getAllSlotKeys());
|
|
358
|
+
const expected = sortSlotKeys([AppHostAPI, mainViewSlotKey, stateSlotKey, MockAPI]);
|
|
359
|
+
expect(actual).toEqual(expected);
|
|
360
|
+
});
|
|
361
|
+
describe('private API slot key', () => {
|
|
362
|
+
it('should equal itself', () => {
|
|
363
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
364
|
+
const API = host.getAPI(MockAPI);
|
|
365
|
+
expect(API).toBeTruthy();
|
|
366
|
+
});
|
|
367
|
+
it('should not equal another key with same name', () => {
|
|
368
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
369
|
+
const fakeKey = { name: MockAPI.name };
|
|
370
|
+
expect(() => {
|
|
371
|
+
host.getAPI(fakeKey);
|
|
372
|
+
}).toThrowError(new RegExp(MockAPI.name));
|
|
373
|
+
});
|
|
374
|
+
it('should not equal another key with same name that claims it is public', () => {
|
|
375
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
376
|
+
const fakeKey1 = {
|
|
377
|
+
name: MockAPI.name,
|
|
378
|
+
public: true
|
|
379
|
+
};
|
|
380
|
+
const fakeKey2 = {
|
|
381
|
+
name: MockAPI.name,
|
|
382
|
+
public: false
|
|
383
|
+
};
|
|
384
|
+
const fakeKey3 = {
|
|
385
|
+
name: MockAPI.name,
|
|
386
|
+
public: 'zzz'
|
|
387
|
+
};
|
|
388
|
+
expect(() => host.getAPI(fakeKey1)).toThrowError(new RegExp(MockAPI.name));
|
|
389
|
+
expect(() => host.getAPI(fakeKey2)).toThrowError(new RegExp(MockAPI.name));
|
|
390
|
+
expect(() => host.getAPI(fakeKey3)).toThrowError(new RegExp(MockAPI.name));
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
describe('public API slot key', () => {
|
|
394
|
+
it('should equal itself', () => {
|
|
395
|
+
const host = createAppHost([mockPackageWithPublicAPI], testHostOptions);
|
|
396
|
+
const API = host.getAPI(MockPublicAPI);
|
|
397
|
+
expect(API).toBeTruthy();
|
|
398
|
+
});
|
|
399
|
+
it('should equal another key with same name that claims it is public', () => {
|
|
400
|
+
const host = createAppHost([mockPackageWithPublicAPI], testHostOptions);
|
|
401
|
+
const anotherKey = {
|
|
402
|
+
name: MockPublicAPI.name,
|
|
403
|
+
public: true
|
|
404
|
+
};
|
|
405
|
+
const API = host.getAPI(anotherKey);
|
|
406
|
+
expect(API).toBeTruthy();
|
|
407
|
+
});
|
|
408
|
+
it('should not equal another key with same name than does not claim it is public', () => {
|
|
409
|
+
const host = createAppHost([mockPackageWithPublicAPI], testHostOptions);
|
|
410
|
+
const anotherKey1 = {
|
|
411
|
+
name: MockPublicAPI.name
|
|
412
|
+
};
|
|
413
|
+
const anotherKey2 = {
|
|
414
|
+
name: MockPublicAPI.name,
|
|
415
|
+
public: false
|
|
416
|
+
};
|
|
417
|
+
const anotherKey3 = {
|
|
418
|
+
name: MockPublicAPI.name,
|
|
419
|
+
public: 'zzz'
|
|
420
|
+
};
|
|
421
|
+
expect(() => host.getAPI(anotherKey1)).toThrowError(new RegExp(MockPublicAPI.name));
|
|
422
|
+
expect(() => host.getAPI(anotherKey2)).toThrowError(new RegExp(MockPublicAPI.name));
|
|
423
|
+
expect(() => host.getAPI(anotherKey3)).toThrowError(new RegExp(MockPublicAPI.name));
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
describe('Shell extension slots', () => {
|
|
428
|
+
describe('hasSlot', () => {
|
|
429
|
+
it('should return false for hasSlot if the slot is not defined on the host', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
430
|
+
const host = createAppHost([], testHostOptions);
|
|
431
|
+
const entryPointWithoutSlot = {
|
|
432
|
+
name: 'MOCK_WITHOUT_SLOT',
|
|
433
|
+
extend(shell) {
|
|
434
|
+
expect(shell.hasSlot(MockSlot)).toBeFalsy();
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
yield host.addShells([entryPointWithoutSlot]);
|
|
438
|
+
}));
|
|
439
|
+
it('should return true for hasSlot if the slot is defined on the host', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
440
|
+
const host = createAppHost([], testHostOptions);
|
|
441
|
+
const entryPointWithSlot = {
|
|
442
|
+
name: 'MOCK_WITH_SLOT',
|
|
443
|
+
attach(shell) {
|
|
444
|
+
shell.declareSlot(MockSlot);
|
|
445
|
+
},
|
|
446
|
+
extend(shell) {
|
|
447
|
+
expect(shell.hasSlot(MockSlot)).toBeTruthy();
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
yield host.addShells([entryPointWithSlot]);
|
|
451
|
+
}));
|
|
452
|
+
});
|
|
453
|
+
it('should allow contribution', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
454
|
+
const host = createAppHost([], testHostOptions);
|
|
455
|
+
const slotKey = {
|
|
456
|
+
name: 'MOCK_SLOT'
|
|
457
|
+
};
|
|
458
|
+
const MockAPIA = {
|
|
459
|
+
name: 'MOCK_API_A'
|
|
460
|
+
};
|
|
461
|
+
const contributedItemA = { value: 'A' };
|
|
462
|
+
const contributedItemB = { value: 'B' };
|
|
463
|
+
const entryPointA = {
|
|
464
|
+
name: 'MOCK_A',
|
|
465
|
+
declareAPIs() {
|
|
466
|
+
return [MockAPIA];
|
|
467
|
+
},
|
|
468
|
+
attach(shell) {
|
|
469
|
+
shell.declareSlot(slotKey);
|
|
470
|
+
shell.contributeAPI(MockAPIA, () => ({
|
|
471
|
+
contributeItem(fromShell, item) {
|
|
472
|
+
shell.getSlot(slotKey).contribute(fromShell, item);
|
|
473
|
+
}
|
|
474
|
+
}));
|
|
475
|
+
},
|
|
476
|
+
extend(shell) {
|
|
477
|
+
shell.getAPI(MockAPIA).contributeItem(shell, contributedItemA);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
const entryPointB = {
|
|
481
|
+
name: 'MOCK_B',
|
|
482
|
+
getDependencyAPIs() {
|
|
483
|
+
return [MockAPIA];
|
|
484
|
+
},
|
|
485
|
+
extend(shell) {
|
|
486
|
+
shell.getAPI(MockAPIA).contributeItem(shell, contributedItemB);
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
yield host.addShells([entryPointA, entryPointB]);
|
|
490
|
+
const getItems = () => host
|
|
491
|
+
.getSlot(slotKey)
|
|
492
|
+
.getItems()
|
|
493
|
+
.map(({ contribution }) => contribution);
|
|
494
|
+
expect(getItems()).toEqual([contributedItemA, contributedItemB]);
|
|
495
|
+
yield host.removeShells(['MOCK_B']);
|
|
496
|
+
expect(getItems()).toEqual([contributedItemA]);
|
|
497
|
+
yield host.addShells([entryPointB]);
|
|
498
|
+
expect(getItems()).toEqual([contributedItemA, contributedItemB]);
|
|
499
|
+
}));
|
|
500
|
+
it('should not allow direct access to slots from other shells', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
501
|
+
const host = createAppHost([], testHostOptions);
|
|
502
|
+
const slotKey = {
|
|
503
|
+
name: 'MOCK_SLOT'
|
|
504
|
+
};
|
|
505
|
+
const MockAPIA = {
|
|
506
|
+
name: 'MOCK_API_A'
|
|
507
|
+
};
|
|
508
|
+
const entryPointA = {
|
|
509
|
+
name: 'MOCK_A',
|
|
510
|
+
declareAPIs() {
|
|
511
|
+
return [MockAPIA];
|
|
512
|
+
},
|
|
513
|
+
attach(shell) {
|
|
514
|
+
shell.declareSlot(slotKey);
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
const entryPointB = {
|
|
518
|
+
name: 'MOCK_B',
|
|
519
|
+
extend(shell) {
|
|
520
|
+
const errorString = `Shell '${entryPointB.name}' is trying to get slot '${slotKey.name}' that is owned by '${entryPointA.name}'`;
|
|
521
|
+
expect(() => shell.getSlot(slotKey)).toThrowError(errorString);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
yield host.addShells([entryPointA]);
|
|
525
|
+
}));
|
|
526
|
+
});
|
|
527
|
+
describe('Host State', () => {
|
|
528
|
+
it('should have a store with initial state', () => {
|
|
529
|
+
const host = createAppHost([], testHostOptions);
|
|
530
|
+
expect(host.getStore().getState()).toEqual({
|
|
531
|
+
$installedShells: {
|
|
532
|
+
installedShells: {
|
|
533
|
+
[AppHostServicesEntryPointName]: true
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
describe('Entry Point Contributions', () => {
|
|
540
|
+
it('should contribute API', () => {
|
|
541
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
542
|
+
expect(host.getAPI(MockAPI)).toBeTruthy();
|
|
543
|
+
});
|
|
544
|
+
it('should contribute API after initial installations', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
545
|
+
const host = createAppHost([], testHostOptions);
|
|
546
|
+
expect(() => host.getAPI(MockAPI)).toThrow();
|
|
547
|
+
yield host.addShells([mockPackage]);
|
|
548
|
+
expect(host.getAPI(MockAPI)).toBeTruthy();
|
|
549
|
+
}));
|
|
550
|
+
it('should execute detach and attach sequence according to dependencies', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
551
|
+
const MockAPI2 = { name: 'MOCK' };
|
|
552
|
+
const dependantEntryPoint = {
|
|
553
|
+
name: 'EP1',
|
|
554
|
+
getDependencyAPIs: () => [MockAPI],
|
|
555
|
+
declareAPIs: () => [MockAPI2],
|
|
556
|
+
attach(shell) {
|
|
557
|
+
shell.contributeAPI(MockAPI2, () => shell.getAPI(MockAPI));
|
|
558
|
+
},
|
|
559
|
+
detach(shell) {
|
|
560
|
+
shell.getAPI(MockAPI).stubTrue();
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
const dependantEntryPoint2 = {
|
|
564
|
+
name: 'EP2',
|
|
565
|
+
getDependencyAPIs: () => [MockAPI, MockAPI2],
|
|
566
|
+
detach(shell) {
|
|
567
|
+
shell.getAPI(MockAPI).stubTrue();
|
|
568
|
+
shell.getAPI(MockAPI2).stubTrue();
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
const host = createAppHost([dependantEntryPoint2, mockPackage, dependantEntryPoint], testHostOptions);
|
|
572
|
+
expect(() => host.removeShells([mockPackage.name])).not.toThrow();
|
|
573
|
+
expect(host.hasShell(mockPackage.name)).toBe(false);
|
|
574
|
+
expect(host.hasShell(dependantEntryPoint.name)).toBe(false);
|
|
575
|
+
expect(host.hasShell(dependantEntryPoint2.name)).toBe(false);
|
|
576
|
+
yield host.addShells([mockPackage]);
|
|
577
|
+
expect(host.hasShell(dependantEntryPoint.name)).toBe(true);
|
|
578
|
+
expect(host.hasShell(dependantEntryPoint2.name)).toBe(true);
|
|
579
|
+
}));
|
|
580
|
+
it('should contribute state', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
581
|
+
const getMockShellState = (host) => _.get(host.getStore().getState(), [mockPackage.name, mockShellStateKey], null);
|
|
582
|
+
const appHost = createAppHost([], testHostOptions);
|
|
583
|
+
expect(getMockShellState(appHost)).toBeNull();
|
|
584
|
+
yield appHost.addShells([mockPackage]);
|
|
585
|
+
expect(getMockShellState(appHost)).toEqual(mockShellInitialState);
|
|
586
|
+
}));
|
|
587
|
+
describe('memoizeForState', () => {
|
|
588
|
+
const memoizedAPI = {
|
|
589
|
+
name: 'memoizedAPI'
|
|
590
|
+
};
|
|
591
|
+
function contributeMemoizedAPI(host, shouldClear) {
|
|
592
|
+
const createAPI = (shell) => ({
|
|
593
|
+
getNewObject: shell.memoizeForState(() => ({}), _.stubTrue, shouldClear)
|
|
594
|
+
});
|
|
595
|
+
const mockShell = addMockShell(host, {
|
|
596
|
+
declareAPIs: () => [memoizedAPI],
|
|
597
|
+
attach(shell) {
|
|
598
|
+
shell.contributeAPI(memoizedAPI, () => createAPI(shell));
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
return mockShell;
|
|
602
|
+
}
|
|
603
|
+
const createMockShell = (host) => {
|
|
604
|
+
let observableState = {};
|
|
605
|
+
const mockShell = addMockShell(host, {
|
|
606
|
+
declareAPIs: () => [memoizedAPI],
|
|
607
|
+
attach(shell) {
|
|
608
|
+
observableState = shell.contributeObservableState(() => ({
|
|
609
|
+
stateValue: (state = 1, action) => {
|
|
610
|
+
return action.type === 'increase' ? state + 1 : state;
|
|
611
|
+
}
|
|
612
|
+
}), state => {
|
|
613
|
+
return {
|
|
614
|
+
getStateValue: () => state.stateValue
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
shell.contributeAPI(memoizedAPI, () => ({
|
|
618
|
+
getNewObject: shell.memoizeForState(() => ({
|
|
619
|
+
value: observableState.current(true).getStateValue()
|
|
620
|
+
}), _.stubTrue)
|
|
621
|
+
}));
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
return {
|
|
625
|
+
mockShell,
|
|
626
|
+
observableState
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
it('should memoize functions upon demand', () => {
|
|
630
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
631
|
+
const getObj = () => host.getAPI(MockAPI).getNewObject();
|
|
632
|
+
expect(getObj()).not.toBe(getObj());
|
|
633
|
+
contributeMemoizedAPI(host);
|
|
634
|
+
const objForStateA = host.getAPI(memoizedAPI).getNewObject();
|
|
635
|
+
expect(objForStateA).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
636
|
+
});
|
|
637
|
+
it('should clear memoized functions on store dispatch', () => {
|
|
638
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
639
|
+
contributeMemoizedAPI(host);
|
|
640
|
+
const objForStateA = host.getAPI(memoizedAPI).getNewObject();
|
|
641
|
+
expect(objForStateA).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
642
|
+
host.getStore().dispatch({ type: 'MOCK_ACTION' });
|
|
643
|
+
host.getStore().flush();
|
|
644
|
+
expect(objForStateA).not.toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
645
|
+
});
|
|
646
|
+
it('should clear memoized functions on store dispatch when synchronous code is executing', () => {
|
|
647
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
648
|
+
contributeMemoizedAPI(host);
|
|
649
|
+
const res1 = host.getAPI(memoizedAPI).getNewObject();
|
|
650
|
+
expect(res1).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
651
|
+
let res3;
|
|
652
|
+
host.getStore().subscribe(() => {
|
|
653
|
+
// cache was flushing, so call memoized API in order to create new cache
|
|
654
|
+
const res2 = host.getAPI(memoizedAPI).getNewObject();
|
|
655
|
+
expect(res1).not.toBe(res2);
|
|
656
|
+
expect(res2).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
657
|
+
// dispatch new action for sync cache flushing
|
|
658
|
+
host.getStore().dispatch({ type: 'MOCK_ACTION' });
|
|
659
|
+
res3 = host.getAPI(memoizedAPI).getNewObject();
|
|
660
|
+
expect(res2).not.toBe(res3);
|
|
661
|
+
});
|
|
662
|
+
host.getStore().flush();
|
|
663
|
+
expect(res3).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
664
|
+
});
|
|
665
|
+
it('should clear memoized functions on observable dispatch', () => {
|
|
666
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
667
|
+
const { mockShell } = createMockShell(host);
|
|
668
|
+
const objForStateA = host.getAPI(memoizedAPI).getNewObject();
|
|
669
|
+
expect(objForStateA).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
670
|
+
const { dispatch, flush } = mockShell.getStore();
|
|
671
|
+
dispatch({ type: 'increase' });
|
|
672
|
+
flush();
|
|
673
|
+
expect(objForStateA).not.toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
674
|
+
});
|
|
675
|
+
it('should clear memoized functions on observable dispatch when synchronous code is executing', () => {
|
|
676
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
677
|
+
const { mockShell, observableState } = createMockShell(host);
|
|
678
|
+
const { dispatch, flush } = mockShell.getStore();
|
|
679
|
+
const res1 = host.getAPI(memoizedAPI).getNewObject();
|
|
680
|
+
expect(res1).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
681
|
+
let res3;
|
|
682
|
+
observableState.subscribe(mockShell, () => {
|
|
683
|
+
// cache was flushing, so call memoized API in order to create new cache
|
|
684
|
+
const res2 = host.getAPI(memoizedAPI).getNewObject();
|
|
685
|
+
expect(res1).not.toBe(res2);
|
|
686
|
+
expect(res2).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
687
|
+
// dispatch new action for sync cache flushing
|
|
688
|
+
dispatch({ type: 'increase' });
|
|
689
|
+
res3 = host.getAPI(memoizedAPI).getNewObject();
|
|
690
|
+
expect(res2).not.toBe(res3);
|
|
691
|
+
});
|
|
692
|
+
dispatch({ type: 'increase' });
|
|
693
|
+
flush();
|
|
694
|
+
expect(res3).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
695
|
+
});
|
|
696
|
+
it('should not clear memoized functions if not needed', () => {
|
|
697
|
+
const host = createAppHost([], testHostOptions);
|
|
698
|
+
contributeMemoizedAPI(host, _.stubFalse);
|
|
699
|
+
const objForStateA = host.getAPI(memoizedAPI).getNewObject();
|
|
700
|
+
host.getStore().dispatch({ type: 'MOCK_ACTION' });
|
|
701
|
+
host.getStore().flush();
|
|
702
|
+
expect(objForStateA).toBe(host.getAPI(memoizedAPI).getNewObject());
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
describe('memory cleanup:', () => {
|
|
706
|
+
let originalFinalizationRegistry;
|
|
707
|
+
let cleanupMemory = (ref) => { };
|
|
708
|
+
beforeEach(() => {
|
|
709
|
+
originalFinalizationRegistry = FinalizationRegistry;
|
|
710
|
+
globalThis.FinalizationRegistry = function (cleanupCb) {
|
|
711
|
+
const heldValueSet = new Map();
|
|
712
|
+
cleanupMemory = ref => {
|
|
713
|
+
const heldValue = heldValueSet.get(ref);
|
|
714
|
+
cleanupCb(heldValue);
|
|
715
|
+
};
|
|
716
|
+
return {
|
|
717
|
+
register(target, heldValue, unregisterToken) {
|
|
718
|
+
heldValueSet.set(target, heldValue);
|
|
719
|
+
},
|
|
720
|
+
unregister() { }
|
|
721
|
+
};
|
|
722
|
+
};
|
|
723
|
+
});
|
|
724
|
+
afterEach(() => {
|
|
725
|
+
globalThis.FinalizationRegistry = originalFinalizationRegistry;
|
|
726
|
+
});
|
|
727
|
+
it('should remove memoized function from memory when there is no ref to memoized function', () => {
|
|
728
|
+
const host = createAppHost([], testHostOptions);
|
|
729
|
+
const newAPI = { name: 'newAPI' };
|
|
730
|
+
let memFn1 = null;
|
|
731
|
+
let memFn2 = null;
|
|
732
|
+
const createAPI = (shell) => {
|
|
733
|
+
memFn1 = shell.memoizeForState(() => ({}), _.stubTrue, _.stubTrue);
|
|
734
|
+
memFn2 = shell.memoizeForState(() => ({}), _.stubTrue, _.stubTrue);
|
|
735
|
+
memFn1.cache.clear = jest.fn();
|
|
736
|
+
memFn2.cache.clear = jest.fn();
|
|
737
|
+
return {
|
|
738
|
+
getNewObject: memFn1,
|
|
739
|
+
getNewObject2: memFn2
|
|
740
|
+
};
|
|
741
|
+
};
|
|
742
|
+
addMockShell(host, {
|
|
743
|
+
declareAPIs: () => [newAPI],
|
|
744
|
+
attach(shell) {
|
|
745
|
+
shell.contributeAPI(newAPI, () => createAPI(shell));
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
if (memFn1 && memFn2) {
|
|
749
|
+
const cacheFnMock1 = memFn1.cache.clear;
|
|
750
|
+
const cacheFnMock2 = memFn2.cache.clear;
|
|
751
|
+
host.getStore().dispatch({ type: 'MOCK_ACTION' });
|
|
752
|
+
host.getStore().flush();
|
|
753
|
+
expect(cacheFnMock1).toHaveBeenCalledTimes(1);
|
|
754
|
+
expect(cacheFnMock2).toHaveBeenCalledTimes(1);
|
|
755
|
+
cleanupMemory(memFn1);
|
|
756
|
+
host.getStore().dispatch({ type: 'MOCK_ACTION' });
|
|
757
|
+
host.getStore().flush();
|
|
758
|
+
expect(cacheFnMock1).toHaveBeenCalledTimes(1);
|
|
759
|
+
expect(cacheFnMock2).toHaveBeenCalledTimes(2);
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
throw Error('memFn1 or memFn2 is not defined');
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
});
|
|
766
|
+
describe('lazyEvaluator', () => {
|
|
767
|
+
it('should return a getter that is evaluated only once', () => {
|
|
768
|
+
const { helperShell } = createHostWithDependantPackages(MockAPI);
|
|
769
|
+
const func = jest.fn(() => 42);
|
|
770
|
+
const lazyEval = helperShell.lazyEvaluator(func);
|
|
771
|
+
expect(lazyEval.get()).toBe(42);
|
|
772
|
+
expect(lazyEval.get()).toBe(42);
|
|
773
|
+
expect(func).toHaveBeenCalledTimes(1);
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
describe('Entry Point Shell Scoping', () => {
|
|
778
|
+
describe('Shell hasAPI', () => {
|
|
779
|
+
it('should return false if the API is not defined on the host', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
780
|
+
const host = createAppHost([], testHostOptions);
|
|
781
|
+
const entryPointWithoutAPI = {
|
|
782
|
+
name: 'ENTRY_POINT_WITHOUT_API',
|
|
783
|
+
getDependencyAPIs: () => [],
|
|
784
|
+
extend(shell) {
|
|
785
|
+
expect(shell.hasAPI(MockAPI)).toBeFalsy();
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
yield host.addShells([entryPointWithoutAPI]);
|
|
789
|
+
}));
|
|
790
|
+
it('should return false if the API is defined on the host but is not declared as dependency', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
791
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
792
|
+
const entryPointWithoutAPIDependency = {
|
|
793
|
+
name: 'ENTRY_POINT_WITHOUT_API_DEPENDENCY',
|
|
794
|
+
getDependencyAPIs: () => [],
|
|
795
|
+
extend(shell) {
|
|
796
|
+
expect(shell.hasAPI(MockAPI)).toBeFalsy();
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
yield host.addShells([entryPointWithoutAPIDependency]);
|
|
800
|
+
}));
|
|
801
|
+
it('should return true if the API is defined on the host and is declared as dependency', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
802
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
803
|
+
const entryPointWithAPIDependency = {
|
|
804
|
+
name: 'ENTRY_POINT_WITH_API_DEPENDENCY',
|
|
805
|
+
getDependencyAPIs: () => [MockAPI],
|
|
806
|
+
extend(shell) {
|
|
807
|
+
expect(shell.hasAPI(MockAPI)).toBeTruthy();
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
yield host.addShells([entryPointWithAPIDependency]);
|
|
811
|
+
}));
|
|
812
|
+
it('should return true if the API is declared on the shell', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
813
|
+
const host = createAppHost([], testHostOptions);
|
|
814
|
+
const entryPointWithAPIDeclaration = {
|
|
815
|
+
name: 'ENTRY_POINT_WITH_API_DECLARATION',
|
|
816
|
+
declareAPIs: () => [MockAPI],
|
|
817
|
+
attach(shell) {
|
|
818
|
+
shell.contributeAPI(MockAPI, () => ({}));
|
|
819
|
+
},
|
|
820
|
+
extend(shell) {
|
|
821
|
+
expect(shell.hasAPI(MockAPI)).toBeTruthy();
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
yield host.addShells([entryPointWithAPIDeclaration]);
|
|
825
|
+
}));
|
|
826
|
+
});
|
|
827
|
+
it('should be able to call an API declared in dependencies', () => {
|
|
828
|
+
const entryPointThatCallsAPI = {
|
|
829
|
+
name: 'ENTRY_POINT_WITH_API_CALL',
|
|
830
|
+
getDependencyAPIs() {
|
|
831
|
+
return [MockAPI];
|
|
832
|
+
},
|
|
833
|
+
extend(shell) {
|
|
834
|
+
shell.getAPI(MockAPI).stubTrue();
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
const appHost = createAppHost([mockPackage], testHostOptions);
|
|
838
|
+
expect(() => appHost.addShells([entryPointThatCallsAPI])).not.toThrow();
|
|
839
|
+
});
|
|
840
|
+
it('should not be able to call an API not declared in dependencies', () => {
|
|
841
|
+
const entryPointThatCallsAPI = {
|
|
842
|
+
name: 'ENTRY_POINT_WITH_API_CALL',
|
|
843
|
+
extend(shell) {
|
|
844
|
+
shell.getAPI(MockAPI).stubTrue();
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
const appHost = createAppHost([mockPackage], testHostOptions);
|
|
848
|
+
expect(() => appHost.addShells([entryPointThatCallsAPI])).toThrow();
|
|
849
|
+
});
|
|
850
|
+
it('should get scoped state', done => {
|
|
851
|
+
const state = {};
|
|
852
|
+
const MOCK_STATE_KEY = 'mockStateKey';
|
|
853
|
+
const entryPointWithState = {
|
|
854
|
+
name: 'ENTRY_POINT_WITH_STATE',
|
|
855
|
+
attach(shell) {
|
|
856
|
+
shell.contributeState(() => ({
|
|
857
|
+
[MOCK_STATE_KEY]: () => state
|
|
858
|
+
}));
|
|
859
|
+
},
|
|
860
|
+
extend(shell) {
|
|
861
|
+
expect(_.get(shell.getStore().getState(), MOCK_STATE_KEY)).toBe(state);
|
|
862
|
+
done();
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
createAppHost([entryPointWithState], testHostOptions);
|
|
866
|
+
});
|
|
867
|
+
it('should be able to uninstall own installed packages', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
868
|
+
// note: this test assumes that addShells and removeShells complete synchronously
|
|
869
|
+
const packageThatInstallsAPackage = {
|
|
870
|
+
name: 'ENTRY_POINT_THAT_INSTALLS_A_PACKAGE',
|
|
871
|
+
extend(shell) {
|
|
872
|
+
shell.addShells([mockPackage]);
|
|
873
|
+
shell.removeShells([mockPackage.name]);
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
createAppHost([packageThatInstallsAPackage], testHostOptions);
|
|
877
|
+
expect(() => createAppHost([packageThatInstallsAPackage], testHostOptions)).not.toThrow();
|
|
878
|
+
}));
|
|
879
|
+
it('should not be able to uninstall not own installed packages', () => {
|
|
880
|
+
const packageThatTriesToUninstallAPackage = {
|
|
881
|
+
name: 'ENTRY_POINT_THAT_TRYIES_TO_UNINSTALL_A_PACKAGE',
|
|
882
|
+
extend(shell) {
|
|
883
|
+
shell.removeShells([mockPackage.name]);
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
expect(() => createAppHost([mockPackage, packageThatTriesToUninstallAPackage], testHostOptions)).toThrow();
|
|
887
|
+
});
|
|
888
|
+
it('should not trigger other reducers by scoped dispatch', () => {
|
|
889
|
+
const INITIAL_STATE = { value: 0 };
|
|
890
|
+
const SET_VALUE = 'SET_VALUE';
|
|
891
|
+
const setValue = (value) => ({ type: SET_VALUE, value });
|
|
892
|
+
const host = createAppHost([], {
|
|
893
|
+
shouldScopeReducers: true,
|
|
894
|
+
monitoring: {}
|
|
895
|
+
});
|
|
896
|
+
const shell1 = addMockShell(host, {
|
|
897
|
+
attach(shell) {
|
|
898
|
+
shell.contributeState(() => ({
|
|
899
|
+
state1: (state = INITIAL_STATE, action) => {
|
|
900
|
+
switch (action.type) {
|
|
901
|
+
case SET_VALUE:
|
|
902
|
+
return { value: action.value };
|
|
903
|
+
}
|
|
904
|
+
return state;
|
|
905
|
+
}
|
|
906
|
+
}));
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
// Initial state
|
|
910
|
+
const getState = () => shell1.getStore().getState().state1.value;
|
|
911
|
+
expect(getState()).toBe(0);
|
|
912
|
+
// Scoped dispatch
|
|
913
|
+
shell1.getStore().dispatch(setValue(73));
|
|
914
|
+
expect(getState()).toBe(73);
|
|
915
|
+
// Unscoped dispatch
|
|
916
|
+
host.getStore().dispatch(setValue(1337));
|
|
917
|
+
expect(getState()).toBe(1337);
|
|
918
|
+
addMockShell(host, {
|
|
919
|
+
extend(shell) {
|
|
920
|
+
// Scoped dispatch in a different scope
|
|
921
|
+
shell.getStore().dispatch(setValue(42));
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
expect(getState()).toBe(1337);
|
|
925
|
+
});
|
|
926
|
+
});
|
|
927
|
+
describe('Entry Point HMR support', () => {
|
|
928
|
+
const LowLevelSlotKey = { name: 'LOW-LEVEL-SLOT' };
|
|
929
|
+
const HighLevelSlotKey = { name: 'HIGH-LEVEL-SLOT' };
|
|
930
|
+
const ConsumerSlotKey = { name: 'CONSUMER-SLOT' };
|
|
931
|
+
const LowLevelAPI = {
|
|
932
|
+
name: 'LOW-LEVEL-API'
|
|
933
|
+
};
|
|
934
|
+
const HighLevelAPI = {
|
|
935
|
+
name: 'HIGH-LEVEL-API'
|
|
936
|
+
};
|
|
937
|
+
const hmrTestPackage = [
|
|
938
|
+
{
|
|
939
|
+
name: 'LOW_LEVEL_API_ENTRY_POINT',
|
|
940
|
+
declareAPIs() {
|
|
941
|
+
return [LowLevelAPI];
|
|
942
|
+
},
|
|
943
|
+
attach(shell) {
|
|
944
|
+
shell.declareSlot(LowLevelSlotKey);
|
|
945
|
+
shell.contributeAPI(LowLevelAPI, () => ({
|
|
946
|
+
lowLevelFunc: jest.fn()
|
|
947
|
+
}));
|
|
948
|
+
}
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
name: 'HIGH_LEVEL_API_ENTRY_POINT',
|
|
952
|
+
getDependencyAPIs() {
|
|
953
|
+
return [LowLevelAPI];
|
|
954
|
+
},
|
|
955
|
+
declareAPIs() {
|
|
956
|
+
return [HighLevelAPI];
|
|
957
|
+
},
|
|
958
|
+
attach(shell) {
|
|
959
|
+
shell.declareSlot(HighLevelSlotKey);
|
|
960
|
+
shell.contributeAPI(HighLevelAPI, () => ({
|
|
961
|
+
highLevelFunc: jest.fn
|
|
962
|
+
}));
|
|
963
|
+
},
|
|
964
|
+
extend(shell) {
|
|
965
|
+
shell.getAPI(LowLevelAPI).lowLevelFunc('HIGH');
|
|
966
|
+
}
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
name: 'CONSUMER_ENTRY_POINT',
|
|
970
|
+
getDependencyAPIs() {
|
|
971
|
+
return [HighLevelAPI];
|
|
972
|
+
},
|
|
973
|
+
extend(shell) {
|
|
974
|
+
shell.declareSlot(ConsumerSlotKey);
|
|
975
|
+
shell.getAPI(HighLevelAPI).highLevelFunc('CONSUMER');
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
];
|
|
979
|
+
it('should be able to reload entry points', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
980
|
+
const appHost = createAppHost(hmrTestPackage, testHostOptions);
|
|
981
|
+
yield appHost.removeShells(['LOW_LEVEL_API_ENTRY_POINT']);
|
|
982
|
+
yield appHost.addShells([hmrTestPackage[0]]);
|
|
983
|
+
expect(appHost.getAPI(HighLevelAPI)).toBeDefined();
|
|
984
|
+
}));
|
|
985
|
+
});
|
|
986
|
+
describe('API layer', () => {
|
|
987
|
+
it('should allow dependency from high to lower level API', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
988
|
+
const MockAPI1 = { name: 'Mock-API', layer: 'INFRA' };
|
|
989
|
+
const layers = [
|
|
990
|
+
{
|
|
991
|
+
level: 0,
|
|
992
|
+
name: 'INFRA'
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
level: 1,
|
|
996
|
+
name: 'PRODUCT'
|
|
997
|
+
}
|
|
998
|
+
];
|
|
999
|
+
const host = createAppHost([], Object.assign(Object.assign({}, emptyLoggerOptions), { layers }));
|
|
1000
|
+
const EntryPoint1 = {
|
|
1001
|
+
name: 'MOCK_ENTRY_POINT_1',
|
|
1002
|
+
layer: 'PRODUCT',
|
|
1003
|
+
getDependencyAPIs: () => [MockAPI1]
|
|
1004
|
+
};
|
|
1005
|
+
const EntryPoint2 = {
|
|
1006
|
+
name: 'MOCK_ENTRY_POINT_2',
|
|
1007
|
+
layer: 'INFRA',
|
|
1008
|
+
declareAPIs: () => [MockAPI1],
|
|
1009
|
+
attach(shell) {
|
|
1010
|
+
shell.contributeAPI(MockAPI1, () => ({}));
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
yield host.addShells([EntryPoint2]);
|
|
1014
|
+
expect(() => host.addShells([EntryPoint1])).not.toThrow();
|
|
1015
|
+
}));
|
|
1016
|
+
it('should not allow dependency from low to higher level API', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1017
|
+
const MockAPI1 = { name: 'Mock-API', layer: 'PRODUCT' };
|
|
1018
|
+
const layers = [
|
|
1019
|
+
{
|
|
1020
|
+
level: 0,
|
|
1021
|
+
name: 'INFRA'
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
level: 1,
|
|
1025
|
+
name: 'PRODUCT'
|
|
1026
|
+
}
|
|
1027
|
+
];
|
|
1028
|
+
const host = createAppHost([], Object.assign(Object.assign({}, emptyLoggerOptions), { layers }));
|
|
1029
|
+
const EntryPoint1 = {
|
|
1030
|
+
name: 'MOCK_ENTRY_POINT_1',
|
|
1031
|
+
layer: 'INFRA',
|
|
1032
|
+
getDependencyAPIs: () => [MockAPI1]
|
|
1033
|
+
};
|
|
1034
|
+
const EntryPoint2 = {
|
|
1035
|
+
name: 'MOCK_ENTRY_POINT_2',
|
|
1036
|
+
layer: 'PRODUCT',
|
|
1037
|
+
declareAPIs: () => [MockAPI1],
|
|
1038
|
+
attach(shell) {
|
|
1039
|
+
shell.contributeAPI(MockAPI1, () => ({}));
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
yield host.addShells([EntryPoint2]);
|
|
1043
|
+
expect(() => host.addShells([EntryPoint1])).toThrowError(`Entry point ${EntryPoint1.name} of layer ${layers[0].name} cannot depend on API ${MockAPI1.name} of layer ${EntryPoint2.layer}`);
|
|
1044
|
+
}));
|
|
1045
|
+
it('should not allow adding shell of unknown layer', () => {
|
|
1046
|
+
const MockAPI1 = {
|
|
1047
|
+
name: 'Mock-API',
|
|
1048
|
+
layer: 'NON_EXIXTING_layer'
|
|
1049
|
+
};
|
|
1050
|
+
const layers = [
|
|
1051
|
+
{
|
|
1052
|
+
level: 0,
|
|
1053
|
+
name: 'INFRA'
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
level: 1,
|
|
1057
|
+
name: 'PRODUCT'
|
|
1058
|
+
}
|
|
1059
|
+
];
|
|
1060
|
+
const host = createAppHost([], Object.assign(Object.assign({}, emptyLoggerOptions), { layers }));
|
|
1061
|
+
const EntryPoint1 = {
|
|
1062
|
+
name: 'MOCK_ENTRY_POINT_1',
|
|
1063
|
+
layer: 'NON_EXIXTING_layer',
|
|
1064
|
+
getDependencyAPIs: () => [MockAPI1]
|
|
1065
|
+
};
|
|
1066
|
+
expect(() => host.addShells([EntryPoint1])).toThrowError(`Cannot find layer ${EntryPoint1.layer}`);
|
|
1067
|
+
});
|
|
1068
|
+
it('should not allow contribution of API with non-matching entry point layer', () => {
|
|
1069
|
+
const MockAPI1 = { name: 'Mock-API', layer: 'PRODUCT' };
|
|
1070
|
+
const layers = [
|
|
1071
|
+
{
|
|
1072
|
+
level: 0,
|
|
1073
|
+
name: 'INFRA'
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
level: 1,
|
|
1077
|
+
name: 'PRODUCT'
|
|
1078
|
+
}
|
|
1079
|
+
];
|
|
1080
|
+
const host = createAppHost([], Object.assign(Object.assign({}, emptyLoggerOptions), { layers }));
|
|
1081
|
+
const EntryPoint1 = {
|
|
1082
|
+
name: 'MOCK_ENTRY_POINT_1',
|
|
1083
|
+
layer: 'INFRA',
|
|
1084
|
+
declareAPIs: () => [MockAPI1],
|
|
1085
|
+
attach(shell) {
|
|
1086
|
+
shell.contributeAPI(MockAPI1, () => ({}));
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
expect(() => host.addShells([EntryPoint1])).toThrowError(`Cannot contribute API ${MockAPI1.name} of layer ${MockAPI1.layer} from entry point ${EntryPoint1.name} of layer ${EntryPoint1.layer}`);
|
|
1090
|
+
});
|
|
1091
|
+
it('should support multi dimensional layers definition', () => {
|
|
1092
|
+
const MockAPI1 = {
|
|
1093
|
+
name: 'Mock-API',
|
|
1094
|
+
layer: ['COMMON', 'INFRA']
|
|
1095
|
+
};
|
|
1096
|
+
const layersDimension1 = [
|
|
1097
|
+
{
|
|
1098
|
+
level: 0,
|
|
1099
|
+
name: 'INFRA'
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
level: 1,
|
|
1103
|
+
name: 'PRODUCT'
|
|
1104
|
+
}
|
|
1105
|
+
];
|
|
1106
|
+
const layersDimension2 = [
|
|
1107
|
+
{
|
|
1108
|
+
level: 0,
|
|
1109
|
+
name: 'COMMON'
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1112
|
+
level: 1,
|
|
1113
|
+
name: 'SPECIFIC'
|
|
1114
|
+
}
|
|
1115
|
+
];
|
|
1116
|
+
const host = createAppHost([], Object.assign(Object.assign({}, emptyLoggerOptions), { layers: [layersDimension1, layersDimension2] }));
|
|
1117
|
+
const EntryPoint1 = {
|
|
1118
|
+
name: 'MOCK_ENTRY_POINT_1',
|
|
1119
|
+
layer: ['INFRA', 'COMMON'],
|
|
1120
|
+
declareAPIs: () => [MockAPI1],
|
|
1121
|
+
attach(shell) {
|
|
1122
|
+
shell.contributeAPI(MockAPI1, () => ({}));
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
const EntryPoint2 = {
|
|
1126
|
+
name: 'MOCK_ENTRY_POINT_2',
|
|
1127
|
+
layer: ['PRODUCT', 'SPECIFIC'],
|
|
1128
|
+
getDependencyAPIs: () => [MockAPI1]
|
|
1129
|
+
};
|
|
1130
|
+
expect(() => host.addShells([EntryPoint1, EntryPoint2])).not.toThrow();
|
|
1131
|
+
});
|
|
1132
|
+
it('should throw for multi dimensional layers violation', () => {
|
|
1133
|
+
const MockAPI1 = {
|
|
1134
|
+
name: 'Mock-API',
|
|
1135
|
+
layer: ['INFRA', 'SPECIFIC']
|
|
1136
|
+
};
|
|
1137
|
+
const layersDimension1 = [
|
|
1138
|
+
{
|
|
1139
|
+
level: 0,
|
|
1140
|
+
name: 'INFRA'
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
level: 1,
|
|
1144
|
+
name: 'PRODUCT'
|
|
1145
|
+
}
|
|
1146
|
+
];
|
|
1147
|
+
const layersDimension2 = [
|
|
1148
|
+
{
|
|
1149
|
+
level: 0,
|
|
1150
|
+
name: 'COMMON'
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
level: 1,
|
|
1154
|
+
name: 'SPECIFIC'
|
|
1155
|
+
}
|
|
1156
|
+
];
|
|
1157
|
+
const host = createAppHost([], Object.assign(Object.assign({}, emptyLoggerOptions), { layers: [layersDimension1, layersDimension2] }));
|
|
1158
|
+
const EntryPoint1 = {
|
|
1159
|
+
name: 'MOCK_ENTRY_POINT_1',
|
|
1160
|
+
layer: ['INFRA', 'SPECIFIC'],
|
|
1161
|
+
declareAPIs: () => [MockAPI1],
|
|
1162
|
+
attach(shell) {
|
|
1163
|
+
shell.contributeAPI(MockAPI1, () => ({}));
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
const EntryPoint2 = {
|
|
1167
|
+
name: 'MOCK_ENTRY_POINT_2',
|
|
1168
|
+
layer: ['COMMON', 'PRODUCT'],
|
|
1169
|
+
getDependencyAPIs: () => [MockAPI1]
|
|
1170
|
+
};
|
|
1171
|
+
expect(() => host.addShells([EntryPoint1, EntryPoint2])).toThrowError(`Entry point ${EntryPoint2.name} of layer COMMON cannot depend on API ${MockAPI1.name} of layer SPECIFIC`);
|
|
1172
|
+
});
|
|
1173
|
+
it('should enforce cross-multi-dimensional-layers name uniqueness', () => {
|
|
1174
|
+
const layersDimension1 = [
|
|
1175
|
+
{
|
|
1176
|
+
level: 0,
|
|
1177
|
+
name: 'INFRA'
|
|
1178
|
+
},
|
|
1179
|
+
{
|
|
1180
|
+
level: 1,
|
|
1181
|
+
name: 'NOT_UNIQUE'
|
|
1182
|
+
}
|
|
1183
|
+
];
|
|
1184
|
+
const layersDimension2 = [
|
|
1185
|
+
{
|
|
1186
|
+
level: 0,
|
|
1187
|
+
name: 'COMMON'
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
level: 1,
|
|
1191
|
+
name: 'NOT_UNIQUE'
|
|
1192
|
+
}
|
|
1193
|
+
];
|
|
1194
|
+
expect(() => createAppHost([], Object.assign(Object.assign({}, emptyLoggerOptions), { layers: [layersDimension1, layersDimension2] }))).toThrowError(`Cannot initialize host with non unique layers: NOT_UNIQUE`);
|
|
1195
|
+
});
|
|
1196
|
+
it('should allow single layered API for multi dimensional layers host', () => {
|
|
1197
|
+
const MockAPI1 = { name: 'Mock-API', layer: 'INFRA' };
|
|
1198
|
+
const layersDimension1 = [
|
|
1199
|
+
{
|
|
1200
|
+
level: 0,
|
|
1201
|
+
name: 'INFRA'
|
|
1202
|
+
},
|
|
1203
|
+
{
|
|
1204
|
+
level: 1,
|
|
1205
|
+
name: 'PRODUCT'
|
|
1206
|
+
}
|
|
1207
|
+
];
|
|
1208
|
+
const layersDimension2 = [
|
|
1209
|
+
{
|
|
1210
|
+
level: 0,
|
|
1211
|
+
name: 'COMMON'
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
level: 1,
|
|
1215
|
+
name: 'SPECIFIC'
|
|
1216
|
+
}
|
|
1217
|
+
];
|
|
1218
|
+
const EntryPoint1 = {
|
|
1219
|
+
name: 'MOCK_ENTRY_POINT_1',
|
|
1220
|
+
layer: 'PRODUCT',
|
|
1221
|
+
getDependencyAPIs: () => [MockAPI1]
|
|
1222
|
+
};
|
|
1223
|
+
const EntryPoint2 = {
|
|
1224
|
+
name: 'MOCK_ENTRY_POINT_2',
|
|
1225
|
+
layer: 'INFRA',
|
|
1226
|
+
declareAPIs: () => [MockAPI1],
|
|
1227
|
+
attach(shell) {
|
|
1228
|
+
shell.contributeAPI(MockAPI1, () => ({}));
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
expect(() => createAppHost([EntryPoint1, EntryPoint2], Object.assign(Object.assign({}, emptyLoggerOptions), { layers: [layersDimension1, layersDimension2] }))).not.toThrow();
|
|
1232
|
+
});
|
|
1233
|
+
});
|
|
1234
|
+
describe('API version', () => {
|
|
1235
|
+
it('should provide API of matching version', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1236
|
+
const MockAPIv0 = { name: 'Mock-API' };
|
|
1237
|
+
const MockAPIv2 = {
|
|
1238
|
+
name: 'Mock-API',
|
|
1239
|
+
version: 2
|
|
1240
|
+
};
|
|
1241
|
+
const host = createAppHost([]);
|
|
1242
|
+
const entryPoint = {
|
|
1243
|
+
name: 'MOCK_ENTRY_POINT',
|
|
1244
|
+
declareAPIs: () => [MockAPIv0, MockAPIv2],
|
|
1245
|
+
attach(shell) {
|
|
1246
|
+
shell.contributeAPI(MockAPIv0, () => ({ f1() { } }));
|
|
1247
|
+
shell.contributeAPI(MockAPIv2, () => ({ f2() { } }));
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
yield host.addShells([entryPoint]);
|
|
1251
|
+
expect(host.getAPI(MockAPIv0).f1).toBeDefined();
|
|
1252
|
+
expect(host.getAPI(MockAPIv0).f2).not.toBeDefined();
|
|
1253
|
+
expect(host.getAPI(MockAPIv2).f2).toBeDefined();
|
|
1254
|
+
expect(host.getAPI(MockAPIv2).f1).not.toBeDefined();
|
|
1255
|
+
const SecondMockAPIv2 = {
|
|
1256
|
+
name: 'Mock-API',
|
|
1257
|
+
version: 2
|
|
1258
|
+
};
|
|
1259
|
+
expect(() => {
|
|
1260
|
+
addMockShell(host, {
|
|
1261
|
+
declareAPIs: () => [SecondMockAPIv2],
|
|
1262
|
+
attach(shell) {
|
|
1263
|
+
shell.contributeAPI(SecondMockAPIv2, () => ({ f2() { } }));
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
}).toThrowError(new RegExp(`Extension slot with key '${SecondMockAPIv2.name}\\\(v${SecondMockAPIv2.version}\\\)' already exists`));
|
|
1267
|
+
}));
|
|
1268
|
+
});
|
|
1269
|
+
describe('Host API', () => {
|
|
1270
|
+
describe('hasAPI', () => {
|
|
1271
|
+
it('should return false if the API is not defined on the host', () => {
|
|
1272
|
+
const host = createAppHost([], testHostOptions);
|
|
1273
|
+
expect(host.hasAPI(MockAPI)).toBeFalsy();
|
|
1274
|
+
});
|
|
1275
|
+
it('should return true if the API is defined on the host', () => {
|
|
1276
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
1277
|
+
expect(host.hasAPI(MockAPI)).toBeTruthy();
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
it('should get all entry points', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1281
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
1282
|
+
yield host.addShells([mockPackageWithPublicAPI]);
|
|
1283
|
+
const allEntryPoints = host.getAPI(AppHostAPI).getAllEntryPoints();
|
|
1284
|
+
expect(_.sortBy(allEntryPoints, 'name')).toEqual(_.sortBy([mockPackage, mockPackageWithPublicAPI, host.getAppHostServicesShell().entryPoint], 'name'));
|
|
1285
|
+
}));
|
|
1286
|
+
it('should get host options', () => {
|
|
1287
|
+
const host = createAppHost([mockPackage], testHostOptions);
|
|
1288
|
+
expect(host.getAPI(AppHostAPI).getAppHostOptions()).toEqual(testHostOptions);
|
|
1289
|
+
});
|
|
1290
|
+
});
|
|
1291
|
+
describe('Cyclic Mode', () => {
|
|
1292
|
+
it('should load cyclic dependencies groups if all other dependencies are ready', () => {
|
|
1293
|
+
const API1 = { name: 'API1' };
|
|
1294
|
+
const API2 = { name: 'API2' };
|
|
1295
|
+
const API3 = { name: 'API3' };
|
|
1296
|
+
const entryPoints = [
|
|
1297
|
+
{
|
|
1298
|
+
name: 'Package1',
|
|
1299
|
+
getDependencyAPIs: () => [API2],
|
|
1300
|
+
declareAPIs: () => [API1],
|
|
1301
|
+
attach(shell) {
|
|
1302
|
+
shell.contributeAPI(API1, () => ({}));
|
|
1303
|
+
}
|
|
1304
|
+
},
|
|
1305
|
+
{
|
|
1306
|
+
name: 'Package2',
|
|
1307
|
+
getDependencyAPIs: () => [API3],
|
|
1308
|
+
declareAPIs: () => [API2],
|
|
1309
|
+
attach(shell) {
|
|
1310
|
+
shell.contributeAPI(API2, () => ({}));
|
|
1311
|
+
}
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
name: 'Package3',
|
|
1315
|
+
getDependencyAPIs: () => [API1],
|
|
1316
|
+
declareAPIs: () => [API3],
|
|
1317
|
+
attach(shell) {
|
|
1318
|
+
shell.contributeAPI(API3, () => ({}));
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
];
|
|
1322
|
+
const host = createAppHost(entryPoints, Object.assign(Object.assign({}, testHostOptions), { experimentalCyclicMode: true }));
|
|
1323
|
+
expect(host.hasShell(entryPoints[0].name)).toBe(true);
|
|
1324
|
+
expect(host.hasShell(entryPoints[1].name)).toBe(true);
|
|
1325
|
+
expect(host.hasShell(entryPoints[2].name)).toBe(true);
|
|
1326
|
+
});
|
|
1327
|
+
it('should not load cyclic dependencies groups if some other dependencies are not ready', () => {
|
|
1328
|
+
const API1 = { name: 'API1' };
|
|
1329
|
+
const API2 = { name: 'API2' };
|
|
1330
|
+
const API3 = { name: 'API3' };
|
|
1331
|
+
const API4 = { name: 'API4' };
|
|
1332
|
+
const entryPoints = [
|
|
1333
|
+
{
|
|
1334
|
+
name: 'Package1',
|
|
1335
|
+
getDependencyAPIs: () => [API2],
|
|
1336
|
+
declareAPIs: () => [API1],
|
|
1337
|
+
attach(shell) {
|
|
1338
|
+
shell.contributeAPI(API1, () => ({}));
|
|
1339
|
+
}
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
name: 'Package2',
|
|
1343
|
+
getDependencyAPIs: () => [API3],
|
|
1344
|
+
declareAPIs: () => [API2],
|
|
1345
|
+
attach(shell) {
|
|
1346
|
+
shell.contributeAPI(API2, () => ({}));
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
name: 'Package3',
|
|
1351
|
+
getDependencyAPIs: () => [API1, API4],
|
|
1352
|
+
declareAPIs: () => [API3],
|
|
1353
|
+
attach(shell) {
|
|
1354
|
+
shell.contributeAPI(API3, () => ({}));
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
];
|
|
1358
|
+
const host = createAppHost(entryPoints, Object.assign(Object.assign({}, testHostOptions), { experimentalCyclicMode: true }));
|
|
1359
|
+
expect(host.hasShell(entryPoints[0].name)).toBe(false);
|
|
1360
|
+
expect(host.hasShell(entryPoints[1].name)).toBe(false);
|
|
1361
|
+
expect(host.hasShell(entryPoints[2].name)).toBe(false);
|
|
1362
|
+
});
|
|
1363
|
+
});
|
|
1364
|
+
describe('Host.executeWhenFree', () => {
|
|
1365
|
+
it('should be invoked immediately', () => {
|
|
1366
|
+
const host = createAppHost([], testHostOptions);
|
|
1367
|
+
const spy = jest.fn();
|
|
1368
|
+
host.executeWhenFree('1', spy);
|
|
1369
|
+
expect(spy).toBeCalledTimes(1);
|
|
1370
|
+
});
|
|
1371
|
+
it('when invoked during entryPoints installation, should run once installation resumes ', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1372
|
+
const host = createAppHost([], testHostOptions);
|
|
1373
|
+
const spy = jest.fn();
|
|
1374
|
+
const API1 = { name: 'API1' };
|
|
1375
|
+
const API2 = { name: 'API2' };
|
|
1376
|
+
const API3 = { name: 'API3' };
|
|
1377
|
+
const entryPoints = [
|
|
1378
|
+
{
|
|
1379
|
+
name: 'Package1',
|
|
1380
|
+
declareAPIs: () => [API1],
|
|
1381
|
+
attach(shell) {
|
|
1382
|
+
host.executeWhenFree('1', spy);
|
|
1383
|
+
shell.contributeAPI(API1, () => ({}));
|
|
1384
|
+
},
|
|
1385
|
+
extend(shell) {
|
|
1386
|
+
expect(spy).toBeCalledTimes(0);
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
name: 'Package2',
|
|
1391
|
+
getDependencyAPIs: () => [API1],
|
|
1392
|
+
declareAPIs: () => [API2],
|
|
1393
|
+
attach(shell) {
|
|
1394
|
+
shell.contributeAPI(API2, () => ({}));
|
|
1395
|
+
},
|
|
1396
|
+
extend(shell) {
|
|
1397
|
+
expect(spy).toBeCalledTimes(0);
|
|
1398
|
+
}
|
|
1399
|
+
},
|
|
1400
|
+
{
|
|
1401
|
+
name: 'Package3',
|
|
1402
|
+
getDependencyAPIs: () => [API2],
|
|
1403
|
+
declareAPIs: () => [API3],
|
|
1404
|
+
attach(shell) {
|
|
1405
|
+
shell.contributeAPI(API3, () => ({}));
|
|
1406
|
+
},
|
|
1407
|
+
extend(shell) {
|
|
1408
|
+
expect(spy).toBeCalledTimes(0);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
];
|
|
1412
|
+
yield host.addShells(entryPoints);
|
|
1413
|
+
expect(spy).toBeCalledTimes(1);
|
|
1414
|
+
}));
|
|
1415
|
+
});
|
|
1416
|
+
describe('Host.onDeclarationsChanged', () => {
|
|
1417
|
+
it('should be called once for an entry point attach phase', () => {
|
|
1418
|
+
const host = createAppHost([], testHostOptions);
|
|
1419
|
+
const spy = jest.fn();
|
|
1420
|
+
host.onDeclarationsChanged(spy);
|
|
1421
|
+
host.addShells([mockPackage, dependsOnMockPackageEntryPoint, mockPackageWithSlot]);
|
|
1422
|
+
expect(spy).toBeCalledTimes(1);
|
|
1423
|
+
});
|
|
1424
|
+
it('should be called once for an entry point detach phase', () => {
|
|
1425
|
+
const host = createAppHost([], testHostOptions);
|
|
1426
|
+
const spy = jest.fn();
|
|
1427
|
+
host.onDeclarationsChanged(spy);
|
|
1428
|
+
host.addShells([mockPackage, dependsOnMockPackageEntryPoint, mockPackageWithSlot]);
|
|
1429
|
+
expect(spy).toBeCalledTimes(1);
|
|
1430
|
+
host.removeShells([mockPackage.name]);
|
|
1431
|
+
expect(spy).toBeCalledTimes(2);
|
|
1432
|
+
});
|
|
1433
|
+
it('should be called once for an async api contribution in the extend phase', () => {
|
|
1434
|
+
const host = createAppHost([], testHostOptions);
|
|
1435
|
+
const spy = jest.fn();
|
|
1436
|
+
host.onDeclarationsChanged(spy);
|
|
1437
|
+
host.addShells([asyncLoadMockPackage]);
|
|
1438
|
+
expect(spy).toBeCalledTimes(1);
|
|
1439
|
+
});
|
|
1440
|
+
it('should be called for a slot declaration outside of an entry point', () => {
|
|
1441
|
+
const host = createAppHost([], testHostOptions);
|
|
1442
|
+
const spy = jest.fn();
|
|
1443
|
+
host.onDeclarationsChanged(spy);
|
|
1444
|
+
const shell = addMockShell(host);
|
|
1445
|
+
expect(spy).toBeCalledTimes(1);
|
|
1446
|
+
shell.declareSlot(MockSlot);
|
|
1447
|
+
expect(spy).toBeCalledTimes(2);
|
|
1448
|
+
});
|
|
1449
|
+
});
|
|
1450
|
+
});
|
|
1451
|
+
//# sourceMappingURL=appHost.spec.js.map
|