repluggable-core 0.0.0-pr349.66 → 0.0.0-pr351.71
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/es/src/repluggableAppDebug/index.d.ts +1 -1
- package/dist/es/src/repluggableAppDebug/index.d.ts.map +1 -1
- package/dist/es/src/repluggableAppDebug/index.js.map +1 -1
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts +20 -0
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -1
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js +41 -42
- package/dist/es/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -1
- package/dist/es/test/repluggableAppDebug.spec.js +122 -0
- package/dist/es/test/repluggableAppDebug.spec.js.map +1 -1
- package/dist/es/test/testKit.spec.js +44 -2
- package/dist/es/test/testKit.spec.js.map +1 -1
- package/dist/es/testKit/index.d.ts +10 -1
- package/dist/es/testKit/index.d.ts.map +1 -1
- package/dist/es/testKit/index.js +56 -13
- package/dist/es/testKit/index.js.map +1 -1
- package/dist/src/repluggableAppDebug/index.d.ts +1 -1
- package/dist/src/repluggableAppDebug/index.d.ts.map +1 -1
- package/dist/src/repluggableAppDebug/index.js.map +1 -1
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts +20 -0
- package/dist/src/repluggableAppDebug/repluggableAppDebug.d.ts.map +1 -1
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js +41 -42
- package/dist/src/repluggableAppDebug/repluggableAppDebug.js.map +1 -1
- package/dist/test/repluggableAppDebug.spec.js +122 -0
- package/dist/test/repluggableAppDebug.spec.js.map +1 -1
- package/dist/test/testKit.spec.js +43 -1
- package/dist/test/testKit.spec.js.map +1 -1
- package/dist/testKit/index.d.ts +10 -1
- package/dist/testKit/index.d.ts.map +1 -1
- package/dist/testKit/index.js +58 -14
- package/dist/testKit/index.js.map +1 -1
- package/package.json +2 -2
- package/src/repluggableAppDebug/debug.d.ts +16 -1
- package/src/repluggableAppDebug/index.ts +1 -1
- package/src/repluggableAppDebug/repluggableAppDebug.ts +65 -43
- package/test/repluggableAppDebug.spec.ts +150 -0
- package/test/testKit.spec.tsx +57 -2
- package/testKit/index.ts +71 -18
package/dist/testKit/index.js
CHANGED
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.mockObservable = exports.addMockShell = exports.createAppHostAndWaitForLoading = exports.createAppHostWithPacts = exports.getPackagesDependencies = exports.createAppHost = exports.createSignalItemsDataStructure = exports.withThrowOnError = exports.withConsoleErrors = exports.emptyLoggerOptions = exports.createShellLogger = void 0;
|
|
29
|
+
exports.mockObservable = exports.addMockShell = exports.createAppHostAndWaitForLoading = exports.AppHostLoadingTimeoutError = exports.createAppHostWithPacts = exports.getPackagesDependencies = exports.createAppHost = exports.createSignalItemsDataStructure = exports.withThrowOnError = exports.withConsoleErrors = exports.emptyLoggerOptions = exports.createShellLogger = void 0;
|
|
30
30
|
const lodash_1 = __importDefault(require("lodash"));
|
|
31
31
|
const index_1 = require("../src/index");
|
|
32
32
|
const loggers_1 = require("../src/loggers");
|
|
@@ -88,28 +88,64 @@ function createAppHostWithPacts(packages, pacts) {
|
|
|
88
88
|
return (0, exports.createAppHost)([...packages, pactsEntryPoint], Object.assign(Object.assign({}, emptyLoggerOptions_1.emptyLoggerOptions), { disableLayersValidation: true }));
|
|
89
89
|
}
|
|
90
90
|
exports.createAppHostWithPacts = createAppHostWithPacts;
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
class AppHostLoadingTimeoutError extends Error {
|
|
92
|
+
constructor(message, report) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.report = report;
|
|
95
|
+
this.name = 'AppHostLoadingTimeoutError';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.AppHostLoadingTimeoutError = AppHostLoadingTimeoutError;
|
|
99
|
+
const WAIT_FOR_LOADING_PROBE_SHELL = 'Depends on all declared APIs';
|
|
100
|
+
const formatUnreadyReport = (timeout, report) => {
|
|
101
|
+
const { utils } = globalThis.repluggableAppDebug;
|
|
102
|
+
const isProbeShell = (name) => name === WAIT_FOR_LOADING_PROBE_SHELL;
|
|
103
|
+
const header = `createAppHostAndWaitForLoading - host not ready within ${timeout}ms.`;
|
|
104
|
+
const unreadyEntryPoints = report.unreadyEntryPoints.filter(entryPoint => !isProbeShell(entryPoint.name));
|
|
105
|
+
const rootUnreadyEntryPoints = report.rootUnreadyEntryPoints.filter(entryPoint => !isProbeShell(entryPoint.name));
|
|
106
|
+
if (report.probableDependencyCycle) {
|
|
107
|
+
const names = unreadyEntryPoints.map(entryPoint => `"${entryPoint.name}"`).join(', ');
|
|
108
|
+
return `${header}
|
|
109
|
+
No root unready API found while ${unreadyEntryPoints.length} entry points are unready - probable dependency cycle between: ${names}`;
|
|
110
|
+
}
|
|
111
|
+
const roots = report.rootUnreadyAPIs.map((info, index) => {
|
|
112
|
+
const declaredBy = info.declaredBy === 'nobody'
|
|
113
|
+
? 'declared by NO entry point (missing package or pact?)'
|
|
114
|
+
: `declared by "${info.declaredBy.entryPointName}" (installed, but its contribution never completed - hung async contributeAPI?)`;
|
|
115
|
+
const requiredBy = info.requiredBy.filter(name => !isProbeShell(name));
|
|
116
|
+
const lines = [`${index + 1}. "${info.key.name}" - ${declaredBy}`];
|
|
117
|
+
if (requiredBy.length) {
|
|
118
|
+
lines.push(` required by: ${requiredBy.join(', ')}`);
|
|
119
|
+
const tree = utils.visualizeDependencyTree(utils.traceAPIDependency(requiredBy[0], info.key.name));
|
|
120
|
+
lines.push(...tree.split('\n').map(line => ` ${line}`));
|
|
121
|
+
}
|
|
122
|
+
return lines.join('\n');
|
|
123
|
+
});
|
|
124
|
+
return `${header}
|
|
125
|
+
|
|
126
|
+
Root unready APIs (${report.rootUnreadyAPIs.length}):
|
|
127
|
+
${roots.join('\n')}
|
|
128
|
+
|
|
129
|
+
Unready entry points: ${rootUnreadyEntryPoints.length} blocked directly on root APIs, ${unreadyEntryPoints.length} total.`;
|
|
130
|
+
};
|
|
131
|
+
function createAppHostAndWaitForLoading(packages_1, pacts_1) {
|
|
132
|
+
return __awaiter(this, arguments, void 0, function* (packages, pacts, { timeout = 3000 } = {}) {
|
|
93
133
|
const appHost = createAppHostWithPacts(packages, pacts);
|
|
94
134
|
const declaredAPIs = (0, lodash_1.default)(packages)
|
|
95
135
|
.flatten()
|
|
96
136
|
.value()
|
|
97
137
|
.flatMap((entryPoint) => (entryPoint.declareAPIs ? entryPoint.declareAPIs() : []));
|
|
138
|
+
let timer;
|
|
98
139
|
const timeoutPromise = new Promise((resolve, reject) => {
|
|
99
|
-
setTimeout(() => {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
reject(new Error(`createAppHostAndWaitForLoading - waiting for loading timed out.
|
|
104
|
-
there's a high chance this missing API is the main reason for it: ${JSON.stringify(rootUnreadyAPI)}
|
|
105
|
-
|
|
106
|
-
in addition here's the full list of declared APIs that have not been contributed: ${JSON.stringify(unreadyAPIs)}`));
|
|
107
|
-
}, 3000);
|
|
140
|
+
timer = setTimeout(() => {
|
|
141
|
+
const report = globalThis.repluggableAppDebug.utils.getUnreadyEntryPointsReport();
|
|
142
|
+
reject(new AppHostLoadingTimeoutError(formatUnreadyReport(timeout, report), report));
|
|
143
|
+
}, timeout);
|
|
108
144
|
});
|
|
109
145
|
const loadingPromise = new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
110
146
|
yield appHost.addShells([
|
|
111
147
|
{
|
|
112
|
-
name:
|
|
148
|
+
name: WAIT_FOR_LOADING_PROBE_SHELL,
|
|
113
149
|
getDependencyAPIs() {
|
|
114
150
|
return declaredAPIs;
|
|
115
151
|
},
|
|
@@ -119,7 +155,15 @@ in addition here's the full list of declared APIs that have not been contributed
|
|
|
119
155
|
}
|
|
120
156
|
]);
|
|
121
157
|
}));
|
|
122
|
-
|
|
158
|
+
try {
|
|
159
|
+
yield Promise.race([timeoutPromise, loadingPromise]);
|
|
160
|
+
return appHost;
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
if (timer) {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
123
167
|
});
|
|
124
168
|
}
|
|
125
169
|
exports.createAppHostAndWaitForLoading = createAppHostAndWaitForLoading;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../testKit/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oDAAsB;AAEtB,wCAAwH;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../testKit/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "repluggable-core",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-pr351.71",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Allows composition of a React-with-Redux application entirely from a list of pluggable packages",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"registry": "https://registry.npmjs.org/",
|
|
52
52
|
"versionBumpStrategy": "patch"
|
|
53
53
|
},
|
|
54
|
-
"stableVersion": "1.302.
|
|
54
|
+
"stableVersion": "1.302.86"
|
|
55
55
|
}
|
|
@@ -23,10 +23,25 @@ export interface DependencyTree {
|
|
|
23
23
|
deps: { api: string; subtree: DependencyTree | null }[]
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export interface RootUnreadyAPIInfo {
|
|
27
|
+
key: AnySlotKey
|
|
28
|
+
declaredBy: 'nobody' | { entryPointName: string }
|
|
29
|
+
requiredBy: string[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface UnreadyEntryPointsReport {
|
|
33
|
+
unreadyEntryPoints: EntryPoint[]
|
|
34
|
+
rootUnreadyAPIs: RootUnreadyAPIInfo[]
|
|
35
|
+
rootUnreadyEntryPoints: EntryPoint[]
|
|
36
|
+
probableDependencyCycle: boolean
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
export interface RepluggableDebugUtils {
|
|
27
40
|
apis(): APIDebugInfo[]
|
|
28
41
|
unReadyEntryPoints(): EntryPoint[]
|
|
29
|
-
|
|
42
|
+
getUnreadyEntryPointsReport(): UnreadyEntryPointsReport
|
|
43
|
+
/** @deprecated use getUnreadyEntryPointsReport() - this returns only the first of possibly many root unready APIs */
|
|
44
|
+
getRootUnreadyAPI(): SlotKey<any> | undefined
|
|
30
45
|
whyEntryPointUnready(name: string): void
|
|
31
46
|
findAPI(name: string): APIDebugInfo[]
|
|
32
47
|
getAPIOrEntryPointsDependencies(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { setupDebugInfo } from './repluggableAppDebug'
|
|
1
|
+
export { setupDebugInfo, RootUnreadyAPIInfo, UnreadyEntryPointsReport } from './repluggableAppDebug'
|
|
@@ -36,54 +36,74 @@ function mapApiToEntryPoint(allPackages: EntryPoint[]) {
|
|
|
36
36
|
return apiToEntryPoint
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
export interface RootUnreadyAPIInfo {
|
|
40
|
+
key: AnySlotKey
|
|
41
|
+
/**
|
|
42
|
+
* 'nobody' -> not declared by any entry point in the host (missing package / pact)
|
|
43
|
+
* otherwise -> declared by an INSTALLED shell whose contributeAPI never completed (hung async contribution)
|
|
44
|
+
*/
|
|
45
|
+
declaredBy: 'nobody' | { entryPointName: string }
|
|
46
|
+
/** names of unready entry points directly blocked on this API */
|
|
47
|
+
requiredBy: string[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface UnreadyEntryPointsReport {
|
|
51
|
+
unreadyEntryPoints: EntryPoint[]
|
|
52
|
+
rootUnreadyAPIs: RootUnreadyAPIInfo[]
|
|
53
|
+
/** unready entry points directly blocked on a root unready API */
|
|
54
|
+
rootUnreadyEntryPoints: EntryPoint[]
|
|
55
|
+
/** true when entry points are unready but no root unready API exists - their dependencies form a cycle */
|
|
56
|
+
probableDependencyCycle: boolean
|
|
47
57
|
}
|
|
48
58
|
|
|
59
|
+
type UnreadyReportParams = Pick<SetupDebugInfoParams, 'readyAPIs' | 'getOwnSlotKey' | 'getUnreadyEntryPoints' | 'addedShells'>
|
|
60
|
+
|
|
49
61
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* will unblock the rest of the entry point (note that there might be more than one)
|
|
53
|
-
*
|
|
54
|
-
* this function basically takes the first unready entry point, get its dependencies and iterates over them to find an API that is not ready
|
|
55
|
-
* at this point it follows the same process recursively until it reaced the target API.
|
|
62
|
+
* Computes all root unready APIs at once: dependencies of unready entry points that are neither ready
|
|
63
|
+
* nor declared by another unready entry point (i.e. the APIs actually blocking the host from loading).
|
|
56
64
|
*/
|
|
57
|
-
const
|
|
58
|
-
return () => {
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
continue
|
|
65
|
+
const createGetUnreadyEntryPointsReport = ({ readyAPIs, getOwnSlotKey, getUnreadyEntryPoints, addedShells }: UnreadyReportParams) => {
|
|
66
|
+
return (): UnreadyEntryPointsReport => {
|
|
67
|
+
const unreadyEntryPoints = getUnreadyEntryPoints()
|
|
68
|
+
const isReady = (key: AnySlotKey) => readyAPIs.has(getOwnSlotKey(key as SlotKey<any>))
|
|
69
|
+
|
|
70
|
+
const declaredByUnready = new Set<string>()
|
|
71
|
+
unreadyEntryPoints.forEach(entryPoint => entryPoint.declareAPIs?.().forEach(key => declaredByUnready.add(key.name)))
|
|
72
|
+
|
|
73
|
+
const declaredByInstalled = new Map<string, string>()
|
|
74
|
+
for (const shell of addedShells.values()) {
|
|
75
|
+
shell.entryPoint.declareAPIs?.().forEach(key => declaredByInstalled.set(key.name, shell.entryPoint.name))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const rootByName = new Map<string, RootUnreadyAPIInfo>()
|
|
79
|
+
unreadyEntryPoints.forEach(entryPoint => {
|
|
80
|
+
entryPoint.getDependencyAPIs?.().forEach(key => {
|
|
81
|
+
if (isReady(key) || declaredByUnready.has(key.name)) {
|
|
82
|
+
return
|
|
76
83
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
const declarerName = declaredByInstalled.get(key.name)
|
|
85
|
+
const info = rootByName.get(key.name) ?? {
|
|
86
|
+
key,
|
|
87
|
+
declaredBy: declarerName ? { entryPointName: declarerName } : ('nobody' as const),
|
|
88
|
+
requiredBy: []
|
|
89
|
+
}
|
|
90
|
+
info.requiredBy.push(entryPoint.name)
|
|
91
|
+
rootByName.set(key.name, info)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const rootUnreadyAPIs = [...rootByName.values()]
|
|
96
|
+
const rootAPINames = new Set(rootByName.keys())
|
|
97
|
+
const rootUnreadyEntryPoints = unreadyEntryPoints.filter(entryPoint =>
|
|
98
|
+
entryPoint.getDependencyAPIs?.().some(key => rootAPINames.has(key.name))
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
unreadyEntryPoints,
|
|
103
|
+
rootUnreadyAPIs,
|
|
104
|
+
rootUnreadyEntryPoints,
|
|
105
|
+
probableDependencyCycle: unreadyEntryPoints.length > 0 && rootUnreadyAPIs.length === 0
|
|
85
106
|
}
|
|
86
|
-
return unReadyAPIsArray.reverse()[0]
|
|
87
107
|
}
|
|
88
108
|
}
|
|
89
109
|
|
|
@@ -207,7 +227,9 @@ export function setupDebugInfo({
|
|
|
207
227
|
}
|
|
208
228
|
})
|
|
209
229
|
},
|
|
210
|
-
|
|
230
|
+
getUnreadyEntryPointsReport: createGetUnreadyEntryPointsReport({ readyAPIs, getOwnSlotKey, getUnreadyEntryPoints, addedShells }),
|
|
231
|
+
/** @deprecated use getUnreadyEntryPointsReport() - this returns only the first of possibly many root unready APIs */
|
|
232
|
+
getRootUnreadyAPI: (): AnySlotKey | undefined => utils.getUnreadyEntryPointsReport().rootUnreadyAPIs[0]?.key,
|
|
211
233
|
unReadyEntryPoints: (): EntryPoint[] => getUnreadyEntryPoints(),
|
|
212
234
|
whyEntryPointUnready: (name: string) => {
|
|
213
235
|
const unreadyEntryPoint = _.find(
|
|
@@ -245,4 +245,154 @@ describe('RepluggableAppDebug', () => {
|
|
|
245
245
|
expect(unreadyAPIs).toEqual({ name: 'unreadyAPI' })
|
|
246
246
|
})
|
|
247
247
|
})
|
|
248
|
+
|
|
249
|
+
describe('getUnreadyEntryPointsReport', () => {
|
|
250
|
+
const getReport = async () => {
|
|
251
|
+
await new Promise(resolve => setTimeout(resolve, 0))
|
|
252
|
+
return globalThis.repluggableAppDebug.utils.getUnreadyEntryPointsReport()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
it('should report no unready entry points when all are loaded', async () => {
|
|
256
|
+
createAppHost([
|
|
257
|
+
{
|
|
258
|
+
name: 'entryPoint',
|
|
259
|
+
declareAPIs: () => []
|
|
260
|
+
}
|
|
261
|
+
])
|
|
262
|
+
|
|
263
|
+
const report = await getReport()
|
|
264
|
+
|
|
265
|
+
expect(report).toEqual({
|
|
266
|
+
unreadyEntryPoints: [],
|
|
267
|
+
rootUnreadyAPIs: [],
|
|
268
|
+
rootUnreadyEntryPoints: [],
|
|
269
|
+
probableDependencyCycle: false
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
it('should report all root unready APIs of independent unready clusters', async () => {
|
|
274
|
+
createAppHost([
|
|
275
|
+
{
|
|
276
|
+
name: 'entryPoint A',
|
|
277
|
+
getDependencyAPIs: () => [{ name: 'missing A' }]
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: 'entryPoint B',
|
|
281
|
+
getDependencyAPIs: () => [{ name: 'missing B' }]
|
|
282
|
+
}
|
|
283
|
+
])
|
|
284
|
+
|
|
285
|
+
const report = await getReport()
|
|
286
|
+
|
|
287
|
+
expect(report.rootUnreadyAPIs).toEqual([
|
|
288
|
+
{ key: { name: 'missing A' }, declaredBy: 'nobody', requiredBy: ['entryPoint A'] },
|
|
289
|
+
{ key: { name: 'missing B' }, declaredBy: 'nobody', requiredBy: ['entryPoint B'] }
|
|
290
|
+
])
|
|
291
|
+
expect(report.rootUnreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint A', 'entryPoint B'])
|
|
292
|
+
expect(report.probableDependencyCycle).toBe(false)
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
it('should report only the root API of a transitively blocked chain', async () => {
|
|
296
|
+
createAppHost([
|
|
297
|
+
{
|
|
298
|
+
name: 'entryPoint A',
|
|
299
|
+
getDependencyAPIs: () => [{ name: 'API B' }]
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: 'entryPoint B',
|
|
303
|
+
declareAPIs: () => [{ name: 'API B' }],
|
|
304
|
+
getDependencyAPIs: () => [unreadAPI]
|
|
305
|
+
}
|
|
306
|
+
])
|
|
307
|
+
|
|
308
|
+
const report = await getReport()
|
|
309
|
+
|
|
310
|
+
expect(report.rootUnreadyAPIs).toEqual([{ key: unreadAPI, declaredBy: 'nobody', requiredBy: ['entryPoint B'] }])
|
|
311
|
+
expect(report.rootUnreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint B'])
|
|
312
|
+
expect(report.unreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint A', 'entryPoint B'])
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it('should report roots of sibling branches, including APIs declared by an installed shell that never contributed them', async () => {
|
|
316
|
+
createAppHost([
|
|
317
|
+
{
|
|
318
|
+
name: 'entryPoint 0',
|
|
319
|
+
getDependencyAPIs: () => [{ name: 'missing API' }, { name: 'API B' }]
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
name: 'entryPoint 1',
|
|
323
|
+
declareAPIs: () => [{ name: 'API B' }]
|
|
324
|
+
}
|
|
325
|
+
])
|
|
326
|
+
|
|
327
|
+
const report = await getReport()
|
|
328
|
+
|
|
329
|
+
expect(report.rootUnreadyAPIs).toEqual([
|
|
330
|
+
{ key: { name: 'missing API' }, declaredBy: 'nobody', requiredBy: ['entryPoint 0'] },
|
|
331
|
+
{ key: { name: 'API B' }, declaredBy: { entryPointName: 'entryPoint 1' }, requiredBy: ['entryPoint 0'] }
|
|
332
|
+
])
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
it('should aggregate all entry points blocked on the same root API', async () => {
|
|
336
|
+
createAppHost([
|
|
337
|
+
{
|
|
338
|
+
name: 'entryPoint A',
|
|
339
|
+
getDependencyAPIs: () => [unreadAPI]
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: 'entryPoint B',
|
|
343
|
+
getDependencyAPIs: () => [unreadAPI]
|
|
344
|
+
}
|
|
345
|
+
])
|
|
346
|
+
|
|
347
|
+
const report = await getReport()
|
|
348
|
+
|
|
349
|
+
expect(report.rootUnreadyAPIs).toEqual([{ key: unreadAPI, declaredBy: 'nobody', requiredBy: ['entryPoint A', 'entryPoint B'] }])
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
it('should flag a probable dependency cycle when unready entry points have no root unready API', async () => {
|
|
353
|
+
createAppHost(
|
|
354
|
+
[
|
|
355
|
+
{
|
|
356
|
+
name: 'entryPoint A',
|
|
357
|
+
declareAPIs: () => [{ name: 'API X' }],
|
|
358
|
+
getDependencyAPIs: () => [{ name: 'API Y' }]
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: 'entryPoint B',
|
|
362
|
+
declareAPIs: () => [{ name: 'API Y' }],
|
|
363
|
+
getDependencyAPIs: () => [{ name: 'API X' }]
|
|
364
|
+
}
|
|
365
|
+
],
|
|
366
|
+
{ monitoring: {}, disableCheckCircularDependencies: true }
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
const report = await getReport()
|
|
370
|
+
|
|
371
|
+
expect(report.rootUnreadyAPIs).toEqual([])
|
|
372
|
+
expect(report.unreadyEntryPoints.map(entryPoint => entryPoint.name)).toEqual(['entryPoint A', 'entryPoint B'])
|
|
373
|
+
expect(report.probableDependencyCycle).toBe(true)
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
it('should not hang getRootUnreadyAPI on a dependency cycle', async () => {
|
|
377
|
+
createAppHost(
|
|
378
|
+
[
|
|
379
|
+
{
|
|
380
|
+
name: 'entryPoint A',
|
|
381
|
+
declareAPIs: () => [{ name: 'API X' }],
|
|
382
|
+
getDependencyAPIs: () => [{ name: 'API Y' }]
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: 'entryPoint B',
|
|
386
|
+
declareAPIs: () => [{ name: 'API Y' }],
|
|
387
|
+
getDependencyAPIs: () => [{ name: 'API X' }]
|
|
388
|
+
}
|
|
389
|
+
],
|
|
390
|
+
{ monitoring: {}, disableCheckCircularDependencies: true }
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
const unreadyAPIs = await getUnreadyAPIs()
|
|
394
|
+
|
|
395
|
+
expect(unreadyAPIs).toBeUndefined()
|
|
396
|
+
}, 3000)
|
|
397
|
+
})
|
|
248
398
|
})
|
package/test/testKit.spec.tsx
CHANGED
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
asyncLoadMockPackage,
|
|
13
13
|
dependsOnMockPackageEntryPoint,
|
|
14
14
|
MockPublicAPI,
|
|
15
|
-
createAppHostAndWaitForLoading
|
|
15
|
+
createAppHostAndWaitForLoading,
|
|
16
|
+
AppHostLoadingTimeoutError
|
|
16
17
|
} from '../testKit'
|
|
17
18
|
|
|
18
19
|
interface APIKeys {
|
|
@@ -147,7 +148,61 @@ describe('App Host TestKit', () => {
|
|
|
147
148
|
it('should throw if failed to load all packages', async () => {
|
|
148
149
|
const hostPromise = createAppHostAndWaitForLoading([dependsOnMockPackageEntryPoint], [])
|
|
149
150
|
jest.runAllTimers()
|
|
150
|
-
await expect(hostPromise).rejects.toThrow(new RegExp(
|
|
151
|
+
await expect(hostPromise).rejects.toThrow(new RegExp(MockAPI.name))
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should reject with a structured report of all root unready APIs', async () => {
|
|
155
|
+
const hostPromise = createAppHostAndWaitForLoading(
|
|
156
|
+
[
|
|
157
|
+
{
|
|
158
|
+
name: 'entryPoint A',
|
|
159
|
+
declareAPIs: () => [{ name: 'API A' }],
|
|
160
|
+
getDependencyAPIs: () => [{ name: 'missing A' }]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'entryPoint B',
|
|
164
|
+
declareAPIs: () => [{ name: 'API B' }],
|
|
165
|
+
getDependencyAPIs: () => [{ name: 'missing B' }]
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
[]
|
|
169
|
+
)
|
|
170
|
+
jest.runAllTimers()
|
|
171
|
+
const error: AppHostLoadingTimeoutError = await hostPromise.then(
|
|
172
|
+
() => {
|
|
173
|
+
throw new Error('expected hostPromise to reject')
|
|
174
|
+
},
|
|
175
|
+
e => e
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
expect(error).toBeInstanceOf(AppHostLoadingTimeoutError)
|
|
179
|
+
expect(error.report.rootUnreadyAPIs.map(info => info.key.name)).toEqual(['missing A', 'missing B'])
|
|
180
|
+
expect(error.message).toContain('"missing A"')
|
|
181
|
+
expect(error.message).toContain('"missing B"')
|
|
182
|
+
expect(error.message).toContain('required by: entryPoint A')
|
|
183
|
+
expect(error.message).toContain('required by: entryPoint B')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('should respect a custom loading timeout', async () => {
|
|
187
|
+
let settled = false
|
|
188
|
+
const hostPromise = createAppHostAndWaitForLoading([dependsOnMockPackageEntryPoint], [], { timeout: 10000 })
|
|
189
|
+
hostPromise.catch(() => (settled = true))
|
|
190
|
+
|
|
191
|
+
jest.advanceTimersByTime(9999)
|
|
192
|
+
await Promise.resolve()
|
|
193
|
+
await Promise.resolve()
|
|
194
|
+
expect(settled).toBe(false)
|
|
195
|
+
|
|
196
|
+
jest.advanceTimersByTime(1)
|
|
197
|
+
await expect(hostPromise).rejects.toBeInstanceOf(AppHostLoadingTimeoutError)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('should not leave a pending timeout after successful loading', async () => {
|
|
201
|
+
const hostPromise = createAppHostAndWaitForLoading([dependsOnMockPackageEntryPoint, asyncLoadMockPackage], [])
|
|
202
|
+
jest.advanceTimersByTime(500)
|
|
203
|
+
const host = await hostPromise
|
|
204
|
+
expect(host.getAPI(MockPublicAPI)).toBeDefined()
|
|
205
|
+
expect(jest.getTimerCount()).toBe(0)
|
|
151
206
|
})
|
|
152
207
|
})
|
|
153
208
|
})
|