From ed525087acf0be33e53c0586a40e0324d37c2f2a Mon Sep 17 00:00:00 2001 From: Tam Mullen Date: Fri, 10 Jul 2020 23:12:21 +0100 Subject: [PATCH] Addressing comments. --- .gitignore | 2 + tests/e2e-utils/components.js | 505 ------------------ tests/e2e-utils/flows.js | 317 ----------- tests/e2e-utils/index.js | 44 -- tests/{e2e-utils => e2e/utils}/README.md | 2 +- tests/e2e/utils/index.js | 187 ++----- tests/{e2e-utils => e2e/utils}/package.json | 7 +- tests/e2e/utils/{ => src}/components.js | 0 tests/e2e/utils/{ => src}/flows.js | 0 .../utils/src}/page-utils.js | 0 tests/e2e/utils/webpack-alias.js | 11 + 11 files changed, 49 insertions(+), 1026 deletions(-) delete mode 100644 tests/e2e-utils/components.js delete mode 100644 tests/e2e-utils/flows.js delete mode 100644 tests/e2e-utils/index.js rename tests/{e2e-utils => e2e/utils}/README.md (87%) rename tests/{e2e-utils => e2e/utils}/package.json (73%) rename tests/e2e/utils/{ => src}/components.js (100%) rename tests/e2e/utils/{ => src}/flows.js (100%) rename tests/{e2e-utils => e2e/utils/src}/page-utils.js (100%) create mode 100644 tests/e2e/utils/webpack-alias.js diff --git a/.gitignore b/.gitignore index 4906d0e7c9e..d9923d9613d 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,8 @@ tests/cli/vendor /tests/e2e/env/docker/wp-cli/initialize.sh /tests/e2e/env/build/ /tests/e2e/env/build-module/ +/tests/e2e/utils/build/ +/tests/e2e/utils/build-module/ # Logs /logs diff --git a/tests/e2e-utils/components.js b/tests/e2e-utils/components.js deleted file mode 100644 index d1d598434bd..00000000000 --- a/tests/e2e-utils/components.js +++ /dev/null @@ -1,505 +0,0 @@ -/** - * @format - */ - -/** - * Internal dependencies - */ -import { StoreOwnerFlow } from './flows'; -import { clickTab, uiUnblocked, verifyCheckboxIsUnset } from './page-utils'; - -const config = require( 'config' ); -const simpleProductName = config.get( 'products.simple.name' ); - -const verifyAndPublish = async () => { - // Wait for auto save - await page.waitFor( 2000 ); - - // Publish product - await expect( page ).toClick( '#publish' ); - await page.waitForSelector( '.updated.notice' ); - - // Verify - await expect( page ).toMatchElement( '.updated.notice', { text: 'Product published.' } ); -}; - -/** - * Complete onboarding wizard. - */ -const completeOnboardingWizard = async () => { - // Wait for "Yes please" button to appear and click on it - await page.waitForSelector( 'button[name=save_step]' ); - await expect( page ).toMatchElement( - 'button[name=save_step]', { text: 'Yes please' } - ); - await Promise.all( [ - // Click on "Yes please" button to move to the next step - page.click( 'button[name=save_step]', { text: 'Yes please' } ), - - // Wait for "Where is your store based?" section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Store Details section - - // Fill store's address - first line - await expect( page ).toFill( '#inspector-text-control-0', config.get( 'addresses.admin.store.addressfirstline' ) ); - - // Fill store's address - second line - await expect( page ).toFill( '#inspector-text-control-1', config.get( 'addresses.admin.store.addresssecondline' ) ); - - // Fill country and state where the store is located - await expect( page ).toFill( '.woocommerce-select-control__control-input', config.get( 'addresses.admin.store.countryandstate' ) ); - - // Fill the city where the store is located - await expect( page ).toFill( '#inspector-text-control-2', config.get( 'addresses.admin.store.city' ) ); - - // Fill postcode of the store - await expect( page ).toFill( '#inspector-text-control-3', config.get( 'addresses.admin.store.postcode' ) ); - - // Verify that checkbox next to "I'm setting up a store for a client" is not selected - await verifyCheckboxIsUnset( '.components-checkbox-control__input' ); - - // Wait for "Continue" button to become active - await page.waitForSelector( 'button.is-primary:not(:disabled)' ); - - // Click on "Continue" button to move to the next step - await page.click( 'button.is-primary', { text: 'Continue' } ); - - // Wait for usage tracking pop-up window to appear - await page.waitForSelector( '.components-modal__header-heading' ); - await expect( page ).toMatchElement( - '.components-modal__header-heading', { text: 'Build a Better WooCommerce' } - ); - - // Query for "Continue" buttons - const continueButtons = await page.$$( 'button.is-primary' ); - expect( continueButtons ).toHaveLength( 2 ); - - await Promise.all( [ - // Click on "Continue" button of the usage pop-up window to move to the next step - continueButtons[1].click(), - - // Wait for "In which industry does the store operate?" section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Industry section - - // Query for the industries checkboxes - const industryCheckboxes = await page.$$( '.components-checkbox-control__input' ); - expect( industryCheckboxes ).toHaveLength( 8 ); - - // Select all industries including "Other" - for ( let i = 0; i < 8; i++ ) { - await industryCheckboxes[i].click(); - } - - // Fill "Other" industry - await expect( page ).toFill( '.components-text-control__input', config.get( 'onboardingwizard.industry' ) ); - - // Wait for "Continue" button to become active - await page.waitForSelector( 'button.is-primary:not(:disabled)' ); - - await Promise.all( [ - // Click on "Continue" button to move to the next step - page.click( 'button.is-primary' ), - - // Wait for "What type of products will be listed?" section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Product types section - - // Query for the product types checkboxes - const productTypesCheckboxes = await page.$$( '.components-checkbox-control__input' ); - expect( productTypesCheckboxes ).toHaveLength( 6 ); - - // Select Physical and Downloadable products - for ( let i = 0; i < 2; i++ ) { - await productTypesCheckboxes[i].click(); - } - - // Wait for "Continue" button to become active - await page.waitForSelector( 'button.woocommerce-profile-wizard__continue:not(:disabled)' ); - - await Promise.all( [ - // Click on "Continue" button to move to the next step - page.click( 'button.woocommerce-profile-wizard__continue' ), - - // Wait for "Tell us about your business" section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Business Details section - - // Query for the s - const selectControls = await page.$$( '.woocommerce-select-control' ); - expect( selectControls ).toHaveLength( 2 ); - - // Fill the number of products you plan to sell - await selectControls[0].click(); - await page.waitForSelector( '.woocommerce-select-control__listbox' ); - await expect( page ).toClick( '.woocommerce-select-control__option', { text: config.get( 'onboardingwizard.numberofproducts' ) } ); - - // Fill currently selling elsewhere - await selectControls[1].click(); - await page.waitForSelector( '.woocommerce-select-control__listbox' ); - await expect( page ).toClick( '.woocommerce-select-control__option', { text: config.get( 'onboardingwizard.sellingelsewhere' ) } ); - - // Query for the plugin upload toggles - const pluginToggles = await page.$$( '.components-form-toggle__input' ); - expect( pluginToggles ).toHaveLength( 3 ); - - // Disable Market on Facebook, Mailchimp and Google Shopping download - for ( let i = 0; i < 3; i++ ) { - await pluginToggles[i].click(); - } - - // Wait for "Continue" button to become active - await page.waitForSelector( 'button.is-primary:not(:disabled)' ); - - await Promise.all( [ - // Click on "Continue" button to move to the next step - page.click( 'button.is-primary' ), - - // Wait for "Theme" section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Theme section - - // Wait for "Continue with my active theme" button to become active - await page.waitForSelector( 'button.is-primary:not(:disabled)' ); - - await Promise.all( [ - // Click on "Continue with my active theme" button to move to the next step - page.click( 'button.is-primary' ), - - // Wait for "Enhance your store with WooCommerce Services" section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Benefits section - - // Wait for Benefits section to appear - await page.waitForSelector( '.woocommerce-profile-wizard__header-title' ); - - // Wait for "No thanks" button to become active - await page.waitForSelector( 'button.is-default:not(:disabled)' ); - // Click on "No thanks" button to move to the next step - await page.click( 'button.is-default' ); - - // End of onboarding wizard - - // Wait for "Woo-hoo almost there" window to appear - await page.waitForSelector( '.components-modal__header-heading' ); - await expect( page ).toMatchElement( - '.components-modal__header-heading', { text: 'Woo hoo - you\'re almost there!' } - ); - - // Wait for "Continue" button to become active - await page.waitForSelector( 'button.is-primary:not(:disabled)' ); - // Click on "Continue" button to move to the next step - await page.click( 'button.is-primary:not(:disabled)' ); -}; - -/** - * Complete old setup wizard. - */ -const completeOldSetupWizard = async () => { - // Fill out store setup section details - // Select country where the store is located - await expect( page ).toSelect( 'select[name="store_country"]', config.get( 'addresses.admin.store.country' ) ); - // Fill store's address - first line - await expect( page ).toFill( '#store_address', config.get( 'addresses.admin.store.addressfirstline' ) ); - - // Fill store's address - second line - await expect( page ).toFill( '#store_address_2', config.get( 'addresses.admin.store.addresssecondline' ) ); - - // Fill the city where the store is located - await expect( page ).toFill( '#store_city', config.get( 'addresses.admin.store.city' ) ); - - // Select the state where the store is located - await expect( page ).toSelect( 'select[name="store_state"]', config.get( 'addresses.admin.store.state') ); - - // Fill postcode of the store - await expect( page ).toFill( '#store_postcode', config.get( 'addresses.admin.store.postcode' ) ); - - // Select currency and type of products to sell details - await expect( page ).toSelect( 'select[name="currency_code"]', '\n' + - '\t\t\t\t\t\tUnited States (US) dollar ($ USD)\t\t\t\t\t' ); - await expect( page ).toSelect( 'select[name="product_type"]', 'I plan to sell both physical and digital products' ); - - // Verify that checkbox next to "I will also be selling products or services in person." is not selected - await verifyCheckboxIsUnset( '#woocommerce_sell_in_person' ); - - // Click on "Let's go!" button to move to the next step - await page.$eval( 'button[name=save_step]', elem => elem.click() ); - - // Wait for usage tracking pop-up window to appear - await page.waitForSelector( '#wc-backbone-modal-dialog' ); - await expect( page ).toMatchElement( - '.wc-backbone-modal-header', { text: 'Help improve WooCommerce with usage tracking' } - ); - - await page.waitForSelector( '#wc_tracker_checkbox_dialog' ); - - // Verify that checkbox next to "Enable usage tracking and help improve WooCommerce" is not selected - await verifyCheckboxIsUnset( '#wc_tracker_checkbox_dialog' ); - - await Promise.all( [ - // Click on "Continue" button to move to the next step - page.$eval( '#wc_tracker_submit', elem => elem.click() ), - - // Wait for the Payment section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Fill out payment section details - // Turn off Stripe account toggle - await page.click( '.wc-wizard-service-toggle' ); - - await Promise.all( [ - // Click on "Continue" button to move to the next step - page.click( 'button[name=save_step]', { text: 'Continue' } ), - - // Wait for the Shipping section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Fill out shipping section details - // Turn off WooCommerce Shipping option - await page.$eval( '#wc_recommended_woocommerce_services', elem => elem.click() ); - - await page.waitForSelector( 'select[name="shipping_zones[domestic][method]"]' ); - await page.waitForSelector( 'select[name="shipping_zones[intl][method]"]' ); - - // Select Flat Rate shipping method for domestic shipping zone - await page.evaluate( () => { - document.querySelector( 'select[name="shipping_zones[domestic][method]"] > option:nth-child(1)' ).selected = true; - let element = document.querySelector( 'select[name="shipping_zones[domestic][method]"]' ); - let event = new Event( 'change', { bubbles: true } ); - event.simulated = true; - element.dispatchEvent( event ); - } ); - - await page.$eval( 'input[name="shipping_zones[domestic][flat_rate][cost]"]', e => e.setAttribute( 'value', '10.00' ) ); - - // Select Flat Rate shipping method for the rest of the world shipping zone - await page.evaluate( () => { - document.querySelector( 'select[name="shipping_zones[intl][method]"] > option:nth-child(1)' ).selected = true; - let element = document.querySelector( 'select[name="shipping_zones[intl][method]"]' ); - let event = new Event( 'change', { bubbles: true } ); - event.simulated = true; - element.dispatchEvent( event ); - } ); - - await page.$eval( 'input[name="shipping_zones[intl][flat_rate][cost]"]', e => e.setAttribute( 'value', '20.00' ) ); - - // Select product weight and product dimensions options - await expect( page ).toSelect( 'select[name="weight_unit"]', 'Pounds' ); - await expect( page ).toSelect( 'select[name="dimension_unit"]', 'Inches' ); - - await Promise.all( [ - // Click on "Continue" button to move to the next step - page.click( 'button[name=save_step]', { text: 'Continue' } ), - - // Wait for the Recommended section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Fill out recommended section details - // Turn off Storefront Theme option - await page.waitForSelector( '#wc_recommended_storefront_theme', { visible: true } ); - await page.$eval( '#wc_recommended_storefront_theme', elem => elem.click() ); - - // Turn off Automated Taxes option - await page.waitForSelector( '#wc_recommended_automated_taxes', { visible: true } ); - await page.$eval( '#wc_recommended_automated_taxes', elem => elem.click() ); - - // Turn off Mailchimp option - await page.waitForSelector( '#wc_recommended_mailchimp', { visible: true } ); - await page.$eval( '#wc_recommended_mailchimp', elem => elem.click() ); - - // Turn off Facebook option - await page.waitForSelector( '#wc_recommended_facebook', { visible: true } ); - await page.$eval( '#wc_recommended_facebook', elem => elem.click() ); - - await Promise.all( [ - // Click on "Continue" button to move to the next step - page.click( 'button[name=save_step]', { text: 'Continue' } ), - - // Wait for the Jetpack section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // Skip activate Jetpack section - // Click on "Skip this step" in order to skip Jetpack installation - await page.click( '.wc-setup-footer-links' ); - - // Finish Setup Wizard - Ready! section - // Visit Dashboard - await StoreOwnerFlow.openDashboard(); -} ; - -/** - * Create simple product. - */ -const createSimpleProduct = async () => { - // Go to "add product" page - await StoreOwnerFlow.openNewProduct(); - - // Make sure we're on the add order page - await expect( page.title() ).resolves.toMatch( 'Add new product' ); - - // Set product data - await expect( page ).toFill( '#title', simpleProductName ); - await clickTab( 'General' ); - await expect( page ).toFill( '#_regular_price', '9.99' ); - - await verifyAndPublish(); - - const simplePostId = await page.$( '#post_ID' ); - let simplePostIdValue = ( await ( await simplePostId.getProperty( 'value' ) ).jsonValue() ); - return simplePostIdValue; -} ; - -/** - * Create variable product. - */ -const createVariableProduct = async () => { - // Go to "add product" page - await StoreOwnerFlow.openNewProduct(); - - // Make sure we're on the add order page - await expect( page.title() ).resolves.toMatch( 'Add new product' ); - - // Set product data - await expect( page ).toFill( '#title', 'Variable Product with Three Variations' ); - await expect( page ).toSelect( '#product-type', 'Variable product' ); - - // Create attributes for variations - await clickTab( 'Attributes' ); - await expect( page ).toSelect( 'select[name="attribute_taxonomy"]', 'Custom product attribute' ); - - for ( let i = 0; i < 3; i++ ) { - await expect( page ).toClick( 'button.add_attribute', { text: 'Add' } ); - // Wait for attribute form to load - await uiUnblocked(); - - await page.focus( `input[name="attribute_names[${ i }]"]` ); - await expect( page ).toFill( `input[name="attribute_names[${ i }]"]`, 'attr #' + ( i + 1 ) ); - await expect( page ).toFill( `textarea[name="attribute_values[${ i }]"]`, 'val1 | val2' ); - await expect( page ).toClick( `input[name="attribute_variation[${ i }]"]` ); - } - - await expect( page ).toClick( 'button', { text: 'Save attributes' } ); - - // Wait for attribute form to save (triggers 2 UI blocks) - await uiUnblocked(); - await page.waitFor( 1000 ); - await uiUnblocked(); - - // Create variations from attributes - await clickTab( 'Variations' ); - await page.waitForSelector( 'select.variation_actions:not([disabled])' ); - await page.focus( 'select.variation_actions' ); - await expect( page ).toSelect( 'select.variation_actions', 'Create variations from all attributes' ); - - const firstDialog = await expect( page ).toDisplayDialog( async () => { - // Using this technique since toClick() isn't working. - // See: https://github.com/GoogleChrome/puppeteer/issues/1805#issuecomment-464802876 - page.$eval( 'a.do_variation_action', elem => elem.click() ); - - } ); - - expect( firstDialog.message() ).toMatch( 'Are you sure you want to link all variations?' ); - - const secondDialog = await expect( page ).toDisplayDialog( async () => { - await firstDialog.accept(); - } ); - - expect( secondDialog.message() ).toMatch( '8 variations added' ); - await secondDialog.dismiss(); - - // Set some variation data - await uiUnblocked(); - await uiUnblocked(); - - await page.waitForSelector( '.woocommerce_variation .handlediv' ); - - // Verify that variations were created - await Promise.all( [ - expect( page ).toMatchElement( 'select[name="attribute_attr-1[0]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[0]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[0]"]', { text: 'val1' } ), - - expect( page ).toMatchElement( 'select[name="attribute_attr-1[1]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[1]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[1]"]', { text: 'val2' } ), - - expect( page ).toMatchElement( 'select[name="attribute_attr-1[2]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[2]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[2]"]', { text: 'val1' } ), - - expect( page ).toMatchElement( 'select[name="attribute_attr-1[3]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[3]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[3]"]', { text: 'val2' } ), - - expect( page ).toMatchElement( 'select[name="attribute_attr-1[4]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[4]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[4]"]', { text: 'val1' } ), - - expect( page ).toMatchElement( 'select[name="attribute_attr-1[5]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[5]"]', { text: 'val1' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[5]"]', { text: 'val2' } ), - - expect( page ).toMatchElement( 'select[name="attribute_attr-1[6]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[6]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[6]"]', { text: 'val1' } ), - - expect( page ).toMatchElement( 'select[name="attribute_attr-1[7]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-2[7]"]', { text: 'val2' } ), - expect( page ).toMatchElement( 'select[name="attribute_attr-3[7]"]', { text: 'val2' } ), - ] ); - - await expect( page ).toClick( '.woocommerce_variation:nth-of-type(2) .handlediv' ); - await page.waitFor( 2000 ); - await page.focus( 'input[name="variable_is_virtual[0]"]' ); - await expect( page ).toClick( 'input[name="variable_is_virtual[0]"]' ); - await expect( page ).toFill( 'input[name="variable_regular_price[0]"]', '9.99' ); - - await expect( page ).toClick( '.woocommerce_variation:nth-of-type(3) .handlediv' ); - await page.waitFor( 2000 ); - await page.focus( 'input[name="variable_is_virtual[1]"]' ); - await expect( page ).toClick( 'input[name="variable_is_virtual[1]"]' ); - await expect( page ).toFill( 'input[name="variable_regular_price[1]"]', '11.99' ); - - await expect( page ).toClick( '.woocommerce_variation:nth-of-type(4) .handlediv' ); - await page.waitFor( 2000 ); - await page.focus( 'input[name="variable_manage_stock[2]"]' ); - await expect( page ).toClick( 'input[name="variable_manage_stock[2]"]' ); - await expect( page ).toFill( 'input[name="variable_regular_price[2]"]', '20' ); - await expect( page ).toFill( 'input[name="variable_weight[2]"]', '200' ); - await expect( page ).toFill( 'input[name="variable_length[2]"]', '10' ); - await expect( page ).toFill( 'input[name="variable_width[2]"]', '20' ); - await expect( page ).toFill( 'input[name="variable_height[2]"]', '15' ); - - await page.focus( 'button.save-variation-changes' ); - await expect( page ).toClick( 'button.save-variation-changes', { text: 'Save changes' } ); - - await verifyAndPublish(); - - const variablePostId = await page.$( '#post_ID' ); - let variablePostIdValue = ( await ( await variablePostId.getProperty( 'value' ) ).jsonValue() ); - return variablePostIdValue; -}; - -export { - completeOldSetupWizard, - completeOnboardingWizard, - createSimpleProduct, - createVariableProduct, - verifyAndPublish, -}; diff --git a/tests/e2e-utils/flows.js b/tests/e2e-utils/flows.js deleted file mode 100644 index ef6d5d3b2bd..00000000000 --- a/tests/e2e-utils/flows.js +++ /dev/null @@ -1,317 +0,0 @@ -/** - * @format - */ - -/** - * External dependencies - */ -import { pressKeyWithModifier } from '@wordpress/e2e-test-utils'; - -/** - * Internal dependencies - */ -import { clearAndFillInput } from './page-utils'; - -const config = require( 'config' ); -const baseUrl = config.get( 'url' ); - -const WP_ADMIN_LOGIN = baseUrl + 'wp-login.php'; -const WP_ADMIN_DASHBOARD = baseUrl + 'wp-admin'; -const WP_ADMIN_PLUGINS = baseUrl + 'wp-admin/plugins.php'; -const WP_ADMIN_SETUP_WIZARD = baseUrl + 'wp-admin/admin.php?page=wc-setup'; -const WP_ADMIN_ALL_ORDERS_VIEW = baseUrl + 'wp-admin/edit.php?post_type=shop_order'; -const WP_ADMIN_NEW_COUPON = baseUrl + 'wp-admin/post-new.php?post_type=shop_coupon'; -const WP_ADMIN_NEW_ORDER = baseUrl + 'wp-admin/post-new.php?post_type=shop_order'; -const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=product'; -const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab='; -const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php'; - -const SHOP_PAGE = baseUrl + 'shop'; -const SHOP_PRODUCT_PAGE = baseUrl + '?p='; -const SHOP_CART_PAGE = baseUrl + 'cart'; -const SHOP_CHECKOUT_PAGE = baseUrl + 'checkout/'; -const SHOP_MY_ACCOUNT_PAGE = baseUrl + 'my-account/'; - -const MY_ACCOUNT_ORDERS = baseUrl + 'my-account/orders'; -const MY_ACCOUNT_DOWNLOADS = baseUrl + 'my-account/downloads'; -const MY_ACCOUNT_ADDRESSES = baseUrl + 'my-account/edit-address'; -const MY_ACCOUNT_ACCOUNT_DETAILS = baseUrl + 'my-account/edit-account'; - -const getProductColumnExpression = ( productTitle ) => ( - 'td[@class="product-name" and ' + - `a[contains(text(), "${ productTitle }")]` + - ']' -); - -const getQtyColumnExpression = ( args ) => ( - 'td[@class="product-quantity" and ' + - './/' + getQtyInputExpression( args ) + - ']' -); - -const getQtyInputExpression = ( args = {} ) => { - let qtyValue = ''; - - if ( args.checkQty ) { - qtyValue = ` and @value="${ args.qty }"`; - } - - return 'input[contains(@class, "input-text")' + qtyValue + ']'; -}; - -const getCartItemExpression = ( productTitle, args ) => ( - '//tr[contains(@class, "cart_item") and ' + - getProductColumnExpression( productTitle ) + - ' and ' + - getQtyColumnExpression( args ) + - ']' -); - -const getRemoveExpression = () => ( - 'td[@class="product-remove"]//a[@class="remove"]' -); - -const CustomerFlow = { - addToCart: async () => { - await Promise.all( [ - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - page.click( '.single_add_to_cart_button' ), - ] ); - }, - - addToCartFromShopPage: async ( productTitle ) => { - const addToCartXPath = `//li[contains(@class, "type-product") and a/h2[contains(text(), "${ productTitle }")]]` + - '//a[contains(@class, "add_to_cart_button") and contains(@class, "ajax_add_to_cart")'; - - const [ addToCartButton ] = await page.$x( addToCartXPath + ']' ); - addToCartButton.click(); - - await page.waitFor( addToCartXPath + ' and contains(@class, "added")]' ); - }, - - goToCheckout: async () => { - await page.goto( SHOP_CHECKOUT_PAGE, { - waitUntil: 'networkidle0', - } ); - }, - - goToOrders: async () => { - await page.goto( MY_ACCOUNT_ORDERS, { - waitUntil: 'networkidle0', - } ); - }, - - goToDownloads: async () => { - await page.goto( MY_ACCOUNT_DOWNLOADS, { - waitUntil: 'networkidle0', - } ); - }, - - goToAddresses: async () => { - await page.goto( MY_ACCOUNT_ADDRESSES, { - waitUntil: 'networkidle0', - } ); - }, - - goToAccountDetails: async () => { - await page.goto( MY_ACCOUNT_ACCOUNT_DETAILS, { - waitUntil: 'networkidle0', - } ); - }, - - goToProduct: async ( postID ) => { - await page.goto( SHOP_PRODUCT_PAGE + postID, { - waitUntil: 'networkidle0', - } ); - }, - - - goToShop: async () => { - await page.goto(SHOP_PAGE, { - waitUntil: 'networkidle0', - }); - }, - - placeOrder: async () => { - await Promise.all( [ - expect( page ).toClick( '#place_order' ), - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - }, - - productIsInCheckout: async ( productTitle, quantity, total, cartSubtotal ) => { - await expect( page ).toMatchElement( '.product-name', { text: productTitle } ); - await expect( page ).toMatchElement( '.product-quantity', { text: quantity } ); - await expect( page ).toMatchElement( '.product-total .amount', { text: total } ); - await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: cartSubtotal } ); - }, - - goToCart: async () => { - await page.goto( SHOP_CART_PAGE, { - waitUntil: 'networkidle0', - } ); - }, - - login: async () => { - await page.goto( SHOP_MY_ACCOUNT_PAGE, { - waitUntil: 'networkidle0', - } ); - - await expect( page.title() ).resolves.toMatch( 'My account' ); - - await page.type( '#username', config.get('users.customer.username') ); - await page.type( '#password', config.get('users.customer.password') ); - - await Promise.all( [ - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - page.click( 'button[name="login"]' ), - ] ); - }, - - productIsInCart: async ( productTitle, quantity = null ) => { - const cartItemArgs = quantity ? { qty: quantity } : {}; - const cartItemXPath = getCartItemExpression( productTitle, cartItemArgs ); - - await expect( page.$x( cartItemXPath ) ).resolves.toHaveLength( 1 ); - }, - - fillBillingDetails: async ( customerBillingDetails ) => { - await expect( page ).toFill( '#billing_first_name', customerBillingDetails.firstname ); - await expect( page ).toFill( '#billing_last_name', customerBillingDetails.lastname ); - await expect( page ).toFill( '#billing_company', customerBillingDetails.company ); - await expect( page ).toSelect( '#billing_country', customerBillingDetails.country ); - await expect( page ).toFill( '#billing_address_1', customerBillingDetails.addressfirstline ); - await expect( page ).toFill( '#billing_address_2', customerBillingDetails.addresssecondline ); - await expect( page ).toFill( '#billing_city', customerBillingDetails.city ); - await expect( page ).toSelect( '#billing_state', customerBillingDetails.state ); - await expect( page ).toFill( '#billing_postcode', customerBillingDetails.postcode ); - await expect( page ).toFill( '#billing_phone', customerBillingDetails.phone ); - await expect( page ).toFill( '#billing_email', customerBillingDetails.email ); - }, - - fillShippingDetails: async ( customerShippingDetails ) => { - await expect( page ).toFill( '#shipping_first_name', customerShippingDetails.firstname ); - await expect( page ).toFill( '#shipping_last_name', customerShippingDetails.lastname ); - await expect( page ).toFill( '#shipping_company', customerShippingDetails.company ); - await expect( page ).toSelect( '#shipping_country', customerShippingDetails.country ); - await expect( page ).toFill( '#shipping_address_1', customerShippingDetails.addressfirstline ); - await expect( page ).toFill( '#shipping_address_2', customerShippingDetails.addresssecondline ); - await expect( page ).toFill( '#shipping_city', customerShippingDetails.city ); - await expect( page ).toSelect( '#shipping_state', customerShippingDetails.state ); - await expect( page ).toFill( '#shipping_postcode', customerShippingDetails.postcode ); - }, - - removeFromCart: async ( productTitle ) => { - const cartItemXPath = getCartItemExpression(productTitle); - const removeItemXPath = cartItemXPath + '//' + getRemoveExpression(); - - const [removeButton] = await page.$x(removeItemXPath); - await removeButton.click(); - }, - - setCartQuantity: async ( productTitle, quantityValue ) => { - const cartItemXPath = getCartItemExpression( productTitle ); - const quantityInputXPath = cartItemXPath + '//' + getQtyInputExpression(); - - const [ quantityInput ] = await page.$x( quantityInputXPath ); - await quantityInput.focus(); - await pressKeyWithModifier( 'primary', 'a' ); - await quantityInput.type( quantityValue.toString() ); - }, -}; - - -const StoreOwnerFlow = { - login: async () => { - await page.goto( WP_ADMIN_LOGIN, { - waitUntil: 'networkidle0', - } ); - - await expect( page.title() ).resolves.toMatch( 'Log In' ); - - await clearAndFillInput( '#user_login', ' ' ); - - await page.type( '#user_login', config.get( 'users.admin.username' ) ); - await page.type( '#user_pass', config.get( 'users.admin.password' ) ); - - await Promise.all( [ - page.click( 'input[type=submit]' ), - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - }, - - logout: async () => { - await page.goto(baseUrl + 'wp-login.php?action=logout', { - waitUntil: 'networkidle0', - }); - - await expect(page).toMatch('You are attempting to log out'); - - await Promise.all([ - page.waitForNavigation({ waitUntil: 'networkidle0' }), - page.click('a'), - ]); - }, - - openAllOrdersView: async () => { - await page.goto( WP_ADMIN_ALL_ORDERS_VIEW, { - waitUntil: 'networkidle0', - } ); - }, - - openDashboard: async () => { - await page.goto( WP_ADMIN_DASHBOARD, { - waitUntil: 'networkidle0', - } ); - }, - - openNewCoupon: async () => { - await page.goto( WP_ADMIN_NEW_COUPON, { - waitUntil: 'networkidle0', - } ); - }, - - openNewOrder: async () => { - await page.goto( WP_ADMIN_NEW_ORDER, { - waitUntil: 'networkidle0', - } ); - }, - - openNewProduct: async () => { - await page.goto( WP_ADMIN_NEW_PRODUCT, { - waitUntil: 'networkidle0', - } ); - }, - - openPermalinkSettings: async () => { - await page.goto( WP_ADMIN_PERMALINK_SETTINGS, { - waitUntil: 'networkidle0', - } ); - }, - - openPlugins: async () => { - await page.goto( WP_ADMIN_PLUGINS, { - waitUntil: 'networkidle0', - } ); - }, - - openSettings: async ( tab, section = null ) => { - let settingsUrl = WP_ADMIN_WC_SETTINGS + tab; - - if ( section ) { - settingsUrl += `§ion=${ section }`; - } - - await page.goto( settingsUrl, { - waitUntil: 'networkidle0', - } ); - }, - - runSetupWizard: async () => { - await page.goto( WP_ADMIN_SETUP_WIZARD, { - waitUntil: 'networkidle0', - } ); - }, -}; - -export { CustomerFlow, StoreOwnerFlow }; diff --git a/tests/e2e-utils/index.js b/tests/e2e-utils/index.js deleted file mode 100644 index f6f914713f9..00000000000 --- a/tests/e2e-utils/index.js +++ /dev/null @@ -1,44 +0,0 @@ -import { CustomerFlow, StoreOwnerFlow } from './flows'; - -import { - completeOnboardingWizard, - completeOldSetupWizard, - createSimpleProduct, - createVariableProduct, - verifyAndPublish, -} from './components'; - -import { - clearAndFillInput, - clickTab, - settingsPageSaveChanges, - permalinkSettingsPageSaveChanges, - setCheckbox, - unsetCheckbox, - uiUnblocked, - verifyPublishAndTrash, - verifyCheckboxIsSet, - verifyCheckboxIsUnset, - verifyValueOfInputField, -} from './page-utils'; - -module.exports = { - CustomerFlow, - StoreOwnerFlow, - completeOnboardingWizard, - completeOldSetupWizard, - createSimpleProduct, - createVariableProduct, - verifyAndPublish, - clearAndFillInput, - clickTab, - settingsPageSaveChanges, - permalinkSettingsPageSaveChanges, - setCheckbox, - unsetCheckbox, - uiUnblocked, - verifyPublishAndTrash, - verifyCheckboxIsSet, - verifyCheckboxIsUnset, - verifyValueOfInputField -} diff --git a/tests/e2e-utils/README.md b/tests/e2e/utils/README.md similarity index 87% rename from tests/e2e-utils/README.md rename to tests/e2e/utils/README.md index b62b53c5b75..9ea08949678 100644 --- a/tests/e2e-utils/README.md +++ b/tests/e2e/utils/README.md @@ -1,6 +1,6 @@ # WooCommerce End to End Test Utilities -This package contains utilities needed to write e2e tests (specific to WooCommerce). +This package contains utilities to simplify writing e2e tests specific to WooCommmerce. ## Installation diff --git a/tests/e2e/utils/index.js b/tests/e2e/utils/index.js index 004766479bd..bd333b76b7c 100644 --- a/tests/e2e/utils/index.js +++ b/tests/e2e/utils/index.js @@ -1,160 +1,14 @@ -/** - * External dependencies - */ -import { pressKeyWithModifier } from '@wordpress/e2e-test-utils'; +import { CustomerFlow, StoreOwnerFlow } from './src/flows'; -/** - * Perform a "select all" and then fill a input. - * - * @param {string} selector - * @param {string} value - */ -const clearAndFillInput = async ( selector, value ) => { - await page.focus( selector ); - await pressKeyWithModifier( 'primary', 'a' ); - await page.type( selector, value ); -}; +import { + completeOnboardingWizard, + completeOldSetupWizard, + createSimpleProduct, + createVariableProduct, + verifyAndPublish, +} from './src/components'; -/** - * Click a tab (on post type edit screen). - * - * @param {string} tabName Tab label - */ -const clickTab = async ( tabName ) => { - await expect( page ).toClick( '.wc-tabs > li > a', { text: tabName } ); -}; - -/** - * Save changes on a WooCommerce settings page. - */ -const settingsPageSaveChanges = async () => { - await page.focus( 'button.woocommerce-save-button' ); - await Promise.all( [ - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - page.click( 'button.woocommerce-save-button' ), - ] ); -}; - -/** - * Save changes on Permalink settings page. - */ -const permalinkSettingsPageSaveChanges = async () => { - await page.focus( '.wp-core-ui .button-primary' ); - await Promise.all( [ - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - page.click( '.wp-core-ui .button-primary' ), - ] ); -}; - -/** - * Set checkbox. - * - * @param {string} selector - */ -const setCheckbox = async( selector ) => { - await page.focus( selector ); - const checkbox = await page.$( selector ); - const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); - if ( checkboxStatus !== true ) { - await page.click( selector ); - } -}; - -/** - * Unset checkbox. - * - * @param {string} selector - */ -const unsetCheckbox = async( selector ) => { - await page.focus( selector ); - const checkbox = await page.$( selector ); - const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); - if ( checkboxStatus === true ) { - await page.click( selector ); - } -}; - -/** - * Wait for UI blocking to end. - */ -const uiUnblocked = async () => { - await page.waitForFunction( () => ! Boolean( document.querySelector( '.blockUI' ) ) ); -}; - -/** - * Publish, verify that item was published. Trash, verify that item was trashed. - * - * @param {string} button (Publish) - * @param {string} publishNotice - * @param {string} publishVerification - * @param {string} trashVerification - */ -const verifyPublishAndTrash = async ( button, publishNotice, publishVerification, trashVerification ) => { - // Wait for auto save - await page.waitFor( 2000 ); - - // Publish - await expect( page ).toClick( button ); - await page.waitForSelector( publishNotice ); - - // Verify - await expect( page ).toMatchElement( publishNotice, { text: publishVerification } ); - if ( button === '.order_actions li .save_order' ) { - await expect( page ).toMatchElement( '#select2-order_status-container', { text: 'Processing' } ); - await expect( page ).toMatchElement( - '#woocommerce-order-notes .note_content', - { - text: 'Order status changed from Pending payment to Processing.', - } - ); - } - - // Trash - await expect( page ).toClick( 'a', { text: "Move to Trash" } ); - await page.waitForSelector( '#message' ); - - // Verify - await expect( page ).toMatchElement( publishNotice, { text: trashVerification } ); -}; - -/** - * Verify that checkbox is set. - * - * @param {string} selector Selector of the checkbox that needs to be verified. - */ -const verifyCheckboxIsSet = async( selector ) => { - await page.focus( selector ); - const checkbox = await page.$( selector ); - const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); - await expect( checkboxStatus ).toBe( true ); -}; - -/** - * Verify that checkbox is unset. - * - * @param {string} selector Selector of the checkbox that needs to be verified. - */ -const verifyCheckboxIsUnset = async( selector ) => { - await page.focus( selector ); - const checkbox = await page.$( selector ); - const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); - await expect( checkboxStatus ).not.toBe( true ); -}; - -/** - * Verify the value of input field once it was saved (can be used for radio buttons verification as well). - * - * @param {string} selector Selector of the input field that needs to be verified. - * @param {string} value Value of the input field that needs to be verified. - */ -const verifyValueOfInputField = async( selector, value ) => { - await page.focus( selector ); - const field = await page.$( selector ); - const fieldValue = ( await ( await field.getProperty( 'value' ) ).jsonValue() ); - await expect( fieldValue ).toBe( value ); -}; - -export { +import { clearAndFillInput, clickTab, settingsPageSaveChanges, @@ -166,4 +20,25 @@ export { verifyCheckboxIsSet, verifyCheckboxIsUnset, verifyValueOfInputField, -}; +} from './src/page-utils'; + +module.exports = { + CustomerFlow, + StoreOwnerFlow, + completeOnboardingWizard, + completeOldSetupWizard, + createSimpleProduct, + createVariableProduct, + verifyAndPublish, + clearAndFillInput, + clickTab, + settingsPageSaveChanges, + permalinkSettingsPageSaveChanges, + setCheckbox, + unsetCheckbox, + uiUnblocked, + verifyPublishAndTrash, + verifyCheckboxIsSet, + verifyCheckboxIsUnset, + verifyValueOfInputField +} diff --git a/tests/e2e-utils/package.json b/tests/e2e/utils/package.json similarity index 73% rename from tests/e2e-utils/package.json rename to tests/e2e/utils/package.json index a5366fe573a..5bc19595935 100644 --- a/tests/e2e-utils/package.json +++ b/tests/e2e/utils/package.json @@ -1,6 +1,6 @@ { "name": "@woocommerce/e2e-utils", - "version": "1.0.0", + "version": "0.1.0", "description": "End-To-End (E2E) test utils for WooCommerce", "homepage": "https://github.com/woocommerce/woocommerce/tree/master/tests/e2e-utils/README.md", "repository": { @@ -8,8 +8,9 @@ "url": "https://github.com/woocommerce/woocommerce.git" }, "license": "GPL-3.0+", - "main": "index.js", + "main": "build/index.js", + "module": "build-module/index.js", "dependencies": { - "@wordpress/e2e-test-utils": "4.3.1" + "@wordpress/e2e-test-utils": "4.6.0" } } diff --git a/tests/e2e/utils/components.js b/tests/e2e/utils/src/components.js similarity index 100% rename from tests/e2e/utils/components.js rename to tests/e2e/utils/src/components.js diff --git a/tests/e2e/utils/flows.js b/tests/e2e/utils/src/flows.js similarity index 100% rename from tests/e2e/utils/flows.js rename to tests/e2e/utils/src/flows.js diff --git a/tests/e2e-utils/page-utils.js b/tests/e2e/utils/src/page-utils.js similarity index 100% rename from tests/e2e-utils/page-utils.js rename to tests/e2e/utils/src/page-utils.js diff --git a/tests/e2e/utils/webpack-alias.js b/tests/e2e/utils/webpack-alias.js new file mode 100644 index 00000000000..3c9d404cc68 --- /dev/null +++ b/tests/e2e/utils/webpack-alias.js @@ -0,0 +1,11 @@ +/** + * External dependencies + */ +const path = require( 'path' ); + +module.exports = { + '@woocommerce/e2e-tests': path.resolve( + __dirname, + 'node_modules/woocommerce/tests/e2e' + ), +};