woocommerce/plugins/woocommerce-blocks/tests/e2e/specs/backend/site-editing-templates.test.js

734 lines
20 KiB
JavaScript
Raw Normal View History

/* eslint-disable jest/no-conditional-expect */
/**
* External dependencies
*/
import { URL } from 'url';
import {
canvas,
Fix 404 and 500 errors in E2E test logs, editor and front-end. (https://github.com/woocommerce/woocommerce-blocks/pull/5989) * Change atomic blocks to not use custom webpack build paths we want to always load lazy loaded components from their default paths to avoid having to handle importing components in different ways for regular and atomic component packages * Add footer parts to test themes The Site Editor is expecting the footer parts to be there or it will try to load them anyways and throw a 404. It's not breaking, but it's polluting the console. * Use REST API to tear down the templates Previously, we used a util called `trashAllPosts` which navigated to the post UI and deleted all the posts to tear down any side-effects of template editing tests. However, with a [recent change](https://github.com/WordPress/wordpress-develop/commit/14e20f72b568cfb5a85f57c77eaa538c17a5f302), WP Core removed the UI for those and that made our tests meet a 500 error. Using the REST API should also make everything faster. * Remove deprecated pupeteer waitFor usage was still present in attribute-filter.test.js * Update package-lock.json * pin package versions * Unify all atomic blocks to register on php side * Remove Atomic Blcoks chunk_translation handling from AllBlocks Before it was responsible for enabling translations for all the atomic blocks * Add per atomic block chunk_translation registration * update @wordpress/e2e-test-utils to 6.0.2 * add optional puppeteer * pin workflows node version to 16.13.2 * upgrade package-lock * upgrade package-lock * set react and react-dom as peerDeps * remove atomic block registration Co-authored-by: Lucio Giannotta <lucio.giannotta@a8c.com> Co-authored-by: Luigi <gigitux@gmail.com>
2022-03-10 10:00:23 +00:00
deleteAllTemplates,
getCurrentSiteEditorContent,
insertBlock,
} from '@wordpress/e2e-test-utils';
import {
getNormalPagePermalink,
visitPostOfType,
} from '@woocommerce/blocks-test-utils';
/**
* Internal dependencies
*/
import {
BASE_URL,
DEFAULT_TIMEOUT,
filterCurrentBlocks,
getAllTemplates,
goToTemplateEditor,
goToTemplatesList,
GUTENBERG_EDITOR_CONTEXT,
saveTemplate,
useTheme,
} from '../../utils';
async function visitTemplateAndAddCustomParagraph(
templateSlug,
customText = CUSTOMIZED_STRING
) {
await goToTemplateEditor( {
postId: `woocommerce/woocommerce//${ templateSlug }`,
} );
await insertBlock( 'Paragraph' );
await page.keyboard.type( customText );
await saveTemplate();
}
function blockSelector( id ) {
return `[data-type="${ id }"]`;
}
function defaultTemplateProps( templateTitle ) {
return {
templateTitle,
addedBy: WOOCOMMERCE_ID,
hasActions: false,
};
}
function classicBlockSelector( title ) {
return `${ blockSelector(
'woocommerce/legacy-template'
) }[data-title="${ title }"]`;
}
const BLOCK_DATA = {
'archive-product': {
attributes: {
placeholder: 'archive-product',
template: 'archive-product',
title: 'WooCommerce Product Grid Block',
},
name: 'woocommerce/legacy-template',
},
'single-product': {
attributes: {
placeholder: 'single-product',
template: 'single-product',
title: 'WooCommerce Single Product Block',
},
name: 'woocommerce/legacy-template',
},
'taxonomy-product_cat': {
attributes: {
placeholder: 'archive-product',
template: 'taxonomy-product_cat',
title: 'WooCommerce Product Taxonomy Block',
},
name: 'woocommerce/legacy-template',
},
'taxonomy-product_tag': {
attributes: {
placeholder: 'archive-product',
template: 'taxonomy-product_tag',
title: 'WooCommerce Product Tag Block',
},
name: 'woocommerce/legacy-template',
},
'taxonomy-product_attribute': {
attributes: {
placeholder: 'archive-product',
template: 'taxonomy-product_attribute',
title: 'WooCommerce Product Attribute Block',
},
name: 'woocommerce/legacy-template',
},
'product-search-results': {
attributes: {
title: 'WooCommerce Product Search Results Block',
template: 'product-search-results',
placeholder: 'archive-product',
},
name: 'woocommerce/legacy-template',
},
};
const SELECTORS = {
blocks: {
paragraph: blockSelector( 'core/paragraph' ),
productArchive: classicBlockSelector(
'WooCommerce Product Grid Block'
),
singleProduct: classicBlockSelector(
'WooCommerce Single Product Block'
),
},
templates: {
templateActions:
'[aria-label="Templates list - Content"] [aria-label="Actions"]',
},
};
const CUSTOMIZED_STRING = 'My awesome customization';
const WOOCOMMERCE_ID = 'woocommerce/woocommerce';
const WOOCOMMERCE_PARSED_ID = 'WooCommerce';
/**
* This is a workaround to avoid the E2E test suite failing when the test site has Gutenberg enabled.
* The problem is that the current version of Gutenberg in WordPress Core and the version of the plugin Gutenberg generate different snapshots.
* It is not easy having different snapshots for the same test: theoretically, we should have a dedicated snapshot when Gutenberg is enabled and another one when Gutenberg is disabled.
* We can remove this workaround when WordPress 6.1 is released.
*
* @todo Remove runOnlyWhenGutenbergIsDisabled function and relative workarounds when WordPress 6.1 is released.
*/
const runOnlyWhenGutenbergIsDisabled = ( fn ) => {
if ( GUTENBERG_EDITOR_CONTEXT === 'core' ) {
fn();
}
};
describe.skip( 'Store Editing Templates', () => {
useTheme( 'emptytheme' );
describe( 'Single Product block template', () => {
beforeAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
} );
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
const EXPECTED_TEMPLATE = defaultTemplateProps( 'Single Product' );
await goToTemplatesList();
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
runOnlyWhenGutenbergIsDisabled( () =>
it( 'should contain the "WooCommerce Single Product Block" classic template', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//single-product',
} );
const [ classicBlock ] = await filterCurrentBlocks(
( block ) =>
block.name === BLOCK_DATA[ 'single-product' ].name
);
// Comparing only the `template` property currently
// because the other properties seem to be slightly unreliable.
// Investigation pending.
expect( classicBlock.attributes.template ).toBe(
BLOCK_DATA[ 'single-product' ].attributes.template
);
expect( await getCurrentSiteEditorContent() ).toMatchSnapshot();
} )
);
it( 'should show the action menu if the template has been customized by the user', async () => {
const EXPECTED_TEMPLATE = {
...defaultTemplateProps( 'Single Product' ),
hasActions: true,
};
await visitTemplateAndAddCustomParagraph( 'single-product' );
await goToTemplatesList( { waitFor: 'actions' } );
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
it( 'should preserve and correctly show the user customization on the back-end', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//single-product',
} );
await expect( canvas() ).toMatchElement(
SELECTORS.blocks.paragraph,
{
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
}
);
} );
it( 'should show the user customization on the front-end', async () => {
const exampleProductName = 'Woo Single #1';
await visitPostOfType( exampleProductName, 'product' );
const permalink = await getNormalPagePermalink();
await page.goto( permalink );
await expect( page ).toMatchElement( 'p', {
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
} );
} );
} );
describe( 'Product Catalog block template', () => {
beforeAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
} );
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
const EXPECTED_TEMPLATE = defaultTemplateProps( 'Product Catalog' );
await goToTemplatesList();
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
runOnlyWhenGutenbergIsDisabled( () =>
it( 'should contain the "WooCommerce Product Grid Block" classic template', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//archive-product',
} );
const [ classicBlock ] = await filterCurrentBlocks(
( block ) =>
block.name === BLOCK_DATA[ 'archive-product' ].name
);
expect( classicBlock.attributes.template ).toBe(
BLOCK_DATA[ 'archive-product' ].attributes.template
);
expect( await getCurrentSiteEditorContent() ).toMatchSnapshot();
} )
);
it( 'should show the action menu if the template has been customized by the user', async () => {
const EXPECTED_TEMPLATE = {
...defaultTemplateProps( 'Product Catalog' ),
hasActions: true,
};
await visitTemplateAndAddCustomParagraph( 'archive-product' );
await goToTemplatesList( { waitFor: 'actions' } );
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
it( 'should preserve and correctly show the user customization on the back-end', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//archive-product',
} );
await expect( canvas() ).toMatchElement(
SELECTORS.blocks.paragraph,
{
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
}
);
} );
it( 'should show the user customization on the front-end', async () => {
await page.goto( new URL( BASE_URL + '/shop' ) );
await expect( page ).toMatchElement( 'p', {
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
} );
} );
} );
describe( 'Product by Category block template', () => {
beforeAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
} );
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
const EXPECTED_TEMPLATE = defaultTemplateProps(
'Products by Category'
);
await goToTemplatesList();
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
runOnlyWhenGutenbergIsDisabled( () =>
it( 'should contain the "WooCommerce Product Taxonomy Block" classic template', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//taxonomy-product_cat',
} );
const [ classicBlock ] = await filterCurrentBlocks(
( block ) =>
block.name === BLOCK_DATA[ 'taxonomy-product_cat' ].name
);
expect( classicBlock.attributes.template ).toBe(
BLOCK_DATA[ 'taxonomy-product_cat' ].attributes.template
);
expect( await getCurrentSiteEditorContent() ).toMatchSnapshot();
} )
);
it( 'should show the action menu if the template has been customized by the user', async () => {
const EXPECTED_TEMPLATE = {
...defaultTemplateProps( 'Products by Category' ),
hasActions: true,
};
await visitTemplateAndAddCustomParagraph( 'taxonomy-product_cat' );
await goToTemplatesList( { waitFor: 'actions' } );
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
it( 'should preserve and correctly show the user customization on the back-end', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//taxonomy-product_cat',
} );
await expect( canvas() ).toMatchElement(
SELECTORS.blocks.paragraph,
{
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
}
);
} );
it( 'should show the user customization on the front-end', async () => {
await page.goto(
new URL( '/product-category/uncategorized', BASE_URL )
);
await expect( page ).toMatchElement( 'p', {
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
} );
} );
} );
describe( 'Products by Tag block template', () => {
beforeAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
} );
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
const EXPECTED_TEMPLATE = defaultTemplateProps( 'Products by Tag' );
await goToTemplatesList();
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
runOnlyWhenGutenbergIsDisabled( () =>
it( 'should contain the "WooCommerce Product Taxonomy Block" classic template', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//taxonomy-product_tag',
} );
const [ classicBlock ] = await filterCurrentBlocks(
( block ) =>
block.name === BLOCK_DATA[ 'taxonomy-product_tag' ].name
);
expect( classicBlock.attributes.template ).toBe(
BLOCK_DATA[ 'taxonomy-product_tag' ].attributes.template
);
expect( await getCurrentSiteEditorContent() ).toMatchSnapshot();
} )
);
it( 'should show the action menu if the template has been customized by the user', async () => {
const EXPECTED_TEMPLATE = {
...defaultTemplateProps( 'Products by Tag' ),
hasActions: true,
};
await visitTemplateAndAddCustomParagraph( 'taxonomy-product_tag' );
await goToTemplatesList( { waitFor: 'actions' } );
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
it( 'should preserve and correctly show the user customization on the back-end', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//taxonomy-product_tag',
} );
await expect( canvas() ).toMatchElement(
SELECTORS.blocks.paragraph,
{
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
}
);
} );
it( 'should show the user customization on the front-end', async () => {
await page.goto( new URL( '/product-tag/newest', BASE_URL ) );
await expect( page ).toMatchElement( 'p', {
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
} );
} );
} );
describe( 'Products by Attribute template', () => {
beforeAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
} );
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
const EXPECTED_TEMPLATE = defaultTemplateProps(
'Products by Attribute'
);
await goToTemplatesList();
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
runOnlyWhenGutenbergIsDisabled( () =>
it( 'should contain the "WooCommerce Product Taxonomy Block" classic template', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//taxonomy-product_attribute',
} );
const [ classicBlock ] = await filterCurrentBlocks(
( block ) =>
block.name ===
BLOCK_DATA[ 'taxonomy-product_attribute' ].name
);
expect( classicBlock.attributes.template ).toBe(
BLOCK_DATA[ 'taxonomy-product_attribute' ].attributes
.template
);
expect( await getCurrentSiteEditorContent() ).toMatchSnapshot();
} )
);
it( 'should show the action menu if the template has been customized by the user', async () => {
const EXPECTED_TEMPLATE = {
...defaultTemplateProps( 'Products by Attribute' ),
hasActions: true,
};
await visitTemplateAndAddCustomParagraph(
'taxonomy-product_attribute'
);
await goToTemplatesList( { waitFor: 'actions' } );
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
it( 'should preserve and correctly show the user customization on the back-end', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//taxonomy-product_attribute',
} );
await expect( canvas() ).toMatchElement(
SELECTORS.blocks.paragraph,
{
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
}
);
} );
it( 'should show the user customization on the front-end', async () => {
await page.goto( new URL( '/shade/red', BASE_URL ) );
await expect( page ).toMatchElement( 'p', {
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
} );
} );
} );
describe( 'Product Search Results block template', () => {
beforeAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
} );
it( 'default template from WooCommerce Blocks is available on an FSE theme', async () => {
const EXPECTED_TEMPLATE = defaultTemplateProps(
'Product Search Results'
);
await goToTemplatesList();
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
runOnlyWhenGutenbergIsDisabled( () =>
it( 'should contain the "WooCommerce Product Grid Block" classic template', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//product-search-results',
} );
const [ classicBlock ] = await filterCurrentBlocks(
( block ) =>
block.name === BLOCK_DATA[ 'archive-product' ].name
);
expect( classicBlock.attributes.template ).toBe(
BLOCK_DATA[ 'product-search-results' ].attributes.template
);
expect( await getCurrentSiteEditorContent() ).toMatchSnapshot();
} )
);
it( 'should show the action menu if the template has been customized by the user', async () => {
const EXPECTED_TEMPLATE = {
...defaultTemplateProps( 'Product Search Results' ),
hasActions: true,
};
await visitTemplateAndAddCustomParagraph(
'product-search-results'
);
await goToTemplatesList( { waitFor: 'actions' } );
const templates = await getAllTemplates();
try {
expect( templates ).toContainEqual( EXPECTED_TEMPLATE );
} catch ( ok ) {
// Depending on the speed of the execution and whether Chrome is headless or not
// the id might be parsed or not
expect( templates ).toContainEqual( {
...EXPECTED_TEMPLATE,
addedBy: WOOCOMMERCE_PARSED_ID,
} );
}
} );
it( 'should preserve and correctly show the user customization on the back-end', async () => {
await goToTemplateEditor( {
postId: 'woocommerce/woocommerce//product-search-results',
} );
await expect( canvas() ).toMatchElement(
SELECTORS.blocks.paragraph,
{
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
}
);
} );
it( 'should show the user customization on the front-end', async () => {
await page.goto(
new URL( '?s=shirt&post_type=product', BASE_URL )
);
await expect( page ).toMatchElement( 'p', {
text: CUSTOMIZED_STRING,
timeout: DEFAULT_TIMEOUT,
} );
} );
} );
} );