diff --git a/src/jest/server/pageContributions/getAndMerge.test.ts b/src/jest/server/pageContributions/getAndMerge.test.ts new file mode 100644 index 000000000..4889e5615 --- /dev/null +++ b/src/jest/server/pageContributions/getAndMerge.test.ts @@ -0,0 +1,72 @@ +import {describe, expect, jest, test as it} from '@jest/globals'; + +jest.mock('/lib/enonic/react4xp/asset/executor/getExecutorUrl', () => ({ + getExecutorUrl: () => '/_/service/com.example.myproject/react4xp/executor.js' +})); + +jest.mock('/lib/enonic/react4xp/pageContributions/buildPageContributions', () => ({ + buildPageContributions: ({entries, suppressJS}: {entries: string[], suppressJS: boolean}) => ({ + headEnd: suppressJS ? [] : entries.map(entry => `\n`) + }) +})); + +import {getAndMerge} from '/lib/enonic/react4xp/pageContributions/getAndMerge'; + +const EXECUTOR = '\n'; + +describe('getAndMerge', () => { + it('adds the executor last when JS is not suppressed', () => { + const result = getAndMerge({ + entryNames: 'Header', + incomingPgContrib: {}, + newPgContrib: {bodyEnd: ['']}, + suppressJS: false + }); + expect(result.bodyEnd).toEqual(['', EXECUTOR]); + }); + + it('does not add the executor when JS is suppressed and no previous rendering needed it', () => { + const result = getAndMerge({ + entryNames: 'Footer', + incomingPgContrib: {}, + newPgContrib: {}, + suppressJS: true + }); + expect(result.bodyEnd).toEqual([]); + }); + + it('keeps the executor last when a previous rendering needed it and the current one suppresses JS', () => { + const header = getAndMerge({ + entryNames: 'Header', + incomingPgContrib: {}, + newPgContrib: {}, + suppressJS: false + }); + expect(header.bodyEnd).toEqual([EXECUTOR]); + + const footer = getAndMerge({ + entryNames: 'Footer', + incomingPgContrib: header, + newPgContrib: {bodyEnd: ['']}, + suppressJS: true + }); + expect(footer.headEnd).toEqual(['\n']); + expect(footer.bodyEnd).toEqual(['', EXECUTOR]); + }); + + it('does not duplicate the executor when chaining two renderings that both need it', () => { + const header = getAndMerge({ + entryNames: 'Header', + incomingPgContrib: {}, + newPgContrib: {}, + suppressJS: false + }); + const footer = getAndMerge({ + entryNames: 'Footer', + incomingPgContrib: header, + newPgContrib: {}, + suppressJS: false + }); + expect(footer.bodyEnd).toEqual([EXECUTOR]); + }); +}); diff --git a/src/main/resources/lib/enonic/react4xp/pageContributions/getAndMerge.ts b/src/main/resources/lib/enonic/react4xp/pageContributions/getAndMerge.ts index 41bee8c64..fefa10517 100644 --- a/src/main/resources/lib/enonic/react4xp/pageContributions/getAndMerge.ts +++ b/src/main/resources/lib/enonic/react4xp/pageContributions/getAndMerge.ts @@ -60,6 +60,8 @@ export function getAndMerge({ const executorEntry = `\n`; + const keepExecutor = !suppressJS || (incomingPgContrib.bodyEnd || []).indexOf(executorEntry) !== -1; + // Keeps track of already-added entries across headBegin, headEnd, bodyBegin and bodyEnd const controlSet = [ executorEntry // Skip until manually added, must be last... @@ -97,6 +99,6 @@ export function getAndMerge({ newPgContrib.bodyEnd ], controlSet - ).concat(suppressJS ? [] : executorEntry) // Manually added last :) + ).concat(keepExecutor ? executorEntry : []) // Manually added last :) }; }