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

Migrate mention to Playwright #39712

Closed
wants to merge 2 commits into from
Closed
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
@@ -0,0 +1,15 @@
/**
* Clicks the default block appender.
*
* @this {import('.').PageUtils}
*/
export async function clickBlockAppender() {
// The block appender is only visible when there's no selection.
await this.page.evaluate( () =>
window.wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock()
);
const appender = await this.page.waitForSelector(
'.block-editor-default-block-appender__content'
);
await appender.click();
}
46 changes: 46 additions & 0 deletions packages/e2e-test-utils-playwright/src/page/delete-user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Delete a user account.
*
* @this {import('.').PageUtils}
* @param {string} username User name.
*/
export async function deleteUser( username ) {
await this.switchUserToAdmin();
await this.visitAdminPage( 'users.php' );

const [ userLink ] = await this.page.$x(
`//td[@data-colname="Username"]//a[contains(text(), "${ username }")]`
);

if ( ! userLink ) {
await this.switchUserToTest();
return;
}

// Focus to unveil actions.
await userLink.focus();

// Tab twice to focus 'Delete'
await this.page.keyboard.press( 'Tab' );
await this.page.keyboard.press( 'Tab' );

await Promise.all( [
this.page.keyboard.press( 'Enter' ),
this.page.waitForNavigation( { waitUntil: 'networkidle0' } ),
] );

// If there's content owned by this user, delete it.
const deleteContentRadioButton = await this.page.$(
'input[type="radio"][name="delete_option"][value="delete"]'
);
if ( deleteContentRadioButton ) {
await deleteContentRadioButton.click();
}

// Confirm.
await Promise.all( [
this.page.click( 'input#submit' ),
this.page.waitForNavigation( { waitUntil: 'networkidle0' } ),
] );
await this.switchUserToTest();
}
17 changes: 17 additions & 0 deletions packages/e2e-test-utils-playwright/src/page/get-current-user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Get the username of the user that's currently logged into WordPress (if any).
*
* @this {import('.').PageUtils}
* @return {string?} username The user that's currently logged into WordPress (if any).
*/
export async function getCurrentUser() {
const cookies = await this.context.cookies();
const cookie = cookies.find(
( c ) => !! c?.name?.startsWith( 'wordpress_logged_in_' )
);

if ( ! cookie?.value ) {
return;
}
return decodeURIComponent( cookie.value ).split( '|' )[ 0 ];
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Returns a promise which resolves with the edited post content (HTML string).
*
* @this {import('./').PageUtils}
* @this {import('.').PageUtils}
* @return {Promise} Promise resolving with post content markup.
*/
export async function getEditedPostContent() {
Expand Down
20 changes: 17 additions & 3 deletions packages/e2e-test-utils-playwright/src/page/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ import { openPreviewPage } from './preview';
import { setBrowserViewport } from './set-browser-viewport';
import { showBlockToolbar } from './show-block-toolbar';
import { visitAdminPage } from './visit-admin-page';
import { clickBlockToolbarButton } from './click-block-toolbar-button';
import { clickBlockAppender } from './click-block-appender';
import { createNewPost } from './create-new-post';
import { getCurrentUser } from './get-current-user';
import { loginUser } from './login-user';
import { showBlockToolbar } from './show-block-toolbar';
import { switchUserToAdmin } from './switch-user-to-admin';
import { switchUserToTest } from './switch-user-to-test';

class PageUtils {
browser: Browser;
Expand All @@ -43,9 +51,15 @@ class PageUtils {
setClipboardData = setClipboardData;
showBlockToolbar = showBlockToolbar;
visitAdminPage = visitAdminPage;
openDocumentSettingsSidebar = openDocumentSettingsSidebar;
openPreviewPage = openPreviewPage;
setBrowserViewport = setBrowserViewport;
clickBlockAppender = clickBlockAppender;
clickBlockToolbarButton = clickBlockToolbarButton;
createNewPost = createNewPost;
getCurrentUser = getCurrentUser;
loginUser = loginUser;
showBlockToolbar = showBlockToolbar;
switchUserToAdmin = switchUserToAdmin;
switchUserToTest = switchUserToTest;

}

export { PageUtils };
30 changes: 30 additions & 0 deletions packages/e2e-test-utils-playwright/src/page/login-user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Internal dependencies
*/
import { WP_USERNAME, WP_PASSWORD } from '../config';

/**
* Performs log in with specified username and password.
*
* @this {import('.').PageUtils}
* @param {?string} username String to be used as user credential.
* @param {?string} password String to be used as user credential.
*/
export async function loginUser(
username = WP_USERNAME,
password = WP_PASSWORD
) {
if ( ! this.isCurrentURL( 'wp-login.php' ) ) {
await this.page.goto( 'wp-login.php' );
}

await this.page.press( '#user_login', 'Control+A' );
await this.page.type( '#user_login', username );
await this.page.press( '#user_pass', 'Control+A' );
await this.page.type( '#user_pass', password );

await Promise.all( [
this.page.waitForNavigation(),
this.page.click( '#wp-submit' ),
] );
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* The block toolbar is not always visible while typing.
* Call this function to reveal it.
*
* @this {import('./').PageUtils}
* @this {import('.').PageUtils}
*/
export async function showBlockToolbar() {
// Move the mouse to disable the isTyping mode. We need at least three
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Internal dependencies
*/
import { WP_ADMIN_USER } from '../config';

/**
* Switches the current user to the admin user (if the user
* running the test is not already the admin user).
*
* @this {import('.').PageUtils}
*/
export async function switchUserToAdmin() {
if ( ( await this.getCurrentUser() ) === WP_ADMIN_USER.username ) {
return;
}
await this.loginUser( WP_ADMIN_USER );
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Internal dependencies
*/
import { WP_USERNAME } from '../config';

/**
* Switches the current user to whichever user we should be
* running the tests as (if we're not already that user).
*
* @this {import('.').PageUtils}
*/
export async function switchUserToTest() {
if ( ( await this.getCurrentUser() ) === WP_USERNAME ) {
return;
}
await this.loginUser();
}
10 changes: 6 additions & 4 deletions packages/e2e-test-utils-playwright/src/request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import { deleteAllTemplates } from './templates';
import { activateTheme } from './themes';
import { deleteAllBlocks } from './blocks';
import { deleteAllPosts } from './posts';
import { deleteAllWidgets, addWidgetBlock } from './widgets';
import { deleteAllWidgets } from './widgets';
import { getUserID, createUser, deleteUser } from './users';

interface StorageState {
cookies: Cookie[];
Expand All @@ -35,7 +36,7 @@ class RequestUtils {
baseURL?: string;

pluginsMap: Record< string, string > | null = null;

userID?: number;
static async setup( {
user,
storageStatePath,
Expand Down Expand Up @@ -118,8 +119,9 @@ class RequestUtils {
deleteAllBlocks = deleteAllBlocks;
deleteAllPosts = deleteAllPosts;
deleteAllWidgets = deleteAllWidgets;
addWidgetBlock = addWidgetBlock;
deleteAllTemplates = deleteAllTemplates;
createUser = createUser;
deleteUser = deleteUser;
getUserID = getUserID;
}

export type { StorageState };
Expand Down
55 changes: 55 additions & 0 deletions packages/e2e-test-utils-playwright/src/request/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Internal dependencies
*/
import type { RequestUtils } from './index';

async function getUserID( this: RequestUtils, username: string ) {
// Get User Details
// https://developer.wordpress.org/rest-api/reference/users/#retrieve-a-user
const user = await this.rest( {
method: 'GET',
path: '/wp/v2/users',
params: {
search: username,
},
} );
this.userID = user.ID;

return this.userID;
}

async function createUser(
this: RequestUtils,
username: string,
firstName: string,
lastName: string
) {
// Create User
// https://developer.wordpress.org/rest-api/reference/users/#create-a-user
await this.rest( {
method: 'POST',
path: '/wp/v2/users',
params: {
username,
first_name: firstName,
last_name: lastName,
email: username + '@example.com',
password: 'secret',
},
} );
}

async function deleteUser( this: RequestUtils, username: string ) {
const userID = await this.getUserID( username );
if ( ! userID ) {
throw new Error( `The user "${ username }" doesn't exist` );
}
// Create User
// https://developer.wordpress.org/rest-api/reference/users/#create-a-user
await this.rest( {
method: 'DELETE',
path: `/wp/v2/users/${ userID }`,
} );
}

export { getUserID, createUser, deleteUser };
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ export async function addWidgetBlock( serializedBlock, widgetAreaId ) {
},
} );
}

71 changes: 71 additions & 0 deletions test/e2e/specs/editor/various/mentions.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* WordPress dependencies
*/
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );

test.describe( 'autocomplete mentions', () => {
test.beforeAll( async ( { requestUtils } ) => {
await requestUtils.createUser( 'testuser', 'Jane', 'Doe' );
} );

test.beforeEach( async ( { pageUtils } ) => {
await pageUtils.createNewPost();
} );

test.afterAll( async ( { requestUtils } ) => {
await requestUtils.deleteUser( 'testuser' );
} );

test( 'should insert mention', async ( { page, pageUtils } ) => {
await pageUtils.clickBlockAppender();
await page.keyboard.type( 'I am @a' );
await page.waitForSelector( '.components-autocomplete__result' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '.' );
expect( await pageUtils.getEditedPostContent() )
.toMatchInlineSnapshot( `
"<!-- wp:paragraph -->
<p>I am @admin.</p>
<!-- /wp:paragraph -->"
` );
} );

test( 'should insert mention between two other words', async ( {
page,
pageUtils,
} ) => {
await pageUtils.clickBlockAppender();
await page.keyboard.type( 'Stuck in the middle with you.' );
await page.pressKeyTimes( 'ArrowLeft', 'you.'.length );
await page.keyboard.type( '@j' );
await page.waitForSelector( '.components-autocomplete__result' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( ' ' );
expect( await pageUtils.getEditedPostContent() )
.toMatchInlineSnapshot( `
"<!-- wp:paragraph -->
<p>Stuck in the middle with @testuser you.</p>
<!-- /wp:paragraph -->"
` );
} );

test( 'should insert two subsequent mentions', async ( {
page,
pageUtils,
} ) => {
await pageUtils.clickBlockAppender();
await page.keyboard.type( 'I am @j' );
await page.waitForSelector( '.components-autocomplete__result' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( ' @a' );
await page.waitForSelector( '.components-autocomplete__result' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '.' );
expect( await pageUtils.getEditedPostContent() )
.toMatchInlineSnapshot( `
"<!-- wp:paragraph -->
<p>I am @testuser @admin.</p>
<!-- /wp:paragraph -->"
` );
} );
} );