From 97f410b58ea9f8a42497921dfc46a225e7675bdb Mon Sep 17 00:00:00 2001 From: Benjamin Franzke <bfr@qbus.de> Date: Wed, 15 Dec 2021 15:26:15 +0100 Subject: [PATCH] [TASK] Prepare ImmediateActionElementTest for ES6 modules In ES6 mode Viewport.Topbar and ModuleMenu.App properties cannot be overwritten (in order to be substituted with a call spy), as they reference other JavaScript modules. The properties of ES6 models are readonly ("frozen") and can therefore not be overwritten in a test setup. Therefore the test is adapted to overwrite the references in Viewport and ModuleMenu instead. Also a timeout is added as await import('TYPO3/CMS/Backend/ModuleMenu') does not guarantee a loading order between modules in ES6, which causes test asserts to be executed too early. Releases: main Resolves: #96396 Related #96323 Change-Id: I5c213b70e43c5e1256e91ffe0d9f12f96dbb6615 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72736 Tested-by: core-ci <typo3@b13.com> Tested-by: Benni Mack <benni@typo3.org> Tested-by: Benjamin Franzke <bfr@qbus.de> Reviewed-by: Benni Mack <benni@typo3.org> Reviewed-by: Benjamin Franzke <bfr@qbus.de> --- .../Element/ImmediateActionElementTest.ts | 58 ++++++++++--------- .../Element/ImmediateActionElementTest.js | 2 +- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/Build/Sources/TypeScript/backend/Tests/Element/ImmediateActionElementTest.ts b/Build/Sources/TypeScript/backend/Tests/Element/ImmediateActionElementTest.ts index 2bb339a1fc59..413da55a9298 100644 --- a/Build/Sources/TypeScript/backend/Tests/Element/ImmediateActionElementTest.ts +++ b/Build/Sources/TypeScript/backend/Tests/Element/ImmediateActionElementTest.ts @@ -29,70 +29,74 @@ describe('TYPO3/CMS/Backend/Element/ImmediateActionElement:', () => { }); it('dispatches action when created via constructor', async () => { - const backup = viewportObject.Topbar.refresh; + const backup = viewportObject.Topbar; const observer = { - callback: (): void => { + refresh: (): void => { return; }, }; - spyOn(observer, 'callback').and.callThrough(); - viewportObject.Topbar.refresh = observer.callback; + spyOn(observer, 'refresh').and.callThrough(); + (viewportObject as any).Topbar = observer; const element = new ImmediateActionElement; element.setAttribute('action', 'TYPO3.Backend.Topbar.refresh'); - expect(observer.callback).not.toHaveBeenCalled(); + expect(observer.refresh).not.toHaveBeenCalled(); root.appendChild(element); await import('TYPO3/CMS/Backend/Viewport'); - expect(observer.callback).toHaveBeenCalled(); - viewportObject.Topbar.refresh = backup; + await new Promise((resolve) => setTimeout(resolve, 100)) + expect(observer.refresh).toHaveBeenCalled(); + (viewportObject as any).Topbar = backup; }); it('dispatches action when created via createElement', async () => { - const backup = viewportObject.Topbar.refresh; + const backup = viewportObject.Topbar; const observer = { - callback: (): void => { + refresh: (): void => { return; }, }; - spyOn(observer, 'callback').and.callThrough(); - viewportObject.Topbar.refresh = observer.callback; + spyOn(observer, 'refresh').and.callThrough(); + (viewportObject as any).Topbar = observer; const element = <ImmediateActionElement>document.createElement('typo3-immediate-action'); element.setAttribute('action', 'TYPO3.Backend.Topbar.refresh'); - expect(observer.callback).not.toHaveBeenCalled(); + expect(observer.refresh).not.toHaveBeenCalled(); root.appendChild(element); await import('TYPO3/CMS/Backend/Viewport'); - expect(observer.callback).toHaveBeenCalled(); - viewportObject.Topbar.refresh = backup; + await new Promise((resolve) => setTimeout(resolve, 100)) + expect(observer.refresh).toHaveBeenCalled(); + (viewportObject as any).Topbar = backup; }); it('dispatches action when created from string', async () => { - const backup = moduleMenuApp.App.refreshMenu; + const backup = moduleMenuApp.App; const observer = { - callback: (): void => { + refreshMenu: (): void => { return; }, }; - spyOn(observer, 'callback').and.callThrough(); - moduleMenuApp.App.refreshMenu = observer.callback; + spyOn(observer, 'refreshMenu').and.callThrough(); + (moduleMenuApp as any).App = observer; const element = document.createRange().createContextualFragment('<typo3-immediate-action action="TYPO3.ModuleMenu.App.refreshMenu"></typo3-immediate-action>').querySelector('typo3-immediate-action'); - expect(observer.callback).not.toHaveBeenCalled(); + expect(observer.refreshMenu).not.toHaveBeenCalled(); root.appendChild(element); await import('TYPO3/CMS/Backend/ModuleMenu'); - expect(observer.callback).toHaveBeenCalled(); - moduleMenuApp.App.refreshMenu = backup; + await new Promise((resolve) => setTimeout(resolve, 100)) + expect(observer.refreshMenu).toHaveBeenCalled(); + (viewportObject as any).App = backup; }); it('dispatches action when created via innerHTML', async () => { - const backup = moduleMenuApp.App.refreshMenu; + const backup = moduleMenuApp.App; const observer = { - callback: (): void => { + refreshMenu: (): void => { return; }, }; - spyOn(observer, 'callback').and.callThrough(); - moduleMenuApp.App.refreshMenu = observer.callback; + spyOn(observer, 'refreshMenu').and.callThrough(); + (moduleMenuApp as any).App = observer; root.innerHTML = '<typo3-immediate-action action="TYPO3.ModuleMenu.App.refreshMenu"></typo3-immediate-action>'; await import('TYPO3/CMS/Backend/ModuleMenu'); - expect(observer.callback).toHaveBeenCalled(); - moduleMenuApp.App.refreshMenu = backup; + await new Promise((resolve) => setTimeout(resolve, 100)) + expect(observer.refreshMenu).toHaveBeenCalled(); + (moduleMenuApp as any).App = backup; }); }); diff --git a/typo3/sysext/backend/Tests/JavaScript/Element/ImmediateActionElementTest.js b/typo3/sysext/backend/Tests/JavaScript/Element/ImmediateActionElementTest.js index aa1b765e4c09..c7fb9d94c15a 100644 --- a/typo3/sysext/backend/Tests/JavaScript/Element/ImmediateActionElementTest.js +++ b/typo3/sysext/backend/Tests/JavaScript/Element/ImmediateActionElementTest.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,a,n){void 0===n&&(n=a),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[a]}})}:function(e,t,a,n){void 0===n&&(n=a),e[n]=t[a]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var a in e)"default"!==a&&Object.prototype.hasOwnProperty.call(e,a)&&__createBinding(t,e,a);return __setModuleDefault(t,e),t};define(["require","exports","TYPO3/CMS/Backend/Element/ImmediateActionElement","TYPO3/CMS/Backend/ModuleMenu","TYPO3/CMS/Backend/Viewport"],(function(e,t,a,n,c){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),describe("TYPO3/CMS/Backend/Element/ImmediateActionElement:",()=>{let t;beforeEach(()=>{t=document.createElement("div"),document.body.appendChild(t)}),afterEach(()=>{t.remove(),t=null}),it("dispatches action when created via constructor",async()=>{const n=c.Topbar.refresh,r={callback:()=>{}};spyOn(r,"callback").and.callThrough(),c.Topbar.refresh=r.callback;const o=new a.ImmediateActionElement;o.setAttribute("action","TYPO3.Backend.Topbar.refresh"),expect(r.callback).not.toHaveBeenCalled(),t.appendChild(o),await new Promise((t,a)=>{e(["TYPO3/CMS/Backend/Viewport"],t,a)}).then(__importStar),expect(r.callback).toHaveBeenCalled(),c.Topbar.refresh=n}),it("dispatches action when created via createElement",async()=>{const a=c.Topbar.refresh,n={callback:()=>{}};spyOn(n,"callback").and.callThrough(),c.Topbar.refresh=n.callback;const r=document.createElement("typo3-immediate-action");r.setAttribute("action","TYPO3.Backend.Topbar.refresh"),expect(n.callback).not.toHaveBeenCalled(),t.appendChild(r),await new Promise((t,a)=>{e(["TYPO3/CMS/Backend/Viewport"],t,a)}).then(__importStar),expect(n.callback).toHaveBeenCalled(),c.Topbar.refresh=a}),it("dispatches action when created from string",async()=>{const a=n.App.refreshMenu,c={callback:()=>{}};spyOn(c,"callback").and.callThrough(),n.App.refreshMenu=c.callback;const r=document.createRange().createContextualFragment('<typo3-immediate-action action="TYPO3.ModuleMenu.App.refreshMenu"></typo3-immediate-action>').querySelector("typo3-immediate-action");expect(c.callback).not.toHaveBeenCalled(),t.appendChild(r),await new Promise((t,a)=>{e(["TYPO3/CMS/Backend/ModuleMenu"],t,a)}).then(__importStar),expect(c.callback).toHaveBeenCalled(),n.App.refreshMenu=a}),it("dispatches action when created via innerHTML",async()=>{const a=n.App.refreshMenu,c={callback:()=>{}};spyOn(c,"callback").and.callThrough(),n.App.refreshMenu=c.callback,t.innerHTML='<typo3-immediate-action action="TYPO3.ModuleMenu.App.refreshMenu"></typo3-immediate-action>',await new Promise((t,a)=>{e(["TYPO3/CMS/Backend/ModuleMenu"],t,a)}).then(__importStar),expect(c.callback).toHaveBeenCalled(),n.App.refreshMenu=a})})})); \ No newline at end of file +var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n),Object.defineProperty(e,a,{enumerable:!0,get:function(){return t[n]}})}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&__createBinding(t,e,n);return __setModuleDefault(t,e),t};define(["require","exports","TYPO3/CMS/Backend/Element/ImmediateActionElement","TYPO3/CMS/Backend/ModuleMenu","TYPO3/CMS/Backend/Viewport"],(function(e,t,n,a,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),describe("TYPO3/CMS/Backend/Element/ImmediateActionElement:",()=>{let t;beforeEach(()=>{t=document.createElement("div"),document.body.appendChild(t)}),afterEach(()=>{t.remove(),t=null}),it("dispatches action when created via constructor",async()=>{const a=r.Topbar,i={refresh:()=>{}};spyOn(i,"refresh").and.callThrough(),r.Topbar=i;const o=new n.ImmediateActionElement;o.setAttribute("action","TYPO3.Backend.Topbar.refresh"),expect(i.refresh).not.toHaveBeenCalled(),t.appendChild(o),await new Promise((t,n)=>{e(["TYPO3/CMS/Backend/Viewport"],t,n)}).then(__importStar),await new Promise(e=>setTimeout(e,100)),expect(i.refresh).toHaveBeenCalled(),r.Topbar=a}),it("dispatches action when created via createElement",async()=>{const n=r.Topbar,a={refresh:()=>{}};spyOn(a,"refresh").and.callThrough(),r.Topbar=a;const i=document.createElement("typo3-immediate-action");i.setAttribute("action","TYPO3.Backend.Topbar.refresh"),expect(a.refresh).not.toHaveBeenCalled(),t.appendChild(i),await new Promise((t,n)=>{e(["TYPO3/CMS/Backend/Viewport"],t,n)}).then(__importStar),await new Promise(e=>setTimeout(e,100)),expect(a.refresh).toHaveBeenCalled(),r.Topbar=n}),it("dispatches action when created from string",async()=>{const n=a.App,i={refreshMenu:()=>{}};spyOn(i,"refreshMenu").and.callThrough(),a.App=i;const o=document.createRange().createContextualFragment('<typo3-immediate-action action="TYPO3.ModuleMenu.App.refreshMenu"></typo3-immediate-action>').querySelector("typo3-immediate-action");expect(i.refreshMenu).not.toHaveBeenCalled(),t.appendChild(o),await new Promise((t,n)=>{e(["TYPO3/CMS/Backend/ModuleMenu"],t,n)}).then(__importStar),await new Promise(e=>setTimeout(e,100)),expect(i.refreshMenu).toHaveBeenCalled(),r.App=n}),it("dispatches action when created via innerHTML",async()=>{const n=a.App,r={refreshMenu:()=>{}};spyOn(r,"refreshMenu").and.callThrough(),a.App=r,t.innerHTML='<typo3-immediate-action action="TYPO3.ModuleMenu.App.refreshMenu"></typo3-immediate-action>',await new Promise((t,n)=>{e(["TYPO3/CMS/Backend/ModuleMenu"],t,n)}).then(__importStar),await new Promise(e=>setTimeout(e,100)),expect(r.refreshMenu).toHaveBeenCalled(),a.App=n})})})); \ No newline at end of file -- GitLab