[Blocks] Migrate stock filter to playwright (#46580)

* try db reset in page teardown

* move reset to setup step

* Use wp db cli

* Fix global setup
That part is overriding the logged in user state and wipes out the nonce and rootUrl fields.

* Try importing instead from a generated dump

* Revert "Try importing instead from a generated dump"

This reverts commit 987dc471c9.

* Revert "Revert "Try importing instead from a generated dump""

This reverts commit c8d008cb20.

* Don't bypass visitSiteEditor so that the Welcome Guide is closed

* use createNewPost

* Revert "Revert "Revert "Try importing instead from a generated dump"""

This reverts commit 2684273582.

* [Blocks]: Fix E2E tests (#46344)

* Load local pickup enabled setting as bool not string

* Add changelog

* Remove unused import

* Update plugins/woocommerce-blocks/assets/js/extensions/shipping-methods/pickup-location/utils.ts

Co-authored-by: Niels Lange <info@nielslange.de>

* Use strict equality test

* try now

* try now

* add a new sql file

* remove default.sql

* fix welcome guide tour

* fix E2E tests

* Fix the template revert tests
...where the template is unreachable due to pagination.

* Add changelog entry

* improve logic to closeWelcomeGuideModal

* fix cart checkout tests

* improve flakiness

* improve flakiness

* fix flaky test

* fix company field

* fix E2E test

* fix E2E tests

---------

Co-authored-by: Thomas Roberts <thomas.roberts@automattic.com>
Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com>
Co-authored-by: Niels Lange <info@nielslange.de>
Co-authored-by: Bart Kalisz <bartlomiej.kalisz@gmail.com>

* Replace beforeAll w/ beforeEach + remove all after* hooks

* Fix broken hooks

* Activate plugins via requestUtils API

* [Blocks - E2E]: Add `playwright/no-hooks` ESlint rule (#46432)

add ESLint configuration

* Clean up console logs

* Remove obsolete language setup steps

* Remove more unnecessary setup steps

* Remove even more obsolete setup steps

* tmp: add the LYS fix

* Try stabilizing the company field test

* Use canvas param instead of manually entering edit mode

* Blocks: Migrate stock filter to playwright

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

* Remove double site editor redirect

* remove not necessary file

* fix test

* Revert "Use canvas param instead of manually entering edit mode"

This reverts commit 5e6cc17154.

* Revert "Remove double site editor redirect"

This reverts commit 69a57a82a8.

* Fix flaky products sorting test

* Blocks: Fix ESLint errors (#46595)

fix eslint error

* improve E2E tests

* fix test

* Fix ESLint errors (#46626)

* Fix ESLint errors

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

---------

Co-authored-by: github-actions <github-actions@github.com>

* address feedback

---------

Co-authored-by: Bart Kalisz <bartlomiej.kalisz@gmail.com>
Co-authored-by: Thomas Roberts <thomas.roberts@automattic.com>
Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com>
Co-authored-by: Niels Lange <info@nielslange.de>
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Luigi Teschio 2024-04-26 15:14:54 +02:00 committed by GitHub
parent f437c538e7
commit ded320df95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 284 additions and 401 deletions

View File

@ -1,75 +0,0 @@
/**
* External dependencies
*/
import {
switchBlockInspectorTab,
switchUserToAdmin,
} from '@wordpress/e2e-test-utils';
import { visitBlockPage } from '@woocommerce/blocks-test-utils';
/**
* Internal dependencies
*/
/**
* Internal dependencies
*/
import { openSettingsSidebar } from '../../utils';
import { findLabelWithText } from '../../../utils';
const block = {
name: 'Filter Products by Stock',
slug: 'woocommerce/stock-filter',
class: '.wc-block-stock-filter',
};
describe( `${ block.name } Block`, () => {
beforeAll( async () => {
await switchUserToAdmin();
await visitBlockPage( `${ block.name } Block` );
} );
it( 'renders without crashing', async () => {
await expect( page ).toRenderBlock( block );
} );
describe( 'attributes', () => {
beforeEach( async () => {
await openSettingsSidebar();
await page.click( block.class );
await switchBlockInspectorTab( 'Settings' );
} );
it( 'product count can be toggled', async () => {
const toggleLabel = await findLabelWithText(
'Display product count'
);
await expect( toggleLabel ).toToggleElement(
`${ block.class } .wc-filter-element-label-list-count`
);
} );
it( 'filter button can be toggled', async () => {
const toggleLabel = await findLabelWithText( 'Apply filters' );
await expect( toggleLabel ).toToggleElement(
`${ block.class } .wc-block-filter-submit-button`
);
} );
it( 'allows changing the Display Style', async () => {
// Turn the display style to Dropdown
await expect( page ).toClick( 'button', { text: 'Dropdown' } );
await expect( page ).toMatchElement(
'.wc-block-stock-filter.style-dropdown'
);
// Turn the display style to List
await expect( page ).toClick( 'button', {
text: 'List',
} );
await expect( page ).toMatchElement(
'.wc-block-stock-filter.style-list'
);
} );
} );
} );

View File

@ -1,326 +0,0 @@
/**
* External dependencies
*/
import {
createNewPost,
deleteAllTemplates,
insertBlock,
switchBlockInspectorTab,
switchUserToAdmin,
publishPost,
ensureSidebarOpened,
} from '@wordpress/e2e-test-utils';
import {
selectBlockByName,
getToggleIdByLabel,
saveOrPublish,
} from '@woocommerce/blocks-test-utils';
import { setCheckbox } from '@woocommerce/e2e-utils';
/**
* Internal dependencies
*/
import {
BASE_URL,
enableApplyFiltersButton,
goToTemplateEditor,
insertAllProductsBlock,
saveTemplate,
useTheme,
waitForAllProductsBlockLoaded,
waitForCanvas,
} from '../../utils';
const block = {
name: 'Filter by Stock',
slug: 'woocommerce/stock-filter',
class: '.wc-block-stock-filter',
selectors: {
frontend: {
productsList: '.wc-block-grid__products > li',
classicProductsList: '.products.columns-3 > li',
filter: 'input[id=outofstock]',
submitButton: '.wc-block-components-filter-submit-button',
queryProductsList: '.wp-block-post-template > li',
},
},
urlSearchParamWhenFilterIsApplied: '?filter_stock_status=outofstock',
foundProduct: 'Woo Single #3',
};
const { selectors } = block;
const goToShopPage = () =>
page.goto( BASE_URL + '/shop', {
waitUntil: 'networkidle0',
} );
describe( `${ block.name } Block`, () => {
describe.skip( 'with All Products Block', () => {
let link = '';
beforeAll( async () => {
await switchUserToAdmin();
await createNewPost( {
postType: 'post',
title: block.name,
} );
await insertBlock( block.name );
await insertAllProductsBlock();
await publishPost();
link = await page.evaluate( () =>
wp.data.select( 'core/editor' ).getPermalink()
);
} );
it( 'should render', async () => {
await page.goto( link );
await waitForAllProductsBlockLoaded();
const products = await page.$$( selectors.frontend.productsList );
expect( products ).toHaveLength( 5 );
} );
it( 'should show only products that match the filter', async () => {
const isRefreshed = jest.fn( () => void 0 );
page.on( 'load', isRefreshed );
await page.click( selectors.frontend.filter );
await waitForAllProductsBlockLoaded();
const products = await page.$$( selectors.frontend.productsList );
expect( isRefreshed ).not.toBeCalled();
expect( products ).toHaveLength( 1 );
await expect( page ).toMatch( block.foundProduct );
} );
} );
describe.skip( 'with PHP classic template (Products Block and Classic Template Block)', () => {
const productCatalogTemplateId =
'woocommerce/woocommerce//archive-product';
useTheme( 'emptytheme' );
beforeAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
await goToTemplateEditor( {
postId: productCatalogTemplateId,
} );
await insertBlock( 'WooCommerce Product Grid Block' );
await insertBlock( block.name );
await saveTemplate();
await goToShopPage();
} );
beforeEach( async () => {
await goToShopPage();
} );
afterAll( async () => {
await deleteAllTemplates( 'wp_template' );
await deleteAllTemplates( 'wp_template_part' );
} );
it( 'should render', async () => {
const products = await page.$$(
selectors.frontend.classicProductsList
);
const productsBlockProductsList = await page.$$(
selectors.frontend.queryProductsList
);
expect( products ).toHaveLength( 5 );
expect( productsBlockProductsList ).toHaveLength( 5 );
} );
it( 'should show only products that match the filter', async () => {
const isRefreshed = jest.fn( () => void 0 );
page.on( 'load', isRefreshed );
await page.waitForSelector( block.class + '.is-loading', {
hidden: true,
} );
expect( isRefreshed ).not.toBeCalled();
await page.waitForSelector( selectors.frontend.filter );
await Promise.all( [
page.waitForNavigation(),
page.click( selectors.frontend.filter ),
] );
const products = await page.$$(
selectors.frontend.classicProductsList
);
const productsBlockProductsList = await page.$$(
selectors.frontend.queryProductsList
);
const pageURL = page.url();
const parsedURL = new URL( pageURL );
expect( isRefreshed ).toBeCalledTimes( 1 );
expect( products ).toHaveLength( 1 );
expect( productsBlockProductsList ).toHaveLength( 1 );
await expect( page ).toMatch( block.foundProduct );
expect( parsedURL.search ).toEqual(
block.urlSearchParamWhenFilterIsApplied
);
} );
it( 'should refresh the page only if the user click on button', async () => {
await goToTemplateEditor( {
postId: productCatalogTemplateId,
} );
await waitForCanvas();
await selectBlockByName( block.slug );
await enableApplyFiltersButton();
await saveTemplate();
await goToShopPage();
const isRefreshed = jest.fn( () => void 0 );
page.on( 'load', isRefreshed );
await page.waitForSelector( block.class + '.is-loading', {
hidden: true,
} );
expect( isRefreshed ).not.toBeCalled();
await page.waitForSelector( selectors.frontend.filter );
await page.click( selectors.frontend.filter );
await Promise.all( [
page.waitForNavigation( {
waitUntil: 'networkidle0',
} ),
page.click( selectors.frontend.submitButton ),
] );
const pageURL = page.url();
const parsedURL = new URL( pageURL );
await page.waitForSelector(
selectors.frontend.classicProductsList
);
const products = await page.$$(
selectors.frontend.classicProductsList
);
const productsBlockProductsList = await page.$$(
selectors.frontend.queryProductsList
);
expect( isRefreshed ).toBeCalledTimes( 1 );
expect( products ).toHaveLength( 1 );
expect( productsBlockProductsList ).toHaveLength( 1 );
await expect( page ).toMatch( block.foundProduct );
expect( parsedURL.search ).toEqual(
block.urlSearchParamWhenFilterIsApplied
);
} );
} );
describe( 'with Product Query Block', () => {
let editorPageUrl = '';
let frontedPageUrl = '';
useTheme( 'emptytheme' );
beforeAll( async () => {
await switchUserToAdmin();
await createNewPost( {
postType: 'post',
title: block.name,
} );
await insertBlock( 'Products (Beta)' );
await insertBlock( block.name );
await publishPost();
editorPageUrl = page.url();
frontedPageUrl = await page.evaluate( () =>
wp.data.select( 'core/editor' ).getPermalink()
);
await page.goto( frontedPageUrl );
} );
it( 'should show only products that match the filter', async () => {
const isRefreshed = jest.fn( () => void 0 );
page.on( 'load', isRefreshed );
await page.waitForSelector( block.class + '.is-loading', {
hidden: true,
} );
expect( isRefreshed ).not.toBeCalled();
await page.waitForSelector( selectors.frontend.filter );
await Promise.all( [
page.waitForNavigation(),
page.click( selectors.frontend.filter ),
] );
const products = await page.$$(
selectors.frontend.queryProductsList
);
const pageURL = page.url();
const parsedURL = new URL( pageURL );
expect( isRefreshed ).toBeCalledTimes( 1 );
expect( products ).toHaveLength( 1 );
expect( parsedURL.search ).toEqual(
block.urlSearchParamWhenFilterIsApplied
);
} );
it( 'should refresh the page only if the user clicks on button', async () => {
await page.goto( editorPageUrl );
await waitForCanvas();
await ensureSidebarOpened();
await selectBlockByName( block.slug );
await switchBlockInspectorTab( 'Settings' );
await setCheckbox(
await getToggleIdByLabel( "Show 'Apply filters' button" )
);
await saveOrPublish();
await page.goto( frontedPageUrl );
const isRefreshed = jest.fn( () => void 0 );
page.on( 'load', isRefreshed );
await page.waitForSelector( block.class + '.is-loading', {
hidden: true,
} );
expect( isRefreshed ).not.toBeCalled();
await page.waitForSelector( selectors.frontend.filter );
await page.click( selectors.frontend.filter );
await Promise.all( [
page.waitForNavigation( {
waitUntil: 'networkidle0',
} ),
page.click( selectors.frontend.submitButton ),
] );
const pageURL = page.url();
const parsedURL = new URL( pageURL );
await page.waitForSelector( selectors.frontend.queryProductsList );
const products = await page.$$(
selectors.frontend.queryProductsList
);
expect( isRefreshed ).toBeCalledTimes( 1 );
expect( products ).toHaveLength( 1 );
expect( parsedURL.search ).toEqual(
block.urlSearchParamWhenFilterIsApplied
);
} );
} );
} );

View File

@ -0,0 +1,276 @@
/**
* External dependencies
*/
import { test as base, expect } from '@woocommerce/e2e-playwright-utils';
import { cli } from '@woocommerce/e2e-utils';
/**
* Internal dependencies
*/
import ProductCollectionPage from '../product-collection/product-collection.page';
export const blockData = {
name: 'Filter by Stock',
slug: 'woocommerce/stock-filter',
urlSearchParamWhenFilterIsApplied: 'filter_stock_status=outofstock',
};
const test = base.extend< {
productCollectionPageObject: ProductCollectionPage;
} >( {
productCollectionPageObject: async (
{ page, admin, editor, templateApiUtils, editorUtils },
use
) => {
const pageObject = new ProductCollectionPage( {
page,
admin,
editor,
templateApiUtils,
editorUtils,
} );
await use( pageObject );
},
} );
test.describe( `${ blockData.name } Block`, () => {
test.beforeEach( async ( { admin, editor } ) => {
await admin.createNewPost();
await editor.insertBlock( {
name: 'woocommerce/filter-wrapper',
attributes: {
filterType: 'stock-filter',
heading: 'Filter By Price',
},
} );
await editor.openDocumentSettingsSidebar();
} );
test( "should allow changing the block's title", async ( { page } ) => {
const textSelector =
'.wp-block-woocommerce-filter-wrapper .wp-block-heading';
const title = 'New Title';
await page.locator( textSelector ).fill( title );
await expect( page.locator( textSelector ) ).toHaveText( title );
} );
test( 'should allow changing the display style', async ( {
page,
editorUtils,
editor,
} ) => {
const stockFilter = await editorUtils.getBlockByName( blockData.slug );
await editor.selectBlocks( stockFilter );
await expect(
stockFilter.getByRole( 'checkbox', {
name: 'In Stock',
} )
).toBeVisible();
await expect(
stockFilter.getByRole( 'checkbox', {
name: 'Out of Stock',
} )
).toBeVisible();
await page.getByLabel( 'DropDown' ).click();
await expect(
stockFilter.getByRole( 'checkbox', {
name: 'In Stock',
} )
).toBeHidden();
await expect(
stockFilter.getByRole( 'checkbox', {
name: 'Out of Stock',
} )
).toBeHidden();
await expect( page.getByRole( 'combobox' ) ).toBeVisible();
} );
test( 'should allow toggling the visibility of the filter button', async ( {
page,
editorUtils,
editor,
} ) => {
const priceFilterControls = await editorUtils.getBlockByName(
blockData.slug
);
await editor.selectBlocks( priceFilterControls );
await expect(
priceFilterControls.getByRole( 'button', {
name: 'Apply',
} )
).toBeHidden();
await page.getByText( "Show 'Apply filters' button" ).click();
await expect(
priceFilterControls.getByRole( 'button', {
name: 'Apply',
} )
).toBeVisible();
} );
} );
test.describe( `${ blockData.name } Block - with PHP classic template`, () => {
test.beforeEach( async ( { admin, page, editor, editorUtils } ) => {
await cli(
'npm run wp-env run tests-cli -- wp option update wc_blocks_use_blockified_product_grid_block_as_template false'
);
await admin.visitSiteEditor( {
postId: 'woocommerce/woocommerce//archive-product',
postType: 'wp_template',
} );
await editorUtils.enterEditMode();
await editor.insertBlock( {
name: 'woocommerce/filter-wrapper',
attributes: {
filterType: 'stock-filter',
heading: 'Filter By Price',
},
} );
await editor.saveSiteEditorEntities();
await page.goto( `/shop` );
} );
test( 'should show all products', async ( { frontendUtils } ) => {
const legacyTemplate = await frontendUtils.getBlockByName(
'woocommerce/legacy-template'
);
const stockFilter = await frontendUtils.getBlockByName(
'woocommerce/filter-wrapper'
);
const products = legacyTemplate
.getByRole( 'list' )
.locator( '.product' );
await expect( products ).toHaveCount( 16 );
await expect( stockFilter.getByText( 'In Stock' ) ).toBeVisible();
await expect( stockFilter.getByText( 'Out of Stock' ) ).toBeVisible();
} );
test( 'should show only products that match the filter', async ( {
frontendUtils,
} ) => {
const stockFilter = await frontendUtils.getBlockByName(
'woocommerce/filter-wrapper'
);
await stockFilter.getByText( 'Out of Stock' ).click();
const legacyTemplate = await frontendUtils.getBlockByName(
'woocommerce/legacy-template'
);
const products = legacyTemplate
.getByRole( 'list' )
.locator( '.product' );
await expect( products ).toHaveCount( 1 );
} );
} );
test.describe( `${ blockData.name } Block - with Product Collection`, () => {
test.beforeEach(
async ( {
admin,
editorUtils,
productCollectionPageObject,
editor,
} ) => {
await admin.createNewPost();
await productCollectionPageObject.insertProductCollection();
await productCollectionPageObject.chooseCollectionInPost(
'productCatalog'
);
await editor.insertBlock( {
name: 'woocommerce/filter-wrapper',
attributes: {
filterType: 'stock-filter',
heading: 'Filter By Stock',
},
} );
await editorUtils.publishAndVisitPost();
}
);
test( 'should show all products', async ( { page } ) => {
const products = page
.locator( '.wp-block-woocommerce-product-template' )
.getByRole( 'listitem' );
await expect( products ).toHaveCount( 9 );
} );
test( 'should show only products that match the filter', async ( {
page,
} ) => {
await page.getByText( 'Out of Stock' ).click();
await expect( page ).toHaveURL(
new RegExp( blockData.urlSearchParamWhenFilterIsApplied )
);
const products = page
.locator( '.wp-block-woocommerce-product-template' )
.getByRole( 'listitem' );
await expect( products ).toHaveCount( 1 );
} );
test( 'should refresh the page only if the user click on button', async ( {
page,
admin,
editor,
editorUtils,
productCollectionPageObject,
} ) => {
await admin.createNewPost();
await productCollectionPageObject.insertProductCollection();
await productCollectionPageObject.chooseCollectionInPost(
'productCatalog'
);
await editor.insertBlock( {
name: 'woocommerce/filter-wrapper',
attributes: {
filterType: 'stock-filter',
heading: 'Filter By Price',
},
} );
const stockFilterControls = await editorUtils.getBlockByName(
blockData.slug
);
await editor.selectBlocks( stockFilterControls );
await editor.openDocumentSettingsSidebar();
await page.getByText( "Show 'Apply filters' button" ).click();
await editorUtils.publishAndVisitPost();
await page.getByText( 'Out of Stock' ).click();
await page.getByRole( 'button', { name: 'Apply' } ).click();
await expect( page ).toHaveURL(
new RegExp( blockData.urlSearchParamWhenFilterIsApplied )
);
const products = page
.locator( '.wp-block-woocommerce-product-template' )
.getByRole( 'listitem' );
await expect( products ).toHaveCount( 1 );
} );
} );

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: Migrate Stock filter tests to Playwright

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: Fix ESLint errors