From 71137edf7bcf1dc0dd59b0acfef74fa2499cd663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Tue, 3 Mar 2026 16:10:40 +0100 Subject: [PATCH 01/10] Introduced some tools for users --- src/users/index.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/users/index.js diff --git a/src/users/index.js b/src/users/index.js new file mode 100644 index 0000000..01b4b29 --- /dev/null +++ b/src/users/index.js @@ -0,0 +1,91 @@ +// @ts-check +import { expect, Admin, RequestUtils } from '@wordpress/e2e-test-utils-playwright'; +import { execSync } from 'child_process'; + +/** + * @typedef {import('@playwright/test').Page} Page + * @typedef {Object} User + * @property {string} username The user name. + * @property {string} password The user's password. + */ + +/** + * Creates a translator user. + * + * @param {Array} langSlugs Language slugs. + * @param {string} userName User name. + * @return {Promise} The user. + */ +export async function createTranslator( langSlugs, userName ) { + userName = + typeof userName === `string` + ? userName + : `${ langSlugs.join( '-' ) }-translator`; + const email = `${ userName.toLowerCase() }@example.com`; + const resultCreateUser = execSync( + `npx wp-env run tests-cli wp user create ${ userName } ${ email } --role=editor`, + { encoding: 'utf8' } + ).trim(); + + expect( resultCreateUser ).toContain( 'Success: Created user' ); + + const { groups: user } = resultCreateUser.match( + /^Success: Created user (?\d+)\.\nPassword: (?[^ ]+)$/m + ); + + user.id = parseInt( user.id, 10 ); + user.username = userName; + + langSlugs.forEach( ( langSlug ) => { + const resultAddCap = execSync( + `npx wp-env run tests-cli wp user add-cap ${ user.id } translate_${ langSlug }`, + { encoding: 'utf8' } + ); + + expect( resultAddCap ).toContain( + `Success: Added 'translate_${ langSlug }' capability` + ); + } ); + + return user; +} + +/** + * Switches to the given user. + * Inspired from https://github.com/WordPress/gutenberg/blob/9ee534a42cd546fc2da23ce0f31607467c78c94c/test/e2e/specs/editor/collaboration/fixtures/collaboration-utils.ts#L104. + * + * @param {User} user The user to switch to. + * @param {Admin} admin The language of the post and page. + * @param {RequestUtils} requestUtils Gutenberg request utils object. + * @return {Promise} The page object. + */ +export async function switchToUser( user, admin, requestUtils ) { + const translatorContext = await admin.browser.newContext( { + baseURL: requestUtils.baseURL, + } ); + const page = await translatorContext.newPage(); + + await page.goto( '/wp-login.php' ); + await page.locator( '#user_login' ).fill( user.username ); + await page.locator( '#user_pass' ).fill( user.password ); + await page.getByRole( 'button', { name: 'Log In' } ).click(); + await page.waitForURL( '**/wp-admin/**' ); + + expect( + page.getByRole( 'menuitem', { + name: `Howdy, ${ user.username }`, + } ) + ).toBeVisible(); + + await page.waitForFunction( () => window?.wp?.data && window?.wp?.blocks ); + await page.evaluate( () => { + window.wp.data + .dispatch( 'core/preferences' ) + .set( 'core/edit-post', 'welcomeGuide', false ); + window.wp.data + .dispatch( 'core/preferences' ) + .set( 'core/edit-post', 'fullscreenMode', false ); + } ); + + return page; +} From 13a040c5fb70b719960949117a098f61d4234958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Tue, 3 Mar 2026 16:17:10 +0100 Subject: [PATCH 02/10] Lint --- src/users/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/users/index.js b/src/users/index.js index 01b4b29..81f8752 100644 --- a/src/users/index.js +++ b/src/users/index.js @@ -1,5 +1,9 @@ // @ts-check -import { expect, Admin, RequestUtils } from '@wordpress/e2e-test-utils-playwright'; +import { + expect, + Admin, + RequestUtils, +} from '@wordpress/e2e-test-utils-playwright'; import { execSync } from 'child_process'; /** From e951bc63bac0e0ac8c4cd6c6e3edd52f8b247ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Tue, 3 Mar 2026 16:30:20 +0100 Subject: [PATCH 03/10] Global export --- src/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index.js b/src/index.js index 77cb858..602fbb8 100644 --- a/src/index.js +++ b/src/index.js @@ -14,6 +14,7 @@ import { createTerm, } from './taxonomies/index.js'; import { fillInXliffExportForm, getXliffRegex } from './xliff/index.js'; +import { createTranslator, switchToUser } from './users/index.js'; import { getDownload, getStringFromFile } from './downloads/index.js'; import { getPlaywrightConfig } from './config/index.js'; import globalSetup from './setup/global.setup.js'; @@ -35,6 +36,8 @@ export { fillInXliffExportForm, getDownload, getXliffRegex, + createTranslator, + switchToUser, getStringFromFile, getPlaywrightConfig, globalSetup, From a78b437e11ebc3cd4027637a15cd3edaf3b26aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Tue, 3 Mar 2026 17:17:36 +0100 Subject: [PATCH 04/10] Removed unnecessary checks after `execSync()` --- src/users/index.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/users/index.js b/src/users/index.js index 81f8752..b8f8ade 100644 --- a/src/users/index.js +++ b/src/users/index.js @@ -31,8 +31,6 @@ export async function createTranslator( langSlugs, userName ) { { encoding: 'utf8' } ).trim(); - expect( resultCreateUser ).toContain( 'Success: Created user' ); - const { groups: user } = resultCreateUser.match( /^Success: Created user (?\d+)\.\nPassword: (?[^ ]+)$/m ); @@ -41,14 +39,10 @@ export async function createTranslator( langSlugs, userName ) { user.username = userName; langSlugs.forEach( ( langSlug ) => { - const resultAddCap = execSync( + execSync( `npx wp-env run tests-cli wp user add-cap ${ user.id } translate_${ langSlug }`, { encoding: 'utf8' } ); - - expect( resultAddCap ).toContain( - `Success: Added 'translate_${ langSlug }' capability` - ); } ); return user; From 32423f5d74152354b9ad0c09a56e532570aa745e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Wed, 4 Mar 2026 10:56:13 +0100 Subject: [PATCH 05/10] Simpler user creation --- src/users/index.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/users/index.js b/src/users/index.js index b8f8ade..a6ec5ef 100644 --- a/src/users/index.js +++ b/src/users/index.js @@ -18,7 +18,7 @@ import { execSync } from 'child_process'; * * @param {Array} langSlugs Language slugs. * @param {string} userName User name. - * @return {Promise} The user. + * @return {Promise} The user. */ export async function createTranslator( langSlugs, userName ) { userName = @@ -26,26 +26,19 @@ export async function createTranslator( langSlugs, userName ) { ? userName : `${ langSlugs.join( '-' ) }-translator`; const email = `${ userName.toLowerCase() }@example.com`; - const resultCreateUser = execSync( - `npx wp-env run tests-cli wp user create ${ userName } ${ email } --role=editor`, + const userId = parseInt( execSync( + `npx wp-env run tests-cli wp user create ${ userName } ${ email } --role=editor --user_pass=password --porcelain`, { encoding: 'utf8' } - ).trim(); - - const { groups: user } = resultCreateUser.match( - /^Success: Created user (?\d+)\.\nPassword: (?[^ ]+)$/m - ); - - user.id = parseInt( user.id, 10 ); - user.username = userName; + ).trim(), 10 ); langSlugs.forEach( ( langSlug ) => { execSync( - `npx wp-env run tests-cli wp user add-cap ${ user.id } translate_${ langSlug }`, + `npx wp-env run tests-cli wp user add-cap ${ userId } translate_${ langSlug }`, { encoding: 'utf8' } ); } ); - return user; + return { id: userId, username: userName, password: 'password' }; } /** From e7d041d958ea8af3b7a575df62166851f30aa767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Wed, 4 Mar 2026 11:13:40 +0100 Subject: [PATCH 06/10] CS --- src/users/index.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/users/index.js b/src/users/index.js index a6ec5ef..e786673 100644 --- a/src/users/index.js +++ b/src/users/index.js @@ -26,10 +26,13 @@ export async function createTranslator( langSlugs, userName ) { ? userName : `${ langSlugs.join( '-' ) }-translator`; const email = `${ userName.toLowerCase() }@example.com`; - const userId = parseInt( execSync( - `npx wp-env run tests-cli wp user create ${ userName } ${ email } --role=editor --user_pass=password --porcelain`, - { encoding: 'utf8' } - ).trim(), 10 ); + const userId = parseInt( + execSync( + `npx wp-env run tests-cli wp user create ${ userName } ${ email } --role=editor --user_pass=password --porcelain`, + { encoding: 'utf8' } + ).trim(), + 10 + ); langSlugs.forEach( ( langSlug ) => { execSync( From 61cdb97981dda7b3373c677310c5661b71f2ae16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Wed, 4 Mar 2026 11:14:44 +0100 Subject: [PATCH 07/10] Better default value --- src/users/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/users/index.js b/src/users/index.js index e786673..e51fc0a 100644 --- a/src/users/index.js +++ b/src/users/index.js @@ -17,14 +17,14 @@ import { execSync } from 'child_process'; * Creates a translator user. * * @param {Array} langSlugs Language slugs. - * @param {string} userName User name. - * @return {Promise} The user. + * @param {string} userName Optional. User name. + * @return {Promise} The user. */ -export async function createTranslator( langSlugs, userName ) { +export async function createTranslator( langSlugs, userName = '' ) { userName = - typeof userName === `string` - ? userName - : `${ langSlugs.join( '-' ) }-translator`; + '' === userName + ? `${ langSlugs.join( '-' ).toUpperCase() }-translator` + : userName; const email = `${ userName.toLowerCase() }@example.com`; const userId = parseInt( execSync( From 67ae0f77f7b7d177e9bbdb4e547a61ce5f5205b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Wed, 4 Mar 2026 11:32:29 +0100 Subject: [PATCH 08/10] Improved and fixed the doc --- src/users/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/users/index.js b/src/users/index.js index e51fc0a..62c5d34 100644 --- a/src/users/index.js +++ b/src/users/index.js @@ -18,7 +18,8 @@ import { execSync } from 'child_process'; * * @param {Array} langSlugs Language slugs. * @param {string} userName Optional. User name. - * @return {Promise} The user. + * Defaults to `XX-YY-translator`, where `XX` and `YY` are language slugs. + * @return {Promise} Promise resolving to a user object containing ID, user name, and password. */ export async function createTranslator( langSlugs, userName = '' ) { userName = @@ -49,9 +50,9 @@ export async function createTranslator( langSlugs, userName = '' ) { * Inspired from https://github.com/WordPress/gutenberg/blob/9ee534a42cd546fc2da23ce0f31607467c78c94c/test/e2e/specs/editor/collaboration/fixtures/collaboration-utils.ts#L104. * * @param {User} user The user to switch to. - * @param {Admin} admin The language of the post and page. + * @param {Admin} admin Instance of `Admin`. * @param {RequestUtils} requestUtils Gutenberg request utils object. - * @return {Promise} The page object. + * @return {Promise} Promise resolving to the `Page` object. */ export async function switchToUser( user, admin, requestUtils ) { const translatorContext = await admin.browser.newContext( { From b62615c45c15cc63694de6b80b03567a1830564f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Wed, 4 Mar 2026 11:33:46 +0100 Subject: [PATCH 09/10] Added doc to `README.md` --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index b704d05..08e9685 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,27 @@ Reads a file and returns its contents as a string. Global setup function for Playwright tests. Ensures fixtures are deleted and global context is set up properly. +#### 👤 User Utilities + +##### `createTranslator( langSlugs, userName = '' )` + +Creates a translator user, based on the `editor` role. + +- **Parameters:** + - `langSlugs`: List of language slugs. + - `userName`: Optional. A user name. Defaults to `XX-YY-translator`, where `XX` and `YY` are language slugs. +- **Returns:** Promise resolving to a user object containing ID, user name, and password. + +##### `switchToUser( user, admin, requestUtils )` + +Switches to the given user. + +- **Parameters:** + - `user`: The user to switch to (an object containing a user name and a password). + - `admin`: Instance of `Admin`. + - `requestUtils`: Gutenberg request utils object. +- **Returns:** Promise resolving to the `Page` object. + #### 💡 Usage Example ```javascript From 0fe3655344ffe19d4a4ccc3edd347564731fed27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Viguier?= Date: Wed, 4 Mar 2026 11:40:36 +0100 Subject: [PATCH 10/10] ffs --- src/users/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/users/index.js b/src/users/index.js index 62c5d34..c96bd61 100644 --- a/src/users/index.js +++ b/src/users/index.js @@ -18,7 +18,7 @@ import { execSync } from 'child_process'; * * @param {Array} langSlugs Language slugs. * @param {string} userName Optional. User name. - * Defaults to `XX-YY-translator`, where `XX` and `YY` are language slugs. + * Defaults to `XX-YY-translator`, where `XX` and `YY` are language slugs. * @return {Promise} Promise resolving to a user object containing ID, user name, and password. */ export async function createTranslator( langSlugs, userName = '' ) {