diff --git a/plugins/woocommerce-blocks/.prettierignore b/plugins/woocommerce-blocks/.prettierignore index 061c1d13a93..7e155376458 100644 --- a/plugins/woocommerce-blocks/.prettierignore +++ b/plugins/woocommerce-blocks/.prettierignore @@ -1,2 +1,3 @@ +*.json *.scss *.yml diff --git a/plugins/woocommerce-blocks/package.json b/plugins/woocommerce-blocks/package.json index c3174880ba6..aaa81faafc8 100644 --- a/plugins/woocommerce-blocks/package.json +++ b/plugins/woocommerce-blocks/package.json @@ -53,8 +53,8 @@ "lint:js:report": "npm run lint:js -- --output-file eslint_report.json --ext=js,ts,tsx --format json", "lint:js-fix": "eslint assets/js --ext=js,jsx,ts,tsx --fix", "lint:md:docs": "wp-scripts lint-md-docs", - "lint:php": "composer run-script phpcs ./src", - "lint:php-fix": "composer run-script phpcbf ./src", + "lint:php": "composer run-script phpcs ./src && composer run-script phpcs ./tests/mocks/woo-test-helper", + "lint:php-fix": "composer run-script phpcbf ./src && composer run-script phpcbf ./tests/mocks/woo-test-helper", "package-plugin": "rimraf woocommerce-gutenberg-products-block.zip && ./bin/build-plugin-zip.sh", "package-plugin:dev": "rimraf woocommerce-gutenberg-products-block.zip && ./bin/build-plugin-zip.sh -d", "package-plugin:zip-only": "rimraf woocommerce-gutenberg-products-block.zip && ./bin/build-plugin-zip.sh -z", diff --git a/plugins/woocommerce-blocks/tests/e2e/specs/backend/__fixtures__/cart.fixture.json b/plugins/woocommerce-blocks/tests/e2e/specs/backend/__fixtures__/cart.fixture.json index 9196f9830ae..caaf0d003ec 100644 --- a/plugins/woocommerce-blocks/tests/e2e/specs/backend/__fixtures__/cart.fixture.json +++ b/plugins/woocommerce-blocks/tests/e2e/specs/backend/__fixtures__/cart.fixture.json @@ -1 +1 @@ -{"title":"Cart Block","pageContent":"\n
\n
\"\"/
\n\n\n\n

Your cart is currently empty!

\n\n\n\n

Browse store.

\n\n\n\n
\n\n\n\n

New in store

\n\n\n
\n"} \ No newline at end of file +{"title": "Cart Block","pageContent": "\n
\n
\n
\n
\n\n\n\n
\n

You may be interested in…

\n\n\n\n
\n
\n
\n\n\n\n
\n
\n
\n\n\n\n
\n\n\n\n
\n\n\n\n
\n\n\n\n
\n\n\n\n
\n\n\n\n
\n
\n\n\n\n
\n\n\n\n
\n\n\n\n
\n
\n
\n\n\n\n
\n
\"\"/
\n\n\n\n

Your cart is currently empty!

\n\n\n\n

Browse store.

\n\n\n\n
\n\n\n\n

New in store

\n\n\n
\n
\n"} diff --git a/plugins/woocommerce-blocks/tests/e2e/specs/backend/cart.test.js b/plugins/woocommerce-blocks/tests/e2e/specs/backend/cart.test.js index f9f8f875dd4..647ed745e5a 100644 --- a/plugins/woocommerce-blocks/tests/e2e/specs/backend/cart.test.js +++ b/plugins/woocommerce-blocks/tests/e2e/specs/backend/cart.test.js @@ -43,6 +43,12 @@ const emptyCartBlock = { class: '.wp-block-woocommerce-empty-cart-block', }; +const crossSellsBlock = { + name: 'Cart Cross-Sells block', + slug: 'woocommerce/cart-cross-sells-products-block', + class: '.wp-block-woocommerce-cart-cross-sells-products-block', +}; + if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 2 ) { // eslint-disable-next-line jest/no-focused-tests, jest/expect-expect test.only( `skipping ${ block.name } tests`, () => {} ); @@ -63,6 +69,7 @@ describe( `${ block.name } Block`, () => { it( 'renders without crashing', async () => { await expect( page ).toRenderBlock( block ); await expect( page ).toRenderBlock( filledCartBlock ); + await expect( page ).toRenderBlock( crossSellsBlock ); await expect( page ).toRenderBlock( emptyCartBlock ); } ); diff --git a/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/cart.test.js b/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/cart.test.js index 5b1b4e9c19f..ba1d4a4b906 100644 --- a/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/cart.test.js +++ b/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/cart.test.js @@ -1,7 +1,12 @@ /** * Internal dependencies */ -import { shopper, SIMPLE_VIRTUAL_PRODUCT_NAME } from '../../../../utils'; +import { + shopper, + SIMPLE_VIRTUAL_PRODUCT_NAME, + SIMPLE_PHYSICAL_PRODUCT_NAME, +} from '../../../../utils'; +import { BASE_URL } from '../../../../utils/constants'; if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 2 ) { // Skips all the tests if it's a WooCommerce Core process environment. @@ -11,6 +16,9 @@ if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 2 ) { describe( 'Shopper → Cart', () => { beforeAll( async () => { + await page.goto( `${ BASE_URL }/?setup_cross_sells` ); + // eslint-disable-next-line jest/no-standalone-expect + await expect( page ).toMatch( 'Cross-Sells products set up.' ); await shopper.block.emptyCart(); } ); @@ -97,6 +105,22 @@ describe( 'Shopper → Cart', () => { await shopper.block.productIsInCart( SIMPLE_VIRTUAL_PRODUCT_NAME, 4 ); } ); + it( 'User can see Cross-Sells products block', async () => { + await shopper.block.emptyCart(); + await shopper.goToShop(); + await shopper.addToCartFromShopPage( SIMPLE_PHYSICAL_PRODUCT_NAME ); + await shopper.block.goToCart(); + await expect( page ).toMatchElement( + '.wp-block-woocommerce-cart-cross-sells-block' + ); + await shopper.block.addCrossSellsProductToCart(); + // To avoid flakiness: Wait until the cart contains two entries. + await page.waitForSelector( + '.wp-block-woocommerce-cart-line-items-block tr:nth-child(2)' + ); + await shopper.block.productIsInCart( '32GB USB Stick', 1 ); + } ); + it( 'User can proceed to checkout', async () => { await shopper.goToShop(); await shopper.addToCartFromShopPage( SIMPLE_VIRTUAL_PRODUCT_NAME ); diff --git a/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php b/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php index e19bcb48eba..4e689448df2 100644 --- a/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php +++ b/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php @@ -28,7 +28,7 @@ function woocommerce_setup_terms_and_privacy_page() { exit( 'Terms & Privacy pages set up.' ); } - // phpcs:disable WordPress.Security.NonceVerification.Recommended + // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( isset( $_GET['teardown_terms_and_privacy'] ) ) { unpublish_privacy_page(); delete_terms_page(); @@ -94,3 +94,32 @@ function delete_terms_page() { $data = array( 'post_title' => 'Terms & Conditions' ); $wpdb->delete( $table, $data ); } + +/** + * Define URL endpoint for setting up cross-sells products. + */ +function woocommerce_setup_cross_sells_products() { + // phpcs:disable WordPress.Security.NonceVerification.Recommended + if ( isset( $_GET['setup_cross_sells'] ) ) { + setup_cross_sells(); + exit( 'Cross-Sells products set up.' ); + } +} +add_action( 'init', 'woocommerce_setup_cross_sells_products' ); + +/** + * Set up Cross-Sells products. + */ +function setup_cross_sells() { + global $wpdb; + + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $select = "SELECT * FROM {$wpdb->prefix}posts WHERE post_title = '128GB USB Stick' AND post_status = 'publish' AND post_type = 'product'"; + $id_product = $wpdb->get_row( $select ); + + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $select = "SELECT * FROM {$wpdb->prefix}posts WHERE post_title = '32GB USB Stick' AND post_status = 'publish' AND post_type = 'product'"; + $id_cross_sell = $wpdb->get_row( $select ); + + add_post_meta( $id_product->ID, '_crosssell_ids', $id_cross_sell->ID ); +} diff --git a/plugins/woocommerce-blocks/tests/utils/shopper.js b/plugins/woocommerce-blocks/tests/utils/shopper.js index 3e65238b5be..e952750492a 100644 --- a/plugins/woocommerce-blocks/tests/utils/shopper.js +++ b/plugins/woocommerce-blocks/tests/utils/shopper.js @@ -311,6 +311,15 @@ export const shopper = { ] ); }, + addCrossSellsProductToCart: async () => { + await page.waitForSelector( + '.wc-block-components-product-add-to-cart-button' + ); + expect( page ).toClick( + '.wc-block-components-product-add-to-cart-button' + ); + }, + selectAndVerifyShippingOption: async ( shippingName, shippingPrice