Product Collection: add e2e tests with all product elements included (#45623)
* Prepare test cases * Shorten out the test description * Add first test in a post with dummy expect * Verify all content is displayed * Add the test in Product Archive and Home Page * Add changelog * Add tag to Beanie product * Switch to Beanie which is on sale to verify on sale badge * Add comments to explain the expects * Adjust the expected content * Switch to lower case in expect * Switch from woocommerce/product-summary to core/post-excerpt * Adjust products.sh * Improve method waiting for products to show so it;'s deterministic * Refresh locators in template * Remove unnecessary check * Eslint disable: expects are extracted to function so disable eslint compaining there's no expect * Adjust other test after amending products setup * Change the verify happening in a wrong place * Tests adjustments * Revert Blog Home template before performing a test * Fix other tests
This commit is contained in:
parent
72f5db9b6d
commit
6cb52c00c0
|
@ -22,12 +22,13 @@ image3=$(wp post list --post_type=attachment --field=ID --name="hoodie-2.jpg" --
|
|||
wp post meta update $hoodie_product_id _product_image_gallery "$image1,$image2,$image3"
|
||||
|
||||
# Create a tag, so we can add tests for tag-related blocks and templates.
|
||||
beanie_product_id=$(wp post list --post_type=product --field=ID --name="Beanie" --format=ids)
|
||||
tag_id=$(wp wc product_tag create --name="Recommended" --slug="recommended" --description="Curated products selected by our experts" --porcelain --user=1)
|
||||
wp wc product update $hoodie_product_id --tags="[ { \"id\": $tag_id } ]" --user=1
|
||||
wp wc product update $beanie_product_id --tags="[ { \"id\": $tag_id } ]" --user=1
|
||||
|
||||
# This is a non-hacky work around to set up the cross sells product.
|
||||
cap_product_id=$(wp post list --post_type=product --field=ID --name="Cap" --format=ids)
|
||||
beanie_product_id=$(wp post list --post_type=product --field=ID --name="Beanie" --format=ids)
|
||||
wp post meta update $beanie_product_id _crosssell_ids "$cap_product_id"
|
||||
|
||||
# Set a product out of stock
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { test as base, expect } from '@woocommerce/e2e-playwright-utils';
|
||||
import type { Request } from '@playwright/test';
|
||||
import type { Request, Locator } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -47,6 +47,108 @@ test.describe( 'Product Collection', () => {
|
|||
await expect( pageObject.addToCartButtons ).toHaveCount( 9 );
|
||||
} );
|
||||
|
||||
test.describe( 'Renders correctly with all Product Elements', async () => {
|
||||
const insertProductElements = async (
|
||||
pageObject: ProductCollectionPage
|
||||
) => {
|
||||
// By default there are inner blocks:
|
||||
// - woocommerce/product-image
|
||||
// - core/post-title
|
||||
// - woocommerce/product-price
|
||||
// - woocommerce/product-button
|
||||
// We're adding remaining ones
|
||||
const productElements = [
|
||||
{ name: 'woocommerce/product-rating', attributes: {} },
|
||||
{ name: 'woocommerce/product-sku', attributes: {} },
|
||||
{ name: 'woocommerce/product-stock-indicator', attributes: {} },
|
||||
{ name: 'woocommerce/product-sale-badge', attributes: {} },
|
||||
{
|
||||
name: 'core/post-excerpt',
|
||||
attributes: {
|
||||
__woocommerceNamespace:
|
||||
'woocommerce/product-collection/product-summary',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'core/post-terms',
|
||||
attributes: { term: 'product_tag' },
|
||||
},
|
||||
{
|
||||
name: 'core/post-terms',
|
||||
attributes: { term: 'product_cat' },
|
||||
},
|
||||
];
|
||||
|
||||
await Promise.all(
|
||||
productElements.map( async ( productElement ) => {
|
||||
await pageObject.insertBlockInProductCollection(
|
||||
productElement
|
||||
);
|
||||
} )
|
||||
);
|
||||
};
|
||||
|
||||
const verifyProductContent = async ( product: Locator ) => {
|
||||
await expect( product ).toContainText( 'Beanie' ); // core/post-title
|
||||
await expect( product ).toContainText(
|
||||
'$20.00 Original price was: $20.00.$18.00Current price is: $18.00.'
|
||||
); // woocommerce/product-price
|
||||
await expect( product ).toContainText( 'woo-beanie' ); // woocommerce/product-sku
|
||||
await expect( product ).toContainText( 'In stock' ); // woocommerce/product-stock-indicator
|
||||
await expect( product ).toContainText(
|
||||
'This is a simple product.'
|
||||
); // core/post-excerpt
|
||||
await expect( product ).toContainText( 'Accessories' ); // core/post-terms - product_cat
|
||||
await expect( product ).toContainText( 'Recommended' ); // core/post-terms - product_tag
|
||||
await expect( product ).toContainText( 'SaleProduct on sale' ); // woocommerce/product-sale-badge
|
||||
await expect( product ).toContainText( 'Add to cart' ); // woocommerce/product-button
|
||||
};
|
||||
|
||||
// Expects are collected in verifyProductContent function
|
||||
// eslint-disable-next-line playwright/expect-expect
|
||||
test( 'In a post', async ( { pageObject } ) => {
|
||||
await pageObject.createNewPostAndInsertBlock();
|
||||
await insertProductElements( pageObject );
|
||||
await pageObject.publishAndGoToFrontend();
|
||||
|
||||
const product = pageObject.products.nth( 1 );
|
||||
|
||||
await verifyProductContent( product );
|
||||
} );
|
||||
|
||||
// Expects are collected in verifyProductContent function
|
||||
// eslint-disable-next-line playwright/expect-expect
|
||||
test( 'In a Product Archive (Product Catalog)', async ( {
|
||||
pageObject,
|
||||
editor,
|
||||
} ) => {
|
||||
await pageObject.replaceProductsWithProductCollectionInTemplate(
|
||||
'woocommerce/woocommerce//archive-product'
|
||||
);
|
||||
await insertProductElements( pageObject );
|
||||
await editor.saveSiteEditorEntities();
|
||||
await pageObject.goToProductCatalogFrontend();
|
||||
|
||||
const product = pageObject.products.nth( 1 );
|
||||
|
||||
await verifyProductContent( product );
|
||||
} );
|
||||
|
||||
// Expects are collected in verifyProductContent function
|
||||
// eslint-disable-next-line playwright/expect-expect
|
||||
test( 'On a Home Page', async ( { pageObject, editor } ) => {
|
||||
await pageObject.goToHomePageAndInsertCollection();
|
||||
|
||||
await insertProductElements( pageObject );
|
||||
await editor.saveSiteEditorEntities();
|
||||
await pageObject.goToHomePageFrontend();
|
||||
|
||||
const product = pageObject.products.nth( 1 );
|
||||
|
||||
await verifyProductContent( product );
|
||||
} );
|
||||
} );
|
||||
|
||||
test.describe( 'Product Collection Sidebar Settings', () => {
|
||||
test.beforeEach( async ( { pageObject } ) => {
|
||||
await pageObject.createNewPostAndInsertBlock();
|
||||
|
@ -200,10 +302,16 @@ test.describe( 'Product Collection', () => {
|
|||
await pageObject.setFilterComboboxValue( filterName, [
|
||||
'Recommended',
|
||||
] );
|
||||
await expect( pageObject.productTitles ).toHaveText( [ 'Hoodie' ] );
|
||||
await expect( pageObject.productTitles ).toHaveText( [
|
||||
'Beanie',
|
||||
'Hoodie',
|
||||
] );
|
||||
|
||||
await pageObject.publishAndGoToFrontend();
|
||||
await expect( pageObject.productTitles ).toHaveText( [ 'Hoodie' ] );
|
||||
await expect( pageObject.productTitles ).toHaveText( [
|
||||
'Beanie',
|
||||
'Hoodie',
|
||||
] );
|
||||
} );
|
||||
|
||||
test( 'Products can be filtered based on product attributes like color, size etc.', async ( {
|
||||
|
@ -316,7 +424,7 @@ test.describe( 'Product Collection', () => {
|
|||
await expect( pageObject.products ).toHaveCount( 4 );
|
||||
} );
|
||||
|
||||
test.describe( 'Sync with current template (former "Inherit query from template")', () => {
|
||||
test.describe( 'Sync with current template', () => {
|
||||
test( 'should not be visible on posts', async ( {
|
||||
pageObject,
|
||||
} ) => {
|
||||
|
@ -333,8 +441,10 @@ test.describe( 'Product Collection', () => {
|
|||
|
||||
test( 'should work as expected in Product Catalog template', async ( {
|
||||
pageObject,
|
||||
editor,
|
||||
} ) => {
|
||||
await pageObject.goToProductCatalogAndInsertCollection();
|
||||
await editor.openDocumentSettingsSidebar();
|
||||
|
||||
const sidebarSettings =
|
||||
await pageObject.locateSidebarSettings();
|
||||
|
@ -385,10 +495,12 @@ test.describe( 'Product Collection', () => {
|
|||
|
||||
test( 'is enabled by default in 1st Product Collection and disabled in 2nd+', async ( {
|
||||
pageObject,
|
||||
editor,
|
||||
} ) => {
|
||||
// First Product Catalog
|
||||
// Option should be visible & ENABLED by default
|
||||
await pageObject.goToProductCatalogAndInsertCollection();
|
||||
await editor.openDocumentSettingsSidebar();
|
||||
|
||||
const sidebarSettings =
|
||||
await pageObject.locateSidebarSettings();
|
||||
|
@ -638,7 +750,7 @@ test.describe( 'Product Collection', () => {
|
|||
await expect( pageObject.products ).toHaveCount( 4 );
|
||||
} );
|
||||
|
||||
test( "Product Catalog Collection can be added in post and doesn't inherit query from template", async ( {
|
||||
test( "Product Catalog Collection can be added in post and doesn't sync query with template", async ( {
|
||||
pageObject,
|
||||
} ) => {
|
||||
await pageObject.createNewPostAndInsertBlock( 'productCatalog' );
|
||||
|
@ -656,12 +768,14 @@ test.describe( 'Product Collection', () => {
|
|||
await expect( pageObject.products ).toHaveCount( 9 );
|
||||
} );
|
||||
|
||||
test( 'Product Catalog Collection can be added in product archive and inherits query from template', async ( {
|
||||
test( 'Product Catalog Collection can be added in product archive and syncs query with template', async ( {
|
||||
pageObject,
|
||||
editor,
|
||||
} ) => {
|
||||
await pageObject.goToProductCatalogAndInsertCollection(
|
||||
'productCatalog'
|
||||
);
|
||||
await editor.openDocumentSettingsSidebar();
|
||||
|
||||
const sidebarSettings = await pageObject.locateSidebarSettings();
|
||||
const input = sidebarSettings.locator(
|
||||
|
|
|
@ -5,6 +5,11 @@ import { Locator, Page } from '@playwright/test';
|
|||
import { TemplateApiUtils, EditorUtils } from '@woocommerce/e2e-utils';
|
||||
import { Editor, Admin } from '@wordpress/e2e-test-utils-playwright';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { BLOCK_THEME_SLUG } from '../../utils/constants';
|
||||
|
||||
export const SELECTORS = {
|
||||
productTemplate: '.wc-block-product-template',
|
||||
product: '.wc-block-product-template .wc-block-product',
|
||||
|
@ -127,6 +132,7 @@ class ProductCollectionPage {
|
|||
|
||||
async createNewPostAndInsertBlock( collection?: Collections ) {
|
||||
await this.admin.createNewPost( { legacyCanvas: true } );
|
||||
await this.editorUtils.closeWelcomeGuideModal();
|
||||
await this.insertProductCollection();
|
||||
await this.chooseCollectionInPost( collection );
|
||||
await this.refreshLocators( 'editor' );
|
||||
|
@ -184,34 +190,55 @@ class ProductCollectionPage {
|
|||
this.BLOCK_SLUG
|
||||
);
|
||||
await this.chooseCollectionInTemplate( collection );
|
||||
await this.refreshLocators( 'editor' );
|
||||
await this.editor.saveSiteEditorEntities();
|
||||
}
|
||||
|
||||
async goToProductCatalogFrontend() {
|
||||
await this.page.goto( `/shop` );
|
||||
await this.refreshLocators( 'frontend' );
|
||||
}
|
||||
|
||||
async goToHomePageFrontend() {
|
||||
await this.page.goto( `/` );
|
||||
await this.refreshLocators( 'frontend' );
|
||||
}
|
||||
|
||||
async insertProductCollection() {
|
||||
await this.editor.insertBlock( { name: this.BLOCK_SLUG } );
|
||||
}
|
||||
|
||||
async goToProductCatalogAndInsertCollection( collection?: Collections ) {
|
||||
await this.templateApiUtils.revertTemplate(
|
||||
'woocommerce/woocommerce//archive-product'
|
||||
);
|
||||
|
||||
async goToTemplateAndInsertCollection(
|
||||
template: string,
|
||||
collection?: Collections
|
||||
) {
|
||||
await this.templateApiUtils.revertTemplate( template );
|
||||
await this.admin.visitSiteEditor( {
|
||||
postId: 'woocommerce/woocommerce//archive-product',
|
||||
postId: template,
|
||||
postType: 'wp_template',
|
||||
} );
|
||||
await this.editorUtils.waitForSiteEditorFinishLoading();
|
||||
await this.editor.canvas.click( 'body' );
|
||||
await this.insertProductCollection();
|
||||
await this.chooseCollectionInTemplate( collection );
|
||||
await this.editor.openDocumentSettingsSidebar();
|
||||
await this.refreshLocators( 'editor' );
|
||||
await this.editor.saveSiteEditorEntities();
|
||||
}
|
||||
|
||||
async goToHomePageAndInsertCollection( collection?: Collections ) {
|
||||
await this.goToTemplateAndInsertCollection(
|
||||
`${ BLOCK_THEME_SLUG }//home`,
|
||||
collection
|
||||
);
|
||||
}
|
||||
|
||||
async goToProductCatalogAndInsertCollection( collection?: Collections ) {
|
||||
await this.goToTemplateAndInsertCollection(
|
||||
'woocommerce/woocommerce//archive-product',
|
||||
collection
|
||||
);
|
||||
}
|
||||
|
||||
async searchProducts( phrase: string ) {
|
||||
await this.page
|
||||
.getByLabel( SELECTORS.productSearchLabel )
|
||||
|
@ -516,6 +543,25 @@ class ProductCollectionPage {
|
|||
await this.page.setViewportSize( { width, height } );
|
||||
}
|
||||
|
||||
async insertBlockInProductCollection( block: {
|
||||
name: string;
|
||||
attributes: object;
|
||||
} ) {
|
||||
await this.waitForProductsToLoad();
|
||||
const productTemplate = await this.editorUtils.getBlockByName(
|
||||
'woocommerce/product-template'
|
||||
);
|
||||
const productTemplateId =
|
||||
( await productTemplate.getAttribute( 'data-block' ) ) ?? '';
|
||||
|
||||
await this.editor.selectBlocks( productTemplate );
|
||||
await this.editorUtils.insertBlock(
|
||||
block,
|
||||
undefined,
|
||||
productTemplateId
|
||||
);
|
||||
}
|
||||
|
||||
async insertProductCollectionInSingleProductBlock() {
|
||||
this.insertSingleProductBlock();
|
||||
|
||||
|
@ -618,10 +664,17 @@ class ProductCollectionPage {
|
|||
}
|
||||
|
||||
private async waitForProductsToLoad() {
|
||||
// Wait for the product blocks to be loaded.
|
||||
await this.page.waitForSelector( 'wc-block-product-template__spinner', {
|
||||
state: 'detached',
|
||||
} );
|
||||
const loaderInTemplate = this.page
|
||||
.frameLocator( 'iframe[name="editor-canvas"]' )
|
||||
.getByLabel( 'Block: Product Template' )
|
||||
.locator( 'circle' );
|
||||
const loaderInPost = this.page
|
||||
.getByLabel( 'Block: Product Template' )
|
||||
.locator( 'circle' );
|
||||
await Promise.all( [
|
||||
loaderInTemplate.waitFor( { state: 'hidden', timeout: 100000 } ),
|
||||
loaderInPost.waitFor( { state: 'hidden', timeout: 100000 } ),
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Product Collection: Add E2E tests confirming all Product Elements are rendered correctly
|
Loading…
Reference in New Issue