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

Navigation: e2e tests: default to classic menu #47867

Merged
merged 15 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import { activateTheme } from './themes';
import { deleteAllBlocks } from './blocks';
import { createComment, deleteAllComments } from './comments';
import { createPost, deleteAllPosts } from './posts';
import {
createClassicMenu,
createNavigationMenu,
deleteAllMenus,
} from './menus';
import { resetPreferences } from './preferences';
import { getSiteSettings, updateSiteSettings } from './site-settings';
import { deleteAllWidgets, addWidgetBlock } from './widgets';
Expand Down Expand Up @@ -125,6 +130,9 @@ class RequestUtils {
deleteAllBlocks = deleteAllBlocks;
createPost = createPost.bind( this );
deleteAllPosts = deleteAllPosts.bind( this );
createClassicMenu = createClassicMenu.bind( this );
createNavigationMenu = createNavigationMenu.bind( this );
deleteAllMenus = deleteAllMenus.bind( this );
createComment = createComment.bind( this );
deleteAllComments = deleteAllComments.bind( this );
deleteAllWidgets = deleteAllWidgets.bind( this );
Expand Down
108 changes: 108 additions & 0 deletions packages/e2e-test-utils-playwright/src/request-utils/menus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* Internal dependencies
*/
import type { RequestUtils } from './index';

export interface MenuData {
title: string;
content: string;
}
export interface NavigationMenu {
id: number;
content: string;
status: 'publish' | 'future' | 'draft' | 'pending' | 'private';
}

/**
* Create a classic menu
*
* @param {string} name Menu name.
* @return {string} Menu content.
*/
export async function createClassicMenu( this: RequestUtils, name: string ) {
const menuItems = [
{
title: 'Custom link',
url: 'http://localhost:8889/',
type: 'custom',
menu_order: 1,
},
];

const menu = await this.rest< NavigationMenu >( {
method: 'POST',
path: `/wp/v2/menus/`,
data: {
name,
},
} );

if ( menuItems?.length ) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure why this is needed? Isn't menuItems statically defined above?

await this.batchRest(
menuItems.map( ( menuItem ) => ( {
method: 'POST',
path: `/wp/v2/menu-items`,
body: {
menus: menu.id,
object_id: undefined,
...menuItem,
parent: undefined,
},
} ) )
);
}

return menu;
}

/**
* Create a navigation menu
*
* @param {Object} menuData navigation menu post data.
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Prefer TS types than JSDoc types. I think we can just omit the type here.

 * @param  menuData navigation menu post data.

* @return {string} Menu content.
*/
export async function createNavigationMenu(
this: RequestUtils,
menuData: MenuData
) {
return this.rest( {
method: 'POST',
path: `/wp/v2/navigation/`,
data: {
status: 'publish',
...menuData,
},
} );
}

/**
* Delete all navigation and classic menus
*
*/
export async function deleteAllMenus( this: RequestUtils ) {
const navMenus = await this.rest< NavigationMenu[] >( {
path: `/wp/v2/navigation/`,
} );

if ( navMenus?.length ) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: It's always going to return an array so let's remove the optional chaining here :)

await this.batchRest(
navMenus.map( ( menu ) => ( {
method: 'DELETE',
path: `/wp/v2/navigation/${ menu.id }?force=true`,
} ) )
);
}

const classicMenus = await this.rest< NavigationMenu[] >( {
path: `/wp/v2/menus/`,
} );

if ( classicMenus?.length ) {
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

await this.batchRest(
classicMenus.map( ( menu ) => ( {
method: 'DELETE',
path: `/wp/v2/menus/${ menu.id }?force=true`,
} ) )
);
}
}
112 changes: 57 additions & 55 deletions test/e2e/specs/editor/blocks/navigation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );

test.use( {
navBlockUtils: async ( { page, requestUtils }, use ) => {
await use( new NavigationBlockUtils( { page, requestUtils } ) );
navBlockUtils: async ( { editor, page, requestUtils }, use ) => {
await use( new NavigationBlockUtils( { editor, page, requestUtils } ) );
},
} );

Expand All @@ -17,16 +17,13 @@ test.describe(
await requestUtils.activateTheme( 'twentytwentythree' );
} );

