diff --git a/tests/e2e/core-tests/CHANGELOG.md b/tests/e2e/core-tests/CHANGELOG.md index 66bfb48daa8..c903a9640b4 100644 --- a/tests/e2e/core-tests/CHANGELOG.md +++ b/tests/e2e/core-tests/CHANGELOG.md @@ -9,6 +9,8 @@ - Merchant Order Refund tests - Merchant Apply Coupon tests - Added new config variable for Simple Product price to `tests/e2e/env/config/default.json`. Defaults to 9.99 +- Merchant Product Edit tests +- Merchant Product Search tests - Shopper Single Product tests - Shopper Checkout Apply Coupon - Merchant Orders Customer Checkout Page diff --git a/tests/e2e/core-tests/README.md b/tests/e2e/core-tests/README.md index 2c22cc29d43..5f6aab8df27 100644 --- a/tests/e2e/core-tests/README.md +++ b/tests/e2e/core-tests/README.md @@ -55,6 +55,8 @@ The functions to access the core tests are: - `runOrderStatusFilterTest` - Merchant can filter orders by order status - `runOrderRefundTest` - Merchant can refund an order - `runOrderApplyCouponTest` - Merchant can apply a coupon to an order + - `runProductEditDetailsTest` - Merchant can edit an existing product + - `runProductSearchTest` - Merchant can search for a product and view it - `runMerchantOrdersCustomerPaymentPage` - Merchant can visit the customer payment page ### Shopper diff --git a/tests/e2e/core-tests/specs/index.js b/tests/e2e/core-tests/specs/index.js index bc694a6e88d..4eb5f563466 100644 --- a/tests/e2e/core-tests/specs/index.js +++ b/tests/e2e/core-tests/specs/index.js @@ -26,6 +26,8 @@ const runTaxSettingsTest = require( './merchant/wp-admin-settings-tax.test' ); const runOrderStatusFiltersTest = require( './merchant/wp-admin-order-status-filters.test' ); const runOrderRefundTest = require( './merchant/wp-admin-order-refund.test' ); const runOrderApplyCouponTest = require( './merchant/wp-admin-order-apply-coupon.test' ); +const runProductEditDetailsTest = require( './merchant/wp-admin-product-edit-details.test' ); +const runProductSearchTest = require( './merchant/wp-admin-product-search.test' ); const runMerchantOrdersCustomerPaymentPage = require( './merchant/wp-admin-order-customer-payment-page.test' ); const runSetupOnboardingTests = () => { @@ -55,6 +57,8 @@ const runMerchantTests = () => { runOrderStatusFiltersTest(); runOrderRefundTest(); runOrderApplyCouponTest(); + runProductEditDetailsTest(); + runProductSearchTest(); runMerchantOrdersCustomerPaymentPage(); } @@ -81,6 +85,8 @@ module.exports = { runOrderStatusFiltersTest, runOrderRefundTest, runOrderApplyCouponTest, + runProductEditDetailsTest, + runProductSearchTest, runMerchantOrdersCustomerPaymentPage, runMerchantTests, }; diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-product-edit-details.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-product-edit-details.test.js new file mode 100644 index 00000000000..238fa9ba425 --- /dev/null +++ b/tests/e2e/core-tests/specs/merchant/wp-admin-product-edit-details.test.js @@ -0,0 +1,50 @@ +/* eslint-disable jest/no-export, jest/no-standalone-expect */ + +/** + * Internal dependencies + */ +const { + merchant, + uiUnblocked, + verifyAndPublish, + createSimpleProduct +} = require( '@woocommerce/e2e-utils' ); + +let productId; + +const runProductEditDetailsTest = () => { + describe('Products > Edit Product', () => { + beforeAll(async () => { + await merchant.login(); + productId = await createSimpleProduct(); + }); + + it('can edit a product and save the changes', async () => { + await merchant.goToProduct(productId); + + // Clear the input fields first, then add the new values + await expect(page).toFill('#title', ''); + await expect(page).toFill('#_regular_price', ''); + + await expect(page).toFill('#title', 'Awesome product'); + + // Switch to text mode to work around the iframe + await expect(page).toClick('#content-html'); + await expect(page).toFill('.wp-editor-area', 'This product is pretty awesome.'); + + await expect(page).toFill('#_regular_price', '100.05'); + + // Save the changes + await expect(page).toClick('#publish'); + await verifyAndPublish('Product updated.'); + await uiUnblocked(); + + // Verify the changes saved + await expect(page).toMatchElement('#title', 'Awesome product'); + await expect(page).toMatchElement('.wp-editor-area', 'This product is pretty awesome.'); + await expect(page).toMatchElement('#_regular_price', '100.05'); + }); + }); +} + +module.exports = runProductEditDetailsTest; diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-product-search.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-product-search.test.js new file mode 100644 index 00000000000..a9640f303ee --- /dev/null +++ b/tests/e2e/core-tests/specs/merchant/wp-admin-product-search.test.js @@ -0,0 +1,77 @@ +/* eslint-disable jest/no-export, jest/no-standalone-expect */ + +/** + * Internal dependencies + */ +const { + merchant, + createSimpleProduct +} = require( '@woocommerce/e2e-utils' ); + +const config = require( 'config' ); +const simpleProductName = config.get( 'products.simple.name' ); +const simpleProductPrice = config.has('products.simple.price') ? config.get('products.simple.price') : '9.99'; + +const runProductSearchTest = () => { + describe('Products > Search and View a product', () => { + beforeAll(async () => { + await merchant.login(); + await createSimpleProduct(); + + // Make sure the simple product name is greater than 1 to do a search + await expect(simpleProductName.length).toBeGreaterThan(1); + }); + + beforeEach(async () => { + await merchant.openAllProductsView(); + }); + + it('can do a partial search for a product', async () => { + // Create partial search string + let searchString = simpleProductName.substring(0, (simpleProductName.length / 2)); + await expect(page).toFill('#post-search-input', searchString); + + // Click search and wait for the page to finish loading + await Promise.all( [ + page.click( '#search-submit' ), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ]); + + // Verify we are getting the results back in the list + await expect(page).toMatchElement('.row-title', { text: simpleProductName }); + }); + + it('can view a product\'s details after search', async () => { + await expect(page).toFill('#post-search-input', simpleProductName); + + await Promise.all( [ + page.click( '#search-submit' ), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ]); + + // Click to view the product and wait for the page to finish loading + await Promise.all( [ + expect(page).toClick('.row-title', simpleProductName), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ]); + + await expect(page).toMatchElement('#title', simpleProductName); + await expect(page).toMatchElement('#_regular_price', simpleProductPrice); + }); + + it('returns no results for non-existent product search', async () => { + await expect(page).toFill('#post-search-input', 'abcd1234'); + + // Click search and wait for the page to finish loading + await Promise.all( [ + page.click( '#search-submit' ), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ]); + + // Verify we are getting the results back in the list + await expect(page).toMatchElement('.no-items', { text: 'No products found' }); + }); + }); +} + +module.exports = runProductSearchTest; diff --git a/tests/e2e/specs/wp-admin/test-product-edit.js b/tests/e2e/specs/wp-admin/test-product-edit.js new file mode 100644 index 00000000000..7dbe32e4fd5 --- /dev/null +++ b/tests/e2e/specs/wp-admin/test-product-edit.js @@ -0,0 +1,6 @@ +/* + * Internal dependencies + */ +const { runProductEditDetailsTest } = require( '@woocommerce/e2e-core-tests' ); + +runProductEditDetailsTest(); diff --git a/tests/e2e/specs/wp-admin/test-product-search.js b/tests/e2e/specs/wp-admin/test-product-search.js new file mode 100644 index 00000000000..402700aa8b2 --- /dev/null +++ b/tests/e2e/specs/wp-admin/test-product-search.js @@ -0,0 +1,6 @@ +/* + * Internal dependencies + */ +const { runProductSearchTest } = require( '@woocommerce/e2e-core-tests' ); + +runProductSearchTest(); diff --git a/tests/e2e/utils/CHANGELOG.md b/tests/e2e/utils/CHANGELOG.md index 8b770fb8b4d..c55b2988e1c 100644 --- a/tests/e2e/utils/CHANGELOG.md +++ b/tests/e2e/utils/CHANGELOG.md @@ -22,6 +22,7 @@ - Deprecated `StoreOwnerFlow`, `CustomerFlow` in favour of `merchant`,`shopper` - `createSimpleOrder( status )` returns the ID of the order that was created - Updated `createCoupon( couponAmount )` component by adding a new parameter `discountType` which allows you to use any coupon discount type in tests +- Updated `verifyAndPublish( noticeText )` component by add a new parameter, `noticeText`, that allows passing in the accepted update notice text. For example, with variations on creation or update. # 0.1.1 diff --git a/tests/e2e/utils/README.md b/tests/e2e/utils/README.md index 4b03105f644..12f814aa992 100644 --- a/tests/e2e/utils/README.md +++ b/tests/e2e/utils/README.md @@ -40,9 +40,11 @@ describe( 'Cart page', () => { | Function | Parameters | Description | |----------|-------------|------------| | `goToOrder` | `orderId` | Go to view a single order | +| `goToProduct` | `productId` | Go to view a single product | | `login` | | Log in as merchant | | `logout` | | Log out of merchant account | | `openAllOrdersView` | | Go to the orders listing | +| `openAllProductsView` | | Go to the products listing | | `openDashboard` | | Go to the WordPress dashboard | | `openNewCoupon` | | Go to the new coupon editor | | `openNewOrder` | | Go to the new order editor | @@ -98,6 +100,7 @@ describe( 'Cart page', () => { | `verifyValueOfInputField` | `selector, value` | Verify an input contains the passed value | | `clickFilter` | `selector` | Click on a list page filter | | `moveAllItemsToTrash` | | Moves all items in a list view to the Trash | +| `verifyAndPublish` | `noticeText` | Verify that an item can be published | | `selectOptionInSelect2` | `selector, value` | helper method that searchs for select2 type fields and select plus insert value inside ### Test Utilities diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index 56cb7b4a75a..9f407e3ab75 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -13,7 +13,12 @@ const config = require( 'config' ); const simpleProductName = config.get( 'products.simple.name' ); const simpleProductPrice = config.has('products.simple.price') ? config.get('products.simple.price') : '9.99'; -const verifyAndPublish = async () => { +/** + * Verify and publish + * + * @param noticeText The text that appears in the notice after publishing. + */ +const verifyAndPublish = async ( noticeText ) => { // Wait for auto save await page.waitFor( 2000 ); @@ -22,7 +27,7 @@ const verifyAndPublish = async () => { await page.waitForSelector( '.updated.notice' ); // Verify - await expect( page ).toMatchElement( '.updated.notice', { text: 'Product published.' } ); + await expect( page ).toMatchElement( '.updated.notice', { text: noticeText } ); }; /** @@ -303,7 +308,7 @@ const createVariableProduct = async () => { await page.focus( 'button.save-variation-changes' ); await expect( page ).toClick( 'button.save-variation-changes', { text: 'Save changes' } ); - await verifyAndPublish(); + await verifyAndPublish( 'Product published.' ); const variablePostId = await page.$( '#post_ID' ); let variablePostIdValue = ( await ( await variablePostId.getProperty( 'value' ) ).jsonValue() ); diff --git a/tests/e2e/utils/src/flows/constants.js b/tests/e2e/utils/src/flows/constants.js index ae8790f3288..e3b6e61717f 100644 --- a/tests/e2e/utils/src/flows/constants.js +++ b/tests/e2e/utils/src/flows/constants.js @@ -10,6 +10,7 @@ export const WP_ADMIN_DASHBOARD = baseUrl + 'wp-admin'; export const WP_ADMIN_PLUGINS = baseUrl + 'wp-admin/plugins.php'; export const WP_ADMIN_SETUP_WIZARD = baseUrl + 'wp-admin/admin.php?page=wc-admin'; export const WP_ADMIN_ALL_ORDERS_VIEW = baseUrl + 'wp-admin/edit.php?post_type=shop_order'; +export const WP_ADMIN_ALL_PRODUCTS_VIEW = baseUrl + 'wp-admin/edit.php?post_type=product'; export const WP_ADMIN_NEW_COUPON = baseUrl + 'wp-admin/post-new.php?post_type=shop_coupon'; export const WP_ADMIN_NEW_ORDER = baseUrl + 'wp-admin/post-new.php?post_type=shop_order'; export const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=product'; diff --git a/tests/e2e/utils/src/flows/merchant.js b/tests/e2e/utils/src/flows/merchant.js index f58d184a829..df4fae99d68 100644 --- a/tests/e2e/utils/src/flows/merchant.js +++ b/tests/e2e/utils/src/flows/merchant.js @@ -9,6 +9,7 @@ const config = require( 'config' ); const { clearAndFillInput } = require( '../page-utils' ); const { WP_ADMIN_ALL_ORDERS_VIEW, + WP_ADMIN_ALL_PRODUCTS_VIEW, WP_ADMIN_DASHBOARD, WP_ADMIN_LOGIN, WP_ADMIN_NEW_COUPON, @@ -60,6 +61,12 @@ const merchant = { } ); }, + openAllProductsView: async () => { + await page.goto( WP_ADMIN_ALL_PRODUCTS_VIEW, { + waitUntil: 'networkidle0', + } ); + }, + openDashboard: async () => { await page.goto( WP_ADMIN_DASHBOARD, { waitUntil: 'networkidle0', @@ -121,6 +128,12 @@ const merchant = { } ); }, + goToProduct: async ( productId ) => { + await page.goto( WP_ADMIN_SINGLE_CPT_VIEW( productId ), { + waitUntil: 'networkidle0', + } ); + }, + updateOrderStatus: async ( orderId, status ) => { await page.goto( WP_ADMIN_SINGLE_CPT_VIEW( orderId ), { waitUntil: 'networkidle0',