diff --git a/tests/e2e/config/jest.config.js b/tests/e2e/config/jest.config.js index 5e18a26fa6f..69e40bf5888 100644 --- a/tests/e2e/config/jest.config.js +++ b/tests/e2e/config/jest.config.js @@ -5,7 +5,7 @@ module.exports = { clearMocks: true, // An array of file extensions your modules use - moduleFileExtensions: [ 'js' ], + moduleFileExtensions: [ 'js', 'ts' ], moduleNameMapper: { '@woocommerce/blocks-test-utils': '/tests/utils', diff --git a/tests/e2e/config/jest.setup.js b/tests/e2e/config/jest.setup.js index 6516fa62205..1af8eb5fc7c 100644 --- a/tests/e2e/config/jest.setup.js +++ b/tests/e2e/config/jest.setup.js @@ -1,7 +1,6 @@ /** * External dependencies */ -import { get } from 'lodash'; import { enablePageDialogAccept, isOfflineMode, @@ -12,7 +11,7 @@ import { } from '@wordpress/e2e-test-utils'; // Set the default test timeout. -let jestTimeoutInMilliSeconds = 40000; +let jestTimeoutInMilliSeconds = 60000; // When running test in the Development mode, the test timeout is increased to 2 minutes which allows for errors to be inspected. // Use `await jestPuppeteer.debug()` in test code to pause execution. @@ -40,16 +39,14 @@ const pageEvents = []; * @type {Object} */ const OBSERVED_CONSOLE_MESSAGE_TYPES = { - warning: 'warn', error: 'error', }; - async function setupBrowser() { await setBrowserViewport( 'large' ); } /** - * Navigates to woocommerce import page and imports sample products. + * Navigates to WooCommerce's import page and imports sample products. * * @return {Promise} Promise resolving once products have been imported. */ @@ -118,26 +115,7 @@ function observeConsoleLogging() { if ( ! OBSERVED_CONSOLE_MESSAGE_TYPES.hasOwnProperty( type ) ) { return; } - - let text = message.text(); - - // An exception is made for _blanket_ deprecation warnings: Those - // which log regardless of whether a deprecated feature is in use. - if ( text.includes( 'This is a global warning' ) ) { - return; - } - - // A chrome advisory warning about SameSite cookies is informational - // about future changes, tracked separately for improvement in core. - // - // See: https://core.trac.wordpress.org/ticket/37000 - // See: https://www.chromestatus.com/feature/5088147346030592 - // See: https://www.chromestatus.com/feature/5633521622188032 - if ( - text.includes( 'A cookie associated with a cross-site resource' ) - ) { - return; - } + const text = message.text(); // Viewing posts on the front end can result in this error, which // has nothing to do with Gutenberg. @@ -154,46 +132,11 @@ function observeConsoleLogging() { return; } - // As of WordPress 5.3.2 in Chrome 79, navigating to the block editor - // (Posts > Add New) will display a console warning about - // non - unique IDs. - // See: https://core.trac.wordpress.org/ticket/23165 - if ( text.includes( 'elements with non-unique id #_wpnonce' ) ) { - return; - } - - // As of WordPress 5.3.2 in Chrome 79, navigating to the block editor - // (Posts > Add New) will display a console warning about - // non - unique IDs. - // See: https://core.trac.wordpress.org/ticket/23165 - if ( text.includes( 'elements with non-unique id #_wpnonce' ) ) { - return; - } - const logFunction = OBSERVED_CONSOLE_MESSAGE_TYPES[ type ]; - // As of Puppeteer 1.6.1, `message.text()` wrongly returns an object of - // type JSHandle for error logging, instead of the expected string. - // - // See: https://github.com/GoogleChrome/puppeteer/issues/3397 - // - // The recommendation there to asynchronously resolve the error value - // upon a console event may be prone to a race condition with the test - // completion, leaving a possibility of an error not being surfaced - // correctly. Instead, the logic here synchronously inspects the - // internal object shape of the JSHandle to find the error text. If it - // cannot be found, the default text value is used instead. - text = get( - message.args(), - [ 0, '_remoteObject', 'description' ], - text - ); - - // Disable reason: We intentionally bubble up the console message - // which, unless the test explicitly anticipates the logging via - // @wordpress/jest-console matchers, will cause the intended test - // failure. - + // Disable reason: We intentionally bubble up console error messages + // for debugging reasons. If you need to test explicitly the logging, + // use @wordpress/jest-console // eslint-disable-next-line no-console console[ logFunction ]( text ); } ); diff --git a/tests/e2e/specs/backend/cart.test.js b/tests/e2e/specs/backend/cart.test.js index f98c77615d2..58283c0534c 100644 --- a/tests/e2e/specs/backend/cart.test.js +++ b/tests/e2e/specs/backend/cart.test.js @@ -31,21 +31,13 @@ if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 2 ) { describe( `${ block.name } Block`, () => { describe( `before compatibility notice is dismissed`, () => { beforeAll( async () => { - await page.evaluate( () => { - localStorage.setItem( - 'wc-blocks_dismissed_compatibility_notices', - '[]' - ); - } ); - await visitBlockPage( `${ block.name } Block` ); - } ); - - afterEach( async () => { + // make sure CartCheckoutCompatibilityNotice will appear await page.evaluate( () => { localStorage.removeItem( 'wc-blocks_dismissed_compatibility_notices' ); } ); + await visitBlockPage( `${ block.name } Block` ); } ); it( 'shows compatibility notice', async () => { @@ -58,11 +50,6 @@ describe( `${ block.name } Block`, () => { describe( 'after compatibility notice is dismissed', () => { beforeAll( async () => { - await page.evaluate( () => { - localStorage.removeItem( - 'wc-blocks_dismissed_compatibility_notices' - ); - } ); await page.evaluate( () => { localStorage.setItem( 'wc-blocks_dismissed_compatibility_notices', @@ -73,6 +60,14 @@ describe( `${ block.name } Block`, () => { await visitBlockPage( `${ block.name } Block` ); } ); + afterAll( async () => { + await page.evaluate( () => { + localStorage.removeItem( + 'wc-blocks_dismissed_compatibility_notices' + ); + } ); + } ); + it( 'can only be inserted once', async () => { await insertBlockDontWaitForInsertClose( block.name ); expect( await getAllBlocks() ).toHaveLength( 1 ); diff --git a/tests/e2e/specs/backend/checkout.test.js b/tests/e2e/specs/backend/checkout.test.js index 95bd2641c60..114e618aa9c 100644 --- a/tests/e2e/specs/backend/checkout.test.js +++ b/tests/e2e/specs/backend/checkout.test.js @@ -30,21 +30,13 @@ if ( process.env.WOOCOMMERCE_BLOCKS_PHASE < 2 ) { describe( `${ block.name } Block`, () => { describe( `before compatibility notice is dismissed`, () => { beforeAll( async () => { - await page.evaluate( () => { - localStorage.setItem( - 'wc-blocks_dismissed_compatibility_notices', - '[]' - ); - } ); - await visitBlockPage( `${ block.name } Block` ); - } ); - - afterEach( async () => { + // make sure CartCheckoutCompatibilityNotice will appear await page.evaluate( () => { localStorage.removeItem( 'wc-blocks_dismissed_compatibility_notices' ); } ); + await visitBlockPage( `${ block.name } Block` ); } ); it( 'shows compatibility notice', async () => { @@ -57,11 +49,6 @@ describe( `${ block.name } Block`, () => { describe( 'after compatibility notice is dismissed', () => { beforeAll( async () => { - await page.evaluate( () => { - localStorage.removeItem( - 'wc-blocks_dismissed_compatibility_notices' - ); - } ); await page.evaluate( () => { localStorage.setItem( 'wc-blocks_dismissed_compatibility_notices', @@ -71,6 +58,13 @@ describe( `${ block.name } Block`, () => { await switchUserToAdmin(); await visitBlockPage( `${ block.name } Block` ); } ); + afterAll( async () => { + await page.evaluate( () => { + localStorage.removeItem( + 'wc-blocks_dismissed_compatibility_notices' + ); + } ); + } ); it( 'can only be inserted once', async () => { await insertBlockDontWaitForInsertClose( block.name ); diff --git a/tests/e2e/specs/frontend/cart.test.js b/tests/e2e/specs/frontend/cart.test.js index 1989af21086..32c359e2c8c 100644 --- a/tests/e2e/specs/frontend/cart.test.js +++ b/tests/e2e/specs/frontend/cart.test.js @@ -51,8 +51,9 @@ describe( `${ block.name } Block (frontend)`, () => { await page.goto( productPermalink ); await shopper.addToCart(); } ); - afterAll( async () => { + // empty cart from shortcode page + await shopper.goToCart(); await shopper.removeFromCart( 'Woo Single #1' ); await page.evaluate( () => { localStorage.removeItem( @@ -133,11 +134,8 @@ describe( `${ block.name } Block (frontend)`, () => { ] ); // go to checkout page - await page.waitForSelector( 'h1' ); - let element = await page.$( 'h1' ); - let title = await page.evaluate( ( el ) => el.textContent, element ); - // shortcode checkout on CI / block on local env - expect( title ).toContain( 'Checkout' ); + // note: shortcode checkout on CI / block on local env + await page.waitForSelector( 'h1', { text: 'Checkout' } ); // navigate back to cart block page await page.goBack( { waitUntil: 'networkidle0' } ); diff --git a/tests/e2e/specs/frontend/checkout.test.js b/tests/e2e/specs/frontend/checkout.test.js index 73654e2df68..562036fbaee 100644 --- a/tests/e2e/specs/frontend/checkout.test.js +++ b/tests/e2e/specs/frontend/checkout.test.js @@ -7,6 +7,7 @@ import { setCheckbox, settingsPageSaveChanges, verifyCheckboxIsSet, + switchUserToAdmin, } from '@woocommerce/e2e-utils'; /** @@ -36,12 +37,7 @@ describe( `${ block.name } Block (frontend)`, () => { let productPermalink; beforeAll( async () => { - //prevent CartCheckoutCompatibilityNotice from appearing - await page.evaluate( () => { - localStorage.removeItem( - 'wc-blocks_dismissed_compatibility_notices' - ); - } ); + // prevent CartCheckoutCompatibilityNotice from appearing await page.evaluate( () => { localStorage.setItem( 'wc-blocks_dismissed_compatibility_notices', @@ -122,7 +118,9 @@ describe( `${ block.name } Block (frontend)`, () => { } ); afterAll( async () => { - await shopper.removeFromCart( simpleProductName ); + // empty cart from shortcode page + await shopper.goToCart(); + await shopper.removeFromCart( 'Woo Single #1' ); await page.evaluate( () => { localStorage.removeItem( 'wc-blocks_dismissed_compatibility_notices' @@ -130,7 +128,15 @@ describe( `${ block.name } Block (frontend)`, () => { } ); } ); - it( 'should display cart items in order summary', async () => { + it( 'should display an empty cart message when cart is empty', async () => { + await shopper.goToCheckoutBlock(); + const html = await page.content(); + + await page.waitForSelector( 'h1', { text: 'Checkout block' } ); + await page.waitForSelector( 'strong', { text: 'Your cart is empty!' } ); + } ); + + it( 'allows customer to choose available payment methods', async () => { await page.goto( productPermalink ); await shopper.addToCart(); await shopper.goToCheckoutBlock(); @@ -140,13 +146,9 @@ describe( `${ block.name } Block (frontend)`, () => { `1`, singleProductPrice ); - } ); - - it( 'allows customer to choose available payment methods', async () => { - await page.goto( productPermalink ); + await page.goBack( { waitUntil: 'networkidle2' } ); await shopper.addToCart(); await shopper.goToCheckoutBlock(); - await shopper.productIsInCheckoutBlock( simpleProductName, `2`, diff --git a/tests/utils/shopper.js b/tests/utils/shopper.js index 8b8f376f600..05d256fb927 100644 --- a/tests/utils/shopper.js +++ b/tests/utils/shopper.js @@ -19,24 +19,28 @@ export const shopper = { await page.goto( checkoutBlockPermalink, { waitUntil: 'networkidle0', } ); + await page.waitForSelector( 'h1', { text: 'Checkout' } ); }, productIsInCheckoutBlock: async ( productTitle, quantity, total ) => { - await expect( page ).toClick( '.wc-block-components-panel__button' ); - await expect( page ).toMatchElement( - '.wc-block-components-product-name', - { - text: productTitle, - } + // Make sure Order summary is expanded + const [ button ] = await page.$x( + `//button[contains(@aria-expanded, 'false')]//span[contains(text(), 'Order summary')]` ); - await expect( page ).toMatchElement( - '.wc-block-components-order-summary-item__quantity', + if ( button ) { + await button.click(); + } + await page.waitForSelector( 'span', { + text: productTitle, + } ); + await page.waitForSelector( + 'div.wc-block-components-order-summary-item__quantity', { text: quantity, } ); - await expect( page ).toMatchElement( - '.wc-block-components-product-price__value', + await page.waitForSelector( + 'span.wc-block-components-product-price__value', { text: total, }