From e908378573ca50b2fc2b91728eeb98e59ff2d7e9 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 8 Jul 2024 19:31:43 +0100 Subject: [PATCH 1/9] feat: Add full-page navigation e2e test Add a new e2e test for full-page navigation. The test ensures that the `` element is preserved during navigation between pages. --- .../full-page-navigation.spec.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 test/e2e/specs/interactivity/full-page-navigation.spec.ts diff --git a/test/e2e/specs/interactivity/full-page-navigation.spec.ts b/test/e2e/specs/interactivity/full-page-navigation.spec.ts new file mode 100644 index 00000000000000..be2c6c771e47ac --- /dev/null +++ b/test/e2e/specs/interactivity/full-page-navigation.spec.ts @@ -0,0 +1,65 @@ +/** + * Internal dependencies + */ +import { test, expect } from './fixtures'; + +test.describe( 'Full-page navigation', () => { + let post1link: string; + test.beforeAll( async ( { requestUtils, interactivityUtils } ) => { + await requestUtils.setGutenbergExperiments( [ + 'gutenberg-full-page-client-side-navigation', + ] ); + + await interactivityUtils.activatePlugins(); + + // We create the second page first because the first page will link to it. + const { link: page2link } = await requestUtils.createPost( { + content: `

Page 2

`, + status: 'publish', + date_gmt: '2023-01-01T00:00:00', + title: 'World', + } ); + + const { link } = await requestUtils.createPost( { + content: ` +

Page 1

+

Page 2 link

+`, + status: 'publish', + date_gmt: '2023-01-01T00:00:00', + title: 'Hello', + } ); + post1link = link; + } ); + + test.afterAll( async ( { interactivityUtils: utils } ) => { + await utils.deactivatePlugins(); + await utils.deleteAllPosts(); + } ); + + test( 'The element is presered during navigation', async ( { + page, + } ) => { + await page.goto( post1link ); + + // Get a reference to the element before navigation + const initialHeadHandle = await page.evaluateHandle( + () => document.head + ); + + // Navigate to page 2 + await page.getByTestId( 'page-2-link' ).click(); + await page.waitForLoadState( 'load' ); + + // Get a reference to the element after navigation + const newHeadHandle = await page.evaluateHandle( () => document.head ); + + // Compare the two references in the browser context + const isSameHead = await page.evaluate( + ( [ initialHead, newHead ] ) => initialHead === newHead, + [ initialHeadHandle, newHeadHandle ] + ); + + expect( isSameHead, 'The should be the same' ).toBe( true ); + } ); +} ); From 0ed635175d1efb3b765ba6db3bff9c1eadc29b64 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 29 Jul 2024 18:55:13 +0100 Subject: [PATCH 2/9] fix: Add initial data population in interactivity router --- packages/interactivity-router/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/interactivity-router/src/index.ts b/packages/interactivity-router/src/index.ts index 79b67eeb98e656..32a823233bd25d 100644 --- a/packages/interactivity-router/src/index.ts +++ b/packages/interactivity-router/src/index.ts @@ -104,6 +104,7 @@ const regionsToVdom: RegionsToVdom = async ( dom, { vdom } = {} ) => { } const title = dom.querySelector( 'title' )?.innerText; const initialData = parseInitialData( dom ); + populateInitialData( initialData ); return { regions, head, title, initialData }; }; From 8eec50f2dd07a62400f8357745205c4b64fb99de Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 1 Aug 2024 17:28:04 +0100 Subject: [PATCH 3/9] Revert "fix: Add initial data population in interactivity router" This reverts commit 0ed635175d1efb3b765ba6db3bff9c1eadc29b64. --- packages/interactivity-router/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/interactivity-router/src/index.ts b/packages/interactivity-router/src/index.ts index 32a823233bd25d..79b67eeb98e656 100644 --- a/packages/interactivity-router/src/index.ts +++ b/packages/interactivity-router/src/index.ts @@ -104,7 +104,6 @@ const regionsToVdom: RegionsToVdom = async ( dom, { vdom } = {} ) => { } const title = dom.querySelector( 'title' )?.innerText; const initialData = parseInitialData( dom ); - populateInitialData( initialData ); return { regions, head, title, initialData }; }; From e4120e66551fdf2918fd34d2c7255f9fccca483a Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 1 Aug 2024 18:09:15 +0100 Subject: [PATCH 4/9] chore: Update element.innerText to element.textContent in head.ts file --- packages/interactivity-router/src/head.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/interactivity-router/src/head.ts b/packages/interactivity-router/src/head.ts index 2bde7cea520404..052da365cdcc35 100644 --- a/packages/interactivity-router/src/head.ts +++ b/packages/interactivity-router/src/head.ts @@ -87,7 +87,8 @@ export const fetchHeadAssets = async ( const headElement = headElements.get( attributeValue ); const element = doc.createElement( tagName ); - element.innerText = headElement.text; + element.textContent = headElement.text; + for ( const attr of headElement.tag.attributes ) { element.setAttribute( attr.name, attr.value ); } From 1de41fbb88c0ab4bb827ce53fb9f431e7944a17d Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 1 Aug 2024 18:09:56 +0100 Subject: [PATCH 5/9] feat: Exclude src and href attributes when copying head element attributes --- packages/interactivity-router/src/head.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/interactivity-router/src/head.ts b/packages/interactivity-router/src/head.ts index 052da365cdcc35..f2177157fd712e 100644 --- a/packages/interactivity-router/src/head.ts +++ b/packages/interactivity-router/src/head.ts @@ -90,7 +90,10 @@ export const fetchHeadAssets = async ( element.textContent = headElement.text; for ( const attr of headElement.tag.attributes ) { - element.setAttribute( attr.name, attr.value ); + // don't copy the src or href attribute + if ( attr.name !== 'src' && attr.name !== 'href' ) { + element.setAttribute( attr.name, attr.value ); + } } headTags.push( element ); } ) From 13c7a7a59da3b2123d3b56863628576479b47260 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 1 Aug 2024 18:10:25 +0100 Subject: [PATCH 6/9] chore: Populate initial data in interactivity router --- packages/interactivity-router/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/interactivity-router/src/index.ts b/packages/interactivity-router/src/index.ts index 79b67eeb98e656..c2dfb6ef23f875 100644 --- a/packages/interactivity-router/src/index.ts +++ b/packages/interactivity-router/src/index.ts @@ -111,6 +111,7 @@ const regionsToVdom: RegionsToVdom = async ( dom, { vdom } = {} ) => { const renderRegions = ( page: Page ) => { batch( () => { if ( globalThis.IS_GUTENBERG_PLUGIN ) { + populateInitialData( page.initialData ); if ( navigationMode === 'fullPage' ) { // Once this code is tested and more mature, the head should be updated for region based navigation as well. updateHead( page.head ); From e38040a25ad1bff0f1e0defc292ccfbfffb63771 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 1 Aug 2024 18:10:59 +0100 Subject: [PATCH 7/9] chore: Move Populate initial data in interactivity router --- packages/interactivity-router/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/interactivity-router/src/index.ts b/packages/interactivity-router/src/index.ts index c2dfb6ef23f875..851f4ac2bfb050 100644 --- a/packages/interactivity-router/src/index.ts +++ b/packages/interactivity-router/src/index.ts @@ -110,8 +110,8 @@ const regionsToVdom: RegionsToVdom = async ( dom, { vdom } = {} ) => { // Render all interactive regions contained in the given page. const renderRegions = ( page: Page ) => { batch( () => { + populateInitialData( page.initialData ); if ( globalThis.IS_GUTENBERG_PLUGIN ) { - populateInitialData( page.initialData ); if ( navigationMode === 'fullPage' ) { // Once this code is tested and more mature, the head should be updated for region based navigation as well. updateHead( page.head ); @@ -120,7 +120,6 @@ const renderRegions = ( page: Page ) => { } } if ( navigationMode === 'regionBased' ) { - populateInitialData( page.initialData ); const attrName = `data-${ directivePrefix }-router-region`; document .querySelectorAll( `[${ attrName }]` ) From 6fcdee4939c282228165df1dcc8468fd14db079b Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 1 Aug 2024 18:35:02 +0100 Subject: [PATCH 8/9] Wait for `load` event of script element before returning from `fetchHeadAssets()` function --- packages/interactivity-router/src/head.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/interactivity-router/src/head.ts b/packages/interactivity-router/src/head.ts index f2177157fd712e..f1e2601fafec44 100644 --- a/packages/interactivity-router/src/head.ts +++ b/packages/interactivity-router/src/head.ts @@ -95,7 +95,14 @@ export const fetchHeadAssets = async ( element.setAttribute( attr.name, attr.value ); } } + headTags.push( element ); + + // wait for the `load` event to fire before appending the element + return new Promise( ( resolve, reject ) => { + element.onload = resolve; + element.onerror = reject; + } ); } ) ); } From c531afd176f89b618dd4ccc15af20f86de22382f Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 24 Sep 2024 09:46:25 +0100 Subject: [PATCH 9/9] Revert updates to interactivity router --- packages/interactivity-router/src/head.ts | 15 ++------------- packages/interactivity-router/src/index.ts | 1 - 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/packages/interactivity-router/src/head.ts b/packages/interactivity-router/src/head.ts index f1e2601fafec44..2bde7cea520404 100644 --- a/packages/interactivity-router/src/head.ts +++ b/packages/interactivity-router/src/head.ts @@ -87,22 +87,11 @@ export const fetchHeadAssets = async ( const headElement = headElements.get( attributeValue ); const element = doc.createElement( tagName ); - element.textContent = headElement.text; - + element.innerText = headElement.text; for ( const attr of headElement.tag.attributes ) { - // don't copy the src or href attribute - if ( attr.name !== 'src' && attr.name !== 'href' ) { - element.setAttribute( attr.name, attr.value ); - } + element.setAttribute( attr.name, attr.value ); } - headTags.push( element ); - - // wait for the `load` event to fire before appending the element - return new Promise( ( resolve, reject ) => { - element.onload = resolve; - element.onerror = reject; - } ); } ) ); } diff --git a/packages/interactivity-router/src/index.ts b/packages/interactivity-router/src/index.ts index 9e3c6d62839c84..3bd44c7aebd71f 100644 --- a/packages/interactivity-router/src/index.ts +++ b/packages/interactivity-router/src/index.ts @@ -110,7 +110,6 @@ const regionsToVdom: RegionsToVdom = async ( dom, { vdom } = {} ) => { // Render all interactive regions contained in the given page. const renderRegions = ( page: Page ) => { batch( () => { - populateInitialData( page.initialData ); if ( globalThis.IS_GUTENBERG_PLUGIN ) { if ( navigationMode === 'fullPage' ) { // Once this code is tested and more mature, the head should be updated for region based navigation as well.