-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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 automatted tests for Nav block editable list view #49433
Conversation
Size Change: +476 B (0%) Total Size: 1.34 MB
ℹ️ View Unchanged
|
Flaky tests detected in d94e5c1. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4563456799
|
|
||
// The options menu button is a sibling of the menu item gridcell. | ||
const firstItemOptions = firstMenuItem | ||
.locator( '..' ) // parent selector. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL! neat
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same. Turns out reading the docs is useful 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: This technique assumes the structure of the button to be a direct child of the row, which might change as an implementation detail? I would probably refactor this to select the row
instead in the first place:
const firstMenuRow = page.getByRole( 'row' )
.filter({ has: firstMenuItem });
const firstItemOptions = firstMenuRow
.getByRole( 'button', {
name: 'Options for Page Link block',
} );
Isn't critical though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For whatever reason that didn't work. It ended up producing
getByRole( 'treegrid', { name: 'Block navigation structure' } )
.getByRole( 'row' )
.filter( {
has: getByRole( 'treegrid', { name: 'Block navigation structure' } )
.getByRole( 'gridcell', { name: 'Page Link link' } )
.filter( { hasText: 'Block 1 of 2, Level 1' } ),
} )
.getByRole( 'button', { name: 'Options for Page Link block' } );
|
||
// Grab the text from the first result so we can check it was inserted. | ||
const firstResultText = await firstResult | ||
.locator( '.block-editor-link-control__search-item-title' ) // this is the only way to get the label text without the URL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to find a different way to target this to avoid the CSS selector but I couldn't :S
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. There isn't a way which probably points to a flaw in the markup of the component. It's due an a11y review as part of #49091
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add a comment referring that PR so we can update the test once that gets merged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure there's an issue with the markup. It's a tricky one to solve.
You could possibly do something like this pseudocode:
const expectedPageTitle = 'My sample page';
await linkControl.search( expectedPageTitle );
await linkControl.selectOption( expectedPageTitle );
await expect( listView ).toHaveBlock( expectedPageTitle );
Have the test select a known page title, rather than trying to read the text from the option.
It might also be good to assert that the URL added is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would agree with @MaggieCabrera to add a comment referencing that PR, but it's non-blocking 👍 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have the test select a known page title, rather than trying to read the text from the option.
That might be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only thing is if we ever change the implementation of "Recently Added" results in Link UI the test would start failing.
That's why I wanted to get the first result's text. I can extract to a helper on the utility class if that helps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a getSearchResultText
method to the LinkControl
test util class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Nice work on making them so comprehensive.
I think it would be good to add a ListView utils class, as some of the locators for gridcells span multiple lines and are repeated a lot. Test readability is one of the main things that keeps them maintainable, IMO.
It could be done after the initial merge though, as it would be good to get this in before #49417 (as was mentioned on that PR).
@@ -317,3 +317,480 @@ test.describe( 'Navigation block', () => { | |||
} ); | |||
} ); | |||
} ); | |||
|
|||
test.describe( 'List view editing', () => { | |||
test( 'it should show a list view in the inspector controls', async ( { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test( 'it should show a list view in the inspector controls', async ( { | |
test( 'shows list view in the inspector controls', async ( { |
In most frameworks test
is just an alias for it
, so the word it
doesn't need to be in the description itself. I always think removing the word 'should' makes the description shorter and easier to read, so also suggesting that.
Maybe I should add some of this to the docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
await expect( | ||
listView | ||
.getByRole( 'gridcell', { | ||
name: 'Page Link link', | ||
} ) | ||
.filter( { | ||
hasText: 'Block 1 of 2, Level 1', // proxy for filtering by description. | ||
} ) | ||
.getByText( 'Top Level Item 1' ) | ||
).toBeVisible(); | ||
|
||
await expect( | ||
listView | ||
.getByRole( 'gridcell', { | ||
name: 'Submenu link', | ||
} ) | ||
.filter( { | ||
hasText: 'Block 2 of 2, Level 1', // proxy for filtering by description. | ||
} ) | ||
.getByText( 'Top Level Item 2' ) | ||
).toBeVisible(); | ||
|
||
await expect( | ||
listView | ||
.getByRole( 'gridcell', { | ||
name: 'Page Link link', | ||
} ) | ||
.filter( { | ||
hasText: 'Block 1 of 1, Level 2', // proxy for filtering by description. | ||
} ) | ||
.getByText( 'Test Submenu Item' ) | ||
).toBeVisible(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really nice. I wonder if there's a way to ensure that the blocks are in the right order, maybe by selecting an nth
row in the table as part of the selector.
It might also be good to port some of these tests over to the main List View once this PR is in, perhaps with groups and other blocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if there's a way to ensure that the blocks are in the right order, maybe by selecting an nth row in the table as part of the selector.
The tricky part is getting a list of gridcells for the blocks but not including other gridcells
. If you have that then you can do nth()
and assert on that.
I spent far too long trying to do that with @kevin940726 yesterday so ended up settling on this route.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty cool!
const blockResults = page.getByRole( 'listbox', { | ||
name: 'Blocks', | ||
} ); | ||
|
||
await expect( blockResults ).toBeVisible(); | ||
|
||
const blockResultOptions = blockResults.getByRole( 'option' ); | ||
|
||
// Expect to see the Page Link and Custom Link blocks as the nth(0) and nth(1) results. | ||
// This is important for usability as the Page Link block is the most likely to be used. | ||
await expect( blockResultOptions.nth( 0 ) ).toHaveText( 'Page Link' ); | ||
await expect( blockResultOptions.nth( 1 ) ).toHaveText( 'Custom Link' ); | ||
|
||
// Select the Page Link option. | ||
const pageLinkResult = blockResultOptions.nth( 0 ); | ||
await pageLinkResult.click(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some of these operations that are a bit more complex, it might help to include a utility class in the test file. Possibly one for LinkControl and one for ListView itself.
There's an example here:
gutenberg/test/e2e/specs/site-editor/style-variations.spec.js
Lines 215 to 234 in 9ee0f4b
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]' ); | |
} | |
} |
And here's where it gets configured:
gutenberg/test/e2e/specs/site-editor/style-variations.spec.js
Lines 6 to 10 in 9ee0f4b
test.use( { | |
siteEditorStyleVariations: async ( { page }, use ) => { | |
await use( new SiteEditorStyleVariations( { page } ) ); | |
}, | |
} ); |
I think it could also be worth considering moving the block's List View tests into a separate file to keep things tidy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't made any utilities yet. Curious to try that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made one for Link Control.
and one for ListView itself.
I decided this was too much for this PR. Going to do a follow up.
|
||
// Grab the text from the first result so we can check it was inserted. | ||
const firstResultText = await firstResult | ||
.locator( '.block-editor-link-control__search-item-title' ) // this is the only way to get the label text without the URL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure there's an issue with the markup. It's a tricky one to solve.
You could possibly do something like this pseudocode:
const expectedPageTitle = 'My sample page';
await linkControl.search( expectedPageTitle );
await linkControl.selectOption( expectedPageTitle );
await expect( listView ).toHaveBlock( expectedPageTitle );
Have the test select a known page title, rather than trying to read the text from the option.
It might also be good to assert that the URL added is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! LGTM! 👍 Thanks! ❤️
Should be visible by default. Left one test which will fail if the tab isn’t automatically pre-selected.
What?
Adds a series of tests to provide high level coverage for the editable list view in the Navigation block.
Why?
Currently this feature has no test coverage. These tests provide that.
Moreover, the
<OffcanvasEditor>
which currently powers the editable list view in the Nav block is due to be refactor to use the standard<ListView>
component. This refactoring would be a lot easier if the current functionality of the editable list view were covered by tests.How?
Adds Playwright e2e tests to cover the top level scenarios:
Testing Instructions
Run
Testing Instructions for Keyboard
Screenshots or screencast