2023-06-01 11:51:59 +00:00
|
|
|
|
/**
|
|
|
|
|
* External dependencies
|
|
|
|
|
*/
|
2023-06-27 10:01:38 +00:00
|
|
|
|
import { Page } from '@playwright/test';
|
2024-04-26 09:39:11 +00:00
|
|
|
|
import { Editor, expect, Admin } from '@wordpress/e2e-test-utils-playwright';
|
2023-06-27 10:01:38 +00:00
|
|
|
|
import { BlockRepresentation } from '@wordpress/e2e-test-utils-playwright/build-types/editor/insert-block';
|
2023-06-01 11:51:59 +00:00
|
|
|
|
|
2024-02-20 09:35:27 +00:00
|
|
|
|
/**
|
|
|
|
|
* Internal dependencies
|
|
|
|
|
*/
|
|
|
|
|
import type { TemplateType } from '../../utils/types';
|
|
|
|
|
|
2023-06-01 11:51:59 +00:00
|
|
|
|
export class EditorUtils {
|
|
|
|
|
editor: Editor;
|
2023-06-27 10:01:38 +00:00
|
|
|
|
page: Page;
|
2024-04-26 09:39:11 +00:00
|
|
|
|
admin: Admin;
|
|
|
|
|
constructor( editor: Editor, page: Page, admin: Admin ) {
|
2023-06-01 11:51:59 +00:00
|
|
|
|
this.editor = editor;
|
2023-06-27 10:01:38 +00:00
|
|
|
|
this.page = page;
|
2024-04-26 09:39:11 +00:00
|
|
|
|
this.admin = admin;
|
2023-06-01 11:51:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-07 17:32:18 +00:00
|
|
|
|
/**
|
|
|
|
|
* Check to see if there are any errors in the editor.
|
|
|
|
|
*/
|
|
|
|
|
async ensureNoErrorsOnBlockPage() {
|
|
|
|
|
const errorMessages = [
|
|
|
|
|
/This block contains unexpected or invalid content/gi,
|
|
|
|
|
/Your site doesn’t include support for/gi,
|
|
|
|
|
/There was an error whilst rendering/gi,
|
|
|
|
|
/This block has encountered an error and cannot be previewed/gi,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for ( const error of errorMessages ) {
|
|
|
|
|
if ( ( await this.editor.canvas.getByText( error ).count() ) > 0 ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-27 09:54:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Checks if the editor is inside an iframe.
|
|
|
|
|
*/
|
|
|
|
|
private async isEditorInsideIframe() {
|
|
|
|
|
try {
|
|
|
|
|
return ( await this.editor.canvas.locator( '*' ).count() ) > 0;
|
|
|
|
|
} catch ( e ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-01 11:51:59 +00:00
|
|
|
|
async getBlockByName( name: string ) {
|
2024-03-27 09:54:44 +00:00
|
|
|
|
if ( await this.isEditorInsideIframe() ) {
|
|
|
|
|
return this.editor.canvas.locator( `[data-type="${ name }"]` );
|
|
|
|
|
}
|
|
|
|
|
return this.page.locator( `[data-type="${ name }"]` );
|
2023-06-01 11:51:59 +00:00
|
|
|
|
}
|
2023-06-27 10:01:38 +00:00
|
|
|
|
|
2023-08-04 11:07:31 +00:00
|
|
|
|
async getBlockByTypeWithParent( name: string, parentName: string ) {
|
|
|
|
|
const parentBlock = await this.getBlockByName( parentName );
|
|
|
|
|
if ( ! parentBlock ) {
|
|
|
|
|
throw new Error( `Parent block "${ parentName }" not found.` );
|
|
|
|
|
}
|
2023-08-08 13:25:45 +00:00
|
|
|
|
const block = parentBlock.locator( `[data-type="${ name }"]` );
|
2023-08-04 11:07:31 +00:00
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-27 10:01:38 +00:00
|
|
|
|
// todo: Make a PR to @wordpress/e2e-test-utils-playwright to add this method.
|
|
|
|
|
/**
|
2024-02-01 16:55:38 +00:00
|
|
|
|
* Inserts a block inside a given client ID.
|
2023-06-27 10:01:38 +00:00
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
async insertBlock(
|
|
|
|
|
blockRepresentation: BlockRepresentation,
|
|
|
|
|
index?: string,
|
|
|
|
|
rootClientId?: string
|
|
|
|
|
) {
|
|
|
|
|
await this.page.evaluate(
|
|
|
|
|
( {
|
|
|
|
|
blockRepresentation: _blockRepresentation,
|
|
|
|
|
index: _index,
|
|
|
|
|
rootClientId: _rootClientId,
|
|
|
|
|
} ) => {
|
|
|
|
|
function recursiveCreateBlock( {
|
|
|
|
|
name,
|
|
|
|
|
attributes = {},
|
|
|
|
|
innerBlocks = [],
|
|
|
|
|
}: BlockRepresentation ): BlockRepresentation {
|
|
|
|
|
return window.wp.blocks.createBlock(
|
|
|
|
|
name,
|
|
|
|
|
attributes,
|
|
|
|
|
innerBlocks.map( ( innerBlock ) =>
|
|
|
|
|
recursiveCreateBlock( innerBlock )
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
const block = recursiveCreateBlock( _blockRepresentation );
|
|
|
|
|
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/block-editor' )
|
|
|
|
|
.insertBlock( block, _index, _rootClientId );
|
|
|
|
|
},
|
|
|
|
|
{ blockRepresentation, index, rootClientId }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-29 09:11:43 +00:00
|
|
|
|
async removeBlocks( { name }: { name: string } ) {
|
|
|
|
|
await this.page.evaluate(
|
|
|
|
|
( { name: _name } ) => {
|
|
|
|
|
const blocks = window.wp.data
|
|
|
|
|
.select( 'core/block-editor' )
|
|
|
|
|
.getBlocks() as ( BlockRepresentation & {
|
|
|
|
|
clientId: string;
|
|
|
|
|
} )[];
|
|
|
|
|
const matchingBlocksClientIds = blocks
|
|
|
|
|
.filter( ( block ) => {
|
|
|
|
|
return block && block.name === _name;
|
|
|
|
|
} )
|
|
|
|
|
.map( ( block ) => block?.clientId );
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/block-editor' )
|
|
|
|
|
.removeBlocks( matchingBlocksClientIds );
|
|
|
|
|
},
|
|
|
|
|
{ name }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-02 08:36:51 +00:00
|
|
|
|
async removeBlockByClientId( clientId: string ) {
|
|
|
|
|
await this.page.evaluate(
|
|
|
|
|
( { clientId: _clientId } ) => {
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/block-editor' )
|
|
|
|
|
.removeBlocks( _clientId );
|
|
|
|
|
},
|
|
|
|
|
{ clientId }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-28 10:04:28 +00:00
|
|
|
|
async closeModalByName( name: string ) {
|
|
|
|
|
const isModalOpen = await this.page.getByLabel( name ).isVisible();
|
|
|
|
|
|
|
|
|
|
// eslint-disable-next-line playwright/no-conditional-in-test
|
|
|
|
|
if ( isModalOpen ) {
|
|
|
|
|
await this.page
|
|
|
|
|
.getByLabel( name )
|
|
|
|
|
.getByRole( 'button', { name: 'Close' } )
|
|
|
|
|
.click();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-16 09:54:09 +00:00
|
|
|
|
async replaceBlockByBlockName( name: string, nameToInsert: string ) {
|
|
|
|
|
await this.page.evaluate(
|
|
|
|
|
( { name: _name, nameToInsert: _nameToInsert } ) => {
|
|
|
|
|
const blocks = window.wp.data
|
|
|
|
|
.select( 'core/block-editor' )
|
|
|
|
|
.getBlocks();
|
|
|
|
|
const firstMatchingBlock = blocks
|
|
|
|
|
.flatMap(
|
|
|
|
|
( {
|
|
|
|
|
innerBlocks,
|
|
|
|
|
}: {
|
|
|
|
|
innerBlocks: BlockRepresentation[];
|
|
|
|
|
} ) => innerBlocks
|
|
|
|
|
)
|
|
|
|
|
.find(
|
|
|
|
|
( block: BlockRepresentation ) => block.name === _name
|
|
|
|
|
);
|
|
|
|
|
const { clientId } = firstMatchingBlock;
|
|
|
|
|
const block = window.wp.blocks.createBlock( _nameToInsert );
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/block-editor' )
|
|
|
|
|
.replaceBlock( clientId, block );
|
|
|
|
|
},
|
|
|
|
|
{ name, nameToInsert }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-27 10:01:38 +00:00
|
|
|
|
async getBlockRootClientId( clientId: string ) {
|
|
|
|
|
return this.page.evaluate< string | null, string >( ( id ) => {
|
|
|
|
|
return window.wp.data
|
|
|
|
|
.select( 'core/block-editor' )
|
|
|
|
|
.getBlockRootClientId( id );
|
|
|
|
|
}, clientId );
|
|
|
|
|
}
|
2023-06-29 13:41:22 +00:00
|
|
|
|
|
2023-08-07 15:59:06 +00:00
|
|
|
|
/**
|
|
|
|
|
* Toggles the global inserter.
|
|
|
|
|
*/
|
|
|
|
|
async toggleGlobalBlockInserter() {
|
2024-03-27 09:54:44 +00:00
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', { name: 'Toggle block inserter' } )
|
|
|
|
|
.click();
|
2023-08-07 15:59:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks if the global inserter is open.
|
|
|
|
|
*
|
|
|
|
|
* @return {Promise<boolean>} Whether the inserter is open or not.
|
|
|
|
|
*/
|
|
|
|
|
async isGlobalInserterOpen() {
|
2024-03-27 09:54:44 +00:00
|
|
|
|
const button = this.page.getByRole( 'button', {
|
|
|
|
|
name: 'Toggle block inserter',
|
2023-08-07 15:59:06 +00:00
|
|
|
|
} );
|
2024-03-27 09:54:44 +00:00
|
|
|
|
|
|
|
|
|
return ( await button.getAttribute( 'aria-pressed' ) ) === 'true';
|
2023-08-07 15:59:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Opens the global inserter.
|
|
|
|
|
*/
|
|
|
|
|
async openGlobalBlockInserter() {
|
|
|
|
|
if ( ! ( await this.isGlobalInserterOpen() ) ) {
|
|
|
|
|
await this.toggleGlobalBlockInserter();
|
2024-05-14 08:23:17 +00:00
|
|
|
|
await this.page.locator( '.block-editor-inserter__menu' ).waitFor();
|
2023-08-07 15:59:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-29 13:41:22 +00:00
|
|
|
|
async enterEditMode() {
|
2023-08-10 23:28:38 +00:00
|
|
|
|
await this.editor.page
|
|
|
|
|
.getByRole( 'button', {
|
|
|
|
|
name: 'Edit',
|
|
|
|
|
exact: true,
|
|
|
|
|
} )
|
2024-03-27 09:54:44 +00:00
|
|
|
|
.dispatchEvent( 'click' );
|
|
|
|
|
|
2024-05-16 12:49:32 +00:00
|
|
|
|
const sidebar = this.page.locator( '.edit-site-layout__sidebar' );
|
|
|
|
|
const canvasLoader = this.page.locator( '.edit-site-canvas-loader' );
|
|
|
|
|
|
|
|
|
|
await sidebar.waitFor( {
|
|
|
|
|
state: 'hidden',
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
await canvasLoader.waitFor( {
|
2024-03-27 09:54:44 +00:00
|
|
|
|
state: 'hidden',
|
|
|
|
|
} );
|
2023-06-29 13:41:22 +00:00
|
|
|
|
}
|
2023-08-04 11:07:31 +00:00
|
|
|
|
|
|
|
|
|
async isBlockEarlierThan< T >(
|
|
|
|
|
containerBlock: T,
|
|
|
|
|
firstBlock: string,
|
|
|
|
|
secondBlock: string
|
|
|
|
|
) {
|
|
|
|
|
const container =
|
|
|
|
|
containerBlock instanceof Function
|
|
|
|
|
? await containerBlock()
|
|
|
|
|
: containerBlock;
|
|
|
|
|
|
|
|
|
|
if ( ! container ) {
|
|
|
|
|
throw new Error( 'Container block not found.' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const childBlocks = container.locator( ':scope > .wp-block' );
|
|
|
|
|
|
|
|
|
|
let firstBlockIndex = -1;
|
|
|
|
|
let secondBlockIndex = -1;
|
|
|
|
|
|
|
|
|
|
for ( let i = 0; i < ( await childBlocks.count() ); i++ ) {
|
|
|
|
|
const blockName = await childBlocks
|
|
|
|
|
.nth( i )
|
|
|
|
|
.getAttribute( 'data-type' );
|
|
|
|
|
|
|
|
|
|
if ( blockName === firstBlock ) {
|
|
|
|
|
firstBlockIndex = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( blockName === secondBlock ) {
|
|
|
|
|
secondBlockIndex = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( firstBlockIndex !== -1 && secondBlockIndex !== -1 ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( firstBlockIndex === -1 || secondBlockIndex === -1 ) {
|
|
|
|
|
throw new Error( 'Both blocks must exist within the editor' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return firstBlockIndex < secondBlockIndex;
|
|
|
|
|
}
|
2023-08-10 23:28:38 +00:00
|
|
|
|
|
2023-08-28 16:32:45 +00:00
|
|
|
|
async setLayoutOption(
|
|
|
|
|
option:
|
|
|
|
|
| 'Align Top'
|
|
|
|
|
| 'Align Bottom'
|
|
|
|
|
| 'Align Middle'
|
|
|
|
|
| 'Stretch to Fill'
|
|
|
|
|
) {
|
|
|
|
|
const button = this.page.locator(
|
|
|
|
|
"button[aria-label='Change vertical alignment']"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await button.click();
|
|
|
|
|
|
|
|
|
|
await this.page.getByText( option ).click();
|
|
|
|
|
}
|
2023-08-31 16:15:31 +00:00
|
|
|
|
|
|
|
|
|
async setAlignOption(
|
|
|
|
|
option: 'Align Left' | 'Align Center' | 'Align Right' | 'None'
|
|
|
|
|
) {
|
|
|
|
|
const button = this.page.locator( "button[aria-label='Align']" );
|
|
|
|
|
|
|
|
|
|
await button.click();
|
|
|
|
|
|
|
|
|
|
await this.page.getByText( option ).click();
|
|
|
|
|
}
|
2023-09-05 13:22:17 +00:00
|
|
|
|
|
2023-09-20 12:56:00 +00:00
|
|
|
|
async closeWelcomeGuideModal() {
|
2024-04-26 09:39:11 +00:00
|
|
|
|
await this.page.waitForFunction( () => {
|
|
|
|
|
return (
|
|
|
|
|
window.wp &&
|
|
|
|
|
window.wp.data &&
|
|
|
|
|
window.wp.data.dispatch( 'core/preferences' )
|
|
|
|
|
);
|
|
|
|
|
} );
|
2023-09-20 12:56:00 +00:00
|
|
|
|
|
2024-04-26 09:39:11 +00:00
|
|
|
|
// Disable the welcome guide for the site editor.
|
|
|
|
|
await this.page.evaluate( () => {
|
|
|
|
|
return Promise.all( [
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-site', 'welcomeGuide', false ),
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-site', 'welcomeGuideStyles', false ),
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-site', 'welcomeGuidePage', false ),
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-site', 'welcomeGuideTemplate', false ),
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-post', 'welcomeGuide', false ),
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-post', 'welcomeGuideStyles', false ),
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-post', 'welcomeGuidePage', false ),
|
|
|
|
|
|
|
|
|
|
window.wp.data
|
|
|
|
|
.dispatch( 'core/preferences' )
|
|
|
|
|
.set( 'core/edit-post', 'welcomeGuideTemplate', false ),
|
|
|
|
|
] );
|
|
|
|
|
} );
|
2023-09-20 12:56:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async transformIntoBlocks() {
|
2023-11-14 10:32:19 +00:00
|
|
|
|
// Select the block, so the button is visible.
|
2024-05-20 18:56:32 +00:00
|
|
|
|
const block = this.editor.canvas
|
2023-11-14 10:32:19 +00:00
|
|
|
|
.locator( `[data-type="woocommerce/legacy-template"]` )
|
|
|
|
|
.first();
|
2023-09-20 12:56:00 +00:00
|
|
|
|
|
2023-11-14 10:32:19 +00:00
|
|
|
|
if ( ! ( await block.isVisible() ) ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await this.editor.selectBlocks( block );
|
|
|
|
|
|
|
|
|
|
const transformButton = block.getByRole( 'button', {
|
|
|
|
|
name: 'Transform into blocks',
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
if ( transformButton ) {
|
|
|
|
|
await transformButton.click();
|
2023-09-20 12:56:00 +00:00
|
|
|
|
|
|
|
|
|
// save changes
|
|
|
|
|
await this.saveSiteEditorEntities();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This method is the same as the one in @wordpress/e2e-test-utils-playwright. But for some reason
|
|
|
|
|
// it doesn't work as expected when imported from there. For its first run we get the following error:
|
|
|
|
|
// Error: locator.waitFor: Target closed
|
|
|
|
|
async saveSiteEditorEntities() {
|
|
|
|
|
const editorTopBar = this.page.getByRole( 'region', {
|
|
|
|
|
name: 'Editor top bar',
|
|
|
|
|
} );
|
|
|
|
|
const savePanel = this.page.getByRole( 'region', {
|
|
|
|
|
name: 'Save panel',
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
// First Save button in the top bar.
|
|
|
|
|
await editorTopBar
|
|
|
|
|
.getByRole( 'button', { name: 'Save', exact: true } )
|
|
|
|
|
.click();
|
|
|
|
|
|
|
|
|
|
// Second Save button in the entities panel.
|
|
|
|
|
await savePanel
|
|
|
|
|
.getByRole( 'button', { name: 'Save', exact: true } )
|
|
|
|
|
.click();
|
|
|
|
|
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', { name: 'Dismiss this notice' } )
|
|
|
|
|
.getByText( 'Site updated.' )
|
|
|
|
|
.waitFor();
|
|
|
|
|
}
|
2023-12-22 08:33:18 +00:00
|
|
|
|
|
2024-02-20 09:35:27 +00:00
|
|
|
|
async visitTemplateEditor(
|
|
|
|
|
templateName: string,
|
|
|
|
|
templateType: TemplateType
|
|
|
|
|
) {
|
|
|
|
|
if ( templateType === 'wp_template_part' ) {
|
2024-04-26 09:39:11 +00:00
|
|
|
|
await this.admin.visitSiteEditor( {
|
|
|
|
|
path: `/${ templateType }/all`,
|
|
|
|
|
} );
|
2024-02-20 09:35:27 +00:00
|
|
|
|
const templateLink = this.page.getByRole( 'link', {
|
|
|
|
|
name: templateName,
|
|
|
|
|
exact: true,
|
|
|
|
|
} );
|
|
|
|
|
await templateLink.click();
|
|
|
|
|
} else {
|
2024-04-26 09:39:11 +00:00
|
|
|
|
await this.admin.visitSiteEditor( {
|
|
|
|
|
path: '/' + templateType,
|
|
|
|
|
} );
|
2024-02-20 09:35:27 +00:00
|
|
|
|
const templateButton = this.page.getByRole( 'button', {
|
|
|
|
|
name: templateName,
|
|
|
|
|
exact: true,
|
|
|
|
|
} );
|
|
|
|
|
await templateButton.click();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await this.enterEditMode();
|
|
|
|
|
|
|
|
|
|
// Verify we are editing the correct template and it has the correct title.
|
|
|
|
|
const templateTypeName =
|
|
|
|
|
templateType === 'wp_template' ? 'template' : 'template part';
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'heading', {
|
|
|
|
|
name: `Editing ${ templateTypeName }: ${ templateName }`,
|
|
|
|
|
} )
|
|
|
|
|
.waitFor();
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-08 09:18:33 +00:00
|
|
|
|
async revertTemplateCreation( templateName: string ) {
|
2024-04-24 12:57:18 +00:00
|
|
|
|
await this.page.getByPlaceholder( 'Search' ).fill( templateName );
|
|
|
|
|
|
2024-02-08 22:15:11 +00:00
|
|
|
|
const templateRow = this.page.getByRole( 'row' ).filter( {
|
2024-03-27 09:54:44 +00:00
|
|
|
|
has: this.page.getByRole( 'link', {
|
2024-02-08 22:15:11 +00:00
|
|
|
|
name: templateName,
|
|
|
|
|
exact: true,
|
|
|
|
|
} ),
|
2024-02-08 09:18:33 +00:00
|
|
|
|
} );
|
2024-03-27 09:54:44 +00:00
|
|
|
|
await templateRow.getByRole( 'button', { name: 'Delete' } ).click();
|
2024-02-08 09:18:33 +00:00
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', {
|
|
|
|
|
name: 'Delete',
|
|
|
|
|
} )
|
|
|
|
|
.click();
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', { name: 'Dismiss this notice' } )
|
|
|
|
|
.getByText( `"${ templateName }" deleted.` )
|
|
|
|
|
.waitFor();
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-10 15:51:53 +00:00
|
|
|
|
async revertTemplateCustomizations( templateName: string ) {
|
2024-04-09 15:03:00 +00:00
|
|
|
|
await this.page.getByPlaceholder( 'Search' ).fill( templateName );
|
|
|
|
|
|
2024-02-08 22:15:11 +00:00
|
|
|
|
const templateRow = this.page.getByRole( 'row' ).filter( {
|
2024-03-27 09:54:44 +00:00
|
|
|
|
has: this.page.getByRole( 'link', {
|
2024-02-08 22:15:11 +00:00
|
|
|
|
name: templateName,
|
|
|
|
|
exact: true,
|
|
|
|
|
} ),
|
2024-01-10 15:51:53 +00:00
|
|
|
|
} );
|
2024-04-09 15:03:00 +00:00
|
|
|
|
const resetButton = templateRow.getByLabel( 'Reset', { exact: true } );
|
|
|
|
|
const revertedNotice = this.page
|
2024-03-27 09:54:44 +00:00
|
|
|
|
.getByLabel( 'Dismiss this notice' )
|
2024-04-09 15:03:00 +00:00
|
|
|
|
.getByText( `"${ templateName }" reverted.` );
|
|
|
|
|
const savedButton = this.page.getByRole( 'button', { name: 'Saved' } );
|
2024-03-27 09:54:44 +00:00
|
|
|
|
|
|
|
|
|
await resetButton.click();
|
2024-04-09 15:03:00 +00:00
|
|
|
|
|
|
|
|
|
await expect( revertedNotice ).toBeVisible();
|
|
|
|
|
await expect( savedButton ).toBeVisible();
|
2024-01-10 15:51:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-29 09:11:43 +00:00
|
|
|
|
async updatePost() {
|
2024-03-27 09:54:44 +00:00
|
|
|
|
await this.page.getByRole( 'button', { name: 'Update' } ).click();
|
2024-01-29 09:11:43 +00:00
|
|
|
|
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', { name: 'Dismiss this notice' } )
|
|
|
|
|
.filter( { hasText: 'updated' } )
|
|
|
|
|
.waitFor();
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-22 08:33:18 +00:00
|
|
|
|
async publishAndVisitPost() {
|
|
|
|
|
await this.editor.publishPost();
|
|
|
|
|
const url = new URL( this.page.url() );
|
|
|
|
|
const postId = url.searchParams.get( 'post' );
|
|
|
|
|
await this.page.goto( `/?p=${ postId }`, { waitUntil: 'commit' } );
|
|
|
|
|
}
|
2023-12-28 10:33:53 +00:00
|
|
|
|
|
|
|
|
|
async openWidgetEditor() {
|
|
|
|
|
await this.page.goto( '/wp-admin/widgets.php' );
|
|
|
|
|
await this.closeModalByName( 'Welcome to block Widgets' );
|
|
|
|
|
}
|
2024-01-10 11:17:00 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Unlike the `insertBlock` method, which manipulates the block tree
|
|
|
|
|
* directly, this method simulates real user behavior when inserting a
|
|
|
|
|
* block to the editor by searching for block name then clicking on the
|
|
|
|
|
* first matching result.
|
|
|
|
|
*
|
|
|
|
|
* Besides, some blocks that manipulate their attributes after insertion
|
|
|
|
|
* aren't work probably with `insertBlock` as that method requires
|
|
|
|
|
* attributes object and uses that data to creat the block object.
|
|
|
|
|
*/
|
|
|
|
|
async insertBlockUsingGlobalInserter( blockTitle: string ) {
|
|
|
|
|
await this.openGlobalBlockInserter();
|
|
|
|
|
await this.page.getByPlaceholder( 'Search' ).fill( blockTitle );
|
2024-01-11 11:27:33 +00:00
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'option', { name: blockTitle, exact: true } )
|
|
|
|
|
.first()
|
|
|
|
|
.click();
|
2024-01-10 11:17:00 +00:00
|
|
|
|
}
|
2024-02-12 19:59:40 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Opens a specific Single Product template.
|
|
|
|
|
*/
|
|
|
|
|
async openSpecificProductTemplate(
|
|
|
|
|
productName: string,
|
|
|
|
|
productSlug: string,
|
|
|
|
|
createIfDoesntExist = true
|
|
|
|
|
) {
|
2024-04-26 09:39:11 +00:00
|
|
|
|
await this.admin.visitSiteEditor();
|
2024-02-12 19:59:40 +00:00
|
|
|
|
await this.page.getByRole( 'button', { name: 'Templates' } ).click();
|
|
|
|
|
|
|
|
|
|
const templateButton = this.page.getByRole( 'button', {
|
|
|
|
|
name: `Product: ${ productName }`,
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
// Template can be created only once. Go to template if exists,
|
|
|
|
|
// otherwise create one.
|
|
|
|
|
if ( await templateButton.isVisible() ) {
|
|
|
|
|
await templateButton.click();
|
|
|
|
|
await this.enterEditMode();
|
|
|
|
|
} else if ( createIfDoesntExist ) {
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', { name: 'Add New Template' } )
|
|
|
|
|
.click();
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', { name: 'Single Item: Product' } )
|
|
|
|
|
.click();
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'option', {
|
|
|
|
|
name: `${ productName } http://localhost:8889/product/${ productSlug }/`,
|
|
|
|
|
} )
|
|
|
|
|
.click();
|
|
|
|
|
await this.page
|
|
|
|
|
.getByRole( 'button', {
|
|
|
|
|
name: 'Skip',
|
|
|
|
|
} )
|
|
|
|
|
.click();
|
|
|
|
|
}
|
|
|
|
|
await this.closeWelcomeGuideModal();
|
|
|
|
|
}
|
2023-06-01 11:51:59 +00:00
|
|
|
|
}
|