diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/assets/10x10_e2e_test_image_blue.png b/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/assets/10x10_e2e_test_image_blue.png deleted file mode 100644 index c4f8e7c5146d36..00000000000000 Binary files a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/assets/10x10_e2e_test_image_blue.png and /dev/null differ diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/block.json b/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/block.json deleted file mode 100644 index 644ea70f74dca1..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/block.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "test/router-styles-blue", - "title": "E2E Interactivity tests - router styles - Blue", - "category": "text", - "icon": "heart", - "description": "", - "supports": { - "interactivity": true - }, - "textdomain": "e2e-interactivity", - "viewStyle": "file:./style.css", - "render": "file:./render.php" -} diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/render.php b/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/render.php deleted file mode 100644 index 3f5da308db092a..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/render.php +++ /dev/null @@ -1,35 +0,0 @@ - 'blue-block' ) -); -?> -

>Blue

diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/style-from-link.css b/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/style-from-link.css deleted file mode 100644 index f55f12f4d594cf..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/style-from-link.css +++ /dev/null @@ -1,7 +0,0 @@ -.blue-from-link { - color: rgb(0, 0, 255); -} - -.background-from-link { - background-image: url('./assets/10x10_e2e_test_image_blue.png'); -} \ No newline at end of file diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/style.css b/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/style.css deleted file mode 100644 index 84d891e90242a5..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-blue/style.css +++ /dev/null @@ -1,4 +0,0 @@ -.wp-block-test-router-styles-blue, -.blue { - color: rgb(0, 0, 255); -} \ No newline at end of file diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/assets/10x10_e2e_test_image_green.png b/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/assets/10x10_e2e_test_image_green.png deleted file mode 100644 index 34ec87925d8c50..00000000000000 Binary files a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/assets/10x10_e2e_test_image_green.png and /dev/null differ diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/block.json b/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/block.json deleted file mode 100644 index e2edda625571b9..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/block.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "test/router-styles-green", - "title": "E2E Interactivity tests - router styles - Green", - "category": "text", - "icon": "heart", - "description": "", - "supports": { - "interactivity": true - }, - "textdomain": "e2e-interactivity", - "viewStyle": "file:./style.css", - "render": "file:./render.php" -} diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/render.php b/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/render.php deleted file mode 100644 index 4418a2d3ab0f3d..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/render.php +++ /dev/null @@ -1,35 +0,0 @@ - 'green-block' ) -); -?> -

>Green

diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/style-from-link.css b/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/style-from-link.css deleted file mode 100644 index b3d7d7b111e52a..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/style-from-link.css +++ /dev/null @@ -1,7 +0,0 @@ -.green-from-link { - color: rgb(0, 255, 0); -} - -.background-from-link { - background-image: url('./assets/10x10_e2e_test_image_green.png'); -} \ No newline at end of file diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/style.css b/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/style.css deleted file mode 100644 index 0c457588f625cb..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-green/style.css +++ /dev/null @@ -1,4 +0,0 @@ -.wp-block-test-router-styles-green, -.green { - color: rgb(0, 255, 0); -} \ No newline at end of file diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/assets/10x10_e2e_test_image_red.png b/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/assets/10x10_e2e_test_image_red.png deleted file mode 100644 index 3264bf6427c276..00000000000000 Binary files a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/assets/10x10_e2e_test_image_red.png and /dev/null differ diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/block.json b/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/block.json deleted file mode 100644 index 582d7019062c6e..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/block.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "test/router-styles-red", - "title": "E2E Interactivity tests - router styles - Red", - "category": "text", - "icon": "heart", - "description": "", - "supports": { - "interactivity": true - }, - "textdomain": "e2e-interactivity", - "viewStyle": "file:./style.css", - "render": "file:./render.php" -} diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/render.php b/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/render.php deleted file mode 100644 index e8474cf69b825a..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/render.php +++ /dev/null @@ -1,35 +0,0 @@ - 'red-block' ) -); -?> -

>Red

diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/style-from-link.css b/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/style-from-link.css deleted file mode 100644 index 0f7d6228079897..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/style-from-link.css +++ /dev/null @@ -1,7 +0,0 @@ -.red-from-link { - color: rgb(255, 0, 0); -} - -.background-from-link { - background-image: url('./assets/10x10_e2e_test_image_red.png'); -} \ No newline at end of file diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/style.css b/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/style.css deleted file mode 100644 index eac7e3af16e0b5..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-red/style.css +++ /dev/null @@ -1,4 +0,0 @@ -.wp-block-test-router-styles-red, -.red { - color: rgb(255, 0, 0); -} \ No newline at end of file diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/block.json b/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/block.json deleted file mode 100644 index a1a95b4c81e3b6..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/block.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "test/router-styles-wrapper", - "title": "E2E Interactivity tests - router styles - Wrapper", - "category": "text", - "icon": "heart", - "description": "", - "supports": { - "interactivity": true - }, - "textdomain": "e2e-interactivity", - "viewScriptModule": "file:./view.js", - "viewStyle": "file:./style.css", - "render": "file:./render.php" -} diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/render.php b/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/render.php deleted file mode 100644 index 6373e8e9bc235b..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/render.php +++ /dev/null @@ -1,70 +0,0 @@ - -
> - -
- Styles from block styles -

Red

-

Green

-

Blue

-

All

-
- - -
- Styles from referenced style sheets - - - - - -
- - -
- Styles from inline styles -

Red

-

Green

-

Blue

-

All

