Add Playwright tests for All Reviews, Reviews by Product and Reviews by Category blocks (#42903)

* Remove Reviews blocks Puppeteer tests

* Minor code cleanup

* Typos

* Create publishAndVisitPost() editor util

* Fix subcategories when importing products in Playwright and add reviews

* Add Reviews blocks tests in Playwright

* More typos

* Add changefile(s) from automation for the following project(s): woocommerce-blocks

* Create a 'reviews' object in data.ts so we can store reviews data in one single place

* Update test so instead of creating a new post in each test, we go to the already-created post

* Add source comments to reviews data to match it with the script

---------

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Albert Juhé Lluveras 2023-12-22 09:33:18 +01:00 committed by GitHub
parent a355346be2
commit 2da7b73e76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 239 additions and 174 deletions

View File

@ -1,35 +0,0 @@
/**
* External dependencies
*/
import { switchUserToAdmin } from '@wordpress/e2e-test-utils';
import { visitBlockPage } from '@woocommerce/blocks-test-utils';
const block = {
name: 'All Reviews',
slug: 'woocommerce/all-reviews',
class: '.wc-block-all-reviews',
};
describe( `${ block.name } Block`, () => {
beforeAll( async () => {
await switchUserToAdmin();
await visitBlockPage( `${ block.name } Block` );
} );
it( 'renders without crashing', async () => {
await expect( page ).toRenderBlock( block );
} );
it.skip( 'shows reviews', async () => {
await page.waitForSelector(
'.wc-block-review-list .wc-block-review-list-item__item:not(.is-loading)'
);
expect(
await page.$$eval(
'.wc-block-review-list .wc-block-review-list-item__item',
( reviews ) => reviews.length
)
).toBeGreaterThanOrEqual( 6 ); // Fixture data has three reviews per product.
} );
} );

View File

@ -1,48 +0,0 @@
/**
* External dependencies
*/
import { switchUserToAdmin, clickButton } from '@wordpress/e2e-test-utils';
import { visitBlockPage } from '@woocommerce/blocks-test-utils';
const block = {
name: 'Reviews by Category',
slug: 'woocommerce/reviews-by-category',
class: '.wc-block-reviews-by-category',
};
describe( `${ block.name } Block`, () => {
beforeAll( async () => {
await switchUserToAdmin();
await visitBlockPage( `${ block.name } Block` );
} );
it( 'renders without crashing', async () => {
await expect( page ).toRenderBlock( block );
} );
it( 'shows category selector', async () => {
await expect( page ).toMatchElement(
`${ block.class } .woocommerce-search-list`
);
} );
it.skip( 'can select a category and show reviews', async () => {
// we focus on the block
await page.click( block.class );
await page.waitForSelector(
`${ block.class } .woocommerce-search-list__item`
);
await page.click( `${ block.class } .woocommerce-search-list__item` );
await clickButton( 'Done' );
// Selected.
await page.waitForSelector(
'.wc-block-review-list .wc-block-review-list-item__item:not(.is-loading)'
);
expect(
await page.$$eval(
'.wc-block-review-list .wc-block-review-list-item__item',
( reviews ) => reviews.length
)
).toBeGreaterThanOrEqual( 6 ); // Fixture data has three reviews per product, and there are multiple products.
} );
} );

View File

@ -1,62 +0,0 @@
/**
* External dependencies
*/
import { switchUserToAdmin, clickButton } from '@wordpress/e2e-test-utils';
import { visitBlockPage } from '@woocommerce/blocks-test-utils';
const block = {
name: 'Reviews by Product',
slug: 'woocommerce/reviews-by-product',
class: '.wc-block-reviews-by-product',
};
describe( `${ block.name } Block`, () => {
beforeAll( async () => {
await switchUserToAdmin();
await visitBlockPage( `${ block.name } Block` );
} );
it( 'renders without crashing', async () => {
await expect( page ).toRenderBlock( block );
} );
it( 'shows product selector', async () => {
await expect( page ).toMatchElement(
`${ block.class } .woocommerce-search-list`
);
} );
it.skip( 'can select a product and show reviews', async () => {
// we focus on the block
await page.click( block.class );
await page.waitForSelector(
`${ block.class } .woocommerce-search-list__item`
);
do {
await page.click(
`${ block.class } .woocommerce-search-list__item`
);
} while (
await page.evaluate(
( blockClass ) =>
document
.querySelector(
`${ blockClass } .woocommerce-search-list__item`
)
.getAttribute( 'aria-checked' ) === 'false',
block.class
)
);
await clickButton( 'Done' );
// Selected.
await page.waitForSelector(
'.wc-block-review-list .wc-block-review-list-item__item:not(.is-loading)'
);
expect(
await page.$$eval(
'.wc-block-review-list .wc-block-review-list-item__item',
( reviews ) => reviews.length
)
).toBeGreaterThanOrEqual( 3 ); // Fixture data has three reviews per product.
} );
} );

View File

@ -2,7 +2,7 @@
* External dependencies
*/
import { setDefaultOptions, getDefaultOptions } from 'expect-puppeteer';
import { default as WooCommerceRestApi } from '@woocommerce/woocommerce-rest-api';
import WooCommerceRestApi from '@woocommerce/woocommerce-rest-api';
import { SHOP_PAGE, SHOP_CART_PAGE } from '@woocommerce/e2e-utils';
/**

View File

@ -1,3 +1,3 @@
<!-- wp:woocommerce/reviews-by-category {"editMode":false,"categoryIds":[14]} -->
<div class="wp-block-woocommerce-reviews-by-category wc-block-reviews-by-category has-image has-name has-date has-rating has-content has-product-name" data-image-type="reviewer" data-orderby="most-recent" data-reviews-on-page-load="10" data-reviews-on-load-more="10" data-show-load-more="true" data-show-orderby="true" data-category-ids="14,20,22,11,18,10"></div>
<!-- wp:woocommerce/reviews-by-category {"editMode":false,"categoryIds":[20]} -->
<div class="wp-block-woocommerce-reviews-by-category wc-block-reviews-by-category has-image has-name has-date has-rating has-content has-product-name" data-image-type="reviewer" data-orderby="most-recent" data-reviews-on-page-load="10" data-reviews-on-load-more="10" data-show-load-more="true" data-show-orderby="true" data-category-ids="20"></div>
<!-- /wp:woocommerce/reviews-by-category -->

View File

@ -1,3 +1,3 @@
<!-- wp:woocommerce/reviews-by-product {"editMode":false,"productId":10} -->
<div class="wp-block-woocommerce-reviews-by-product wc-block-reviews-by-product has-image has-name has-date has-rating has-content" data-image-type="reviewer" data-orderby="most-recent" data-reviews-on-page-load="10" data-reviews-on-load-more="10" data-show-load-more="true" data-show-orderby="true" data-product-id="10"></div>
<!-- wp:woocommerce/reviews-by-product {"editMode":false,"productId":7} -->
<div class="wp-block-woocommerce-reviews-by-product wc-block-reviews-by-product has-image has-name has-date has-rating has-content" data-image-type="reviewer" data-orderby="most-recent" data-reviews-on-page-load="10" data-reviews-on-load-more="10" data-show-load-more="true" data-show-orderby="true" data-product-id="7"></div>
<!-- /wp:woocommerce/reviews-by-product -->

View File

@ -8,8 +8,11 @@ wp site empty --yes
# Attributes must be created before importing products.
bash $script_dir/attributes.sh
# Run all scripts in parallel at maximum 10 at a time
# Products must be created before anything else so the ids are deterministic.
bash $script_dir/products.sh
# Run all scripts in parallel at maximum 10 at a time.
find $script_dir/parallel/*.sh -maxdepth 1 -type f | xargs -P10 -n1 bash
# Run rewrite script last to ensure all posts are created before running it
# Run rewrite script last to ensure all posts are created before running it.
bash $script_dir/rewrite.sh

View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Add a couple of reviews to Hoodie.
post_id=$(wp post list --post_type=product --field=ID --name="Hoodie" --format=ids)
wp wc product_review create $post_id --name="Jane Smith" --email="customer@woocommerceblockse2etestsuite.com" --review="Nice album!" --rating=5 --user=1
wp wc product_review create $post_id --name="Jane Smith" --email="customer@woocommerceblockse2etestsuite.com" --review="Not bad." --rating=4 --user=1

View File

@ -6,6 +6,13 @@
wp import wp-content/plugins/woocommerce/sample-data/sample_products.xml --authors=skip
wp wc tool run regenerate_product_lookup_tables --user=1
# This is a hacky work around to fix product categories not having their parent category correctly assigned.
clothing_category_id=$(wp wc product_cat list --search="Clothing" --field=id --user=1)
tshirts_category_id=$(wp wc product_cat list --search="Tshirts" --field=id --user=1)
hoodies_category_id=$(wp wc product_cat list --search="Hoodies" --field=id --user=1)
wp wc product_cat update $tshirts_category_id --parent=$clothing_category_id --user=1
wp wc product_cat update $hoodies_category_id --parent=$clothing_category_id --user=1
# This is a hacky work around to fix product gallery images not being imported
# This sets up the product Hoodie to have product gallery images for e2e testing
post_id=$(wp post list --post_type=product --field=ID --name="Hoodie" --format=ids)

View File

@ -58,6 +58,22 @@ export const customer = {
},
};
// source: plugins/woocommerce-blocks/tests/e2e/bin/scripts/parallel/reviews.sh
export const reviews = [
{
name: `${ customer.first_name } ${ customer.last_name }`,
email: customer.email,
review: 'Nice album!',
rating: 5,
},
{
name: `${ customer.first_name } ${ customer.last_name }`,
email: customer.email,
review: 'Not bad.',
rating: 4,
},
];
export const storeDetails = {
us: {
store: {

View File

@ -0,0 +1,55 @@
/**
* External dependencies
*/
import { expect, test } from '@woocommerce/e2e-playwright-utils';
/**
* Internal dependencies
*/
import { reviews } from '../../test-data/data/data';
const blockData = {
name: 'woocommerce/all-reviews',
selectors: {
frontend: {
firstReview:
'.wc-block-review-list-item__item:first-child .wc-block-review-list-item__text p',
},
},
};
test.describe( `${ blockData.name } Block`, () => {
test( 'block can be inserted and it successfully renders a review in the editor and the frontend', async ( {
admin,
editor,
page,
editorUtils,
} ) => {
await admin.createNewPost();
await editor.insertBlock( { name: blockData.name } );
await expect( page.getByText( reviews[ 0 ].review ) ).toBeVisible();
await editorUtils.publishAndVisitPost();
await expect( page.getByText( reviews[ 0 ].review ) ).toBeVisible();
} );
test( 'can change sort order in the frontend', async ( {
page,
frontendUtils,
} ) => {
await page.goto( '/all-reviews-block/' );
const block = await frontendUtils.getBlockByName( blockData.name );
let firstReview;
firstReview = block.locator( blockData.selectors.frontend.firstReview );
await expect( firstReview ).toHaveText( reviews[ 1 ].review );
const select = page.getByLabel( 'Order by' );
select.selectOption( 'Highest rating' );
firstReview = block.locator( blockData.selectors.frontend.firstReview );
await expect( firstReview ).toHaveText( reviews[ 0 ].review );
} );
} );

View File

@ -17,13 +17,6 @@ const blockData = {
},
};
const publishAndVisitPost = async ( { page, editor } ) => {
await editor.publishPost();
const url = new URL( page.url() );
const postId = url.searchParams.get( 'post' );
await page.goto( `/?p=${ postId }`, { waitUntil: 'commit' } );
};
const selectTextOnlyOption = async ( { page } ) => {
await page
.locator( blockData.selectors.editor.iconOptions )
@ -54,13 +47,14 @@ test.describe( `${ blockData.name } Block`, () => {
editor,
page,
frontendUtils,
editorUtils,
} ) => {
await admin.createNewPost( { legacyCanvas: true } );
await editor.insertBlock( { name: blockData.name } );
await selectTextOnlyOption( { page } );
await publishAndVisitPost( { page, editor } );
await editorUtils.publishAndVisitPost();
const block = await frontendUtils.getBlockByName( blockData.name );
@ -77,13 +71,14 @@ test.describe( `${ blockData.name } Block`, () => {
editor,
page,
frontendUtils,
editorUtils,
} ) => {
await admin.createNewPost( { legacyCanvas: true } );
await editor.insertBlock( { name: blockData.name } );
await selectIconOnlyOption( { page } );
await publishAndVisitPost( { page, editor } );
await editorUtils.publishAndVisitPost();
const block = await frontendUtils.getBlockByName( blockData.name );
@ -100,13 +95,14 @@ test.describe( `${ blockData.name } Block`, () => {
editor,
page,
frontendUtils,
editorUtils,
} ) => {
await admin.createNewPost( { legacyCanvas: true } );
await editor.insertBlock( { name: blockData.name } );
await selectIconAndTextOption( { page } );
await publishAndVisitPost( { page, editor } );
await editorUtils.publishAndVisitPost();
const block = await frontendUtils.getBlockByName( blockData.name );

View File

@ -19,7 +19,7 @@ type Scenario = {
amount: number;
};
const singleOccurranceScenarios: Scenario[] = [
const singleOccurrenceScenarios: Scenario[] = [
{
title: 'Before Main Content',
dataTestId: 'woocommerce_before_main_content',
@ -46,7 +46,7 @@ const singleOccurranceScenarios: Scenario[] = [
},
];
const multipleOccurranceScenarios: Scenario[] = [
const multipleOccurrenceScenarios: Scenario[] = [
{
title: 'Before Shop Loop Item Title',
dataTestId: 'woocommerce_before_shop_loop_item_title',
@ -79,7 +79,7 @@ const multipleOccurranceScenarios: Scenario[] = [
},
];
const compatiblityPluginFileName = 'compatibility-plugin.php';
const compatibilityPluginFileName = 'compatibility-plugin.php';
const test = base.extend< { pageObject: ProductCollectionPage } >( {
pageObject: async (
{ page, admin, editor, templateApiUtils, editorUtils },
@ -100,7 +100,7 @@ const test = base.extend< { pageObject: ProductCollectionPage } >( {
test.describe( 'Compatibility Layer with Product Collection block', () => {
test.beforeAll( async () => {
await installPluginFromPHPFile(
`${ __dirname }/${ compatiblityPluginFileName }`
`${ __dirname }/${ compatibilityPluginFileName }`
);
} );
@ -112,7 +112,7 @@ test.describe( 'Compatibility Layer with Product Collection block', () => {
await pageObject.goToProductCatalogFrontend();
} );
for ( const scenario of singleOccurranceScenarios ) {
for ( const scenario of singleOccurrenceScenarios ) {
test( `${ scenario.title } is attached to the page`, async ( {
pageObject,
} ) => {
@ -123,7 +123,7 @@ test.describe( 'Compatibility Layer with Product Collection block', () => {
} );
}
for ( const scenario of multipleOccurranceScenarios ) {
for ( const scenario of multipleOccurrenceScenarios ) {
test( `${ scenario.title } is attached to the page`, async ( {
pageObject,
} ) => {
@ -137,7 +137,7 @@ test.describe( 'Compatibility Layer with Product Collection block', () => {
test.afterAll( async ( { requestUtils } ) => {
await uninstallPluginFromPHPFile(
`${ __dirname }/${ compatiblityPluginFileName }`
`${ __dirname }/${ compatibilityPluginFileName }`
);
await requestUtils.deleteAllTemplates( 'wp_template' );
} );

View File

@ -0,0 +1,60 @@
/**
* External dependencies
*/
import { expect, test } from '@woocommerce/e2e-playwright-utils';
/**
* Internal dependencies
*/
import { reviews } from '../../test-data/data/data';
const blockData = {
name: 'woocommerce/reviews-by-category',
selectors: {
frontend: {
firstReview:
'.wc-block-review-list-item__item:first-child .wc-block-review-list-item__text p',
},
},
};
test.describe( `${ blockData.name } Block`, () => {
test( 'block can be inserted and it successfully renders a review in the editor and the frontend', async ( {
admin,
editor,
page,
editorUtils,
} ) => {
await admin.createNewPost();
await editor.insertBlock( { name: blockData.name } );
const categoryCheckbox = page.getByLabel( 'Clothing' );
categoryCheckbox.check();
await expect( categoryCheckbox ).toBeChecked();
const doneButton = page.getByRole( 'button', { name: 'Done' } );
await doneButton.click();
await expect( page.getByText( reviews[ 0 ].review ) ).toBeVisible();
await editorUtils.publishAndVisitPost();
await expect( page.getByText( reviews[ 0 ].review ) ).toBeVisible();
} );
test( 'can change sort order in the frontend', async ( {
page,
frontendUtils,
} ) => {
await page.goto( '/reviews-by-category/' );
const block = await frontendUtils.getBlockByName( blockData.name );
let firstReview;
firstReview = block.locator( blockData.selectors.frontend.firstReview );
await expect( firstReview ).toHaveText( reviews[ 1 ].review );
const select = page.getByLabel( 'Order by' );
select.selectOption( 'Highest rating' );
firstReview = block.locator( blockData.selectors.frontend.firstReview );
await expect( firstReview ).toHaveText( reviews[ 0 ].review );
} );
} );

View File

@ -0,0 +1,60 @@
/**
* External dependencies
*/
import { expect, test } from '@woocommerce/e2e-playwright-utils';
/**
* Internal dependencies
*/
import { reviews } from '../../test-data/data/data';
const blockData = {
name: 'woocommerce/reviews-by-product',
selectors: {
frontend: {
firstReview:
'.wc-block-review-list-item__item:first-child .wc-block-review-list-item__text p',
},
},
};
test.describe( `${ blockData.name } Block`, () => {
test( 'block can be inserted and it successfully renders a review in the editor and the frontend', async ( {
admin,
editor,
page,
editorUtils,
} ) => {
await admin.createNewPost();
await editor.insertBlock( { name: blockData.name } );
const productCheckbox = page.getByLabel( 'Hoodie, has 2 reviews' );
productCheckbox.check();
await expect( productCheckbox ).toBeChecked();
const doneButton = page.getByRole( 'button', { name: 'Done' } );
await doneButton.click();
await expect( page.getByText( reviews[ 0 ].review ) ).toBeVisible();
await editorUtils.publishAndVisitPost();
await expect( page.getByText( reviews[ 0 ].review ) ).toBeVisible();
} );
test( 'can change sort order in the frontend', async ( {
page,
frontendUtils,
} ) => {
await page.goto( '/reviews-by-product/' );
const block = await frontendUtils.getBlockByName( blockData.name );
let firstReview;
firstReview = block.locator( blockData.selectors.frontend.firstReview );
await expect( firstReview ).toHaveText( reviews[ 1 ].review );
const select = page.getByLabel( 'Order by' );
select.selectOption( 'Highest rating' );
firstReview = block.locator( blockData.selectors.frontend.firstReview );
await expect( firstReview ).toHaveText( reviews[ 0 ].review );
} );
} );

View File

@ -3,6 +3,7 @@
*/
import { request as req } from '@playwright/test';
import fs from 'fs/promises';
/**
* Internal dependencies
*/

View File

@ -339,4 +339,11 @@ export class EditorUtils {
.getByText( 'Site updated.' )
.waitFor();
}
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' } );
}
}

View File

@ -1,13 +1,8 @@
/**
* External dependencies
*/
import { RequestUtils } from '@wordpress/e2e-test-utils-playwright';
/**
* Internal dependencies
*/
export class StoreApiUtils {
private requestUtils: RequestUtils;

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: Add Playwright tests for All Reviews, Reviews by Product and Reviews by Category blocks