mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[ftr/asyncInstance] fix error thrown for undefined provider instances (#22689)
When a FTR service is created async the promise created by its provider is wrapped in a [`Proxy`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy) that checks before each property access if the instance has finished initializing. This breaks if the service provider returns undefined, which is the case for the `failureDebugging` service, because our truthy check will fail and we throw the error claiming the service is uninitialized, which is probably incorrect. This PR updates the proxy to use a `Symbol` to indicate when a service instance is not available yet and throws a different error when the proxy receives any request (get, set, etc.) and the service instance is not an object, as required by the Reflect APIs.
This commit is contained in:
parent
a64738d277
commit
5baa6d51c9
1 changed files with 23 additions and 16 deletions
|
@ -18,95 +18,102 @@
|
|||
*/
|
||||
|
||||
const createdInstanceProxies = new WeakSet();
|
||||
const INITIALIZING = Symbol('async instance initializing');
|
||||
|
||||
export const isAsyncInstance = val =>(
|
||||
createdInstanceProxies.has(val)
|
||||
);
|
||||
|
||||
export const createAsyncInstance = (type, name, promiseForValue) => {
|
||||
let finalValue;
|
||||
let instance = INITIALIZING;
|
||||
|
||||
const initPromise = promiseForValue.then(v => finalValue = v);
|
||||
const initPromise = promiseForValue.then(v => instance = v);
|
||||
const initFn = () => initPromise;
|
||||
|
||||
const assertReady = desc => {
|
||||
if (!finalValue) {
|
||||
if (instance === INITIALIZING) {
|
||||
throw new Error(`
|
||||
${type} \`${desc}\` is loaded asynchronously but isn't available yet. Either await the
|
||||
promise returned from ${name}.init(), or move this access into a test hook
|
||||
like \`before()\` or \`beforeEach()\`.
|
||||
`);
|
||||
}
|
||||
|
||||
if (typeof instance !== 'object') {
|
||||
throw new TypeError(`
|
||||
${type} \`${desc}\` is not supported because ${name} is ${typeof instance}
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
const proxy = new Proxy({}, {
|
||||
apply(target, context, args) {
|
||||
assertReady(`${name}()`);
|
||||
return Reflect.apply(finalValue, context, args);
|
||||
return Reflect.apply(instance, context, args);
|
||||
},
|
||||
|
||||
construct(target, args, newTarget) {
|
||||
assertReady(`new ${name}()`);
|
||||
return Reflect.construct(finalValue, args, newTarget);
|
||||
return Reflect.construct(instance, args, newTarget);
|
||||
},
|
||||
|
||||
defineProperty(target, prop, descriptor) {
|
||||
assertReady(`${name}.${prop}`);
|
||||
return Reflect.defineProperty(finalValue, prop, descriptor);
|
||||
return Reflect.defineProperty(instance, prop, descriptor);
|
||||
},
|
||||
|
||||
deleteProperty(target, prop) {
|
||||
assertReady(`${name}.${prop}`);
|
||||
return Reflect.deleteProperty(finalValue, prop);
|
||||
return Reflect.deleteProperty(instance, prop);
|
||||
},
|
||||
|
||||
get(target, prop, receiver) {
|
||||
if (prop === 'init') return initFn;
|
||||
|
||||
assertReady(`${name}.${prop}`);
|
||||
return Reflect.get(finalValue, prop, receiver);
|
||||
return Reflect.get(instance, prop, receiver);
|
||||
},
|
||||
|
||||
getOwnPropertyDescriptor(target, prop) {
|
||||
assertReady(`${name}.${prop}`);
|
||||
return Reflect.getOwnPropertyDescriptor(finalValue, prop);
|
||||
return Reflect.getOwnPropertyDescriptor(instance, prop);
|
||||
},
|
||||
|
||||
getPrototypeOf() {
|
||||
assertReady(`${name}`);
|
||||
return Reflect.getPrototypeOf(finalValue);
|
||||
return Reflect.getPrototypeOf(instance);
|
||||
},
|
||||
|
||||
has(target, prop) {
|
||||
if (prop === 'init') return true;
|
||||
|
||||
assertReady(`${name}.${prop}`);
|
||||
return Reflect.has(finalValue, prop);
|
||||
return Reflect.has(instance, prop);
|
||||
},
|
||||
|
||||
isExtensible() {
|
||||
assertReady(`${name}`);
|
||||
return Reflect.isExtensible(finalValue);
|
||||
return Reflect.isExtensible(instance);
|
||||
},
|
||||
|
||||
ownKeys() {
|
||||
assertReady(`${name}`);
|
||||
return Reflect.ownKeys(finalValue);
|
||||
return Reflect.ownKeys(instance);
|
||||
},
|
||||
|
||||
preventExtensions() {
|
||||
assertReady(`${name}`);
|
||||
return Reflect.preventExtensions(finalValue);
|
||||
return Reflect.preventExtensions(instance);
|
||||
},
|
||||
|
||||
set(target, prop, value, receiver) {
|
||||
assertReady(`${name}.${prop}`);
|
||||
return Reflect.set(finalValue, prop, value, receiver);
|
||||
return Reflect.set(instance, prop, value, receiver);
|
||||
},
|
||||
|
||||
setPrototypeOf(target, prototype) {
|
||||
assertReady(`${name}`);
|
||||
return Reflect.setPrototypeOf(finalValue, prototype);
|
||||
return Reflect.setPrototypeOf(instance, prototype);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue