diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index a11fac4e599..7c8345d423c 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -61,4 +61,4 @@ jobs: - uses: actions/upload-artifact@v3 with: name: playwright-report - path: ./tests/e2e-pw/artifacts/test-results + path: playwright-report diff --git a/.wp-env.json b/.wp-env.json index eb415e8c496..3c1fe7067cf 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -4,7 +4,8 @@ "https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip", "https://github.com/WP-API/Basic-Auth/archive/master.zip", "https://downloads.wordpress.org/plugin/wordpress-importer.0.8.zip", - "./tests/mocks/woo-test-helper" + "./tests/mocks/woo-test-helper", + "." ], "env": { "tests": { diff --git a/docs/contributors/e2e-guidelines.md b/docs/contributors/e2e-guidelines.md index d392205dc72..2aa26ae31b3 100644 --- a/docs/contributors/e2e-guidelines.md +++ b/docs/contributors/e2e-guidelines.md @@ -18,13 +18,16 @@ The first folder is named "e2e" and it contains all the E2E tests that were crea #### Structure -There are two Playwright projects configuration: +There are three Playwright projects configuration: -- blockTheme -- classicTheme +- blockTheme +- blockThemeWithGlobalSideEffects +- classicTheme The blockTheme project runs the tests with the suffix _block_theme_. In this case, the theme is a block theme. The block theme is the default WordPress theme. Currently, it is Twenty-Twenty Three. You should use this configuration if you want test the block with the Site Editor. +The blockThemeWithGlobalSideEffects project runs the tests with the suffix _block_theme.side_effects_. These tests have side effects that can potentially impact other end-to-end (E2E) tests. Due to the nature of these tests and their potential impact, they are not executed in parallel with other tests. + The classicTheme project runs the tests with the suffix _classic_theme_. In this case, the theme is a Twenty Twenty-One. You should use this configuration if you want test the block with a classic theme. Each block should have a dedicated folder with a scoped util file if you want share some logic related to the block. diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index fb964e4dc8c..df06d5faf16 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -70,10 +70,7 @@ protected function init() { add_filter( 'current_theme_supports-block-templates', array( $this, 'remove_block_template_support_for_shop_page' ) ); add_filter( 'taxonomy_template_hierarchy', array( $this, 'add_archive_product_to_eligible_for_fallback_templates' ), 10, 1 ); add_filter( 'post_type_archive_title', array( $this, 'update_product_archive_title' ), 10, 2 ); - - if ( $this->package->is_experimental_build() ) { - add_action( 'after_switch_theme', array( $this, 'check_should_use_blockified_product_grid_templates' ), 10, 2 ); - } + add_action( 'after_switch_theme', array( $this, 'check_should_use_blockified_product_grid_templates' ), 10, 2 ); } /** @@ -373,11 +370,7 @@ public function get_block_templates_from_woocommerce( $slugs, $already_found_tem foreach ( $template_files as $template_file ) { // Skip the template if it's blockified, and we should only use classic ones. - // Until the blockified Product Grid Block is implemented, we need to always skip the blockified templates. - // phpcs:ignore Squiz.PHP.CommentedOutCode - if ( // $this->package->is_experimental_build() && - // ! BlockTemplateUtils::should_use_blockified_product_grid_templates() && - strpos( $template_file, 'blockified' ) !== false ) { + if ( ! BlockTemplateUtils::should_use_blockified_product_grid_templates() && strpos( $template_file, 'blockified' ) !== false ) { continue; } @@ -466,10 +459,9 @@ protected function get_templates_directory( $template_type = 'wp_template' ) { return $this->template_parts_directory; } - // When the blockified Product Grid Block will be implemented, we need to use the blockified templates. - // if ( $this->package->is_experimental_build() && BlockTemplateUtils::should_use_blockified_product_grid_templates() ) { - // return $this->templates_directory . '/blockified'; - // }. + if ( BlockTemplateUtils::should_use_blockified_product_grid_templates() ) { + return $this->templates_directory . '/blockified'; + } return $this->templates_directory; } diff --git a/src/Domain/Bootstrap.php b/src/Domain/Bootstrap.php index f50b6597cf8..f0c1bed7c00 100644 --- a/src/Domain/Bootstrap.php +++ b/src/Domain/Bootstrap.php @@ -96,7 +96,7 @@ protected function init() { $this->register_dependencies(); $this->register_payment_methods(); - if ( $this->package->is_experimental_build() && is_admin() ) { + if ( is_admin() ) { if ( $this->package->get_version() !== $this->package->get_version_stored_on_db() ) { $this->migration->run_migrations(); $this->package->set_version_stored_on_db(); diff --git a/src/Migration.php b/src/Migration.php index e55534a892a..8a80059069e 100644 --- a/src/Migration.php +++ b/src/Migration.php @@ -7,7 +7,6 @@ * @since 2.5.0 */ class Migration { - /** * DB updates and callbacks that need to be run per version. * @@ -17,10 +16,9 @@ class Migration { * @var array */ private $db_upgrades = array( - // We don't need to do the following migration yet, but we'll keep it here for future use. - // '7.10.0' => array( - // 'wc_blocks_update_710_blockified_product_grid_block', - // ). + '10.3.0' => array( + 'wc_blocks_update_1030_blockified_product_grid_block', + ), ); /** @@ -31,7 +29,14 @@ class Migration { public function run_migrations() { $current_db_version = get_option( Options::WC_BLOCK_VERSION, '' ); + // This check is necessary because the version was not being set in the database until 10.3.0. + // We can remove this check in the next months. + if ( ! empty( get_option( 'wc_blocks_db_schema_version', '' ) ) ) { + $this->wc_blocks_update_1030_blockified_product_grid_block(); + } + if ( empty( $current_db_version ) ) { + // This is a fresh install, so we don't need to run any migrations. return; } @@ -47,7 +52,7 @@ public function run_migrations() { /** * Set a flag to indicate if the blockified Product Grid Block should be rendered by default. */ - public static function wc_blocks_update_710_blockified_product_grid_block() { + public static function wc_blocks_update_1030_blockified_product_grid_block() { update_option( Options::WC_BLOCK_USE_BLOCKIFIED_PRODUCT_GRID_BLOCK_AS_TEMPLATE, wc_bool_to_string( false ) ); } } diff --git a/templates/templates/blockified/taxonomy-product_tag.html b/templates/templates/blockified/taxonomy-product_tag.html index 62d797de82c..1de3af7a0ed 100644 --- a/templates/templates/blockified/taxonomy-product_tag.html +++ b/templates/templates/blockified/taxonomy-product_tag.html @@ -43,7 +43,4 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/tests/e2e-pw/playwright-utils/test.ts b/tests/e2e-pw/playwright-utils/test.ts index f3dc7ef94b7..693915ea97c 100644 --- a/tests/e2e-pw/playwright-utils/test.ts +++ b/tests/e2e-pw/playwright-utils/test.ts @@ -10,7 +10,11 @@ import { RequestUtils, } from '@wordpress/e2e-test-utils-playwright'; -import { TemplateApiUtils, STORAGE_STATE_PATH } from '@woocommerce/e2e-utils'; +import { + TemplateApiUtils, + STORAGE_STATE_PATH, + EditorUtils, +} from '@woocommerce/e2e-utils'; /** * Set of console logging types observed to protect against unexpected yet @@ -100,6 +104,7 @@ const test = base.extend< editor: Editor; pageUtils: PageUtils; templateApiUtils: TemplateApiUtils; + editorUtils: EditorUtils; snapshotConfig: void; }, { @@ -129,6 +134,9 @@ const test = base.extend< }, templateApiUtils: async ( {}, use ) => await use( new TemplateApiUtils( request ) ), + editorUtils: async ( { editor }, use ) => { + await use( new EditorUtils( editor ) ); + }, requestUtils: [ async ( {}, use, workerInfo ) => { const requestUtils = await RequestUtils.setup( { diff --git a/tests/e2e-pw/playwright.config.ts b/tests/e2e-pw/playwright.config.ts index 5124db0ea68..db83ef4d4d0 100644 --- a/tests/e2e-pw/playwright.config.ts +++ b/tests/e2e-pw/playwright.config.ts @@ -27,9 +27,10 @@ const config: ExtendedPlaywrightTestConfig = { globalTeardown: require.resolve( './global-teardown' ), testDir: 'tests', retries: CI ? 2 : 0, - workers: 4, - fullyParallel: true, - reporter: process.env.CI ? [ [ 'github' ], [ 'list' ] ] : 'list', + workers: 1, + reporter: process.env.CI + ? [ [ 'github' ], [ 'list' ], [ 'html' ] ] + : 'list', maxFailures: E2E_MAX_FAILURES ? Number( E2E_MAX_FAILURES ) : 0, use: { baseURL: BASE_URL, @@ -50,10 +51,16 @@ const config: ExtendedPlaywrightTestConfig = { testMatch: /.*.block_theme.spec.ts/, dependencies: [ 'blockThemeConfiguration' ], }, + { + name: 'blockThemeWithGlobalSideEffects', + testMatch: /.*.block_theme.side_effects.spec.ts/, + dependencies: [ 'blockTheme' ], + fullyParallel: false, + }, { name: 'classicThemeConfiguration', testMatch: /block-theme.setup.ts/, - dependencies: [ 'blockTheme' ], + dependencies: [ 'blockThemeWithGlobalSideEffects' ], }, { name: 'classicTheme', diff --git a/tests/e2e-pw/tests/classic-template/classic-template.block_theme.side_effects.spec.ts b/tests/e2e-pw/tests/classic-template/classic-template.block_theme.side_effects.spec.ts new file mode 100644 index 00000000000..e0ef9a694c4 --- /dev/null +++ b/tests/e2e-pw/tests/classic-template/classic-template.block_theme.side_effects.spec.ts @@ -0,0 +1,117 @@ +/** + * External dependencies + */ +import { BlockData } from '@woocommerce/e2e-types'; +import { test, expect } from '@woocommerce/e2e-playwright-utils'; +import { cli } from '@woocommerce/e2e-utils'; + +/** + * Internal dependencies + */ + +const blockData: BlockData = { + name: 'woocommerce/legacy-template', + mainClass: '.wc-block-price-filter', + selectors: { + frontend: {}, + editor: {}, + }, +}; + +const templates = { + 'single-product': { + templateTitle: 'Single Product', + slug: 'single-product', + frontendPage: '/product/single/', + }, + 'taxonomy-product_attribute': { + templateTitle: 'Product Attribute', + slug: 'taxonomy-product_attribute', + frontendPage: '/product-attribute/color/', + }, + + 'taxonomy-product_cat': { + templateTitle: 'Product Category', + slug: 'taxonomy-product_cat', + frontendPage: '/product-category/music/', + }, + // We don't have products with tags in the test site. Uncomment this when we have products with tags. + // 'taxonomy-product_tag': { + // templateTitle: 'Product Tag', + // slug: 'taxonomy-product_tag', + // frontendPage: '/product-tag/hoodie/', + // }, + 'archive-product': { + templateTitle: 'Product Catalog', + slug: 'archive-product', + frontendPage: '/shop/', + }, + 'product-search-results': { + templateTitle: 'Product Search Results', + slug: 'product-search-results', + frontendPage: '/?s=single&post_type=product', + }, +}; + +for ( const { templateTitle, slug, frontendPage } of Object.values( + templates +) ) { + test.describe( `${ blockData.name } Block `, () => { + test.beforeAll( async () => { + await cli( + 'npm run wp-env run tests-cli "wp option update wc_blocks_use_blockified_product_grid_block_as_template false"' + ); + } ); + + test( `is rendered on ${ templateTitle } template`, async ( { + admin, + editorUtils, + editor, + } ) => { + await admin.visitSiteEditor( { + postId: `woocommerce/woocommerce//${ slug }`, + postType: 'wp_template', + } ); + + await editor.canvas.click( 'body' ); + + const block = await editorUtils.getBlockByName( blockData.name ); + expect( block ).not.toBeNull(); + } ); + + test( `is rendered on ${ templateTitle } template - frontend side`, async ( { + admin, + editor, + page, + } ) => { + await admin.visitSiteEditor( { + postId: `woocommerce/woocommerce//${ slug }`, + postType: 'wp_template', + } ); + + await editor.canvas.click( 'body' ); + + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Hello World' }, + } ); + + await editor.saveSiteEditorEntities(); + + await page.goto( frontendPage ); + + const helloWorldText = await page.getByText( 'Hello World' ); + + expect( helloWorldText ).not.toBeNull(); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await cli( + 'npm run wp-env run tests-cli "wp option delete wc_blocks_use_blockified_product_grid_block_as_template"' + ); + + await requestUtils.deleteAllTemplates( 'wp_template' ); + await requestUtils.deleteAllTemplates( 'wp_template_part' ); + } ); + } ); +} diff --git a/tests/e2e-pw/tests/classic-template/utils.ts b/tests/e2e-pw/tests/classic-template/utils.ts new file mode 100644 index 00000000000..a4fa9102821 --- /dev/null +++ b/tests/e2e-pw/tests/classic-template/utils.ts @@ -0,0 +1,9 @@ +export const WOOCOMMERCE_ID = 'woocommerce/woocommerce'; + +export const getDefaultTemplateProps = ( templateTitle: string ) => { + return { + templateTitle, + addedBy: WOOCOMMERCE_ID, + hasActions: false, + }; +}; diff --git a/tests/e2e-pw/tests/price-filter/price-filter.block_theme.spec.ts b/tests/e2e-pw/tests/price-filter/price-filter.block_theme.side_effects.spec.ts similarity index 91% rename from tests/e2e-pw/tests/price-filter/price-filter.block_theme.spec.ts rename to tests/e2e-pw/tests/price-filter/price-filter.block_theme.side_effects.spec.ts index 65eee1d1b26..27a034c835f 100644 --- a/tests/e2e-pw/tests/price-filter/price-filter.block_theme.spec.ts +++ b/tests/e2e-pw/tests/price-filter/price-filter.block_theme.side_effects.spec.ts @@ -3,7 +3,7 @@ */ import { BlockData } from '@woocommerce/e2e-types'; import { test, expect } from '@woocommerce/e2e-playwright-utils'; -import { BASE_URL, getBlockByName } from '@woocommerce/e2e-utils'; +import { BASE_URL, cli, getBlockByName } from '@woocommerce/e2e-utils'; /** * Internal dependencies @@ -105,6 +105,11 @@ test.describe( `${ blockData.name } Block - with All products Block`, () => { } ); test.describe( `${ blockData.name } Block - with PHP classic template`, () => { + test.beforeAll( async () => { + await cli( + 'npm run wp-env run tests-cli "wp option update wc_blocks_use_blockified_product_grid_block_as_template false"' + ); + } ); test.beforeEach( async ( { admin, page, editor } ) => { await admin.visitSiteEditor( { postId: 'woocommerce/woocommerce//archive-product', @@ -178,4 +183,10 @@ test.describe( `${ blockData.name } Block - with PHP classic template`, () => { expect( products ).toHaveLength( 1 ); } ); + + test.afterAll( async () => { + await cli( + 'npm run wp-env run tests-cli "wp option delete wc_blocks_use_blockified_product_grid_block_as_template"' + ); + } ); } ); diff --git a/tests/e2e-pw/tests/products/products.block_theme.side_effects.spec.ts b/tests/e2e-pw/tests/products/products.block_theme.side_effects.spec.ts new file mode 100644 index 00000000000..7bf146101e8 --- /dev/null +++ b/tests/e2e-pw/tests/products/products.block_theme.side_effects.spec.ts @@ -0,0 +1,157 @@ +/** + * External dependencies + */ +import { BlockData } from '@woocommerce/e2e-types'; +import { test, expect } from '@woocommerce/e2e-playwright-utils'; + +/** + * Internal dependencies + */ +import { + getProductsNameFromClassicTemplate, + getProductsNameFromProductQuery, +} from './utils'; + +const blockData: BlockData = { + name: 'core/query', + mainClass: '.wc-block-price-filter', + selectors: { + frontend: {}, + editor: {}, + }, +}; + +const templates = { + 'taxonomy-product_attribute': { + templateTitle: 'Product Attribute', + slug: 'taxonomy-product_attribute', + frontendPage: '/product-attribute/color/', + }, + 'taxonomy-product_cat': { + templateTitle: 'Product Category', + slug: 'taxonomy-product_cat', + frontendPage: '/product-category/music/', + }, + // We don't have products with tags in the test site. Uncomment this when we have products with tags. + // 'taxonomy-product_tag': { + // templateTitle: 'Product Tag', + // slug: 'taxonomy-product_tag', + // frontendPage: '/product-tag/hoodie/', + // }, + 'archive-product': { + templateTitle: 'Product Catalog', + slug: 'archive-product', + frontendPage: '/shop/', + }, + 'product-search-results': { + templateTitle: 'Product Search Results', + slug: 'product-search-results', + frontendPage: '/?s=shirt&post_type=product', + }, +}; + +test.describe( `${ blockData.name } Block `, () => { + test( 'when Inherit Query from template is enabled all the settings that customize the query should be hidden', async ( { + admin, + editorUtils, + editor, + page, + } ) => { + await admin.visitSiteEditor( { + postId: 'woocommerce/woocommerce//archive-product', + postType: 'wp_template', + } ); + + await editor.canvas.click( 'body' ); + + const block = await editorUtils.getBlockByName( blockData.name ); + await editor.selectBlocks( block ); + + await editor.openDocumentSettingsSidebar(); + + const advancedFilterOption = await page.getByLabel( + 'Advanced Filters options' + ); + const inheritQueryFromTemplateOption = await page.getByLabel( + 'Inherit query from template' + ); + + await expect( advancedFilterOption ).not.toBeVisible(); + await expect( inheritQueryFromTemplateOption ).toBeVisible(); + } ); + test( 'when Inherit Query from template is disabled all the settings that customize the query should be visble', async ( { + admin, + editorUtils, + editor, + page, + } ) => { + await admin.visitSiteEditor( { + postId: 'woocommerce/woocommerce//archive-product', + postType: 'wp_template', + } ); + + await editor.canvas.click( 'body' ); + + const block = await editorUtils.getBlockByName( blockData.name ); + await editor.selectBlocks( block ); + + await editor.openDocumentSettingsSidebar(); + + const advancedFilterOption = await page.getByLabel( + 'Advanced Filters options' + ); + const inheritQueryFromTemplateOption = await page.getByLabel( + 'Inherit query from template' + ); + + await inheritQueryFromTemplateOption.click(); + + await expect( advancedFilterOption ).toBeVisible(); + await expect( inheritQueryFromTemplateOption ).toBeVisible(); + } ); +} ); +for ( const { templateTitle, slug, frontendPage } of Object.values( + templates +) ) { + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deleteAllTemplates( 'wp_template' ); + await requestUtils.deleteAllTemplates( 'wp_template_part' ); + } ); + test.describe( `${ templateTitle } template`, () => + test( 'Products block matches with classic template block', async ( { + admin, + editor, + page, + editorUtils, + } ) => { + await admin.visitSiteEditor( { + postId: `woocommerce/woocommerce//${ slug }`, + postType: 'wp_template', + } ); + + await editor.canvas.click( 'body' ); + await editor.canvas.waitForLoadState( 'networkidle' ); + const block = await editorUtils.getBlockByName( blockData.name ); + await editor.selectBlocks( block ); + await editor.insertBlock( { + name: 'woocommerce/legacy-template', + attributes: { + template: slug, + }, + } ); + + await editor.saveSiteEditorEntities(); + + await page.goto( frontendPage ); + + const classicProducts = await getProductsNameFromClassicTemplate( + page + ); + const productQueryProducts = await getProductsNameFromProductQuery( + page + ); + + expect( classicProducts ).toEqual( productQueryProducts ); + } ) + ); +} diff --git a/tests/e2e-pw/tests/products/utils.ts b/tests/e2e-pw/tests/products/utils.ts new file mode 100644 index 00000000000..8b382ee7bdd --- /dev/null +++ b/tests/e2e-pw/tests/products/utils.ts @@ -0,0 +1,16 @@ +/** + * External dependencies + */ +import { Page } from '@playwright/test'; + +export const getProductsNameFromClassicTemplate = async ( page: Page ) => { + const products = await page.locator( '.woocommerce-loop-product__title' ); + return products.allTextContents(); +}; + +export const getProductsNameFromProductQuery = async ( page: Page ) => { + const products = await page.locator( + '.wp-block-query .wp-block-post-title' + ); + return products.allTextContents(); +}; diff --git a/tests/e2e-pw/types/block-data.ts b/tests/e2e-pw/types/block-data.ts index 6437a0f68b8..fa1af0d034f 100644 --- a/tests/e2e-pw/types/block-data.ts +++ b/tests/e2e-pw/types/block-data.ts @@ -1,4 +1,4 @@ -export type BlockData< T = undefined > = { +export type BlockData< T = unknown > = { name: string; mainClass: string; selectors: Record< 'editor' | 'frontend', Record< string, unknown > >; diff --git a/tests/e2e-pw/utils/api/TemplateApiUtils.ts b/tests/e2e-pw/utils/api/TemplateApiUtils.ts index 6b8170e40db..f4e1ec01a93 100644 --- a/tests/e2e-pw/utils/api/TemplateApiUtils.ts +++ b/tests/e2e-pw/utils/api/TemplateApiUtils.ts @@ -50,4 +50,25 @@ export class TemplateApiUtils { } ); } + + async getTemplates() { + const storageState = JSON.parse( + await fs.readFile( STORAGE_STATE_PATH, 'utf-8' ) + ); + + const requestUtils = await this.request.newContext( { + baseURL: BASE_URL, + storageState: storageState && { + cookies: storageState.cookies, + origins: [], + }, + } ); + const response = await requestUtils.get( `/wp-json/wp/v2/templates`, { + headers: { + 'X-WP-Nonce': storageState.nonce, + }, + } ); + + return await response.json(); + } } diff --git a/tests/e2e-pw/utils/editor/EditorUtils.ts b/tests/e2e-pw/utils/editor/EditorUtils.ts new file mode 100644 index 00000000000..a4e7075b9c5 --- /dev/null +++ b/tests/e2e-pw/utils/editor/EditorUtils.ts @@ -0,0 +1,18 @@ +/** + * External dependencies + */ +import { Editor } from '@wordpress/e2e-test-utils-playwright'; +/** + * Internal dependencies + */ + +export class EditorUtils { + editor: Editor; + constructor( editor: Editor ) { + this.editor = editor; + } + + async getBlockByName( name: string ) { + return this.editor.canvas.locator( `[data-type="${ name }"]` ); + } +} diff --git a/tests/e2e-pw/utils/editor/index.ts b/tests/e2e-pw/utils/editor/index.ts new file mode 100644 index 00000000000..9016ba8813c --- /dev/null +++ b/tests/e2e-pw/utils/editor/index.ts @@ -0,0 +1 @@ +export * from './EditorUtils'; diff --git a/tests/e2e-pw/utils/index.ts b/tests/e2e-pw/utils/index.ts index becfa58d01c..6b13546eeea 100644 --- a/tests/e2e-pw/utils/index.ts +++ b/tests/e2e-pw/utils/index.ts @@ -3,3 +3,4 @@ export * from './constants'; export * from './use-block-theme'; export * from './cli'; export * from './api'; +export * from './editor'; diff --git a/tests/e2e/specs/backend/__snapshots__/site-editing-templates.test.js.snap b/tests/e2e/specs/backend/__snapshots__/site-editing-templates.test.js.snap deleted file mode 100644 index 13f68464c66..00000000000 --- a/tests/e2e/specs/backend/__snapshots__/site-editing-templates.test.js.snap +++ /dev/null @@ -1,51 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Store Editing Templates Product Catalog block template should contain the "WooCommerce Product Grid Block" classic template 1`] = ` -" - - -
- - -" -`; - -exports[`Store Editing Templates Product Search Results block template should contain the "WooCommerce Product Grid Block" classic template 1`] = ` -" - - - - - -" -`; - -exports[`Store Editing Templates Product by Category block template should contain the "WooCommerce Product Taxonomy Block" classic template 1`] = ` -" - - - - - -" -`; - -exports[`Store Editing Templates Products by Tag block template should contain the "WooCommerce Product Taxonomy Block" classic template 1`] = ` -" - - - - - -" -`; - -exports[`Store Editing Templates Single Product block template should contain the "WooCommerce Single Product Block" classic template 1`] = ` -" - - - - - -" -`; diff --git a/tests/e2e/specs/backend/add-to-cart-form.test.js b/tests/e2e/specs/backend/add-to-cart-form.test.js index 2745d566e63..4f4e2b7d0dd 100644 --- a/tests/e2e/specs/backend/add-to-cart-form.test.js +++ b/tests/e2e/specs/backend/add-to-cart-form.test.js @@ -54,7 +54,6 @@ describe( `${ block.name } Block`, () => { } ); it( 'can be inserted more than once', async () => { - await insertBlockDontWaitForInsertClose( block.name ); await insertBlockDontWaitForInsertClose( block.name ); const filteredBlocks = await filterCurrentBlocks( ( b ) => b.name === block.slug diff --git a/tests/e2e/specs/backend/single-product-details.test.js b/tests/e2e/specs/backend/single-product-details.test.js index 9a8e63aa65b..d9c04f55a87 100644 --- a/tests/e2e/specs/backend/single-product-details.test.js +++ b/tests/e2e/specs/backend/single-product-details.test.js @@ -50,7 +50,6 @@ describe( `${ block.name } Block`, () => { } ); it( 'can be inserted more than once', async () => { - await insertBlockDontWaitForInsertClose( block.name ); await insertBlockDontWaitForInsertClose( block.name ); const filteredBlocks = await filterCurrentBlocks( ( b ) => b.name === block.slug diff --git a/tests/e2e/specs/backend/site-editing-templates.test.js b/tests/e2e/specs/backend/site-editing-templates.test.js deleted file mode 100644 index 7abef3e64b9..00000000000 --- a/tests/e2e/specs/backend/site-editing-templates.test.js +++ /dev/null @@ -1,701 +0,0 @@ -/* eslint-disable jest/no-conditional-expect */ -/** - * External dependencies - */ -import { URL } from 'url'; -import { - canvas, - 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, - 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/woocommerceCustomized'; - -describe( '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, - } ); - } - } ); - - 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, - } ); - } - } ); - - 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, - } ); - } - } ); - - 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, - } ); - } - } ); - - 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, - } ); - } - } ); - - 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, - } ); - } - } ); - - 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, - } ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/frontend/legacy-template-blocks.test.ts b/tests/e2e/specs/frontend/legacy-template-blocks.test.ts deleted file mode 100644 index 0cd13d14589..00000000000 --- a/tests/e2e/specs/frontend/legacy-template-blocks.test.ts +++ /dev/null @@ -1,146 +0,0 @@ -/** - * External dependencies - */ -import { URL } from 'url'; - -/** - * Internal dependencies - */ -import { BASE_URL, useTheme } from '../../utils'; -const SELECTORS = { - productArchivePage: { - paginationUI: '.woocommerce-pagination', - productContainers: '.products .product', - productsList: '.products', - resultsCount: '.woocommerce-result-count', - title: '.page-title', - }, -}; - -/** - * Extracts data regarding pagination from the page - * - * @return {Promise<{ displayedCount: number, shouldHavePaginationUI: boolean }>} How many products are displayed - * and whether there should be a pagination UI (i.e. the displayed products are lesser than the total - * number of products). - */ -function extractPaginationData() { - const { productArchivePage } = SELECTORS; - - return page.$eval( productArchivePage.resultsCount, ( $el ) => { - const resultsCountRegEx = /1–(\d+)|\d+/; - const matches = $el.textContent.match( resultsCountRegEx ); - - // Depending on pagination, string can be either: - // a) 'Showing x–y of z results' - // b) 'Showing all x results' - return { - displayedCount: Number( matches[ 1 ] ) || Number( matches[ 0 ] ), - shouldHavePaginationUI: !! matches[ 1 ], - }; - } ); -} - -describe( 'Classic Template blocks', () => { - useTheme( 'emptytheme' ); - - describe( 'Product Archive block', () => { - it( 'renders a list of products with their count and pagination', async () => { - const { productArchivePage } = SELECTORS; - - await page.goto( - new URL( '/?post_type=product', BASE_URL ).toString() - ); - - await page.waitForSelector( productArchivePage.productsList ); - await page.waitForSelector( productArchivePage.resultsCount ); - - const { displayedCount, shouldHavePaginationUI } = - await extractPaginationData(); - - if ( shouldHavePaginationUI ) { - await expect( page ).toMatchElement( - productArchivePage.paginationUI - ); - } - - const $productElements = await page.$$( - productArchivePage.productContainers - ); - - expect( $productElements ).toHaveLength( Number( displayedCount ) ); - } ); - } ); - - describe( 'Products by Category block', () => { - it( 'renders a list of products with their count, pagination and the category title', async () => { - const CATEGORY_NAME = 'Uncategorized'; - const { productArchivePage } = SELECTORS; - - await page.goto( - new URL( - `/product-category/${ CATEGORY_NAME.toLowerCase() }`, - BASE_URL - ).toString() - ); - - await expect( page ).toMatchElement( productArchivePage.title, { - text: CATEGORY_NAME, - } ); - - await page.waitForSelector( productArchivePage.productsList ); - await page.waitForSelector( productArchivePage.resultsCount ); - - const { displayedCount, shouldHavePaginationUI } = - await extractPaginationData(); - - if ( shouldHavePaginationUI ) { - await expect( page ).toMatchElement( - productArchivePage.paginationUI - ); - } - - const $productElements = await page.$$( - productArchivePage.productContainers - ); - - expect( $productElements ).toHaveLength( Number( displayedCount ) ); - } ); - } ); - - describe( 'Products by Tag block', () => { - it( 'renders a list of products with their count, pagination and the tag title', async () => { - const TAG_NAME = 'Newest'; - const { productArchivePage } = SELECTORS; - - await page.goto( - new URL( - `/product-tag/${ TAG_NAME.toLowerCase() }`, - BASE_URL - ).toString() - ); - - await expect( page ).toMatchElement( productArchivePage.title, { - text: TAG_NAME, - } ); - - await page.waitForSelector( productArchivePage.productsList ); - await page.waitForSelector( productArchivePage.resultsCount ); - - const { displayedCount, shouldHavePaginationUI } = - await extractPaginationData(); - - if ( shouldHavePaginationUI ) { - await expect( page ).toMatchElement( - productArchivePage.paginationUI - ); - } - - const $productElements = await page.$$( - productArchivePage.productContainers - ); - - expect( $productElements ).toHaveLength( displayedCount ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/shopper/active-filters.test.ts b/tests/e2e/specs/shopper/active-filters.test.ts index 1793f050bcd..03c9696cd1c 100644 --- a/tests/e2e/specs/shopper/active-filters.test.ts +++ b/tests/e2e/specs/shopper/active-filters.test.ts @@ -47,6 +47,7 @@ const block = { stockFilterBlock: '.wc-block-stock-filter-list', attributeFilterBlock: '.wc-block-attribute-filter-list', productsList: '.wc-block-grid__products > li', + productsBlockProducts: '.wp-block-post-template > li', classicProductsList: '.products.columns-3 > li', }, }, @@ -209,7 +210,7 @@ describe( 'Shopper → Active Filters Block', () => { expect( isRefreshed ).not.toHaveBeenCalled(); } ); } ); - describe( 'With PHP Templates', () => { + describe( 'With PHP Templates (Products Block and Classic Template Block)', () => { useTheme( 'emptytheme' ); beforeAll( async () => { await deleteAllTemplates( 'wp_template_part' ); @@ -218,6 +219,7 @@ describe( 'Shopper → Active Filters Block', () => { postId: 'woocommerce/woocommerce//archive-product', } ); + await insertBlock( 'WooCommerce Product Grid Block' ); await insertBlocks(); const canvasEl = canvas(); @@ -273,12 +275,17 @@ describe( 'Shopper → Active Filters Block', () => { const activeFilterNameText = await getActiveFilterNameText(); expect( activeFilterNameText ).toBe( FILTER_STOCK_STATUS_PROPERTY ); - const products = await page.$$( + const classicProductsList = await page.$$( selectors.frontend.classicProductsList ); + const products = await page.$$( + selectors.frontend.productsBlockProducts + ); + expect( isRefreshed ).toHaveBeenCalledTimes( 2 ); expect( products ).toHaveLength( 1 ); + expect( classicProductsList ).toHaveLength( 1 ); await expect( page ).toMatch( SIMPLE_PHYSICAL_PRODUCT_NAME ); } ); @@ -306,14 +313,19 @@ describe( 'Shopper → Active Filters Block', () => { await clickLink( selectors.frontend.removeFilterButton ); - const products = await page.$$( + const classicProductsList = await page.$$( selectors.frontend.classicProductsList ); + const products = await page.$$( + selectors.frontend.productsBlockProducts + ); + expect( page.url() ).not.toMatch( 'instock' ); expect( page.url() ).toMatch( FILTER_CAPACITY_PROPERTY ); expect( isRefreshed ).toHaveBeenCalledTimes( 3 ); expect( products ).toHaveLength( 1 ); + expect( classicProductsList ).toHaveLength( 1 ); await expect( page ).toMatch( SIMPLE_PHYSICAL_PRODUCT_NAME ); } ); @@ -332,13 +344,18 @@ describe( 'Shopper → Active Filters Block', () => { await clickLink( selectors.frontend.removeAllFiltersButton ); - const products = await page.$$( + const classicProductsList = await page.$$( selectors.frontend.classicProductsList ); + const products = await page.$$( + selectors.frontend.productsBlockProducts + ); + expect( page.url() ).not.toMatch( 'instock' ); expect( page.url() ).toMatch( SHOP_PAGE ); expect( isRefreshed ).toHaveBeenCalledTimes( 2 ); + expect( classicProductsList ).toHaveLength( 5 ); expect( products ).toHaveLength( 5 ); } ); } ); diff --git a/tests/e2e/specs/shopper/filter-products-by-attribute.test.ts b/tests/e2e/specs/shopper/filter-products-by-attribute.test.ts index b1a75f84400..ba53704ed04 100644 --- a/tests/e2e/specs/shopper/filter-products-by-attribute.test.ts +++ b/tests/e2e/specs/shopper/filter-products-by-attribute.test.ts @@ -112,7 +112,7 @@ describe( `${ block.name } Block`, () => { } ); } ); - describe( 'with PHP classic template', () => { + describe( 'with PHP classic template (Products Block and Classic Template Block)', () => { const productCatalogTemplateId = 'woocommerce/woocommerce//archive-product'; @@ -124,6 +124,7 @@ describe( `${ block.name } Block`, () => { await goToTemplateEditor( { postId: productCatalogTemplateId, } ); + await insertBlock( 'WooCommerce Product Grid Block' ); await insertFilterByAttributeBlock(); await saveTemplate(); } ); @@ -142,6 +143,11 @@ describe( `${ block.name } Block`, () => { selectors.frontend.classicProductsList ); + const productsBlockProductsList = await page.$$( + selectors.frontend.queryProductsList + ); + + expect( productsBlockProductsList ).toHaveLength( 5 ); expect( products ).toHaveLength( 5 ); } ); @@ -169,8 +175,13 @@ describe( `${ block.name } Block`, () => { const pageURL = page.url(); const parsedURL = new URL( pageURL ); + 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 @@ -208,11 +219,17 @@ describe( `${ block.name } Block`, () => { 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 diff --git a/tests/e2e/specs/shopper/filter-products-by-rating.test.ts b/tests/e2e/specs/shopper/filter-products-by-rating.test.ts index fe43f77985f..f1c8da27ae0 100644 --- a/tests/e2e/specs/shopper/filter-products-by-rating.test.ts +++ b/tests/e2e/specs/shopper/filter-products-by-rating.test.ts @@ -93,7 +93,7 @@ describe( `${ block.name } Block`, () => { } ); } ); - describe( 'with PHP classic template', () => { + describe( 'with PHP classic template (Products Block and Classic Template Block)', () => { const productCatalogTemplateId = 'woocommerce/woocommerce//archive-product'; @@ -104,6 +104,7 @@ describe( `${ block.name } Block`, () => { await goToTemplateEditor( { postId: productCatalogTemplateId, } ); + await insertBlock( 'WooCommerce Product Grid Block' ); await insertBlock( block.name ); await saveTemplate(); await goToShopPage(); @@ -142,11 +143,19 @@ describe( `${ block.name } Block`, () => { 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( FIVE_STAR_PRODUCTS_AMOUNT ); + expect( productsBlockProductsList ).toHaveLength( + FIVE_STAR_PRODUCTS_AMOUNT + ); expect( parsedURL.search ).toEqual( block.urlSearchParamWhenFilterIsApplied ); @@ -191,8 +200,16 @@ describe( `${ block.name } Block`, () => { selectors.frontend.classicProductsList ); + const productsBlockProductsList = await page.$$( + selectors.frontend.queryProductsList + ); + expect( isRefreshed ).toBeCalledTimes( 1 ); expect( products ).toHaveLength( FIVE_STAR_PRODUCTS_AMOUNT ); + expect( productsBlockProductsList ).toHaveLength( + FIVE_STAR_PRODUCTS_AMOUNT + ); + expect( parsedURL.search ).toEqual( block.urlSearchParamWhenFilterIsApplied ); @@ -213,7 +230,6 @@ describe( `${ block.name } Block`, () => { await insertBlock( 'Products (Beta)' ); await insertBlock( block.name ); - await page.waitForNetworkIdle(); await publishPost(); editorPageUrl = page.url(); @@ -260,7 +276,7 @@ describe( `${ block.name } Block`, () => { await selectBlockByName( block.slug ); await switchBlockInspectorTab( 'Settings' ); await setCheckbox( - await getToggleIdByLabel( "Show 'Apply filters' button", 1 ) + await getToggleIdByLabel( "Show 'Apply filters' button" ) ); await saveOrPublish(); diff --git a/tests/e2e/specs/shopper/filter-products-by-stock.test.ts b/tests/e2e/specs/shopper/filter-products-by-stock.test.ts index 61283a76584..2327d044df5 100644 --- a/tests/e2e/specs/shopper/filter-products-by-stock.test.ts +++ b/tests/e2e/specs/shopper/filter-products-by-stock.test.ts @@ -94,7 +94,7 @@ describe( `${ block.name } Block`, () => { } ); } ); - describe( 'with PHP classic template', () => { + describe( 'with PHP classic template (Products Block and Classic Template Block)', () => { const productCatalogTemplateId = 'woocommerce/woocommerce//archive-product'; @@ -105,6 +105,7 @@ describe( `${ block.name } Block`, () => { await goToTemplateEditor( { postId: productCatalogTemplateId, } ); + await insertBlock( 'WooCommerce Product Grid Block' ); await insertBlock( block.name ); await saveTemplate(); await goToShopPage(); @@ -124,7 +125,12 @@ describe( `${ block.name } Block`, () => { 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 () => { @@ -147,11 +153,18 @@ describe( `${ block.name } Block`, () => { 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 @@ -197,8 +210,13 @@ describe( `${ block.name } Block`, () => { 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 diff --git a/tests/e2e/specs/shopper/product-query/product-query-with-templates.test.ts b/tests/e2e/specs/shopper/product-query/product-query-with-templates.test.ts deleted file mode 100644 index bfd948485f3..00000000000 --- a/tests/e2e/specs/shopper/product-query/product-query-with-templates.test.ts +++ /dev/null @@ -1,192 +0,0 @@ -/** - * External dependencies - */ -import { - deleteAllTemplates, - ensureSidebarOpened, -} from '@wordpress/e2e-test-utils'; - -/** - * Internal dependencies - */ -import { - BASE_URL, - goToTemplateEditor, - saveTemplate, - useTheme, -} from '../../../utils'; -import { - addProductQueryBlock, - block, - getProductsNameFromClassicTemplate, - getProductsNameFromProductQuery, - toggleInheritQueryFromTemplateSetting, -} from './utils'; - -describe( `${ block.name } Block`, () => { - useTheme( 'emptytheme' ); - - describe( 'with All Templates', () => { - beforeEach( async () => { - const productCatalogTemplateId = - 'woocommerce/woocommerce//archive-product'; - - await goToTemplateEditor( { - postId: productCatalogTemplateId, - } ); - await ensureSidebarOpened(); - await addProductQueryBlock(); - } ); - - it( 'when Inherit Query from template is disabled all the settings that customize the query should be hidden', async () => { - await toggleInheritQueryFromTemplateSetting(); - - await expect( page ).toMatchElement( - block.selectors.editor.popularFilter - ); - - await expect( page ).toMatchElement( - block.selectors.editor.advanceFilterOptionsButton - ); - } ); - - it( 'when Inherit Query from template is enabled all the settings that customize the query should be hidden', async () => { - await ensureSidebarOpened(); - - const popularFilterEl = await page.$( - block.selectors.editor.popularFilter - ); - const advanceFilterOptionsButton = await page.$( - block.selectors.editor.advanceFilterOptionsButton - ); - - expect( popularFilterEl ).toBeNull(); - expect( advanceFilterOptionsButton ).toBeNull(); - } ); - } ); - - describe( 'with Product Catalog Template', () => { - beforeAll( async () => { - const productCatalogTemplateId = - 'woocommerce/woocommerce//archive-product'; - - await goToTemplateEditor( { - postId: productCatalogTemplateId, - } ); - await addProductQueryBlock(); - await ensureSidebarOpened(); - await page.waitForNetworkIdle(); - await saveTemplate(); - await page.waitForNetworkIdle(); - await page.goto( BASE_URL + '/shop' ); - await page.waitForNetworkIdle(); - } ); - - afterAll( async () => { - await deleteAllTemplates( 'wp_template' ); - } ); - - it( 'should render the same products in the same position of the classic template', async () => { - const classicProducts = await getProductsNameFromClassicTemplate(); - const products = await getProductsNameFromProductQuery(); - - expect( classicProducts ).toEqual( products ); - } ); - } ); - - describe( 'with Products By Category Template', () => { - beforeAll( async () => { - const taxonomyProductCategory = - 'woocommerce/woocommerce//taxonomy-product_cat'; - - await goToTemplateEditor( { - postId: taxonomyProductCategory, - } ); - await addProductQueryBlock(); - await ensureSidebarOpened(); - await page.waitForNetworkIdle(); - await saveTemplate(); - await page.waitForNetworkIdle(); - await Promise.all( [ - page.goto( BASE_URL + '/product-category/uncategorized/' ), - page.waitForNavigation( { - waitUntil: 'networkidle0', - } ), - ] ); - } ); - - afterAll( async () => { - await deleteAllTemplates( 'wp_template' ); - } ); - - it( 'should render the same products in the same position of the classic template', async () => { - const classicProducts = await getProductsNameFromClassicTemplate(); - const products = await getProductsNameFromProductQuery(); - - expect( classicProducts ).toEqual( products ); - } ); - } ); - - describe( 'with Products By Tag Template', () => { - beforeAll( async () => { - const tagProductCategory = - 'woocommerce/woocommerce//taxonomy-product_tag'; - await goToTemplateEditor( { - postId: tagProductCategory, - } ); - await addProductQueryBlock(); - await ensureSidebarOpened(); - await page.waitForNetworkIdle(); - await saveTemplate(); - await page.waitForNetworkIdle(); - await Promise.all( [ - page.goto( BASE_URL + '/product-tag/newest/' ), - page.waitForNavigation( { - waitUntil: 'networkidle0', - } ), - ] ); - } ); - - afterAll( async () => { - await deleteAllTemplates( 'wp_template' ); - } ); - - it( 'should render the same products in the same position of the classic template', async () => { - const classicProducts = await getProductsNameFromClassicTemplate(); - const products = await getProductsNameFromProductQuery(); - - expect( classicProducts ).toEqual( products ); - } ); - } ); - - describe( 'with Products Search Results Template', () => { - beforeAll( async () => { - const productSearchResults = - 'woocommerce/woocommerce//product-search-results'; - await goToTemplateEditor( { - postId: productSearchResults, - } ); - await addProductQueryBlock(); - await ensureSidebarOpened(); - await page.waitForNetworkIdle(); - await saveTemplate(); - await page.waitForNetworkIdle(); - await Promise.all( [ - page.goto( BASE_URL + '/?s=usb&post_type=product' ), - page.waitForNavigation( { - waitUntil: 'networkidle0', - } ), - ] ); - } ); - - afterAll( async () => { - await deleteAllTemplates( 'wp_template' ); - } ); - - it( 'should render the same products in the same position of the classic template', async () => { - const classicProducts = await getProductsNameFromClassicTemplate(); - const products = await getProductsNameFromProductQuery(); - expect( classicProducts ).toEqual( products ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/shopper/product-query/utils.ts b/tests/e2e/specs/shopper/product-query/utils.ts deleted file mode 100644 index da8e3f2b30b..00000000000 --- a/tests/e2e/specs/shopper/product-query/utils.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * External dependencies - */ -import { insertBlock } from '@wordpress/e2e-test-utils'; - -/** - * Internal dependencies - */ - -export const block = { - name: 'Products (Beta)', - slug: 'woocommerce/product-query', - selectors: { - editor: { - inheritQueryFromTemplateSetting: - "//label[text()='Inherit query from template']", - popularFilter: '.woocommerce-product-query-panel__sort', - advanceFilterOptionsButton: - "button[aria-label='Advanced Filters options']", - }, - frontend: { - classicProductsListName: '.woocommerce-loop-product__title', - productQueryProductsListName: - '.wp-block-query .wp-block-post-title', - }, - }, -}; - -export const addProductQueryBlock = async () => { - await insertBlock( block.name ); - await page.waitForNetworkIdle(); -}; - -export const toggleInheritQueryFromTemplateSetting = async () => { - const [ button ] = await page.$x( - block.selectors.editor.inheritQueryFromTemplateSetting - ); - await button.click(); -}; - -export const getProductsNameFromClassicTemplate = async () => { - const products = await page.$$( - block.selectors.frontend.classicProductsListName - ); - return Promise.all( - products.map( ( el ) => - page.evaluate( ( node ) => node.textContent, el ) - ) - ); -}; - -export const getProductsNameFromProductQuery = async () => { - const products = await page.$$( - block.selectors.frontend.productQueryProductsListName - ); - - return Promise.all( - products.map( ( el ) => - page.evaluate( ( element ) => element.textContent, el ) - ) - ); -}; diff --git a/tests/php/Utils/BlockTemplateUtilsTest.php b/tests/php/Utils/BlockTemplateUtilsTest.php index 9dbdad5f82f..7577dfffa28 100644 --- a/tests/php/Utils/BlockTemplateUtilsTest.php +++ b/tests/php/Utils/BlockTemplateUtilsTest.php @@ -336,7 +336,7 @@ public function test_plugin_update_with_a_classic_theme_switching_to_a_block_sho */ public function update_plugin(): void { update_option( Options::WC_BLOCK_VERSION, 1 ); - Migration::wc_blocks_update_710_blockified_product_grid_block(); + Migration::wc_blocks_update_1030_blockified_product_grid_block(); } /**