diff --git a/packages/js/e2e-core-tests/specs/keep/onboarding-tasklist.test.js b/packages/js/e2e-core-tests/specs/keep/onboarding-tasklist.test.js deleted file mode 100644 index 47aeecb715f..00000000000 --- a/packages/js/e2e-core-tests/specs/keep/onboarding-tasklist.test.js +++ /dev/null @@ -1,83 +0,0 @@ -/* eslint-disable jest/no-export, jest/no-disabled-tests */ - -/** - * Internal dependencies - */ -const { - merchant, - completeOnboardingWizard, - withRestApi, - addShippingZoneAndMethod, - IS_RETEST_MODE, -} = require( '@woocommerce/e2e-utils' ); - -/** - * External dependencies - */ -const config = require( 'config' ); -const { - it, - describe, -} = require( '@jest/globals' ); - -const shippingZoneNameUS = config.get( 'addresses.customer.shipping.country' ); - -const runOnboardingFlowTest = () => { - describe('Store owner can go through store Onboarding', () => { - if ( IS_RETEST_MODE ) { - it('can reset onboarding to default settings', async () => { - await withRestApi.resetOnboarding(); - }); - - it('can reset shipping zones to default settings', async () => { - await withRestApi.deleteAllShippingZones(); - }); - - it('can reset to default settings', async () => { - await withRestApi.resetSettingsGroupToDefault('general'); - await withRestApi.resetSettingsGroupToDefault('products'); - await withRestApi.resetSettingsGroupToDefault('tax'); - }); - } - - it('can start and complete onboarding when visiting the site for the first time.', async () => { - await completeOnboardingWizard(); - }); - }); -}; - -const runTaskListTest = () => { - describe('Store owner can go through setup Task List', () => { - it('can setup shipping', async () => { - await page.evaluate(() => { - document.querySelector('.woocommerce-list__item-title').scrollIntoView(); - }); - // Query for all tasks on the list - const taskListItems = await page.$$('.woocommerce-list__item-title'); - expect(taskListItems.length).toBeInRange( 5, 6 ); - - // Work around for https://github.com/woocommerce/woocommerce-admin/issues/6761 - if ( taskListItems.length == 6 ) { - // Click on "Set up shipping" task to move to the next step - const [ setupTaskListItem ] = await page.$x( '//div[contains(text(),"Set up shipping")]' ); - await setupTaskListItem.click(); - - // Wait for "Proceed" button to become active - await page.waitForSelector('button.is-primary:not(:disabled)'); - await page.waitFor(3000); - - // Click on "Proceed" button to save shipping settings - await page.click('button.is-primary'); - await page.waitFor(3000); - } else { - await merchant.openNewShipping(); - await addShippingZoneAndMethod(shippingZoneNameUS); - } - }); - }); -}; - -module.exports = { - runOnboardingFlowTest, - runTaskListTest, -}; diff --git a/packages/js/e2e-core-tests/specs/merchant/wp-admin-coupon-new.test.js b/packages/js/e2e-core-tests/specs/merchant/wp-admin-coupon-new.test.js index cccd3d8aa39..87921c63ce2 100644 --- a/packages/js/e2e-core-tests/specs/merchant/wp-admin-coupon-new.test.js +++ b/packages/js/e2e-core-tests/specs/merchant/wp-admin-coupon-new.test.js @@ -5,9 +5,8 @@ const { merchant, clickTab, AdminEdit, - factories, + withRestApi, } = require( '@woocommerce/e2e-utils' ); -const { Coupon } = require( '@woocommerce/api' ); /** * External dependencies @@ -50,8 +49,7 @@ const runCreateCouponTest = () => { // Delete the coupon const couponId = await adminEdit.getId(); if ( couponId ) { - const repository = Coupon.restRepository( factories.api.withDefaultPermalinks ); - await repository.delete( couponId ); + await withRestApi.deleteCoupon( couponId ); } }); }); diff --git a/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-new.test.js b/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-new.test.js index 176b11cb768..3dd15e2d758 100644 --- a/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-new.test.js +++ b/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-new.test.js @@ -4,9 +4,10 @@ const { merchant, uiUnblocked, + withRestApi, AdminEdit, -} = require('@woocommerce/e2e-utils'); -const config = require('config'); +} = require( '@woocommerce/e2e-utils' ); +const config = require( 'config' ); const { HTTPClientFactory, VariableProduct, @@ -14,22 +15,34 @@ const { SimpleProduct, ProductVariation, ExternalProduct -} = require('@woocommerce/api'); +} = require( '@woocommerce/api' ); + +const taxClasses = [ + { + name: 'Tax Class Simple', + }, + { + name: 'Tax Class Variable', + }, + { + name: 'Tax Class External', + }, +]; const taxRates = [ { name: 'Tax Rate Simple', - rate: '10', + rate: '10.0000', class: 'tax-class-simple' }, { name: 'Tax Rate Variable', - rate: '20', + rate: '20.0000', class: 'tax-class-variable' }, { name: 'Tax Rate External', - rate: '30', + rate: '30.0000', class: 'tax-class-external' } ]; @@ -43,60 +56,22 @@ const initProducts = async () => { const httpClient = HTTPClientFactory.build(apiUrl) .withBasicAuth(adminUsername, adminPassword) .create(); - const taxClassesPath = '/wc/v3/taxes/classes'; - const taxClasses = [ - { - name: 'Tax Class Simple', - slug: 'tax-class-simple-698962' - }, - { - name: 'Tax Class Variable', - slug: 'tax-class-variable-790238' - }, - { - name: 'Tax Class External', - slug: 'tax-class-external-991321' - } - ]; - // Enable taxes in settings - const enableTaxes = async () => { - const path = '/wc/v3/settings/general/woocommerce_calc_taxes'; - const data = { - value: 'yes' - }; - await httpClient.put(path, data); - }; - await enableTaxes(); - - // Initialize tax classes - const initTaxClasses = async () => { - for (const classToBeAdded of taxClasses) { - await httpClient.post(taxClassesPath, classToBeAdded); - } - }; - await initTaxClasses(); - - // Initialize tax rates - const initTaxRates = async () => { - const path = '/wc/v3/taxes'; - - for (const rateToBeAdded of taxRates) { - await httpClient.post(path, rateToBeAdded); - } - }; - await initTaxRates(); + await withRestApi.updateSettingOption( 'general', 'woocommerce_calc_taxes', { value: 'yes' } ); + await withRestApi.addTaxClasses( taxClasses ); + await withRestApi.addTaxRates( taxRates ); // Initialization functions per product type const initSimpleProduct = async () => { - const repo = SimpleProduct.restRepository(httpClient); + const repo = SimpleProduct.restRepository( httpClient ); const simpleProduct = { name: 'Simple Product 273722', regularPrice: '100', taxClass: 'Tax Class Simple' }; - return await repo.create(simpleProduct); + return await repo.create( simpleProduct ); }; + const initVariableProduct = async () => { const variations = [ { @@ -264,12 +239,12 @@ const runCreateOrderTest = () => { } // Verify that the names of each tax class were shown - for (const { name } of taxRates) { + for (const taxRate of taxRates) { await expect(page).toMatchElement('th.line_tax', { - text: name + text: taxRate.name }); await expect(page).toMatchElement('.wc-order-totals td.label', { - text: name + text: taxRate.name }); } diff --git a/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-searching.test.js b/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-searching.test.js index b054460607c..306b3a5add2 100644 --- a/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-searching.test.js +++ b/packages/js/e2e-core-tests/specs/merchant/wp-admin-order-searching.test.js @@ -51,7 +51,7 @@ const updateCustomerBilling = async () => { search: 'Jane', role: 'all', } ); - if ( ! customers.data | ! customers.data.length ) { + if ( ! customers.data || ! customers.data.length ) { return; } diff --git a/packages/js/e2e-utils/CHANGELOG.md b/packages/js/e2e-utils/CHANGELOG.md index d6d3488b78e..9fef3023ed3 100644 --- a/packages/js/e2e-utils/CHANGELOG.md +++ b/packages/js/e2e-utils/CHANGELOG.md @@ -5,8 +5,11 @@ - `utils.waitForTimeout( delay )` pause processing for `delay` milliseconds - `AdminEdit` class with utility functions for the respective edit screens - Update `shopper.addToCartFromShopPage()` and `.removeFromCart()` to accept product Id or Title -- Added `deleteAllProductAttributes()`, `deleteAllProductCategories()`, and `deleteAllProductTags()` to clean up meta data added when products are imported -- Added `withRestApi.createProductCategory()` that creates a product category and returns the ID +- `deleteAllProductAttributes()`, `deleteAllProductCategories()`, and `deleteAllProductTags()` to clean up meta data added when products are imported +- `withRestApi.createProductCategory()` that creates a product category and returns the ID +- `withRestApi.deleteCoupon()` that deletes a single coupon +- `withRestApi.addTaxClasses()` that adds an array of tax classes if they do not exist +- `withRestApi.addTaxRates()` that adds an array of tax rates if they do not exist # 0.1.6 diff --git a/packages/js/e2e-utils/README.md b/packages/js/e2e-utils/README.md index 065005b7508..4e17767d1ac 100644 --- a/packages/js/e2e-utils/README.md +++ b/packages/js/e2e-utils/README.md @@ -142,22 +142,25 @@ Please note: if you're using a non-SSL environment (such as a Docker container f | Function | Parameters | Description | |----------|------------|-------------| -| `resetOnboarding` | | Reset onboarding settings | -| `deleteAllCoupons` | | Permanently delete all coupons | -| `deleteAllProducts` | | Permanently delete all products | -| `deleteAllShippingZones` | | Permanently delete all shipping zones except the default | -| `deleteAllShippingClasses` | Permanently delete all shipping classes | -| `deleteCustomerByEmail` | `emailAddress` | Delete customer user account. Posts are reassigned to user ID 1 | -| `resetSettingsGroupToDefault` | `settingsGroup` | Reset settings in settings group to default except `select` fields | | `batchCreateOrders` | `orders` | Create a batch of orders using the "Batch Create Order" API endpoint | +| `addTaxClasses` | `taxClasses` | Add an array of tax classes if they do not exist | +| `addTaxRates` | `taxRates` | Add an array of tax rates if they do not exist | +| `createProductCategory` | `categoryName` | Create a product category with the provided name | +| `deleteAllCoupons` | | Permanently delete all coupons | | `deleteAllOrders` | | Permanently delete all orders | +| `deleteAllProductAttributes` | | Permanently delete all product attributes | +| `deleteAllProductCategories` | | Permanently delete all product categories | +| `deleteAllProducts` | | Permanently delete all products | +| `deleteAllProductTags` | | Permanently delete all product tags | +| `deleteAllShippingClasses` | Permanently delete all shipping classes | +| `deleteAllShippingZones` | | Permanently delete all shipping zones except the default | +| `deleteCoupon` | `couponId` | Permanently delete a coupon | +| `deleteCustomerByEmail` | `emailAddress` | Delete customer user account. Posts are reassigned to user ID 1 | +| `getSystemEnvironment` | | Get the current environment from the WooCommerce system status API. | +| `resetOnboarding` | | Reset onboarding settings | +| `resetSettingsGroupToDefault` | `settingsGroup` | Reset settings in settings group to default except `select` fields | | `updateSettingOption` | `settingsGroup`, `settingID`, `payload` | Update a settings group | | `updatePaymentGateway`| `paymentGatewayId`, `payload` | Update a payment gateway | -| `getSystemEnvironment` | | Get the current environment from the WooCommerce system status API. | -| `deleteAllProductAttributes` | | Permanently delete all product attributes. | -| `deleteAllProductCategories` | | Permanently delete all product categories. | -| `deleteAllProductTags` | | Permanently delete all product tags. | -| `createProductCategory` | `categoryName` | Create a product category with the provided name. | ### Classes diff --git a/packages/js/e2e-utils/src/components.js b/packages/js/e2e-utils/src/components.js index 1349be25edd..21767d578c2 100644 --- a/packages/js/e2e-utils/src/components.js +++ b/packages/js/e2e-utils/src/components.js @@ -190,13 +190,13 @@ const completeOnboardingWizard = async () => { /** * Create simple product. * - * @param productTitle - Defaults to Simple Product. Customizable title. - * @param productPrice - Defaults to $9.99. Customizable pricing. + * @param productTitle Defaults to Simple Product. Customizable title. + * @param productPrice Defaults to $9.99. Customizable pricing. */ const createSimpleProduct = async ( productTitle = simpleProductName, productPrice = simpleProductPrice ) => { const product = await factories.products.simple.create( { name: productTitle, - regularPrice: productPrice + regularPrice: productPrice, } ); return product.id; } ; diff --git a/packages/js/e2e-utils/src/flows/with-rest-api.js b/packages/js/e2e-utils/src/flows/with-rest-api.js index 49b496d273c..15f65e8da51 100644 --- a/packages/js/e2e-utils/src/flows/with-rest-api.js +++ b/packages/js/e2e-utils/src/flows/with-rest-api.js @@ -4,12 +4,14 @@ import {Coupon, Setting, SimpleProduct, Order} from '@woocommerce/api'; const client = factories.api.withDefaultPermalinks; const onboardingProfileEndpoint = '/wc-admin/onboarding/profile'; -const shippingZoneEndpoint = '/wc/v3/shipping/zones'; -const shippingClassesEndpoint = '/wc/v3/products/shipping_classes'; -const userEndpoint = '/wp/v2/users'; -const systemStatusEndpoint = '/wc/v3/system_status'; const productsEndpoint = '/wc/v3/products'; const productCategoriesEndpoint = '/wc/v3/products/categories'; +const shippingClassesEndpoint = '/wc/v3/products/shipping_classes'; +const shippingZoneEndpoint = '/wc/v3/shipping/zones'; +const systemStatusEndpoint = '/wc/v3/system_status'; +const taxClassesEndpoint = '/wc/v3/taxes/classes'; +const taxRatesEndpoint = '/wc/v3/taxes'; +const userEndpoint = '/wp/v2/users'; /** * Utility function to delete all merchant created data store objects. @@ -42,6 +44,16 @@ const deleteAllRepositoryObjects = async ( repository, defaultObjectId = null, s } }; +/** + * Utility to flatten a tax rate. + * + * @param {object} taxRate Tax rate to be flattened. + * @return {string} + */ +const flattenTaxRate = ( taxRate ) => { + return taxRate.rate + '/' + taxRate.class + '/' + taxRate.name; +}; + /** * Utility functions that use the REST API to process the requested function. */ @@ -77,6 +89,16 @@ export const withRestApi = { const repository = Coupon.restRepository( client ); await deleteAllRepositoryObjects( repository ); }, + /** + * Use api package to delete a coupon. + * + * @param {number} couponId Coupon ID. + * @return {Promise} Promise resolving once coupon has been deleted. + */ + deleteCoupon: async ( couponId ) => { + const repository = Coupon.restRepository( client ); + await repository.delete( couponId ); + }, /** * Use api package to delete products. * @@ -331,13 +353,46 @@ export const withRestApi = { * * @param orders Array of orders to be created */ - batchCreateOrders: async (orders) => { + batchCreateOrders: async ( orders ) => { const path = '/wc/v3/orders/batch'; const payload = { create: orders }; const response = await client.post(path, payload); expect( response.status ).toEqual(200); }, + /** + * Add tax classes. + * + * @param {>} taxClasses Array of tax class objects. + * @returns {Promise} + */ + addTaxClasses: async ( taxClasses ) => { + // Only add tax classes which don't already exist. + const existingTaxClasses = await client.get( taxClassesEndpoint ); + const existingTaxNames = existingTaxClasses.data.map( taxClass => taxClass.name ); + const newTaxClasses = taxClasses.filter( taxClass => ! existingTaxNames.includes( taxClass.name ) ); + + for ( const taxClass of newTaxClasses ) { + await client.post( taxClassesEndpoint, taxClass ); + } + }, + /** + * Add tax rates. + * + * @param {>} taxRates Array of tax rate objects. + * @returns {Promise} + */ + addTaxRates: async ( taxRates ) => { + // Only add rates which don't already exist + const existingTaxRates = await client.get( taxRatesEndpoint ); + const existingRates = existingTaxRates.data.map( taxRate => flattenTaxRate( taxRate ) ); + + for ( const taxRate of taxRates ) { + if ( ! existingRates.includes( flattenTaxRate( taxRate ) ) ) { + await client.post( taxRatesEndpoint, taxRate ); + } + } + }, /** * Get the current environment from the WooCommerce system status API. *