-
- - - - - -
- -
- - -
- Client-side navigation -
-
diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/style.css b/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/style.css deleted file mode 100644 index 12773560c4180f..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/style.css +++ /dev/null @@ -1,3 +0,0 @@ -.wp-block-test-router-styles-wrapper { - color: rgb(160, 12, 60); -} \ No newline at end of file diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/view.asset.php b/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/view.asset.php deleted file mode 100644 index bdaec8d1b67a9d..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/view.asset.php +++ /dev/null @@ -1,9 +0,0 @@ - array( - '@wordpress/interactivity', - array( - 'id' => '@wordpress/interactivity-router', - 'import' => 'dynamic', - ), - ), -); diff --git a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/view.js b/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/view.js deleted file mode 100644 index 5b3b42f2b413e4..00000000000000 --- a/packages/e2e-tests/plugins/interactive-blocks/router-styles-wrapper/view.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * WordPress dependencies - */ -import { store } from '@wordpress/interactivity'; - -const { state } = store( 'test/router-styles', { - state: { - clientSideNavigation: false, - }, - actions: { - *navigate( e ) { - e.preventDefault(); - const { actions } = yield import( - '@wordpress/interactivity-router' - ); - yield actions.navigate( e.target.href ); - state.clientSideNavigation = true; - }, - }, -} ); diff --git a/packages/interactivity-router/src/assets/styles.ts b/packages/interactivity-router/src/assets/styles.ts deleted file mode 100644 index ddb41eabc7a758..00000000000000 --- a/packages/interactivity-router/src/assets/styles.ts +++ /dev/null @@ -1,79 +0,0 @@ -const cssUrlRegEx = - /url\(\s*(?:(["'])((?:\\.|[^\n\\"'])+)\1|((?:\\.|[^\s,"'()\\])+))\s*\)/g; - -const resolveUrl = ( relativeUrl: string, baseUrl: string ) => { - try { - return new URL( relativeUrl, baseUrl ).toString(); - } catch ( e ) { - return relativeUrl; - } -}; - -const withAbsoluteUrls = ( cssText: string, baseUrl: string ) => - cssText.replace( - cssUrlRegEx, - ( _match, quotes = '', relUrl1, relUrl2 ) => - `url(${ quotes }${ resolveUrl( - relUrl1 || relUrl2, - baseUrl - ) }${ quotes })` - ); - -const styleSheetCache = new Map< string, Promise< CSSStyleSheet > >(); - -const getCachedSheet = async ( - sheetId: string, - factory: () => Promise< CSSStyleSheet > -) => { - if ( ! styleSheetCache.has( sheetId ) ) { - styleSheetCache.set( sheetId, factory() ); - } - return styleSheetCache.get( sheetId ); -}; - -const sheetFromLink = async ( - { id, href, sheet: elementSheet }: HTMLLinkElement, - baseUrl: string -) => { - const sheetId = id || href; - const sheetUrl = resolveUrl( href, baseUrl ); - - if ( elementSheet ) { - return getCachedSheet( sheetId, () => { - const sheet = new CSSStyleSheet(); - for ( const { cssText } of elementSheet.cssRules ) { - sheet.insertRule( withAbsoluteUrls( cssText, sheetUrl ) ); - } - return Promise.resolve( sheet ); - } ); - } - return getCachedSheet( sheetId, async () => { - const response = await fetch( href ); - const text = await response.text(); - const sheet = new CSSStyleSheet(); - await sheet.replace( withAbsoluteUrls( text, sheetUrl ) ); - return sheet; - } ); -}; - -const sheetFromStyle = async ( { textContent }: HTMLStyleElement ) => { - const sheetId = textContent; - return getCachedSheet( sheetId, async () => { - const sheet = new CSSStyleSheet(); - await sheet.replace( textContent ); - return sheet; - } ); -}; - -export const generateCSSStyleSheets = ( - doc: Document, - baseUrl: string = ( doc.location || window.location ).href -): Promise< CSSStyleSheet >[] => - [ ...doc.querySelectorAll( 'style,link[rel=stylesheet]' ) ].map( - ( element ) => { - if ( 'LINK' === element.nodeName ) { - return sheetFromLink( element as HTMLLinkElement, baseUrl ); - } - return sheetFromStyle( element as HTMLStyleElement ); - } - ); diff --git a/packages/interactivity-router/src/head.ts b/packages/interactivity-router/src/head.ts new file mode 100644 index 00000000000000..69139348b582ff --- /dev/null +++ b/packages/interactivity-router/src/head.ts @@ -0,0 +1,126 @@ +/** + * The cache of prefetched stylesheets and scripts. + */ +export const headElements = new Map< + string, + { tag: HTMLElement; text?: string } +>(); + +/** + * Helper to update only the necessary tags in the head. + * + * @async + * @param newHead The head elements of the new page. + */ +export const updateHead = async ( newHead: HTMLHeadElement[] ) => { + // Helper to get the tag id store in the cache. + const getTagId = ( tag: Element ) => tag.id || tag.outerHTML; + + // Map incoming head tags by their content. + const newHeadMap = new Map< string, Element >(); + for ( const child of newHead ) { + newHeadMap.set( getTagId( child ), child ); + } + + const toRemove: Element[] = []; + + // Detect nodes that should be added or removed. + for ( const child of document.head.children ) { + const id = getTagId( child ); + // Always remove styles and links as they might change. + if ( child.nodeName === 'LINK' || child.nodeName === 'STYLE' ) { + toRemove.push( child ); + } else if ( newHeadMap.has( id ) ) { + newHeadMap.delete( id ); + } else if ( child.nodeName !== 'SCRIPT' && child.nodeName !== 'META' ) { + toRemove.push( child ); + } + } + + await Promise.all( + [ ...headElements.entries() ] + .filter( ( [ , { tag } ] ) => tag.nodeName === 'SCRIPT' ) + .map( async ( [ url ] ) => { + await import( /* webpackIgnore: true */ url ); + } ) + ); + + // Prepare new assets. + const toAppend = [ ...newHeadMap.values() ]; + + // Apply the changes. + toRemove.forEach( ( n ) => n.remove() ); + document.head.append( ...toAppend ); +}; + +/** + * Fetches and processes head assets (stylesheets and scripts) from a specified document. + * + * @async + * @param doc The document from which to fetch head assets. It should support standard DOM querying methods. + * + * @return Returns an array of HTML elements representing the head assets. + */ +export const fetchHeadAssets = async ( + doc: Document +): Promise< HTMLElement[] > => { + const headTags = []; + + // We only want to fetch module scripts because regular scripts (without + // `async` or `defer` attributes) can depend on the execution of other scripts. + // Scripts found in the head are blocking and must be executed in order. + const scripts = doc.querySelectorAll< HTMLScriptElement >( + 'script[type="module"][src]' + ); + + scripts.forEach( ( script ) => { + const src = script.getAttribute( 'src' ); + if ( ! headElements.has( src ) ) { + // add the elements to prefetch the module scripts + const link = doc.createElement( 'link' ); + link.rel = 'modulepreload'; + link.href = src; + document.head.append( link ); + headElements.set( src, { tag: script } ); + } + } ); + + const stylesheets = doc.querySelectorAll< HTMLLinkElement >( + 'link[rel=stylesheet]' + ); + + await Promise.all( + Array.from( stylesheets ).map( async ( tag ) => { + const href = tag.getAttribute( 'href' ); + if ( ! href ) { + return; + } + + if ( ! headElements.has( href ) ) { + try { + const response = await fetch( href ); + const text = await response.text(); + headElements.set( href, { + tag, + text, + } ); + } catch ( e ) { + // eslint-disable-next-line no-console + console.error( e ); + } + } + + const headElement = headElements.get( href ); + const styleElement = doc.createElement( 'style' ); + styleElement.textContent = headElement.text; + + headTags.push( styleElement ); + } ) + ); + + return [ + doc.querySelector( 'title' ), + ...doc.querySelectorAll( 'style' ), + ...headTags, + ]; +}; diff --git a/packages/interactivity-router/src/index.ts b/packages/interactivity-router/src/index.ts index c128ac8a962de2..d23a1e644f5be6 100644 --- a/packages/interactivity-router/src/index.ts +++ b/packages/interactivity-router/src/index.ts @@ -6,7 +6,7 @@ import { store, privateApis, getConfig } from '@wordpress/interactivity'; /** * Internal dependencies */ -import { generateCSSStyleSheets } from './assets/styles'; +import { fetchHeadAssets, updateHead, headElements } from './head'; const { directivePrefix, @@ -37,18 +37,16 @@ interface PrefetchOptions { interface VdomParams { vdom?: typeof initialVdom; - baseUrl?: string; } interface Page { regions: Record< string, any >; - styles: Promise< CSSStyleSheet >[]; - scriptModules: string[]; + head: HTMLHeadElement[]; title: string; initialData: any; } -type RegionsToVdom = ( dom: Document, params?: VdomParams ) => Page; +type RegionsToVdom = ( dom: Document, params?: VdomParams ) => Promise< Page >; // Check if the navigation mode is full page or region based. const navigationMode: 'regionBased' | 'fullPage' = @@ -75,7 +73,7 @@ const fetchPage = async ( url: string, { html }: { html: string } ) => { html = await res.text(); } const dom = new window.DOMParser().parseFromString( html, 'text/html' ); - return regionsToVdom( dom, { baseUrl: url } ); + return regionsToVdom( dom ); } catch ( e ) { return false; } @@ -83,17 +81,12 @@ const fetchPage = async ( url: string, { html }: { html: string } ) => { // Return an object with VDOM trees of those HTML regions marked with a // `router-region` directive. -const regionsToVdom: RegionsToVdom = ( dom, { vdom, baseUrl } = {} ) => { +const regionsToVdom: RegionsToVdom = async ( dom, { vdom } = {} ) => { const regions = { body: undefined }; - const styles = generateCSSStyleSheets( dom, baseUrl ); - const scriptModules = [ - ...dom.querySelectorAll< HTMLScriptElement >( - 'script[type=module][src]' - ), - ].map( ( s ) => s.src ); - + let head: HTMLElement[]; if ( globalThis.IS_GUTENBERG_PLUGIN ) { if ( navigationMode === 'fullPage' ) { + head = await fetchHeadAssets( dom ); regions.body = vdom ? vdom.get( document.body ) : toVdom( dom.body ); @@ -110,28 +103,15 @@ const regionsToVdom: RegionsToVdom = ( dom, { vdom, baseUrl } = {} ) => { } const title = dom.querySelector( 'title' )?.innerText; const initialData = parseServerData( dom ); - return { regions, styles, scriptModules, title, initialData }; + return { regions, head, title, initialData }; }; // Render all interactive regions contained in the given page. const renderRegions = async ( page: Page ) => { - // Wait for styles and modules to be ready. - await Promise.all( [ - ...page.styles, - ...page.scriptModules.map( - ( src ) => import( /* webpackIgnore: true */ src ) - ), - ] ); - // Replace style sheets. - const sheets = await Promise.all( page.styles ); - window.document - .querySelectorAll( 'style,link[rel=stylesheet]' ) - .forEach( ( element ) => element.remove() ); - window.document.adoptedStyleSheets = sheets; - if ( globalThis.IS_GUTENBERG_PLUGIN ) { if ( navigationMode === 'fullPage' ) { - // Update HTML. + // Once this code is tested and more mature, the head should be updated for region based navigation as well. + await updateHead( page.head ); const fragment = getRegionRootFragment( document.body ); batch( () => { populateServerData( page.initialData ); @@ -189,14 +169,23 @@ window.addEventListener( 'popstate', async () => { // Initialize the router and cache the initial page using the initial vDOM. // Once this code is tested and more mature, the head should be updated for // region based navigation as well. +if ( globalThis.IS_GUTENBERG_PLUGIN ) { + if ( navigationMode === 'fullPage' ) { + // Cache the scripts. Has to be called before fetching the assets. + [].map.call( + document.querySelectorAll( 'script[type="module"][src]' ), + ( script ) => { + headElements.set( script.getAttribute( 'src' ), { + tag: script, + } ); + } + ); + await fetchHeadAssets( document ); + } +} pages.set( getPagePath( window.location.href ), - Promise.resolve( - regionsToVdom( document, { - vdom: initialVdom, - baseUrl: window.location.href, - } ) - ) + Promise.resolve( regionsToVdom( document, { vdom: initialVdom } ) ) ); // Check if the link is valid for client-side navigation. diff --git a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-1-chromium.png b/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-1-chromium.png deleted file mode 100644 index 4bc0f7a6b1dd70..00000000000000 Binary files a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-1-chromium.png and /dev/null differ diff --git a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-2-chromium.png b/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-2-chromium.png deleted file mode 100644 index 7339cccdb78f28..00000000000000 Binary files a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-2-chromium.png and /dev/null differ diff --git a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-3-chromium.png b/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-3-chromium.png deleted file mode 100644 index 97943030eb1e88..00000000000000 Binary files a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-3-chromium.png and /dev/null differ diff --git a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-4-chromium.png b/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-4-chromium.png deleted file mode 100644 index b7c455784e8a42..00000000000000 Binary files a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-4-chromium.png and /dev/null differ diff --git a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-5-chromium.png b/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-5-chromium.png deleted file mode 100644 index b7c455784e8a42..00000000000000 Binary files a/test/e2e/specs/interactivity/__snapshots__/Router-styles-should-support-relative-URLs-in-referenced-style-sheets-5-chromium.png and /dev/null differ diff --git a/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts b/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts index 74436673f10b79..fd850a6e39fae2 100644 --- a/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts +++ b/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts @@ -6,30 +6,6 @@ import type { RequestUtils } from '@wordpress/e2e-test-utils-playwright'; type AddPostWithBlockOptions = { alias?: string; attributes?: Record< string, any >; - innerBlocks?: Block[]; -}; - -type Block = [ - type: string, - attributes?: Record< string, any >, - innerBlocks?: Block[], -]; - -const generateBlockMarkup = ( [ - type, - attributes, - innerBlocks, -]: Block ): string => { - const typeAndAttributes = attributes - ? `${ type } ${ JSON.stringify( attributes ) }` - : type; - - if ( ! innerBlocks ) { - return ``; - } - return `${ innerBlocks - .map( generateBlockMarkup ) - .join( '' ) }`; }; export default class InteractivityUtils { @@ -64,7 +40,7 @@ export default class InteractivityUtils { async addPostWithBlock( name: string, - { attributes, alias, innerBlocks }: AddPostWithBlockOptions = {} + { attributes, alias }: AddPostWithBlockOptions = {} ) { const block = attributes ? `${ name } ${ JSON.stringify( attributes ) }` @@ -74,14 +50,8 @@ export default class InteractivityUtils { alias = block; } - const content = generateBlockMarkup( [ - name, - attributes, - innerBlocks, - ] ); - const payload = { - content, + content: ``, status: 'publish' as 'publish', date_gmt: '2023-01-01T00:00:00', title: alias, diff --git a/test/e2e/specs/interactivity/router-styles.spec.ts b/test/e2e/specs/interactivity/router-styles.spec.ts deleted file mode 100644 index 7bc575af37816c..00000000000000 --- a/test/e2e/specs/interactivity/router-styles.spec.ts +++ /dev/null @@ -1,232 +0,0 @@ -/** - * Internal dependencies - */ -import { test, expect } from './fixtures'; - -const COLOR_RED = 'rgb(255, 0, 0)'; -const COLOR_GREEN = 'rgb(0, 255, 0)'; -const COLOR_BLUE = 'rgb(0, 0, 255)'; -const COLOR_WRAPPER = 'rgb(160, 12, 60)'; - -test.describe( 'Router styles', () => { - test.beforeAll( async ( { interactivityUtils: utils } ) => { - await utils.activatePlugins(); - const red = await utils.addPostWithBlock( - 'test/router-styles-wrapper', - { - alias: 'red', - innerBlocks: [ [ 'test/router-styles-red' ] ], - } - ); - const green = await utils.addPostWithBlock( - 'test/router-styles-wrapper', - { - alias: 'green', - innerBlocks: [ [ 'test/router-styles-green' ] ], - } - ); - const blue = await utils.addPostWithBlock( - 'test/router-styles-wrapper', - { - alias: 'blue', - innerBlocks: [ [ 'test/router-styles-blue' ] ], - } - ); - - const all = await utils.addPostWithBlock( - 'test/router-styles-wrapper', - { - alias: 'all', - innerBlocks: [ - [ 'test/router-styles-red' ], - [ 'test/router-styles-green' ], - [ 'test/router-styles-blue' ], - ], - } - ); - - await utils.addPostWithBlock( 'test/router-styles-wrapper', { - alias: 'none', - attributes: { links: { red, green, blue, all } }, - } ); - } ); - - test.beforeEach( async ( { page, interactivityUtils: utils } ) => { - await page.goto( utils.getLink( 'none' ) ); - } ); - - test.afterAll( async ( { interactivityUtils: utils } ) => { - await utils.deactivatePlugins(); - await utils.deleteAllPosts(); - } ); - - test( 'should add and remove styles from style tags', async ( { - page, - } ) => { - const csn = page.getByTestId( 'client-side navigation' ); - const red = page.getByTestId( 'red' ); - const green = page.getByTestId( 'green' ); - const blue = page.getByTestId( 'blue' ); - const all = page.getByTestId( 'all' ); - - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_WRAPPER ); - - await page.getByTestId( 'link red' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_RED ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_RED ); - - await page.getByTestId( 'link green' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_GREEN ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_GREEN ); - - await page.getByTestId( 'link blue' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_BLUE ); - await expect( all ).toHaveCSS( 'color', COLOR_BLUE ); - - await page.getByTestId( 'link all' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_RED ); - await expect( green ).toHaveCSS( 'color', COLOR_GREEN ); - await expect( blue ).toHaveCSS( 'color', COLOR_BLUE ); - await expect( all ).toHaveCSS( 'color', COLOR_BLUE ); - } ); - - test( 'should add and remove styles from referenced style sheets', async ( { - page, - } ) => { - const csn = page.getByTestId( 'client-side navigation' ); - const red = page.getByTestId( 'red-from-link' ); - const green = page.getByTestId( 'green-from-link' ); - const blue = page.getByTestId( 'blue-from-link' ); - const all = page.getByTestId( 'all-from-link' ); - - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_WRAPPER ); - - await page.getByTestId( 'link red' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_RED ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_RED ); - - await page.getByTestId( 'link green' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_GREEN ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_GREEN ); - - await page.getByTestId( 'link blue' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_BLUE ); - await expect( all ).toHaveCSS( 'color', COLOR_BLUE ); - - await page.getByTestId( 'link all' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_RED ); - await expect( green ).toHaveCSS( 'color', COLOR_GREEN ); - await expect( blue ).toHaveCSS( 'color', COLOR_BLUE ); - await expect( all ).toHaveCSS( 'color', COLOR_BLUE ); - } ); - - test( 'should support relative URLs in referenced style sheets', async ( { - page, - } ) => { - const csn = page.getByTestId( 'client-side navigation' ); - const background = page.getByTestId( 'background-from-link' ); - - await expect( background ).toHaveScreenshot(); - - await page.getByTestId( 'link red' ).click(); - - await expect( csn ).toBeVisible(); - await expect( background ).toHaveScreenshot(); - - await page.getByTestId( 'link green' ).click(); - - await expect( csn ).toBeVisible(); - await expect( background ).toHaveScreenshot(); - - await page.getByTestId( 'link blue' ).click(); - - await expect( csn ).toBeVisible(); - await expect( background ).toHaveScreenshot(); - - await page.getByTestId( 'link all' ).click(); - - await expect( csn ).toBeVisible(); - await expect( background ).toHaveScreenshot(); - } ); - - test( 'should update style tags with modified content', async ( { - page, - } ) => { - const csn = page.getByTestId( 'client-side navigation' ); - const red = page.getByTestId( 'red-from-inline' ); - const green = page.getByTestId( 'green-from-inline' ); - const blue = page.getByTestId( 'blue-from-inline' ); - const all = page.getByTestId( 'all-from-inline' ); - - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_WRAPPER ); - - await page.getByTestId( 'link red' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_RED ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_RED ); - - await page.getByTestId( 'link green' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_GREEN ); - await expect( blue ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( all ).toHaveCSS( 'color', COLOR_GREEN ); - - await page.getByTestId( 'link blue' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( green ).toHaveCSS( 'color', COLOR_WRAPPER ); - await expect( blue ).toHaveCSS( 'color', COLOR_BLUE ); - await expect( all ).toHaveCSS( 'color', COLOR_BLUE ); - - await page.getByTestId( 'link all' ).click(); - - await expect( csn ).toBeVisible(); - await expect( red ).toHaveCSS( 'color', COLOR_RED ); - await expect( green ).toHaveCSS( 'color', COLOR_GREEN ); - await expect( blue ).toHaveCSS( 'color', COLOR_BLUE ); - await expect( all ).toHaveCSS( 'color', COLOR_BLUE ); - } ); -} );