-
Notifications
You must be signed in to change notification settings - Fork 67
fix: use only target document to decide if constructable stylesheet i… #3747
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| import { test, expect } from 'e2e/test-utils' | ||
|
|
||
| const TEMPLATE_SLUG = 'stk-e2e-fse-constructable-styles' | ||
| const TEMPLATE_TITLE = 'STK E2E FSE Styles' | ||
| const EDITOR_CRASH = 'The editor has encountered an unexpected error.' | ||
| const STYLESHEET_ERROR = /adoptedStyleSheets|Sharing constructed stylesheets in multiple documents/i | ||
|
|
||
| const TEMPLATE_TEXT_BLOCK = `<!-- wp:stackable/text {"uniqueId":"e2efsecss","hasBackground":true,"blockBackgroundColor":"#1a73e8","textColor1":"#ffffff","text":"FSE template styles","generatedCss":".stk-e2efsecss {background-color:#1a73e8 !important;}.stk-e2efsecss .stk-block-text__text{color:#ffffff !important;}"} --> | ||
| <div class="wp-block-stackable-text stk-block-text stk-block stk-e2efsecss stk-block-background" data-block-id="e2efsecss"><style>.stk-e2efsecss {background-color:#1a73e8 !important;}.stk-e2efsecss .stk-block-text__text{color:#ffffff !important;}</style><p class="stk-block-text__text has-text-color">FSE template styles</p></div> | ||
| <!-- /wp:stackable/text -->` | ||
|
|
||
| const activateBlockTheme = async requestUtils => { | ||
| const themes = await requestUtils.rest( { path: '/wp/v2/themes' } ) | ||
| const active = themes.find( theme => theme.status === 'active' ) | ||
| if ( active?.is_block_theme ) { | ||
| return | ||
| } | ||
|
|
||
| for ( const slug of [ 'twentytwentyfive', 'twentytwentyfour' ] ) { | ||
| try { | ||
| await requestUtils.activateTheme( slug ) | ||
| return | ||
| } catch { | ||
| // Try the next bundled block theme. | ||
| } | ||
| } | ||
|
|
||
| throw new Error( 'Site Editor e2e needs a block theme (Twenty Twenty-Five or Twenty Twenty-Four).' ) | ||
| } | ||
|
|
||
| const templateTitle = template => | ||
| typeof template.title === 'string' ? template.title : template.title?.rendered || template.title?.raw || '' | ||
|
|
||
| const deleteE2eTemplate = async requestUtils => { | ||
| try { | ||
| const templates = await requestUtils.rest( { path: '/wp/v2/templates' } ) | ||
| for ( const template of templates ) { | ||
| if ( ! template.wp_id ) { | ||
| continue | ||
| } | ||
| if ( template.slug !== TEMPLATE_SLUG && templateTitle( template ) !== TEMPLATE_TITLE ) { | ||
| continue | ||
| } | ||
| await requestUtils.rest( { | ||
| method: 'DELETE', | ||
| path: `/wp/v2/templates/${ template.id }`, | ||
| params: { force: true }, | ||
| } ) | ||
| } | ||
| } catch { | ||
| // Playground may already be gone during teardown. | ||
| } | ||
| } | ||
|
|
||
| const templatesSidebar = page => | ||
| page.locator( '.edit-site-layout__sidebar, .edit-site-sidebar-dataviews, .edit-site-sidebar-navigation-screen' ) | ||
|
|
||
| const sidebarItem = ( page, name ) => | ||
| templatesSidebar( page ).getByRole( 'button', { name, exact: true } ) | ||
| .or( templatesSidebar( page ).getByRole( 'link', { name, exact: true } ) ) | ||
| .or( templatesSidebar( page ).getByText( name, { exact: true } ) ) | ||
| .or( page.getByRole( 'button', { name, exact: true } ) ) | ||
| .or( page.getByRole( 'link', { name, exact: true } ) ) | ||
|
|
||
| test.describe( 'Site Editor', () => { | ||
| test.afterEach( async ( { requestUtils } ) => { | ||
| await deleteE2eTemplate( requestUtils ) | ||
| } ) | ||
|
|
||
| test( 'switching to user templates after editing one does not crash the Site Editor', async ( { | ||
| page, | ||
| admin, | ||
| editor, | ||
| requestUtils, | ||
| stackable, | ||
| } ) => { | ||
| test.setTimeout( 120_000 ) | ||
|
|
||
| let stylesheetError = '' | ||
| page.on( 'pageerror', error => { | ||
| if ( STYLESHEET_ERROR.test( error.message ) ) { | ||
| stylesheetError = error.message | ||
| } | ||
| } ) | ||
| page.on( 'console', message => { | ||
| if ( message.type() === 'error' && STYLESHEET_ERROR.test( message.text() ) ) { | ||
| stylesheetError = message.text() | ||
| } | ||
| } ) | ||
|
|
||
| await activateBlockTheme( requestUtils ) | ||
| await deleteE2eTemplate( requestUtils ) | ||
|
|
||
| const author = process.env.WP_USERNAME || 'admin' | ||
| const template = await requestUtils.createTemplate( 'wp_template', { | ||
| slug: TEMPLATE_SLUG, | ||
| title: TEMPLATE_TITLE, | ||
| content: TEMPLATE_TEXT_BLOCK, | ||
| } ) | ||
| expect( template.wp_id ).toBeTruthy() | ||
|
|
||
| await admin.visitAdminPage( 'site-editor.php', '' ) | ||
| await stackable.dismissToursAndNotices() | ||
| await editor.setPreferences( 'core/edit-site', { | ||
| welcomeGuide: false, | ||
| welcomeGuideStyles: false, | ||
| welcomeGuidePage: false, | ||
| welcomeGuideTemplate: false, | ||
| } ) | ||
|
|
||
| const templatesNav = page.getByRole( 'button', { name: 'Templates', exact: true } ) | ||
| .or( page.getByRole( 'link', { name: 'Templates', exact: true } ) ) | ||
| await expect( templatesNav.first() ).toBeVisible( { timeout: 60_000 } ) | ||
| await templatesNav.first().click() | ||
| await expect( page.getByRole( 'button', { name: 'Add Template' } ) ).toBeVisible( { timeout: 30_000 } ) | ||
| await expect( page.getByText( TEMPLATE_TITLE, { exact: true } ).first() ).toBeVisible( { timeout: 30_000 } ) | ||
|
|
||
| await sidebarItem( page, author ).first().click() | ||
| await expect( page.getByText( `Author is: ${ author }` ) ).toBeVisible( { timeout: 30_000 } ) | ||
|
|
||
| await page.getByText( TEMPLATE_TITLE, { exact: true } ).first().click() | ||
| await expect( editor.canvas.getByText( 'FSE template styles' ) ).toBeVisible( { timeout: 30_000 } ) | ||
|
|
||
| const welcome = page.getByRole( 'button', { name: 'Get started' } ) | ||
| if ( await welcome.isVisible().catch( () => false ) ) { | ||
| await welcome.click() | ||
| } | ||
| await page.locator( '.components-modal__screen-overlay' ).waitFor( { state: 'hidden', timeout: 5_000 } ).catch( () => {} ) | ||
|
|
||
| const editorBack = page.locator( '.editor-header__back-button button, .editor-header__back-button a, .editor-header__back-button [role="button"]' ) | ||
| .or( page.getByRole( 'button', { name: 'Back', exact: true } ) ) | ||
| await expect( editorBack.first() ).toBeVisible( { timeout: 15_000 } ) | ||
| await editorBack.first().click() | ||
|
|
||
| await expect( page.getByRole( 'button', { name: 'Add Template' } ) ).toBeVisible( { timeout: 30_000 } ) | ||
|
|
||
| await sidebarItem( page, 'All templates' ).first().click() | ||
| await sidebarItem( page, author ).first().click() | ||
|
|
||
| const crash = page.getByText( EDITOR_CRASH ) | ||
| const deadline = Date.now() + 8_000 | ||
| while ( Date.now() < deadline && ! stylesheetError ) { | ||
| if ( await crash.isVisible().catch( () => false ) ) { | ||
| stylesheetError = EDITOR_CRASH | ||
| break | ||
| } | ||
| await page.waitForTimeout( 200 ) | ||
| } | ||
|
|
||
| expect( | ||
| stylesheetError, | ||
| stylesheetError || 'Site Editor crashed after switching to user templates' | ||
| ).toBe( '' ) | ||
| } ) | ||
| } ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,9 @@ import { useQueryLoopInstanceId } from '~stackable/util' | |
| import { | ||
| useLayoutEffect, useMemo, useRef, | ||
| } from '@wordpress/element' | ||
| import { dispatch, select } from '@wordpress/data' | ||
| import { | ||
| dispatch, select, useSelect, | ||
| } from '@wordpress/data' | ||
| import { useRafEffect } from '~stackable/hooks' | ||
| import CssSaveCompiler from './css-save-compiler' | ||
| import { createStyleDependencyFingerprint } from './util' | ||
|
|
@@ -79,6 +81,18 @@ export const useBlockCssGenerator = props => { | |
| }, [ styleFingerprint, version, blockStyles, setAttributes ] ) | ||
|
|
||
| const styleKey = `${ clientId }-${ instanceId }` | ||
| const editorDom = useSelect( select => { | ||
| return select( 'stackable/editor-dom' )?.getEditorDom() | ||
| } ) | ||
|
|
||
| // Returning null for every block left template-preview iframes without CSS. | ||
| // Use the unified stylesheet only for a current editor document, otherwise | ||
| // return CSS so each preview is styled inside its own document. | ||
| const editorCanvasDocument = document.querySelector( 'iframe[name="editor-canvas"]' )?.contentDocument | ||
| const isCurrentEditorDom = editorDom?.isConnected && ( | ||
| editorDom.ownerDocument === document || | ||
| editorDom.ownerDocument === editorCanvasDocument | ||
| ) | ||
|
Comment on lines
+84
to
+95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate the editor-DOM store implementation and iframe registration paths.
rg -n -C 12 \
'getEditorDom\s*\(|setEditorDom|stackable/editor-dom|RegistryProvider|editor-canvas|contentDocument' \
srcRepository: gambitph/Stackable Length of output: 50374 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- editor-DOM store ---'
cat -n src/plugins/get-editor-dom/index.js | sed -n '1,130p'
cat -n src/plugins/get-editor-dom/store.js | sed -n '1,100p'
printf '%s\n' '--- target-document and stylesheet routing ---'
cat -n src/plugins/editor-block-css/block-style-sheets.js | sed -n '1,220p'
cat -n src/components/block-css/use-block-style-generator.js | sed -n '1,150p'
printf '%s\n' '--- hook callers and preview-related code ---'
rg -n -C 8 'useBlockStyleGenerator|template-preview|preview.*iframe|iframe.*preview|RegistryProvider|createRegistry|createRoot' srcRepository: gambitph/Stackable Length of output: 44184 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- exact hook usage ---'
rg -n -C 10 'useBlockCssGenerator|use-block-style-generator|generatedCss.*editCss|editCss.*generatedCss' src
printf '%s\n' '--- editor CSS plugin registration and mounting ---'
cat -n src/plugins/editor-block-css/index.js | sed -n '1,190p'
rg -n -C 12 'EditorDom|editor-block-css|registerPlugin|BlockEditor|editor-canvas' src/index.js src src/block 2>/dev/null | head -n 400Repository: gambitph/Stackable Length of output: 50375 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- hook output insertion ---'
for file in src/block/count-up/edit.js src/block/button/edit.js src/block/columns/edit.js; do
if [ -f "$file" ]; then
printf '\n--- %s ---\n' "$file"
rg -n -C 12 'blockCss|<style|style=' "$file"
fi
done
printf '%s\n' '--- editor plugin entry points ---'
git ls-files 'src/*' 'src/**/*' | rg '(^|/)(index|editor-block-css|get-editor-dom)(\.[^.]+)?\.js$' | head -n 100
rg -n -C 8 'editor-block-css|<EditorDom|EditorDom\b' src --glob '*.js' | head -n 300Repository: gambitph/Stackable Length of output: 27883 🏁 Script executed: #!/bin/bash
set -euo pipefail
node - <<'JS'
const mainDocument = { name: 'main' }
const previewDocument = { name: 'unnamed-template-preview' }
const editorDom = { isConnected: true, ownerDocument: mainDocument }
const editorCanvasDocument = null
const isCurrentEditorDom = editorDom.isConnected && (
editorDom.ownerDocument === mainDocument ||
editorDom.ownerDocument === editorCanvasDocument
)
console.log(JSON.stringify({
editorDomDocument: editorDom.ownerDocument.name,
renderedDocument: previewDocument.name,
editorCanvasDocument,
isCurrentEditorDom,
localCssReturned: ! isCurrentEditorDom,
}))
JSRepository: gambitph/Stackable Length of output: 310 Scope An unnamed template-preview render can see a connected 🤖 Prompt for AI Agents |
||
|
|
||
| useLayoutEffect( () => { | ||
| dispatch( 'stackable/editor-block-css' ).setBlockCss( styleKey, editCss || '' ) | ||
|
|
@@ -92,7 +106,5 @@ export const useBlockCssGenerator = props => { | |
| } | ||
| }, [ styleKey, editCss, clientId ] ) | ||
|
|
||
| // We used to return the CSS here, but for optimization, now | ||
| // CSS is injected via the unified editor stylesheet plugin. | ||
| return null | ||
| return isCurrentEditorDom ? null : editCss | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: gambitph/Stackable
Length of output: 9017
Wait for the final Author view before checking for the crash.
The second
sidebarItem(...).click()starts the transition, but the test does not wait for a final-view locator. If the transition exceeds eight seconds, the test can pass without checking the completed regression path. Wait forAuthor is: ${ author }or another locator unique to the final Author view.🤖 Prompt for AI Agents
Source: Coding guidelines