Skip to content

Commit 01c8ba2

Browse files
authored
Merge pull request #3747 from gambitph/fix/template-list-crash
fix: use only target document to decide if constructable stylesheet i…
2 parents 5ebf10c + e6dedae commit 01c8ba2

3 files changed

Lines changed: 172 additions & 6 deletions

File tree

e2e/tests/site-editor.spec.ts

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { test, expect } from 'e2e/test-utils'
2+
3+
const TEMPLATE_SLUG = 'stk-e2e-fse-constructable-styles'
4+
const TEMPLATE_TITLE = 'STK E2E FSE Styles'
5+
const EDITOR_CRASH = 'The editor has encountered an unexpected error.'
6+
const STYLESHEET_ERROR = /adoptedStyleSheets|Sharing constructed stylesheets in multiple documents/i
7+
8+
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;}"} -->
9+
<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>
10+
<!-- /wp:stackable/text -->`
11+
12+
const activateBlockTheme = async requestUtils => {
13+
const themes = await requestUtils.rest( { path: '/wp/v2/themes' } )
14+
const active = themes.find( theme => theme.status === 'active' )
15+
if ( active?.is_block_theme ) {
16+
return
17+
}
18+
19+
for ( const slug of [ 'twentytwentyfive', 'twentytwentyfour' ] ) {
20+
try {
21+
await requestUtils.activateTheme( slug )
22+
return
23+
} catch {
24+
// Try the next bundled block theme.
25+
}
26+
}
27+
28+
throw new Error( 'Site Editor e2e needs a block theme (Twenty Twenty-Five or Twenty Twenty-Four).' )
29+
}
30+
31+
const templateTitle = template =>
32+
typeof template.title === 'string' ? template.title : template.title?.rendered || template.title?.raw || ''
33+
34+
const deleteE2eTemplate = async requestUtils => {
35+
try {
36+
const templates = await requestUtils.rest( { path: '/wp/v2/templates' } )
37+
for ( const template of templates ) {
38+
if ( ! template.wp_id ) {
39+
continue
40+
}
41+
if ( template.slug !== TEMPLATE_SLUG && templateTitle( template ) !== TEMPLATE_TITLE ) {
42+
continue
43+
}
44+
await requestUtils.rest( {
45+
method: 'DELETE',
46+
path: `/wp/v2/templates/${ template.id }`,
47+
params: { force: true },
48+
} )
49+
}
50+
} catch {
51+
// Playground may already be gone during teardown.
52+
}
53+
}
54+
55+
const templatesSidebar = page =>
56+
page.locator( '.edit-site-layout__sidebar, .edit-site-sidebar-dataviews, .edit-site-sidebar-navigation-screen' )
57+
58+
const sidebarItem = ( page, name ) =>
59+
templatesSidebar( page ).getByRole( 'button', { name, exact: true } )
60+
.or( templatesSidebar( page ).getByRole( 'link', { name, exact: true } ) )
61+
.or( templatesSidebar( page ).getByText( name, { exact: true } ) )
62+
.or( page.getByRole( 'button', { name, exact: true } ) )
63+
.or( page.getByRole( 'link', { name, exact: true } ) )
64+
65+
test.describe( 'Site Editor', () => {
66+
test.afterEach( async ( { requestUtils } ) => {
67+
await deleteE2eTemplate( requestUtils )
68+
} )
69+
70+
test( 'switching to user templates after editing one does not crash the Site Editor', async ( {
71+
page,
72+
admin,
73+
editor,
74+
requestUtils,
75+
stackable,
76+
} ) => {
77+
test.setTimeout( 120_000 )
78+
79+
let stylesheetError = ''
80+
page.on( 'pageerror', error => {
81+
if ( STYLESHEET_ERROR.test( error.message ) ) {
82+
stylesheetError = error.message
83+
}
84+
} )
85+
page.on( 'console', message => {
86+
if ( message.type() === 'error' && STYLESHEET_ERROR.test( message.text() ) ) {
87+
stylesheetError = message.text()
88+
}
89+
} )
90+
91+
await activateBlockTheme( requestUtils )
92+
await deleteE2eTemplate( requestUtils )
93+
94+
const author = process.env.WP_USERNAME || 'admin'
95+
const template = await requestUtils.createTemplate( 'wp_template', {
96+
slug: TEMPLATE_SLUG,
97+
title: TEMPLATE_TITLE,
98+
content: TEMPLATE_TEXT_BLOCK,
99+
} )
100+
expect( template.wp_id ).toBeTruthy()
101+
102+
await admin.visitAdminPage( 'site-editor.php', '' )
103+
await stackable.dismissToursAndNotices()
104+
await editor.setPreferences( 'core/edit-site', {
105+
welcomeGuide: false,
106+
welcomeGuideStyles: false,
107+
welcomeGuidePage: false,
108+
welcomeGuideTemplate: false,
109+
} )
110+
111+
const templatesNav = page.getByRole( 'button', { name: 'Templates', exact: true } )
112+
.or( page.getByRole( 'link', { name: 'Templates', exact: true } ) )
113+
await expect( templatesNav.first() ).toBeVisible( { timeout: 60_000 } )
114+
await templatesNav.first().click()
115+
await expect( page.getByRole( 'button', { name: 'Add Template' } ) ).toBeVisible( { timeout: 30_000 } )
116+
await expect( page.getByText( TEMPLATE_TITLE, { exact: true } ).first() ).toBeVisible( { timeout: 30_000 } )
117+
118+
await sidebarItem( page, author ).first().click()
119+
await expect( page.getByText( `Author is: ${ author }` ) ).toBeVisible( { timeout: 30_000 } )
120+
121+
await page.getByText( TEMPLATE_TITLE, { exact: true } ).first().click()
122+
await expect( editor.canvas.getByText( 'FSE template styles' ) ).toBeVisible( { timeout: 30_000 } )
123+
124+
const welcome = page.getByRole( 'button', { name: 'Get started' } )
125+
if ( await welcome.isVisible().catch( () => false ) ) {
126+
await welcome.click()
127+
}
128+
await page.locator( '.components-modal__screen-overlay' ).waitFor( { state: 'hidden', timeout: 5_000 } ).catch( () => {} )
129+
130+
const editorBack = page.locator( '.editor-header__back-button button, .editor-header__back-button a, .editor-header__back-button [role="button"]' )
131+
.or( page.getByRole( 'button', { name: 'Back', exact: true } ) )
132+
await expect( editorBack.first() ).toBeVisible( { timeout: 15_000 } )
133+
await editorBack.first().click()
134+
135+
await expect( page.getByRole( 'button', { name: 'Add Template' } ) ).toBeVisible( { timeout: 30_000 } )
136+
137+
await sidebarItem( page, 'All templates' ).first().click()
138+
await sidebarItem( page, author ).first().click()
139+
140+
const crash = page.getByText( EDITOR_CRASH )
141+
const deadline = Date.now() + 8_000
142+
while ( Date.now() < deadline && ! stylesheetError ) {
143+
if ( await crash.isVisible().catch( () => false ) ) {
144+
stylesheetError = EDITOR_CRASH
145+
break
146+
}
147+
await page.waitForTimeout( 200 )
148+
}
149+
150+
expect(
151+
stylesheetError,
152+
stylesheetError || 'Site Editor crashed after switching to user templates'
153+
).toBe( '' )
154+
} )
155+
} )

src/components/block-css/use-block-style-generator.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { useQueryLoopInstanceId } from '~stackable/util'
22
import {
33
useLayoutEffect, useMemo, useRef,
44
} from '@wordpress/element'
5-
import { dispatch, select } from '@wordpress/data'
5+
import {
6+
dispatch, select, useSelect,
7+
} from '@wordpress/data'
68
import { useRafEffect } from '~stackable/hooks'
79
import CssSaveCompiler from './css-save-compiler'
810
import { createStyleDependencyFingerprint } from './util'
@@ -79,6 +81,18 @@ export const useBlockCssGenerator = props => {
7981
}, [ styleFingerprint, version, blockStyles, setAttributes ] )
8082

8183
const styleKey = `${ clientId }-${ instanceId }`
84+
const editorDom = useSelect( select => {
85+
return select( 'stackable/editor-dom' )?.getEditorDom()
86+
} )
87+
88+
// Returning null for every block left template-preview iframes without CSS.
89+
// Use the unified stylesheet only for a current editor document, otherwise
90+
// return CSS so each preview is styled inside its own document.
91+
const editorCanvasDocument = document.querySelector( 'iframe[name="editor-canvas"]' )?.contentDocument
92+
const isCurrentEditorDom = editorDom?.isConnected && (
93+
editorDom.ownerDocument === document ||
94+
editorDom.ownerDocument === editorCanvasDocument
95+
)
8296

8397
useLayoutEffect( () => {
8498
dispatch( 'stackable/editor-block-css' ).setBlockCss( styleKey, editCss || '' )
@@ -92,7 +106,5 @@ export const useBlockCssGenerator = props => {
92106
}
93107
}, [ styleKey, editCss, clientId ] )
94108

95-
// We used to return the CSS here, but for optimization, now
96-
// CSS is injected via the unified editor stylesheet plugin.
97-
return null
109+
return isCurrentEditorDom ? null : editCss
98110
}

src/plugins/editor-block-css/block-style-sheets.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ export const shouldUseConstructableStyleSheets = editorDom => {
5959
}
6060

6161
const targetDoc = getTargetEditorDocument( editorDom )
62-
const canvasDoc = getEditorCanvasDocument()
6362

64-
return ! canvasDoc || targetDoc === document
63+
return targetDoc === document
6564
}
6665

6766
const getFallbackStyleId = key => {

0 commit comments

Comments
 (0)