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

Refactored e2e keyboard navigation util functions / tests #16707

Conversation

tjnicolaides
Copy link
Contributor

@tjnicolaides tjnicolaides commented Jul 22, 2019

Description

Per @gziolo's suggestion, refactored the keyboard navigability tests to make the individual assertions easier to reuse and to make the tab orders less brittle. There is now an additional test that checks the keyboard navigation tab order of many different types of content blocks.

Related PR: #13455

How has this been tested?

The test is passing when running npm run test-e2e.
It also returns no errors or warnings when running npm run lint-js.

Screenshots

This recording of the new test running in non-headless mode shows the script adding blocks and tabbing through them:
end to end test that adds one of every type of core content block, then tabs through them all in the correct order

Types of changes

  • This PR introduces a new e2e test: keyboard-navigable-content-editor.test.js
  • It abstracts many of the routine actions (such as tabThroughTextBlock, or insertAndPopulateBlock, and assertions (such as inserterToggleHasFocus or textContentAreasHaveFocus) into e2e-test-utils

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.

TJ Nicolaides and others added 16 commits January 23, 2019 17:12
…ThroughBlockMoverControl` and `tabThroughBlockToolbar` to the parent scope. Using pressKeyWithModifier within navigateToContentEditorTop.
…5-add-e2e-keyboard-navigation-util-functions

# Conflicts:
#	packages/e2e-tests/specs/keyboard-navigable-blocks.test.js
…olbar, tab-through-block-mover-control, keyboard-navigable-blocks-test. Add some detail to JSDocs
…-functions

# Conflicts:
#	packages/e2e-tests/specs/keyboard-navigable-blocks.test.js
@gziolo gziolo added [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. [Type] Code Quality Issues or PRs that relate to code quality [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). labels Jul 29, 2019
@gziolo
Copy link
Member

gziolo commented Jul 29, 2019

This is great work ❤️

I hope to find some time to give it a spin and perform in-depth testing later this week. This PR is quite big so it might take some time to land it unless you have some idea how to extract some chunk into smaller PRs.

@gziolo gziolo requested review from tellthemachines and a team July 29, 2019 13:04
@tjnicolaides
Copy link
Contributor Author

I'm glad to hear you say that - I'd let enough time pass that I was worried I had lost sight of what we really wanted in this PR. It's okay if this takes longer to get in - I'll keep it updated while it's in the review process. I see we already have a conflict, so I'll get on that. Thanks!

…-functions

# Conflicts:
#	packages/e2e-tests/specs/keyboard-navigable-blocks.test.js
Copy link
Contributor

@tellthemachines tellthemachines left a comment

Choose a reason for hiding this comment

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

I'm just about halfway through this so expect further comments, but in the name of getting things moving I'm posting what I've got so far.
Thanks for working on this, it's always great to see improvements to tests 🙂

packages/e2e-test-utils/src/external-wrapper-has-focus.js Outdated Show resolved Hide resolved
packages/e2e-test-utils/src/get-element-list.js Outdated Show resolved Hide resolved
await page.keyboard.type( content );

// if there are more contenteditable elements, select and populate them too:
const blocks = await textContentAreas( { empty: true } );
Copy link
Contributor

Choose a reason for hiding this comment

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

This should populate other content areas within the same block, is that correct? Yet I noticed when running keyboard-navigable-blocks.test.js in interactive mode that the citation field in the Quote block did not get populated. Shouldn't it have done so?

'.wp-block.is-selected [contenteditable]',
'.wp-block.is-typing [contenteditable]',
].map( ( selector ) => {
return empty ? selector + '[data-is-placeholder-visible="true"]' : selector;
Copy link
Contributor

Choose a reason for hiding this comment

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

Where is data-is-placeholder-visible expected to appear? I can't find it anywhere in the codebase.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey, sorry to just now be getting on these changes. data-is-placeholder-visible appears to be a tinymce thing. The project had some snapshot tests that displayed those attributes at one point: ad182a5

Copy link
Contributor

Choose a reason for hiding this comment

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

Yup, it's not being used. None of the files in that commit even exist anymore. So if you inspect the rich text elements with your browser dev tools, you can confirm that data-is-placeholder-visible never appears on any element.
That's why the blocks variable here is always an empty array, so the for loop underneath never runs, so the citation in the quote block doesn't get populated.

Copy link
Contributor

@tellthemachines tellthemachines left a comment

Choose a reason for hiding this comment

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

OK, done! Apart from the comments I left, my only general observation is it's not great to depend too much on static classnames to target elements in the e2e tests, as changing a class by itself should not cause a test to fail. But there are instances of that sprinkled throughout the tests, so not something to be fixed in this PR 🙂

packages/e2e-test-utils/src/tab-through-block-toolbar.js Outdated Show resolved Hide resolved

describe( 'Order of block keyboard navigation', () => {
beforeEach( async () => {
await createNewPost();
} );
it( 'permits tabbing through blocks in the expected order', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be better to break this up into a test for each block; possibly even a describe section for each block and a separate test for each part of the block. We should aim to have as few assertions as possible in each test.
As it stands, if I cause the test to fail by changing the classname for one of the block-mover__controls, it tells me nothing about which block the failure happened in, or if it failed for all the blocks, so it won't be very useful in identifying where the problem is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I hear what you're saying, and after starting to look at this this evening, here's what I think I am moving towards for this PR. Please let me know if I'm misunderstanding your recommendation at all, or if I have any opportunities to consolidate Jest logic:

describe( 'Order of heading block keyboard navigation', () => {
	beforeEach( async () => {
		await createNewPost();
	} );

	it( 'permits tabbing through heading blocks in the expected order', async () => {
		await insertAndPopulateBlock( 'Heading', 'Heading Block Content' );

		await navigateToContentEditorTop();

		await tabThroughTextBlock( 'core/heading', 'Heading Block Content' );
	} );
} );

describe( 'Order of quote block keyboard navigation', () => {
	beforeEach( async () => {
		await createNewPost();
	} );

	it( 'permits tabbing through quote blocks in the expected order', async () => {
		await insertAndPopulateBlock( 'Quote', 'Quote Block Content' );
		await insertAndPopulateBlock( 'Quote', 'Quote Block Content 2' );

		await navigateToContentEditorTop();

		await tabThroughTextBlock( 'core/quote', 'Quote Block Content' );
	} );
} );

describe( 'Order of list block keyboard navigation', () => {
	beforeEach( async () => {
		await createNewPost();
	} );

	it( 'permits tabbing through list blocks in the expected order', async () => {
		await insertAndPopulateBlock( 'List', 'List Block Content' );
		await insertAndPopulateBlock( 'List', 'List Block Content 2' );

		await navigateToContentEditorTop();

		await tabThroughTextBlock( 'core/list', 'List Block Content' );
	} );
} );

// ..... etc., etc.

Copy link
Member

Choose a reason for hiding this comment

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

How about:

describe( 'Order of block keyboard navigation', () => {
	beforeEach( async () => {
		await createNewPost();
	} );

	// ...

	it( 'permits tabbing through quote blocks in the expected order', async () => {
		await insertAndPopulateBlock( 'Quote', 'Quote Block Content' );
		await insertAndPopulateBlock( 'Quote', 'Quote Block Content 2' );

		await navigateToContentEditorTop();

		await tabThroughTextBlock( 'core/quote', 'Quote Block Content' );
	} );

	it( 'permits tabbing through list blocks in the expected order', async () => {
		await insertAndPopulateBlock( 'List', 'List Block Content' );
		await insertAndPopulateBlock( 'List', 'List Block Content 2' );

		await navigateToContentEditorTop();

		await tabThroughTextBlock( 'core/list', 'List Block Content' );
	} );
} );

This way you won't have to add several describe and beforeEach sections.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Update: I went the rest of the way and made the change here. Looking forward to seeing how this reports out in travis. https://github.com/WordPress/gutenberg/pull/16707/files#diff-448359ec0ae4a4e7ee9545bf9f9b43fc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you both for the feedback - this should be looking closer to what you had in mind, at this point: https://github.com/WordPress/gutenberg/pull/16707/files#diff-448359ec0ae4a4e7ee9545bf9f9b43fc

export async function textContentAreasHaveFocus( content ) {
const blocks = await textContentAreas( { empty: false } );
const isFocusedTextContentArea = await page.evaluate( () => document.activeElement.contentEditable );
const textContentAreaContent = await page.evaluate( () => document.activeElement.innerHTML );
Copy link
Contributor

Choose a reason for hiding this comment

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

isFocusedTextContentArea and textContentAreaContent need to be moved inside the loop, under the if block, otherwise their value won't be updated as you cycle through the content areas.

Copy link
Contributor

Choose a reason for hiding this comment

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

(Doing so will cause the tests to fail, which confirms my earlier observation that the citation in the Quote block isn't being populated.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll have a closer look at this, but when I'm looking at the tests run, I'm seeing the citation field of the quote block being populated with text as expected. It should be entering "Quote Block Content" into the main content area, as well as the lighter grey, smaller font size citation content area. Is this correct?
quote block with the main content text area and the citation content area populated with sample text

Copy link
Contributor

Choose a reason for hiding this comment

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

It should be entering "Quote Block Content" into the main content area, as well as the lighter grey, smaller font size citation content area.

That's what I was expecting it to do, but when I ran the tests on this branch locally the citation wasn't populated. And after making the change to the loop I mentioned above, the tests failed, which is consistent with the citation field being empty.


describe( 'Order of block keyboard navigation', () => {
beforeEach( async () => {
await createNewPost();
} );
it( 'permits tabbing through blocks in the expected order', async () => {
Copy link
Member

Choose a reason for hiding this comment

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

How about:

describe( 'Order of block keyboard navigation', () => {
	beforeEach( async () => {
		await createNewPost();
	} );

	// ...

	it( 'permits tabbing through quote blocks in the expected order', async () => {
		await insertAndPopulateBlock( 'Quote', 'Quote Block Content' );
		await insertAndPopulateBlock( 'Quote', 'Quote Block Content 2' );

		await navigateToContentEditorTop();

		await tabThroughTextBlock( 'core/quote', 'Quote Block Content' );
	} );

	it( 'permits tabbing through list blocks in the expected order', async () => {
		await insertAndPopulateBlock( 'List', 'List Block Content' );
		await insertAndPopulateBlock( 'List', 'List Block Content 2' );

		await navigateToContentEditorTop();

		await tabThroughTextBlock( 'core/list', 'List Block Content' );
	} );
} );

This way you won't have to add several describe and beforeEach sections.

packages/e2e-test-utils/src/tab-through-block.js Outdated Show resolved Hide resolved
packages/e2e-tests/specs/keyboard-navigable-blocks.test.js Outdated Show resolved Hide resolved
packages/e2e-test-utils/src/inserter-toggle-has-focus.js Outdated Show resolved Hide resolved
packages/e2e-test-utils/src/insert-and-populate-block.js Outdated Show resolved Hide resolved
@gziolo
Copy link
Member

gziolo commented Aug 27, 2019

This PR is getting closer to be ready to merge, great iterations 👍

I added mostly nitpicks to ensure we only expose general-purpose helpers which are named in a way where it's easier to identify what they do when located outside of the existing tests.

tjnicolaides and others added 8 commits August 27, 2019 00:38
…overControls to tabThroughBlockMovers. Changing the name of one describe block, and removing unnecessary nesting added to keyboard-navigable-blocks.test.js
…TextContentAreas. Updating e2e-test-utils/README
…-functions

# Conflicts:
#	packages/e2e-test-utils/README.md
#	packages/e2e-test-utils/src/index.js
Base automatically changed from master to trunk March 1, 2021 15:42
@youknowriad
Copy link
Contributor

In the mean time, we moved from puppeteer to playwright so if this PR still need to be merged, it will need to be redone entirely. So I'm just closing for now. Thanks for the efforts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. [Type] Code Quality Issues or PRs that relate to code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants