From b78f8c77bf77c4abcd90d2e53389f6b87c622f2c Mon Sep 17 00:00:00 2001 From: Thorsten Suckow-Homberg Date: Fri, 2 Dec 2022 10:15:08 +0100 Subject: [PATCH] refactor(tests): add test for apply refs conjoon/extjs-app-webmail#255 --- src/ioc/sencha/FactoryProxy.js | 20 +++++--- tests/src/ioc/sencha/FactoryProxyTest.js | 65 +++++++++++++++++++++++- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/ioc/sencha/FactoryProxy.js b/src/ioc/sencha/FactoryProxy.js index 3d6e620..8f4fa4f 100644 --- a/src/ioc/sencha/FactoryProxy.js +++ b/src/ioc/sencha/FactoryProxy.js @@ -57,20 +57,23 @@ Ext.define("coon.core.ioc.sencha.FactoryProxy", { * Apply handler for proxying calls to Ext.Factory["proxy", "store", "controller", ...] * factory methods are usually invoked with aliases instead of class names which are * then resolved by Ext JS' underlying class system. The handler will utilize this - * functionality and assume the alias is available with argumentsList[0], + * functionality and assume the alias is available with the key "type" in argumentsList[0], * inspect the "requireProperty" available with the resolved class and then * resolve dependencies with the help of resolveDependencies(), - * if the arguments found in argumentsList[1] do not already contain + * if the object found in argumentsList[0] does not already contain * configurations for these dependencies. + * The target is the Factory this handler operates on. The "aliasPrefix" of this argument + * will be used to determine the prefix used in conjunction with the "type" to resolve + * the proper class. * * @example * // acme.Request.require = {requestor: "acme.RequestConfigurator"} * // alias: "acme-request" - * proxy.apply({}, {}, ["acme-request", {}]; + * proxy.apply({}, {}, [{type: "acme-request"}, {}]; * // config has no "requestor" configured with arguments, will resolve * // dependencies using available bindings by calling resolveDependencies() * - * proxy.apply({}, {}, ["acme-request", {requestor: {}]; + * proxy.apply({}, {}, [{type: "acme-request"}, {requestor: {}]; * // config has "requestor" configured with arguments, will not resolve * // dependencies * @@ -89,11 +92,14 @@ Ext.define("coon.core.ioc.sencha.FactoryProxy", { const type = cfg.type ? cfg.type : (l8.isString(cfg) ? cfg : undefined); if (type && target.instance?.aliasPrefix) { - const cls = Ext.ClassManager.getByAlias(`${target.instance.aliasPrefix}${type}`); - if (cls.require) { + const + cls = Ext.ClassManager.getByAlias(`${target.instance.aliasPrefix}${type}`), + requireCfg = cls?.[me.requireProperty]; + + if (requireCfg) { cfg = Object.assign( cfg, - me.resolveDependencies(cls.require, Ext.ClassManager.getName(cls)) + me.resolveDependencies(Ext.ClassManager.getName(cls), requireCfg) ); cfg.type = cfg.type || type; argumentsList[0] = cfg; diff --git a/tests/src/ioc/sencha/FactoryProxyTest.js b/tests/src/ioc/sencha/FactoryProxyTest.js index 19a407e..b7473c8 100644 --- a/tests/src/ioc/sencha/FactoryProxyTest.js +++ b/tests/src/ioc/sencha/FactoryProxyTest.js @@ -77,7 +77,70 @@ StartTest(t => { t.it("apply()", t => { - t.fail(); + + let defaultClass = {}; + + const + proxy = create({}), + getByAliasSpy = t.spyOn(Ext.ClassManager, "getByAlias").and.callFake(() => defaultClass), + getNameSpy = t.spyOn(Ext.ClassManager, "getName").and.callFake(() => "className"), + reflectSpy = t.spyOn(Reflect, "apply").and.callFake(() => "reflect"), + resolveDependenciesSpy = t.spyOn(proxy, "resolveDependencies").and.callFake(() => ({"prop": "resolved"})), + thisArg = {}, + assertReflectSpy = (thirdArg) => { + t.expect(reflectSpy.calls.mostRecent().args[0]).toBe(target); + t.expect(reflectSpy.calls.mostRecent().args[1]).toBe(thisArg); + + if (thirdArg !== undefined) { + t.expect(reflectSpy.calls.mostRecent().args[2]).toEqual(thirdArg); + } + }; + + let target = {}; + + // no "type" passed in object with 1st argument + let argsList = [{}]; + t.expect(proxy.apply(target, thisArg, argsList)).toBe(reflectSpy.calls.mostRecent().returnValue); + t.expect(resolveDependenciesSpy.calls.count()).toBe(0); + assertReflectSpy(argsList); + + // no "aliasPrefix" available + argsList = [{type: "foo"}]; + t.expect(proxy.apply(target, thisArg, argsList)).toBe(reflectSpy.calls.mostRecent().returnValue); + t.expect(resolveDependenciesSpy.calls.count()).toBe(0); + assertReflectSpy(argsList); + + // class alias cannot be resolved + target = {instance: {aliasPrefix: "bar"}}; + defaultClass = undefined; + argsList = [{type: "foo"}]; + t.expect(proxy.apply(target, thisArg, argsList)).toBe(reflectSpy.calls.mostRecent().returnValue); + t.expect(resolveDependenciesSpy.calls.count()).toBe(0); + assertReflectSpy(); + + // target class has no requireCfg + target = {instance: {aliasPrefix: "bar"}}; + defaultClass = {}; + argsList = [{type: "foo"}]; + t.expect(proxy.apply(target, thisArg, argsList)).toBe(reflectSpy.calls.mostRecent().returnValue); + t.expect(resolveDependenciesSpy.calls.count()).toBe(0); + assertReflectSpy(); + + // target class requireCfg + const requireConfig = {"config": {}}; + defaultClass = {}; + defaultClass[proxy.requireProperty] = requireConfig; + argsList = [{type: "foo", width: 800, height: 600}]; + t.expect(proxy.apply(target, thisArg, argsList)).toBe(reflectSpy.calls.mostRecent().returnValue); + t.expect(resolveDependenciesSpy.calls.count()).toBe(1); + t.expect(resolveDependenciesSpy.calls.mostRecent().args[0]).toBe( + getNameSpy.calls.mostRecent().returnValue + ); + t.expect(resolveDependenciesSpy.calls.mostRecent().args[1]).toBe(requireConfig); + assertReflectSpy([{type: "foo", width: 800, height: 600, prop: "resolved"}]); + + [reflectSpy, resolveDependenciesSpy, getNameSpy, getByAliasSpy].map(spy => spy.remove()); + });