From c9e6f91c34a4da5ece3c568560d584af9d7127ea Mon Sep 17 00:00:00 2001 From: Ramon Date: Sun, 19 Jun 2022 10:43:24 +1000 Subject: [PATCH] E2E Tests: Migrate style variations tests to Playwright (#41427) --- .wp-env.json | 2 +- .../src/editor/site-editor.ts | 2 +- .../src/request-utils/themes.ts | 6 +- .../site-editor/style-variations.test.js | 213 ----------------- .../components/global-styles/context-menu.js | 3 + .../src/components/global-styles/palette.js | 5 +- .../global-styles/screen-block-list.js | 11 +- .../components/global-styles/screen-colors.js | 21 +- .../components/global-styles/screen-root.js | 10 +- .../global-styles/screen-typography.js | 13 +- .../site-editor/style-variations.spec.js | 224 ++++++++++++++++++ .../block-templates/index.html | 0 .../style-variations/index.php | 0 .../style-variations/style.css | 0 .../style-variations/styles/pink.json | 0 .../style-variations/styles/yellow.json | 0 .../style-variations/theme.json | 0 17 files changed, 282 insertions(+), 228 deletions(-) delete mode 100644 packages/e2e-tests/specs/site-editor/style-variations.test.js create mode 100644 test/e2e/specs/site-editor/style-variations.spec.js rename {packages/e2e-tests/themes => test/gutenberg-test-themes}/style-variations/block-templates/index.html (100%) rename {packages/e2e-tests/themes => test/gutenberg-test-themes}/style-variations/index.php (100%) rename {packages/e2e-tests/themes => test/gutenberg-test-themes}/style-variations/style.css (100%) rename {packages/e2e-tests/themes => test/gutenberg-test-themes}/style-variations/styles/pink.json (100%) rename {packages/e2e-tests/themes => test/gutenberg-test-themes}/style-variations/styles/yellow.json (100%) rename {packages/e2e-tests/themes => test/gutenberg-test-themes}/style-variations/theme.json (100%) diff --git a/.wp-env.json b/.wp-env.json index 86e72e0964232..aa8dfaf3c0c4a 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -8,7 +8,7 @@ "wp-content/plugins/gutenberg": ".", "wp-content/mu-plugins": "./packages/e2e-tests/mu-plugins", "wp-content/plugins/gutenberg-test-plugins": "./packages/e2e-tests/plugins", - "wp-content/themes/gutenberg-test-themes": "./packages/e2e-tests/themes" + "wp-content/themes/gutenberg-test-themes": "./test/gutenberg-test-themes" } } } diff --git a/packages/e2e-test-utils-playwright/src/editor/site-editor.ts b/packages/e2e-test-utils-playwright/src/editor/site-editor.ts index 1b218bd7b3af3..9ea4fdeb0675e 100644 --- a/packages/e2e-test-utils-playwright/src/editor/site-editor.ts +++ b/packages/e2e-test-utils-playwright/src/editor/site-editor.ts @@ -23,6 +23,6 @@ export async function saveSiteEditorEntities( this: Editor ) { // not have that classname. // TODO - find a way to improve this selector to use role/name. await this.page.waitForSelector( - '.edit-site-save-button__button:not(.is-busy)' + 'css=.edit-site-save-button__button:not(.is-busy)' ); } diff --git a/packages/e2e-test-utils-playwright/src/request-utils/themes.ts b/packages/e2e-test-utils-playwright/src/request-utils/themes.ts index 1bbb7fb410b49..bb2fbd8978159 100644 --- a/packages/e2e-test-utils-playwright/src/request-utils/themes.ts +++ b/packages/e2e-test-utils-playwright/src/request-utils/themes.ts @@ -13,9 +13,9 @@ async function activateTheme( let response = await this.request.get( THEMES_URL ); const html = await response.text(); const matchGroup = html.match( - new RegExp( - `action=activate&stylesheet=${ themeSlug }&_wpnonce=[a-z0-9]+` - ) + `action=activate&stylesheet=${ encodeURIComponent( + themeSlug + ) }&_wpnonce=[a-z0-9]+` ); if ( ! matchGroup ) { diff --git a/packages/e2e-tests/specs/site-editor/style-variations.test.js b/packages/e2e-tests/specs/site-editor/style-variations.test.js deleted file mode 100644 index 16f50fdf9154c..0000000000000 --- a/packages/e2e-tests/specs/site-editor/style-variations.test.js +++ /dev/null @@ -1,213 +0,0 @@ -/** - * WordPress dependencies - */ -import { - trashAllPosts, - activateTheme, - visitSiteEditor, - toggleGlobalStyles, - openGlobalStylesPanel, - openPreviousGlobalStylesPanel, -} from '@wordpress/e2e-test-utils'; - -async function openOtherStyles() { - const OTHER_STYLES_SELECTOR = '//div[contains(text(),"Browse styles")]'; - await ( await page.waitForXPath( OTHER_STYLES_SELECTOR ) ).click(); -} - -async function getAvailableStyleVariations() { - const VARIATION_ITEMS_STYLES_SELECTOR = - '.edit-site-global-styles-variations_item'; - await page.waitForSelector( VARIATION_ITEMS_STYLES_SELECTOR ); - return page.$$( VARIATION_ITEMS_STYLES_SELECTOR ); -} - -async function applyVariation( label ) { - await toggleGlobalStyles(); - await openOtherStyles(); - const variation = await page.waitForXPath( - `//*[@role="button"][@aria-label="${ label }"]` - ); - await variation.click(); -} - -async function applyPinkVariation() { - await applyVariation( 'pink' ); -} - -async function applyYellowVariation() { - await applyVariation( 'yellow' ); -} - -async function openColorsPanel() { - await openGlobalStylesPanel( 'Colors' ); -} - -async function openTypographyPanel() { - await openGlobalStylesPanel( 'Typography' ); -} - -async function openTextPanel() { - await openGlobalStylesPanel( 'Text' ); -} - -async function openPalettePanel() { - const selector = `//div[./h2[text()="Palette"]]//button`; - await ( await page.waitForXPath( selector ) ).click(); -} - -async function getFontSizeHint() { - const element = await page.$( - '.components-font-size-picker__header__hint' - ); - return element.evaluate( ( el ) => el.textContent ); -} - -async function getCustomFontSizeValue() { - const element = await page.$( - '.components-font-size-picker input[aria-label="Custom"]' - ); - return element.evaluate( ( el ) => el.value ); -} - -async function getColorValue( colorType ) { - return page.evaluate( ( _colorType ) => { - return document.evaluate( - `substring-before(substring-after(//div[contains(@class, "edit-site-global-styles-sidebar__panel")]//button[.//*[text()="${ _colorType }"]]//*[contains(@class,"component-color-indicator")]/@style, "background: "), ";")`, - document, - null, - XPathResult.ANY_TYPE, - null - ).stringValue; - }, colorType ); -} - -async function getBackgroundColorValue() { - return getColorValue( 'Background' ); -} - -async function getTextColorValue() { - return getColorValue( 'Text' ); -} - -async function getColorPalette( paletteSource ) { - const paletteOptions = await page.$x( - `//div[./*/h2[text()="${ paletteSource }"]]//button[contains(@class,"components-circular-option-picker__option")]` - ); - return Promise.all( - paletteOptions.map( ( element ) => { - return element.evaluate( ( el ) => { - const color = el.style.backgroundColor; - const name = el - .getAttribute( 'aria-label' ) - .substring( 'Color: '.length ); - return { color, name }; - } ); - } ) - ); -} - -async function getThemePalette() { - return getColorPalette( 'Theme' ); -} - -describe( 'Global styles variations', () => { - beforeAll( async () => { - await activateTheme( 'gutenberg-test-themes/style-variations' ); - await trashAllPosts( 'wp_template' ); - await trashAllPosts( 'wp_template_part' ); - } ); - afterAll( async () => { - await activateTheme( 'twentytwentyone' ); - } ); - beforeEach( async () => { - await visitSiteEditor(); - } ); - - it( 'Should have three variations available with the first one being active', async () => { - await toggleGlobalStyles(); - await openOtherStyles(); - const variations = await getAvailableStyleVariations(); - expect( variations ).toHaveLength( 3 ); - expect( - await ( - await variations[ 0 ].getProperty( 'className' ) - ).jsonValue() - ).toContain( 'is-active' ); - expect( - await ( - await variations[ 1 ].getProperty( 'className' ) - ).jsonValue() - ).not.toContain( 'is-active' ); - expect( - await ( - await variations[ 2 ].getProperty( 'className' ) - ).jsonValue() - ).not.toContain( 'is-active' ); - } ); - - it( 'Should apply preset colors and font sizes in a variation', async () => { - await applyPinkVariation(); - await openPreviousGlobalStylesPanel(); - await openColorsPanel(); - expect( await getBackgroundColorValue() ).toBe( 'rgb(202, 105, 211)' ); - expect( await getTextColorValue() ).toBe( 'rgb(74, 7, 74)' ); - await openPreviousGlobalStylesPanel(); - await openTypographyPanel(); - await openTextPanel(); - expect( await getFontSizeHint() ).toBe( 'Medium(px)' ); - } ); - - it( 'Should apply custom colors and font sizes in a variation', async () => { - await applyYellowVariation(); - await openPreviousGlobalStylesPanel(); - await openColorsPanel(); - expect( await getBackgroundColorValue() ).toBe( 'rgb(255, 239, 11)' ); - expect( await getTextColorValue() ).toBe( 'rgb(25, 25, 17)' ); - await openPreviousGlobalStylesPanel(); - await openTypographyPanel(); - await openTextPanel(); - expect( await getFontSizeHint() ).toBe( '(Custom)' ); - expect( await getCustomFontSizeValue() ).toBe( '15' ); - } ); - - it( 'Should apply a color palette in a variation', async () => { - await applyPinkVariation(); - await openPreviousGlobalStylesPanel(); - await openColorsPanel(); - await openPalettePanel(); - expect( await getThemePalette() ).toMatchObject( [ - { - color: 'rgb(74, 7, 74)', - name: 'Foreground', - }, - { - color: 'rgb(202, 105, 211)', - name: 'Background', - }, - { - color: 'rgba(204, 0, 255, 0.77)', - name: 'Awesome pink', - }, - ] ); - } ); - - it( 'Should reflect style variations in the styles applied to the editor', async () => { - await applyYellowVariation(); - const frame = await ( - await page.waitForSelector( '.edit-site-visual-editor iframe' ) - ).contentFrame(); - const paragraph = await frame.waitForXPath( - `//p[text()="My awesome paragraph"]` - ); - const paragraphColor = await paragraph.evaluate( ( el ) => { - return window.getComputedStyle( el ).color; - } ); - expect( paragraphColor ).toBe( 'rgb(25, 25, 17)' ); - const body = await frame.$( 'body' ); - const backgroundColor = await body.evaluate( ( el ) => { - return window.getComputedStyle( el ).backgroundColor; - } ); - expect( backgroundColor ).toBe( 'rgb(255, 239, 11)' ); - } ); -} ); diff --git a/packages/edit-site/src/components/global-styles/context-menu.js b/packages/edit-site/src/components/global-styles/context-menu.js index e33aa99fe8195..19a252763ff7e 100644 --- a/packages/edit-site/src/components/global-styles/context-menu.js +++ b/packages/edit-site/src/components/global-styles/context-menu.js @@ -27,6 +27,7 @@ function ContextMenu( { name, parentMenu = '' } ) { { __( 'Typography' ) } @@ -35,6 +36,7 @@ function ContextMenu( { name, parentMenu = '' } ) { { __( 'Colors' ) } @@ -43,6 +45,7 @@ function ContextMenu( { name, parentMenu = '' } ) { { __( 'Layout' ) } diff --git a/packages/edit-site/src/components/global-styles/palette.js b/packages/edit-site/src/components/global-styles/palette.js index c0c1d0968832a..dd7bff6fd2ee6 100644 --- a/packages/edit-site/src/components/global-styles/palette.js +++ b/packages/edit-site/src/components/global-styles/palette.js @@ -58,7 +58,10 @@ function Palette( { name } ) { { __( 'Palette' ) } - + + { block.title } diff --git a/packages/edit-site/src/components/global-styles/screen-colors.js b/packages/edit-site/src/components/global-styles/screen-colors.js index 4e961dcf0e75b..78607e0d1997f 100644 --- a/packages/edit-site/src/components/global-styles/screen-colors.js +++ b/packages/edit-site/src/components/global-styles/screen-colors.js @@ -33,11 +33,15 @@ function BackgroundColorItem( { name, parentMenu } ) { } return ( - + { __( 'Background' ) } @@ -56,10 +60,16 @@ function TextColorItem( { name, parentMenu } ) { } return ( - + - + { __( 'Text' ) } @@ -77,7 +87,10 @@ function LinkColorItem( { name, parentMenu } ) { } return ( - + diff --git a/packages/edit-site/src/components/global-styles/screen-root.js b/packages/edit-site/src/components/global-styles/screen-root.js index da8c13d28f017..0674b56319c70 100644 --- a/packages/edit-site/src/components/global-styles/screen-root.js +++ b/packages/edit-site/src/components/global-styles/screen-root.js @@ -46,7 +46,10 @@ function ScreenRoot() { { !! variations?.length && ( - + { __( 'Browse styles' ) } @@ -82,7 +85,10 @@ function ScreenRoot() { ) } - + { __( 'Blocks' ) } + { + await use( new SiteEditorStyleVariations( { page } ) ); + }, +} ); + +test.describe( 'Global styles variations', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( + 'gutenberg-test-themes/style-variations' + ); + await requestUtils.deleteAllTemplates( 'wp_template' ); + await requestUtils.deleteAllTemplates( 'wp_template_part' ); + } ); + + test.afterEach( async ( { requestUtils } ) => { + await Promise.all( [ + requestUtils.deleteAllTemplates( 'wp_template' ), + requestUtils.deleteAllTemplates( 'wp_template_part' ), + ] ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'twentytwentyone' ); + } ); + + test( 'should have three variations available with the first one being active', async ( { + admin, + page, + siteEditorStyleVariations, + } ) => { + await admin.visitSiteEditor( { + postId: 'gutenberg-test-themes/style-variations//index', + postType: 'wp_template', + } ); + + await siteEditorStyleVariations.browseStyles(); + + // TODO: instead of locating these elements by class, + // we could update the source code to group them in a
or other container, + // then add `aria-labelledby` and `aria-describedby` etc to provide accessible information, + const variations = page.locator( + '.edit-site-global-styles-variations_item' + ); + + await expect( variations ).toHaveCount( 3 ); + + await expect( variations.first() ).toHaveAttribute( + 'aria-current', + 'true' + ); + await expect( variations.nth( 1 ) ).toHaveAttribute( + 'aria-current', + 'false' + ); + await expect( variations.nth( 2 ) ).toHaveAttribute( + 'aria-current', + 'false' + ); + } ); + + test( 'should apply preset colors and font sizes in a variation', async ( { + admin, + page, + siteEditorStyleVariations, + } ) => { + await admin.visitSiteEditor( { + postId: 'gutenberg-test-themes/style-variations//index', + postType: 'wp_template', + } ); + await siteEditorStyleVariations.browseStyles(); + await page.click( 'role=button[name="pink"i]' ); + await page.click( + 'role=button[name="Navigate to the previous view"i]' + ); + await page.click( 'role=button[name="Colors styles"i]' ); + + await expect( + page.locator( + 'role=button[name="Colors background styles"i] >> data-testid=background-color-indicator' + ) + ).toHaveCSS( 'background', /rgb\(202, 105, 211\)/ ); + + await expect( + page.locator( + 'role=button[name="Colors text styles"i] >> data-testid=text-color-indicator' + ) + ).toHaveCSS( 'background', /rgb\(74, 7, 74\)/ ); + + await page.click( + 'role=button[name="Navigate to the previous view"i]' + ); + await page.click( 'role=button[name="Typography styles"i]' ); + await page.click( 'role=button[name="Typography Text styles"i]' ); + + await expect( + page.locator( 'css=.components-font-size-picker__header__hint' ) + ).toHaveText( 'Medium(px)' ); + } ); + + test( 'should apply custom colors and font sizes in a variation', async ( { + admin, + page, + siteEditorStyleVariations, + } ) => { + await admin.visitSiteEditor( { + postId: 'gutenberg-test-themes/style-variations//index', + postType: 'wp_template', + } ); + await siteEditorStyleVariations.browseStyles(); + await page.click( 'role=button[name="yellow"i]' ); + await page.click( + 'role=button[name="Navigate to the previous view"i]' + ); + await page.click( 'role=button[name="Colors styles"i]' ); + + await expect( + page.locator( + 'role=button[name="Colors background styles"i] >> data-testid=background-color-indicator' + ) + ).toHaveCSS( 'background', /rgb\(255, 239, 11\)/ ); + + await expect( + page.locator( + 'role=button[name="Colors text styles"i] >> data-testid=text-color-indicator' + ) + ).toHaveCSS( 'background', /rgb\(25, 25, 17\)/ ); + + await page.click( + 'role=button[name="Navigate to the previous view"i]' + ); + await page.click( 'role=button[name="Typography styles"i]' ); + await page.click( 'role=button[name="Typography Text styles"i]' ); + + // TODO: to avoid use classnames to locate these elements, + // we could provide accessible attributes to the source code in packages/components/src/font-size-picker/index.js. + await expect( + page.locator( 'css=.components-font-size-picker__header__hint' ) + ).toHaveText( '(Custom)' ); + + await expect( + page.locator( 'role=spinbutton[name="Custom"i]' ) + ).toHaveValue( '15' ); + } ); + + test( 'should apply a color palette in a variation', async ( { + admin, + page, + siteEditorStyleVariations, + } ) => { + await admin.visitSiteEditor( { + postId: 'gutenberg-test-themes/style-variations//index', + postType: 'wp_template', + } ); + await siteEditorStyleVariations.browseStyles(); + await page.click( 'role=button[name="pink"i]' ); + await page.click( + 'role=button[name="Navigate to the previous view"i]' + ); + await page.click( 'role=button[name="Colors styles"i]' ); + await page.click( 'role=button[name="Color palettes"i]' ); + + await expect( + page.locator( 'role=button[name="Color: Foreground"i]' ) + ).toHaveCSS( 'background-color', 'rgb(74, 7, 74)' ); + + await expect( + page.locator( 'role=button[name="Color: Background"i]' ) + ).toHaveCSS( 'background-color', 'rgb(202, 105, 211)' ); + + await expect( + page.locator( 'role=button[name="Color: Awesome pink"i]' ) + ).toHaveCSS( 'background-color', 'rgba(204, 0, 255, 0.77)' ); + } ); + + test( 'should reflect style variations in the styles applied to the editor', async ( { + admin, + page, + siteEditorStyleVariations, + } ) => { + await admin.visitSiteEditor( { + postId: 'gutenberg-test-themes/style-variations//index', + postType: 'wp_template', + } ); + await siteEditorStyleVariations.browseStyles(); + await page.click( 'role=button[name="yellow"i]' ); + + const frame = page.frame( 'editor-canvas' ); + const paragraph = frame.locator( 'text="My awesome paragraph"' ); + await expect( paragraph ).toHaveCSS( 'color', 'rgb(25, 25, 17)' ); + + const body = frame.locator( 'css=body' ); + await expect( body ).toHaveCSS( + 'background-color', + 'rgb(255, 239, 11)' + ); + } ); +} ); + +class SiteEditorStyleVariations { + constructor( { page } ) { + this.page = page; + } + + async disableWelcomeGuide() { + // Turn off the welcome guide. + await this.page.evaluate( () => { + window.wp.data + .dispatch( 'core/preferences' ) + .set( 'core/edit-site', 'welcomeGuideStyles', false ); + } ); + } + + async browseStyles() { + await this.disableWelcomeGuide(); + await this.page.click( 'role=button[name="Styles"i]' ); + await this.page.click( 'role=button[name="Browse styles"i]' ); + } +} diff --git a/packages/e2e-tests/themes/style-variations/block-templates/index.html b/test/gutenberg-test-themes/style-variations/block-templates/index.html similarity index 100% rename from packages/e2e-tests/themes/style-variations/block-templates/index.html rename to test/gutenberg-test-themes/style-variations/block-templates/index.html diff --git a/packages/e2e-tests/themes/style-variations/index.php b/test/gutenberg-test-themes/style-variations/index.php similarity index 100% rename from packages/e2e-tests/themes/style-variations/index.php rename to test/gutenberg-test-themes/style-variations/index.php diff --git a/packages/e2e-tests/themes/style-variations/style.css b/test/gutenberg-test-themes/style-variations/style.css similarity index 100% rename from packages/e2e-tests/themes/style-variations/style.css rename to test/gutenberg-test-themes/style-variations/style.css diff --git a/packages/e2e-tests/themes/style-variations/styles/pink.json b/test/gutenberg-test-themes/style-variations/styles/pink.json similarity index 100% rename from packages/e2e-tests/themes/style-variations/styles/pink.json rename to test/gutenberg-test-themes/style-variations/styles/pink.json diff --git a/packages/e2e-tests/themes/style-variations/styles/yellow.json b/test/gutenberg-test-themes/style-variations/styles/yellow.json similarity index 100% rename from packages/e2e-tests/themes/style-variations/styles/yellow.json rename to test/gutenberg-test-themes/style-variations/styles/yellow.json diff --git a/packages/e2e-tests/themes/style-variations/theme.json b/test/gutenberg-test-themes/style-variations/theme.json similarity index 100% rename from packages/e2e-tests/themes/style-variations/theme.json rename to test/gutenberg-test-themes/style-variations/theme.json