test.beforeEach( async ( { admin, navBlockUtils } ) => {
await Promise.all( [
navBlockUtils.deleteAllNavigationMenus(),
admin.createNewPost(),
] );
test.beforeEach( async ( { requestUtils } ) => {
await Promise.all( [ requestUtils.deleteAllMenus() ] );
} );

test.afterAll( async ( { requestUtils, navBlockUtils } ) => {
test.afterAll( async ( { requestUtils } ) => {
await Promise.all( [
navBlockUtils.deleteAllNavigationMenus(),
requestUtils.deleteAllMenus(),
requestUtils.activateTheme( 'twentytwentyone' ),
] );
} );
Expand All @@ -36,8 +33,10 @@ test.describe(
} );

test( 'default to a list of pages if there are no menus', async ( {
admin,
editor,
} ) => {
await admin.createNewPost();
await editor.insertBlock( { name: 'core/navigation' } );

const pageListBlock = editor.canvas.getByRole( 'document', {
Expand All @@ -63,24 +62,23 @@ test.describe(
} );

test( 'default to my only existing menu', async ( {
admin,
editor,
page,
requestUtils,
navBlockUtils,
} ) => {
const createdMenu = await navBlockUtils.createNavigationMenu( {
await admin.createNewPost();
const createdMenu = await requestUtils.createNavigationMenu( {
title: 'Test Menu 1',
content:
'<!-- wp:navigation-link {"label":"WordPress","type":"custom","url":"http://www.wordpress.org/","kind":"custom","isTopLevelLink":true} /-->',
} );

await editor.insertBlock( { name: 'core/navigation' } );

//check the block in the canvas.
await expect(
editor.canvas.locator(
'role=textbox[name="Navigation link text"i] >> text="WordPress"'
)
).toBeVisible();
// Check the block in the canvas.
await navBlockUtils.selectNavigationItemOnCanvas( 'WordPress' );

// Check the markup of the block is correct.
await editor.publishPost();
Expand All @@ -92,13 +90,35 @@ test.describe(
] );
await page.locator( 'role=button[name="Close panel"i]' ).click();

//check the block in the frontend.
await page.goto( '/' );
await expect(
page.locator(
'role=navigation >> role=link[name="WordPress"i]'
)
).toBeVisible();
// Check the block in the frontend.
await navBlockUtils.selectNavigationItemOnFrontend( 'WordPress' );
} );

test( 'default to the only existing classic menu if there are no block menus', async ( {
admin,
editor,
requestUtils,
navBlockUtils,
} ) => {
// Create a classic menu.
await requestUtils.createClassicMenu( 'Test Classic 1' );
await admin.createNewPost();

await editor.insertBlock( { name: 'core/navigation' } );
// We need to check the canvas after inserting the navigation block to be able to target the block.
await expect.poll( editor.getBlocks ).toMatchObject( [
{
name: 'core/navigation',
},
] );

// Check the block in the canvas.
await editor.page.pause();
Copy link
Member

Choose a reason for hiding this comment

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

Forgot to delete?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ugh, again!

await navBlockUtils.selectNavigationItemOnCanvas( 'Custom link' );

// Check the block in the frontend.
await navBlockUtils.selectNavigationItemOnFrontend( 'Custom link' );
await editor.page.pause();
Copy link
Member

Choose a reason for hiding this comment

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

Ditto.

} );
}
);
Expand All @@ -110,39 +130,21 @@ class NavigationBlockUtils {
this.requestUtils = requestUtils;
}

/**
* Create a navigation menu
*
* @param {Object} menuData navigation menu post data.
* @return {string} Menu content.
*/
async createNavigationMenu( menuData ) {
return this.requestUtils.rest( {
method: 'POST',
path: `/wp/v2/navigation/`,
data: {
status: 'publish',
...menuData,
},
} );
async selectNavigationItemOnCanvas( name ) {
Copy link
Member

Choose a reason for hiding this comment

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

Prefer inlining one-liner assertions like this, makes the test a bit easier to read. selectNavigationItemOnCanvas doesn't really select anything here anyway 😆 .

await expect(
this.editor.canvas.locator(
`role=textbox[name="Navigation link text"i] >> text="${ name }"`
)
).toBeVisible();
}

/**
* Delete all navigation menus
*
*/
async deleteAllNavigationMenus() {
const menus = await this.requestUtils.rest( {
path: `/wp/v2/navigation/`,
} );

if ( ! menus?.length ) return;

await this.requestUtils.batchRest(
menus.map( ( menu ) => ( {
method: 'DELETE',
path: `/wp/v2/navigation/${ menu.id }?force=true`,
} ) )
);
async selectNavigationItemOnFrontend( name ) {
Copy link
Member

Choose a reason for hiding this comment

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

Ditto.

await this.page.goto( '/' );
await this.editor.page.pause();
Copy link
Member

Choose a reason for hiding this comment

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

Ditto.

await expect(
this.page.locator(
`role=navigation >> role=link[name="${ name }"i]`
)
).toBeVisible();
}
}