From 36fd7f64e5eb7ce5794a703c5ca68f1bc06f85dd Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Thu, 16 Jun 2022 15:18:43 +0100 Subject: [PATCH] Refactor preview e2e tests to use Playwright. (#41380) * Refactor preview e2e tests to use Playwright. * Fix failing test * Address review feedback * remove only :P * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update test/e2e/specs/editor/various/preview.spec.js Co-authored-by: Kai Hao * Update to role selector * Remove old test * Specify dialog's name * Add comments for unnamed dialog Co-authored-by: Kai Hao Co-authored-by: Kai Hao --- .../src/editor/index.ts | 2 + .../src/editor/publish-post.ts | 32 ++ .../specs/editor/various/preview.test.js | 425 ------------------ test/e2e/specs/editor/various/preview.spec.js | 342 ++++++++++++++ 4 files changed, 376 insertions(+), 425 deletions(-) create mode 100644 packages/e2e-test-utils-playwright/src/editor/publish-post.ts delete mode 100644 packages/e2e-tests/specs/editor/various/preview.test.js create mode 100644 test/e2e/specs/editor/various/preview.spec.js diff --git a/packages/e2e-test-utils-playwright/src/editor/index.ts b/packages/e2e-test-utils-playwright/src/editor/index.ts index 074cdd358266c8..917d011d7486c8 100644 --- a/packages/e2e-test-utils-playwright/src/editor/index.ts +++ b/packages/e2e-test-utils-playwright/src/editor/index.ts @@ -12,6 +12,7 @@ import { getEditedPostContent } from './get-edited-post-content'; import { insertBlock } from './insert-block'; import { openDocumentSettingsSidebar } from './open-document-settings-sidebar'; import { openPreviewPage } from './preview'; +import { publishPost } from './publish-post'; import { selectBlocks } from './select-blocks'; import { showBlockToolbar } from './show-block-toolbar'; import { saveSiteEditorEntities } from './site-editor'; @@ -58,6 +59,7 @@ export class Editor { insertBlock = insertBlock; openDocumentSettingsSidebar = openDocumentSettingsSidebar; openPreviewPage = openPreviewPage; + publishPost = publishPost; saveSiteEditorEntities = saveSiteEditorEntities; selectBlocks = selectBlocks; showBlockToolbar = showBlockToolbar; diff --git a/packages/e2e-test-utils-playwright/src/editor/publish-post.ts b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts new file mode 100644 index 00000000000000..a1f624981bdc97 --- /dev/null +++ b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts @@ -0,0 +1,32 @@ +/** + * Internal dependencies + */ +import type { Editor } from './index'; + +/** + * Publishes the post, resolving once the request is complete (once a notice + * is displayed). + * + * @param {Editor} this + */ +export async function publishPost( this: Editor ) { + await this.page.click( 'role=button[name="Publish"i]' ); + const publishEditorPanel = this.page.locator( + 'role=region[name="Publish editor"i]' + ); + + const isPublishEditorVisible = await publishEditorPanel.isVisible(); + + // Save any entities. + if ( isPublishEditorVisible ) { + // Handle saving entities. + await this.page.click( + 'role=region[name="Editor publish"i] >> role=button[name="Save"i]' + ); + } + + // Handle saving just the post. + await this.page.click( + 'role=region[name="Editor publish"i] >> role=button[name="Publish"i]' + ); +} diff --git a/packages/e2e-tests/specs/editor/various/preview.test.js b/packages/e2e-tests/specs/editor/various/preview.test.js deleted file mode 100644 index dd3c9e84f8b754..00000000000000 --- a/packages/e2e-tests/specs/editor/various/preview.test.js +++ /dev/null @@ -1,425 +0,0 @@ -/** - * WordPress dependencies - */ -import { - activatePlugin, - clickOnCloseModalButton, - clickOnMoreMenuItem, - createNewPost, - createURL, - deactivatePlugin, - publishPost, - saveDraft, - openPreviewPage, - pressKeyWithModifier, -} from '@wordpress/e2e-test-utils'; - -/** @typedef {import('puppeteer-core').Page} Page */ - -/** - * Given the Page instance for the editor, opens preview drodpdown, and - * awaits the presence of the external preview selector. - * - * @param {Page} editorPage current editor page. - * - * @return {Promise} Promise resolving once selector is visible on page. - */ -async function waitForPreviewDropdownOpen( editorPage ) { - await editorPage.click( '.block-editor-post-preview__button-toggle' ); - return editorPage.waitForSelector( - '.edit-post-header-preview__button-external' - ); -} - -/** - * Given a Puppeteer Page instance for a preview window, clicks Preview, and - * awaits the window navigation. - * - * @param {Page} previewPage Page on which to await navigation. - * - * @return {Promise} Promise resolving once navigation completes. - */ -async function waitForPreviewNavigation( previewPage ) { - await page.click( '.edit-post-header-preview__button-external' ); - return previewPage.waitForNavigation(); -} - -/** - * Enables or disables the custom fields option. - * - * Note that this is implemented separately from the `togglePreferencesOption` - * utility, since the custom fields option triggers a page reload and requires - * extra async logic to wait for navigation to complete. - * - * @param {boolean} shouldBeChecked If true, turns the option on. If false, off. - */ -async function toggleCustomFieldsOption( shouldBeChecked ) { - const baseXPath = '//*[contains(@class, "interface-preferences-modal")]'; - const paneslXPath = `${ baseXPath }//button[contains(text(), "Panels")]`; - const checkboxXPath = `${ baseXPath }//label[contains(text(), "Custom fields")]`; - await clickOnMoreMenuItem( 'Preferences' ); - await page.waitForXPath( paneslXPath ); - const [ tabHandle ] = await page.$x( paneslXPath ); - await tabHandle.click(); - - await page.waitForXPath( checkboxXPath ); - const [ checkboxHandle ] = await page.$x( checkboxXPath ); - - const isChecked = await page.evaluate( - ( element ) => element.control.checked, - checkboxHandle - ); - - if ( isChecked !== shouldBeChecked ) { - await checkboxHandle.click(); - const [ saveButton ] = await page.$x( - shouldBeChecked - ? '//button[text()="Enable & Reload"]' - : '//button[text()="Disable & Reload"]' - ); - const navigationCompleted = page.waitForNavigation(); - saveButton.click(); - await navigationCompleted; - return; - } - - await clickOnCloseModalButton( '.interface-preferences-modal' ); -} - -describe( 'Preview', () => { - beforeEach( async () => { - await createNewPost(); - } ); - - it( 'should open a preview window for a new post', async () => { - const editorPage = page; - - // Disabled until content present. - const isPreviewDisabled = await editorPage.$$eval( - '.block-editor-post-preview__button-toggle:not( :disabled ):not( [aria-disabled="true"] )', - ( enabledButtons ) => ! enabledButtons.length - ); - expect( isPreviewDisabled ).toBe( true ); - - await editorPage.type( '.editor-post-title__input', 'Hello World' ); - - const previewPage = await openPreviewPage( editorPage ); - await previewPage.waitForSelector( '.entry-title' ); - - // When autosave completes for a new post, the URL of the editor should - // update to include the ID. Use this to assert on preview URL. - const [ , postId ] = await ( - await editorPage.waitForFunction( () => { - return window.location.search.match( /[\?&]post=(\d+)/ ); - } ) - ).jsonValue(); - - const expectedPreviewURL = createURL( - '', - `?p=${ postId }&preview=true` - ); - expect( previewPage.url() ).toBe( expectedPreviewURL ); - - // Title in preview should match input. - let previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'Hello World' ); - - // Return to editor to change title. - await editorPage.bringToFront(); - await editorPage.type( '.editor-post-title__input', '!' ); - await waitForPreviewDropdownOpen( editorPage ); - await waitForPreviewNavigation( previewPage ); - - // Title in preview should match updated input. - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'Hello World!' ); - - // Pressing preview without changes should bring same preview window to - // front and reload, but should not show interstitial. - await editorPage.bringToFront(); - await waitForPreviewNavigation( previewPage ); - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'Hello World!' ); - - // Preview for published post (no unsaved changes) directs to canonical URL for post. - await editorPage.bringToFront(); - /** - * Temp workaround until we find a reliable solution for `publishPost` util. - * - * @see https://github.com/WordPress/gutenberg/pull/35565 - */ - await editorPage.click( '.components-snackbar' ); - await publishPost(); - - // Return to editor to change title. - await editorPage.bringToFront(); - await editorPage.waitForSelector( '.editor-post-title__input' ); - await editorPage.click( '.editor-post-title__input' ); - await pressKeyWithModifier( 'primary', 'A' ); - await editorPage.keyboard.press( 'ArrowRight' ); - await editorPage.keyboard.type( ' And more.' ); - await waitForPreviewDropdownOpen( editorPage ); - await waitForPreviewNavigation( previewPage ); - - // Title in preview should match updated input. - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'Hello World! And more.' ); - - // Published preview URL should include ID and nonce parameters. - const { searchParams } = new URL( previewPage.url() ); - expect( searchParams.has( 'preview_id' ) ).toBe( true ); - expect( searchParams.has( 'preview_nonce' ) ).toBe( true ); - - // Return to editor. Previewing already-autosaved preview tab should - // reuse the opened tab, skipping interstitial. This resolves an edge - // cases where the post is dirty but not autosaveable (because the - // autosave is already up-to-date). - // - // See: https://github.com/WordPress/gutenberg/issues/7561 - await editorPage.bringToFront(); - await waitForPreviewNavigation( previewPage ); - - // Title in preview should match updated input. - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'Hello World! And more.' ); - - await previewPage.close(); - } ); - - it( 'should not revert title during a preview right after a save draft', async () => { - const editorPage = page; - - // Type aaaaa in the title field. - await editorPage.type( '.editor-post-title__input', 'aaaaa' ); - await editorPage.keyboard.press( 'Tab' ); - - // Save the post as a draft. - await editorPage.waitForSelector( '.editor-post-save-draft' ); - await saveDraft(); - - // Open the preview page. - const previewPage = await openPreviewPage( editorPage ); - await previewPage.waitForSelector( '.entry-title' ); - - // Title in preview should match input. - let previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'aaaaa' ); - - // Return to editor. - await editorPage.bringToFront(); - - // Append bbbbb to the title, and tab away from the title so blur event is triggered. - await editorPage.focus( '.editor-post-title__input' ); - await pressKeyWithModifier( 'primary', 'a' ); - await editorPage.keyboard.press( 'ArrowRight' ); - await editorPage.keyboard.type( 'bbbbb' ); - await editorPage.keyboard.press( 'Tab' ); - - // Save draft and open the preview page right after. - await editorPage.waitForSelector( '.editor-post-save-draft' ); - await saveDraft(); - await waitForPreviewDropdownOpen( editorPage ); - await waitForPreviewNavigation( previewPage ); - - // Title in preview should match updated input. - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'aaaaabbbbb' ); - - await previewPage.close(); - } ); - - // Verify correct preview. See: https://github.com/WordPress/gutenberg/issues/33616 - it( 'should display the correct preview when switching between published and draft statuses', async () => { - const editorPage = page; - - // Type Lorem in the title field. - await editorPage.type( '[aria-label="Add title"]', 'Lorem' ); - - // Open the preview page. - const previewPage = await openPreviewPage( editorPage ); - await previewPage.waitForSelector( '.entry-title' ); - - // Title in preview should match input. - let previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'Lorem' ); - - // Return to editor and publish post. - await editorPage.bringToFront(); - await publishPost(); - - // Close the panel. - await page.waitForSelector( - '.editor-post-publish-panel button[aria-label="Close panel"]' - ); - await page.click( - '.editor-post-publish-panel button[aria-label="Close panel"]' - ); - - // Change the title and preview again. - await editorPage.type( '[aria-label="Add title"]', ' Ipsum' ); - await editorPage.keyboard.press( 'Tab' ); - await waitForPreviewDropdownOpen( editorPage ); - await waitForPreviewNavigation( previewPage ); - - // Title in preview should match updated input. - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - - expect( previewTitle ).toBe( 'Lorem Ipsum' ); - - // Return to editor and switch to Draft. - await editorPage.bringToFront(); - await editorPage.waitForSelector( '.editor-post-switch-to-draft' ); - await editorPage.click( '.editor-post-switch-to-draft' ); - await page.keyboard.press( 'Enter' ); - - // Change the title. - await editorPage.type( '[aria-label="Add title"]', 'Draft ' ); - await editorPage.keyboard.press( 'Tab' ); - - // Open the preview page. - await waitForPreviewDropdownOpen( editorPage ); - await waitForPreviewNavigation( previewPage ); - - // Title in preview should match updated input. - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - - expect( previewTitle ).toBe( 'Draft Lorem Ipsum' ); - - await previewPage.close(); - } ); -} ); - -describe( 'Preview with Custom Fields enabled', () => { - beforeEach( async () => { - await createNewPost(); - await toggleCustomFieldsOption( true ); - } ); - - afterEach( async () => { - await toggleCustomFieldsOption( false ); - } ); - - // Catch regressions of https://github.com/WordPress/gutenberg/issues/12617 - it( 'displays edits to the post title and content in the preview', async () => { - const editorPage = page; - - // Make sure input is mounted in editor before adding content. - await editorPage.waitForSelector( '.editor-post-title__input' ); - // Add an initial title and content. - await editorPage.type( '.editor-post-title__input', 'title 1' ); - await editorPage.keyboard.press( 'Tab' ); - await editorPage.keyboard.type( 'content 1' ); - - // Publish the post and then close the publish panel. - await publishPost(); - await page.waitForSelector( '.editor-post-publish-panel' ); - await page.click( '.editor-post-publish-panel__header button' ); - - // Open the preview page. - const previewPage = await openPreviewPage( editorPage ); - await previewPage.waitForSelector( '.entry-title' ); - - // Check the title and preview match. - let previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'title 1' ); - let previewContent = await previewPage.$eval( - '.entry-content p', - ( node ) => node.textContent - ); - expect( previewContent ).toBe( 'content 1' ); - - // Return to editor and modify the title and content. - await editorPage.bringToFront(); - await editorPage.click( '.editor-post-title__input' ); - await editorPage.keyboard.press( 'End' ); - await editorPage.keyboard.press( 'Backspace' ); - await editorPage.keyboard.type( '2' ); - await editorPage.keyboard.press( 'Tab' ); - await editorPage.keyboard.press( 'End' ); - await editorPage.keyboard.press( 'Backspace' ); - await editorPage.keyboard.type( '2' ); - - // Open the preview page. - await waitForPreviewDropdownOpen( editorPage ); - await waitForPreviewNavigation( previewPage ); - - // Title in preview should match input. - previewTitle = await previewPage.$eval( - '.entry-title', - ( node ) => node.textContent - ); - expect( previewTitle ).toBe( 'title 2' ); - previewContent = await previewPage.$eval( - '.entry-content p', - ( node ) => node.textContent - ); - expect( previewContent ).toBe( 'content 2' ); - - // Make sure the editor is active for the afterEach function. - await editorPage.bringToFront(); - } ); -} ); - -describe( 'Preview with private custom post type', () => { - beforeAll( async () => { - await activatePlugin( 'gutenberg-test-custom-post-types' ); - } ); - - afterAll( async () => { - await deactivatePlugin( 'gutenberg-test-custom-post-types' ); - } ); - - it( 'should not show the Preview Externally link', async () => { - await createNewPost( { postType: 'not_public' } ); - - // Type in the title filed. - await page.type( '.editor-post-title__input', 'aaaaa' ); - await page.keyboard.press( 'Tab' ); - - // Open the preview menu. - await page.click( '.block-editor-post-preview__button-toggle' ); - - const previewDropdownContents = await page.$( - '.block-editor-post-preview__dropdown-content' - ); - - // Expect the Preview Externally link not to be present. - const previewExternallyLink = await previewDropdownContents.$x( - '//a[contains(text(), "Preview externally")]' - ); - expect( previewExternallyLink.length ).toBe( 0 ); - } ); -} ); diff --git a/test/e2e/specs/editor/various/preview.spec.js b/test/e2e/specs/editor/various/preview.spec.js new file mode 100644 index 00000000000000..9cea861fa8e348 --- /dev/null +++ b/test/e2e/specs/editor/various/preview.spec.js @@ -0,0 +1,342 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.use( { + previewUtils: async ( { page }, use ) => { + await use( new PreviewUtils( { page } ) ); + }, +} ); + +test.describe( 'Preview', () => { + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test( 'should open a preview window for a new post', async ( { + editor, + page, + previewUtils, + requestUtils, + } ) => { + const editorPage = page; + + // Disabled until content present. + await expect( + editorPage.locator( 'role=button[name="Preview"i]' ) + ).toBeDisabled(); + + await editorPage.type( + 'role=textbox[name="Add title"i]', + 'Hello World' + ); + + const previewPage = await editor.openPreviewPage( editorPage ); + const previewTitle = previewPage.locator( 'role=heading[level=1]' ); + + await expect( previewTitle ).toHaveText( 'Hello World' ); + + // When autosave completes for a new post, the URL of the editor should + // update to include the ID. Use this to assert on preview URL. + await expect( editorPage ).toHaveURL( /[\?&]post=(\d+)/ ); + const [ , postId ] = editorPage.url().match( /[\?&]post=(\d+)/ ); + + const expectedPreviewURL = new URL( requestUtils.baseURL ); + expectedPreviewURL.search = `?p=${ postId }&preview=true`; + await expect( previewPage ).toHaveURL( expectedPreviewURL.href ); + + // Return to editor to change title. + await editorPage.bringToFront(); + await editorPage.type( 'role=textbox[name="Add title"i]', '!' ); + await previewUtils.waitForPreviewNavigation( previewPage ); + + // Title in preview should match updated input. + await expect( previewTitle ).toHaveText( 'Hello World!' ); + + // Pressing preview without changes should bring same preview window to + // front and reload, but should not show interstitial. + await editorPage.bringToFront(); + await previewUtils.waitForPreviewNavigation( previewPage ); + + await expect( previewTitle ).toHaveText( 'Hello World!' ); + + // Preview for published post (no unsaved changes) directs to canonical URL for post. + await editorPage.bringToFront(); + await editor.publishPost(); + + // Close the panel. + await page.click( 'role=button[name="Close panel"i]' ); + + // Return to editor to change title. + await editorPage.bringToFront(); + await editorPage.fill( + 'role=textbox[name="Add title"i]', + 'Hello World! And more.' + ); + await previewUtils.waitForPreviewNavigation( previewPage ); + + // Title in preview should match updated input. + await expect( previewTitle ).toHaveText( 'Hello World! And more.' ); + + // Published preview URL should include ID and nonce parameters. + const { searchParams } = new URL( previewPage.url() ); + expect( searchParams.has( 'preview_id' ) ).toEqual( true ); + expect( searchParams.has( 'preview_nonce' ) ).toEqual( true ); + + // Return to editor. Previewing already-autosaved preview tab should + // reuse the opened tab, skipping interstitial. This resolves an edge + // cases where the post is dirty but not autosaveable (because the + // autosave is already up-to-date). + // + // See: https://github.com/WordPress/gutenberg/issues/7561 + await editorPage.bringToFront(); + await previewUtils.waitForPreviewNavigation( previewPage ); + + // Title in preview should match updated input. + await expect( previewTitle ).toHaveText( 'Hello World! And more.' ); + + await previewPage.close(); + } ); + + test( 'should not revert title during a preview right after a save draft', async ( { + editor, + page, + previewUtils, + } ) => { + const editorPage = page; + + // Type aaaaa in the title field. + await editorPage.type( 'role=textbox[name="Add title"]', 'aaaaa' ); + await editorPage.keyboard.press( 'Tab' ); + + // Save the post as a draft. + await editorPage.click( 'role=button[name="Save draft"i]' ); + await editorPage.waitForSelector( + 'role=button[name="Dismiss this notice"] >> text=Draft saved' + ); + + // Open the preview page. + const previewPage = await editor.openPreviewPage( editorPage ); + + // Title in preview should match input. + const previewTitle = previewPage.locator( 'role=heading[level=1]' ); + await expect( previewTitle ).toHaveText( 'aaaaa' ); + + // Return to editor. + await editorPage.bringToFront(); + + // Append bbbbb to the title, and tab away from the title so blur event is triggered. + await editorPage.fill( + 'role=textbox[name="Add title"i]', + 'aaaaabbbbb' + ); + await editorPage.keyboard.press( 'Tab' ); + + // Save draft and open the preview page right after. + await editorPage.click( 'role=button[name="Save draft"i]' ); + await editorPage.waitForSelector( + 'role=button[name="Dismiss this notice"] >> text=Draft saved' + ); + await previewUtils.waitForPreviewNavigation( previewPage ); + + // Title in preview should match updated input. + await expect( previewTitle ).toHaveText( 'aaaaabbbbb' ); + + await previewPage.close(); + } ); + + // Verify correct preview. See: https://github.com/WordPress/gutenberg/issues/33616 + test( 'should display the correct preview when switching between published and draft statuses', async ( { + editor, + page, + previewUtils, + } ) => { + const editorPage = page; + + // Type Lorem in the title field. + await editorPage.type( 'role=textbox[name="Add title"i]', 'Lorem' ); + + // Open the preview page. + const previewPage = await editor.openPreviewPage( editorPage ); + + // Title in preview should match input. + const previewTitle = previewPage.locator( 'role=heading[level=1]' ); + await expect( previewTitle ).toHaveText( 'Lorem' ); + + // Return to editor and publish post. + await editorPage.bringToFront(); + await editor.publishPost(); + + // Close the panel. + await page.click( 'role=button[name="Close panel"i]' ); + + // Change the title and preview again. + await editorPage.type( 'role=textbox[name="Add title"i]', ' Ipsum' ); + await previewUtils.waitForPreviewNavigation( previewPage ); + + // Title in preview should match updated input. + await expect( previewTitle ).toHaveText( 'Lorem Ipsum' ); + + // Return to editor and switch to Draft. + await editorPage.bringToFront(); + await page.click( 'role=button[name="Switch to draft"i]' ); + // FIXME: The confirmation dialog is not named yet. + await page.click( 'role=dialog >> role=button[name="OK"i]' ); + + // Change the title. + await editorPage.type( 'role=textbox[name="Add title"i]', ' Draft' ); + + // Open the preview page. + await previewUtils.waitForPreviewNavigation( previewPage ); + + // Title in preview should match updated input. + await expect( previewTitle ).toHaveText( 'Lorem Ipsum Draft' ); + + await previewPage.close(); + } ); +} ); + +test.describe( 'Preview with Custom Fields enabled', () => { + test.beforeEach( async ( { admin, previewUtils } ) => { + await admin.createNewPost(); + await previewUtils.toggleCustomFieldsOption( true ); + } ); + + test.afterEach( async ( { previewUtils } ) => { + await previewUtils.toggleCustomFieldsOption( false ); + } ); + + // Catch regressions of https://github.com/WordPress/gutenberg/issues/12617 + test( 'displays edits to the post title and content in the preview', async ( { + editor, + page, + previewUtils, + } ) => { + const editorPage = page; + + // Add an initial title and content. + await editorPage.type( 'role=textbox[name="Add title"i]', 'title 1' ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'content 1' }, + } ); + + // Publish the post and then close the publish panel. + await editor.publishPost(); + + // Close the panel. + await page.click( 'role=button[name="Close panel"i]' ); + + // Open the preview page. + const previewPage = await editor.openPreviewPage(); + + // Check the title and preview match. + const previewTitle = previewPage.locator( 'role=heading[level=1]' ); + await expect( previewTitle ).toHaveText( 'title 1' ); + // No semantics we can grab here; it's just a

inside a

:') + const previewContent = previewPage.locator( '.entry-content p' ); + await expect( previewContent ).toHaveText( 'content 1' ); + + // Return to editor and modify the title and content. + await editorPage.bringToFront(); + await editorPage.fill( 'role=textbox[name="Add title"i]', 'title 2' ); + await editorPage.fill( + 'role=document >> text="content 1"', + 'content 2' + ); + + // Open the preview page. + await previewUtils.waitForPreviewNavigation( previewPage ); + + // Title in preview should match input. + await expect( previewTitle ).toHaveText( 'title 2' ); + await expect( previewContent ).toHaveText( 'content 2' ); + + // Make sure the editor is active for the afterEach function. + await editorPage.bringToFront(); + } ); +} ); + +test.describe( 'Preview with private custom post type', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( 'gutenberg-test-custom-post-types' ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-custom-post-types' + ); + } ); + + test( 'should not show the Preview Externally link', async ( { + admin, + page, + } ) => { + await admin.createNewPost( { postType: 'not_public', title: 'aaaaa' } ); + + // Open the preview menu. + await page.click( 'role=button[name="Preview"i]' ); + + await expect( + page.locator( 'role=menuitem[name="Preview in new tab"i]' ) + ).not.toBeVisible(); + } ); +} ); + +class PreviewUtils { + constructor( { page } ) { + this.page = page; + } + + async waitForPreviewNavigation( previewPage ) { + const previewToggle = this.page.locator( + 'role=button[name="Preview"i][expanded=false]' + ); + const isDropdownClosed = await previewToggle.isVisible(); + if ( isDropdownClosed ) { + await previewToggle.click(); + } + + await this.page.click( 'role=menuitem[name="Preview in new tab"i]' ); + return previewPage.waitForNavigation(); + } + + async toggleCustomFieldsOption( shouldBeChecked ) { + // Open preferences dialog. + + await this.page.click( + 'role=region[name="Editor top bar"i] >> role=button[name="Options"i]' + ); + await this.page.click( 'role=menuitem[name="Preferences"i]' ); + + // Navigate to panels section. + await this.page.click( + 'role=dialog[name="Preferences"i] >> role=tab[name="Panels"i]' + ); + + // Find custom fields checkbox. + const customFieldsCheckbox = this.page.locator( + 'role=checkbox[name="Custom fields"i]' + ); + + if ( shouldBeChecked ) { + await customFieldsCheckbox.check(); + } else { + await customFieldsCheckbox.uncheck(); + } + + const saveButton = this.page.locator( + 'role=button[name=/(Dis|En)able & Reload/i]' + ); + const isSaveVisible = await saveButton.isVisible(); + + if ( isSaveVisible ) { + saveButton.click(); + await this.page.waitForNavigation(); + return; + } + + await this.page.click( 'role=button[name="Close dialog"i]' ); + } +}