Skip to content
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

Add E2E tests for shared blocks #7947

Merged
merged 2 commits into from
Jul 17, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 207 additions & 0 deletions test/e2e/specs/shared-blocks.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/**
* Internal dependencies
*/
import '../support/bootstrap';
import {
insertBlock,
newDesktopBrowserPage,
newPost,
pressWithModifier,
searchForBlock,
} from '../support/utils';

function waitForAndAcceptDialog() {
return new Promise( ( resolve ) => {
page.once( 'dialog', async ( dialog ) => {
await dialog.accept();
resolve();
} );
} );
}

describe( 'Shared Blocks', () => {
beforeAll( async () => {
await newDesktopBrowserPage();
await newPost();
} );

beforeEach( async () => {
// Remove all blocks from the post so that we're working with a clean slate
await page.evaluate( () => {
const blocks = wp.data.select( 'core/editor' ).getBlocks();
const uids = blocks.map( ( block ) => block.uid );
wp.data.dispatch( 'core/editor' ).removeBlocks( uids );
} );
} );

it( 'can be created', async () => {
// Insert a paragraph block
await insertBlock( 'Paragraph' );
await page.keyboard.type( 'Hello there!' );

// Trigger isTyping = false
await page.mouse.move( 200, 300 );
await page.mouse.move( 250, 350 );

// Convert block to a shared block
await page.click( 'button[aria-label="More Options"]' );
const convertButton = await page.waitForXPath( '//button[text()="Convert to Shared Block"]' );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selecting elements looks like fun - have we considered using data attributes on our elements to make writing tests a bit easier? e.g. data-test-name: "convert-to-shared-block-button". We could also make test objects for the components containing the selectors so that tests are easier to write const convertButton = await page.waitForXPath( convertToSharedBlockButton.root );

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made an issue here:
#7974

await convertButton.click();

// Wait for creation to finish
await page.waitForXPath(
'//*[contains(@class, "notice-success")]/*[text()="Block created."]'
);

// Select all of the text in the title field by triple-clicking on it. We
// triple-click because, on Mac, Mod+A doesn't work. This step can be removed
// when https://github.com/WordPress/gutenberg/issues/7972 is fixed
await page.click( '.shared-block-edit-panel__title', { clickCount: 3 } );

// Give the shared block a title
await page.keyboard.type( 'Greeting block' );

// Save the shared block
const [ saveButton ] = await page.$x( '//button[text()="Save"]' );
await saveButton.click();

// Wait for saving to finish
await page.waitForXPath( '//button[text()="Edit"]' );

// Check that we have a shared block on the page
const block = await page.$( '.editor-block-list__block[data-type="core/block"]' );
expect( block ).not.toBeNull();

// Check that its title is displayed
const title = await page.$eval(
'.shared-block-edit-panel__info',
( element ) => element.innerText
);
expect( title ).toBe( 'Greeting block' );
} );

it( 'can be created with no title', async () => {
// Insert a paragraph block
await insertBlock( 'Paragraph' );
await page.keyboard.type( 'Hello there!' );

// Trigger isTyping = false
await page.mouse.move( 200, 300 );
await page.mouse.move( 250, 350 );

// Convert block to a shared block
await page.click( 'button[aria-label="More Options"]' );
const convertButton = await page.waitForXPath( '//button[text()="Convert to Shared Block"]' );
await convertButton.click();

// Wait for creation to finish
await page.waitForXPath(
'//*[contains(@class, "notice-success")]/*[text()="Block created."]'
);

// Save the shared block
const [ saveButton ] = await page.$x( '//button[text()="Save"]' );
await saveButton.click();

// Wait for saving to finish
await page.waitForXPath( '//button[text()="Edit"]' );

// Check that we have a shared block on the page
const block = await page.$( '.editor-block-list__block[data-type="core/block"]' );
expect( block ).not.toBeNull();

// Check that it is untitled
const title = await page.$eval(
'.shared-block-edit-panel__info',
( element ) => element.innerText
);
expect( title ).toBe( 'Untitled shared block' );
} );

it( 'can be inserted and edited', async () => {
// Insert the shared block we created above
await insertBlock( 'Greeting block' );
Comment on lines +121 to +123
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should ideally be no concept of "above" as assuming tests to be run in particular order (or even that any others are run at all). I should be able to change this to it.only and the test should be fine to run in isolation. Common behaviors should be established in lifecycle (beforeEach or beforeAll) or repeated in every test case.

Note: I'm encountering this in implementing a new end-to-end test case for verifying the fix at #21205. Ideally I'd like to iterate on the test case with it.only, but at least as currently presented, there's no prior art for me to leverage commonly available reusable blocks to work with. For the purposes of my test, I might just copy the logic from "can be created" to create the reusable block. It could be straight-forward enough to refactor to its own function; not sure if I'll do that or end up just following the pattern here of reusing the block created in an earlier test case once finished.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right, the setup code belongs in a beforeAll(). I think this might have been the first E2E test I ever wrote. Ah, to be young...

I created #21249 to track this.


// Put the shared block in edit mode
const [ editButton ] = await page.$x( '//button[text()="Edit"]' );
await editButton.click();

// Change the block's title
await page.keyboard.type( 'Surprised greeting block' );

// Change the block's content
await pressWithModifier( 'Shift', 'Tab' );
await page.keyboard.type( 'Oh! ' );

// Save the shared block
const [ saveButton ] = await page.$x( '//button[text()="Save"]' );
await saveButton.click();

// Wait for saving to finish
await page.waitForXPath( '//button[text()="Edit"]' );

// Check that we have a shared block on the page
const block = await page.$( '.editor-block-list__block[data-type="core/block"]' );
expect( block ).not.toBeNull();

// Check that its title is displayed
const title = await page.$eval(
'.shared-block-edit-panel__info',
( element ) => element.innerText
);
expect( title ).toBe( 'Surprised greeting block' );

// Check that its content is up to date
const text = await page.$eval(
'.editor-block-list__block[data-type="core/block"] .editor-rich-text',
( element ) => element.innerText
);
expect( text ).toMatch( 'Oh! Hello there!' );
} );

it( 'can be converted to a regular block', async () => {
// Insert the shared block we edited above
await insertBlock( 'Surprised greeting block' );

// Convert block to a regular block
await page.click( 'button[aria-label="More Options"]' );
const convertButton = await page.waitForXPath(
'//button[text()="Convert to Regular Block"]'
);
await convertButton.click();

// Check that we have a paragraph block on the page
const block = await page.$( '.editor-block-list__block[data-type="core/paragraph"]' );
expect( block ).not.toBeNull();

// Check that its content is up to date
const text = await page.$eval(
'.editor-block-list__block[data-type="core/paragraph"] .editor-rich-text',
( element ) => element.innerText
);
expect( text ).toMatch( 'Oh! Hello there!' );
} );

it( 'can be deleted', async () => {
// Insert the shared block we edited above
await insertBlock( 'Surprised greeting block' );

// Delete the block and accept the confirmation dialog
await page.click( 'button[aria-label="More Options"]' );
const convertButton = await page.waitForXPath( '//button[text()="Delete Shared Block"]' );
await Promise.all( [ waitForAndAcceptDialog(), convertButton.click() ] );

// Check that we have an empty post again
const block = await page.$$( '.editor-block-list__block' );
expect( block ).toHaveLength( 0 );

// Search for the block in the inserter
await searchForBlock( 'Surprised greeting block' );

// Check that we couldn't find it
const items = await page.$$(
'.editor-block-types-list__item[aria-label="Surprised greeting block"]'
);
expect( items ).toHaveLength( 0 );
} );
} );