From 3b53e582e9879d41c34038cab01b31af32de7272 Mon Sep 17 00:00:00 2001 From: Anthony Frehner Date: Wed, 27 Jul 2022 16:49:05 -0600 Subject: [PATCH 1/2] Migrate BuyNow and CartCheckout buttons to Vitest --- .../BuyNowButton/tests/BuyNowButton.test.tsx | 173 ------------------ .../tests/BuyNowButton.vitest.tsx | 149 +++++++++++++++ .../tests/CartCheckoutButton.test.tsx | 54 ------ .../tests/CartCheckoutButton.vitest.tsx | 52 ++++++ 4 files changed, 201 insertions(+), 227 deletions(-) delete mode 100644 packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.test.tsx create mode 100644 packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx delete mode 100644 packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.test.tsx create mode 100644 packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.vitest.tsx diff --git a/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.test.tsx b/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.test.tsx deleted file mode 100644 index bb81fd1197..0000000000 --- a/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.test.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React from 'react'; - -import {mountWithProviders} from '../../../utilities/tests/shopifyMount.js'; -import {BaseButton} from '../../BaseButton/index.js'; - -const mockCreateInstantCheckout = jest.fn(); -const mockUseInstantCheckout = jest.fn(); -const mockUseCartFetch = jest.fn(); - -import {BuyNowButton} from '../BuyNowButton.client.js'; - -jest.mock('../../CartProvider', () => ({ - ...(jest.requireActual('../../CartProvider') as {}), - useInstantCheckout: mockUseInstantCheckout, - useCartFetch: mockUseCartFetch, -})); - -describe('BuyNowButton', () => { - beforeEach(() => { - mockUseInstantCheckout.mockReturnValue({ - createInstantCheckout: mockCreateInstantCheckout, - checkoutUrl: undefined, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('renders a button', () => { - const component = mountWithProviders( - Buy now - ); - expect(component).toContainReactComponent('button', { - children: 'Buy now', - }); - }); - - it('can optionally disable the button', () => { - const component = mountWithProviders( - - Buy now - - ); - - expect(component).toContainReactComponent('button', { - disabled: true, - }); - }); - - it('allows pass-through props', () => { - const component = mountWithProviders( - - Buy now - - ); - - expect(component).toContainReactComponent('button', { - className: 'fancy-button', - }); - }); - - describe('when the button is clicked', () => { - it('uses useCartCreateCallback with the correct arguments', () => { - const component = mountWithProviders( - - Buy now - - ); - - component.act(() => { - component.find('button')?.trigger('onClick'); - }); - - expect(mockCreateInstantCheckout).toHaveBeenCalledTimes(1); - expect(mockCreateInstantCheckout).toHaveBeenCalledWith({ - lines: [ - { - quantity: 4, - merchandiseId: 'SKU123', - attributes: [ - {key: 'color', value: 'blue'}, - {key: 'size', value: 'large'}, - ], - }, - ], - }); - }); - - it('disables the button', () => { - const component = mountWithProviders( - Buy now - ); - - expect(component).toContainReactComponent('button', { - disabled: false, - }); - - component.act(() => { - component.find('button')?.trigger('onClick'); - }); - - expect(component.find('button')).toHaveReactProps({disabled: true}); - }); - }); - - describe('when a checkout URL is available', () => { - const {location} = window; - const mockSetHref = jest.fn((href) => href); - - beforeEach(() => { - mockUseInstantCheckout.mockReturnValue({ - createInstantCheckout: mockCreateInstantCheckout, - checkoutUrl: '/checkout?id=123', - }); - - delete (window as Partial).location; - window.location = {...window.location}; - Object.defineProperty(window.location, 'href', { - set: mockSetHref, - }); - }); - - afterEach(() => { - window.location = location; - mockUseInstantCheckout.mockRestore(); - }); - - it('redirects to checkout', () => { - mountWithProviders(Buy now); - - expect(mockSetHref).toHaveBeenCalledTimes(1); - expect(mockSetHref).toHaveBeenCalledWith('/checkout?id=123'); - }); - }); - - describe('BaseButton', () => { - it('passes the onClick handler', () => { - const mockOnClick = jest.fn(); - - const component = mountWithProviders( - - Buy now - - ); - - expect(component).toContainReactComponent(BaseButton, { - onClick: mockOnClick, - }); - }); - - it('passes the buttonRef', () => { - const mockRef = React.createRef(); - - const component = mountWithProviders( - - Buy now - - ); - - expect(component).toContainReactComponent(BaseButton, { - buttonRef: mockRef, - }); - }); - }); -}); diff --git a/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx b/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx new file mode 100644 index 0000000000..8a2c16688e --- /dev/null +++ b/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx @@ -0,0 +1,149 @@ +import React from 'react'; +import {ShopifyTestProviders} from '../../../utilities/tests/provider-helpers.js'; +import {render, screen} from '@testing-library/react'; +import {vi} from 'vitest'; +import userEvent from '@testing-library/user-event'; + +const mockCreateInstantCheckout = vi.fn(); +const mockUseInstantCheckout = vi.fn(); +const mockUseCartFetch = vi.fn(); + +import {BuyNowButton} from '../BuyNowButton.client.js'; + +vi.mock('../../CartProvider/index.js', () => ({ + ...(vi.importActual('../../CartProvider/index.js') as {}), + useInstantCheckout: mockUseInstantCheckout, + useCartFetch: mockUseCartFetch, +})); + +describe('', () => { + beforeEach(() => { + mockUseInstantCheckout.mockReturnValue({ + createInstantCheckout: mockCreateInstantCheckout, + checkoutUrl: undefined, + }); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it('renders a button', () => { + render(Buy now, { + wrapper: ShopifyTestProviders, + }); + expect(screen.getByRole('button')).toHaveTextContent('Buy now'); + }); + + it('can optionally disable the button', () => { + render( + + Buy now + , + { + wrapper: ShopifyTestProviders, + } + ); + + expect(screen.getByRole('button')).toBeDisabled(); + }); + + it('allows pass-through props', () => { + render( + + Buy now + , + { + wrapper: ShopifyTestProviders, + } + ); + + expect(screen.getByRole('button')).toHaveClass('fancy-button'); + }); + + describe('when the button is clicked', () => { + it('uses useCartCreateCallback with the correct arguments', async () => { + const user = userEvent.setup(); + + render( + + Buy now + , + { + wrapper: ShopifyTestProviders, + } + ); + + await user.click(screen.getByRole('button')); + + expect(mockCreateInstantCheckout).toHaveBeenCalledTimes(1); + expect(mockCreateInstantCheckout).toHaveBeenCalledWith({ + lines: [ + { + quantity: 4, + merchandiseId: 'SKU123', + attributes: [ + {key: 'color', value: 'blue'}, + {key: 'size', value: 'large'}, + ], + }, + ], + }); + }); + + it('disables the button', async () => { + const user = userEvent.setup(); + + render(Buy now, { + wrapper: ShopifyTestProviders, + }); + + const button = screen.getByRole('button'); + + expect(button).not.toBeDisabled(); + + await user.click(button); + + expect(button).toBeDisabled(); + }); + }); + + describe('when a checkout URL is available', () => { + const {location} = window; + const mockSetHref = vi.fn((href) => href); + + beforeEach(() => { + mockUseInstantCheckout.mockReturnValue({ + createInstantCheckout: mockCreateInstantCheckout, + checkoutUrl: '/checkout?id=123', + }); + + delete (window as Partial).location; + window.location = {...window.location}; + Object.defineProperty(window.location, 'href', { + set: mockSetHref, + }); + }); + + afterEach(() => { + window.location = location; + mockUseInstantCheckout.mockRestore(); + }); + + it('redirects to checkout', () => { + render(Buy now, { + wrapper: ShopifyTestProviders, + }); + + expect(mockSetHref).toHaveBeenCalledTimes(1); + expect(mockSetHref).toHaveBeenCalledWith('/checkout?id=123'); + }); + }); +}); diff --git a/packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.test.tsx b/packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.test.tsx deleted file mode 100644 index c1c594c248..0000000000 --- a/packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.test.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import {CartProvider} from '../../CartProvider/index.js'; -import {CartCheckoutButton} from '../CartCheckoutButton.client.js'; -import {mountWithProviders} from '../../../utilities/tests/shopifyMount.js'; - -jest.mock('../../CartProvider', () => ({ - ...(jest.requireActual('../../CartProvider') as {}), - useCart: () => { - return { - status: 'idle', - }; - }, -})); - -describe('CartCheckoutButton', () => { - const fetch = global.fetch; - - beforeEach(() => { - // @ts-ignore - global.fetch = jest.fn(async (_url, _init) => { - return { - json: async () => - JSON.stringify({ - data: {}, - }), - }; - }); - }); - - afterEach(() => { - global.fetch = fetch; - }); - - // TODO fix this when @shopify/react-testing supports React 18 experimental - it.skip('redirects to checkout when clicked', () => { - const button = mountWithProviders( - - Checkout - - ); - - Object.defineProperty(window, 'location', { - value: { - href: '', - }, - }); - - button.act(() => { - button.find('button')!.trigger('onClick'); - }); - - expect(window.location.href).toBe('https://shopify.com/checkout'); - }); -}); diff --git a/packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.vitest.tsx b/packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.vitest.tsx new file mode 100644 index 0000000000..f9d3b7d6bc --- /dev/null +++ b/packages/hydrogen/src/components/CartCheckoutButton/tests/CartCheckoutButton.vitest.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import {CartProvider} from '../../CartProvider/index.js'; +import {CartCheckoutButton} from '../CartCheckoutButton.client.js'; +import { + ShopifyTestProviders, + CartTestProviders, +} from '../../../utilities/tests/provider-helpers.js'; +import {vi} from 'vitest'; +import {render, screen} from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +describe('', () => { + const fetch = global.fetch; + + beforeEach(() => { + // @ts-expect-error custom mock of fetch + global.fetch = vi.fn(async (_url, _init) => { + return { + json: async () => + JSON.stringify({ + data: {}, + }), + }; + }); + }); + + afterEach(() => { + global.fetch = fetch; + }); + + it('redirects to checkout when clicked', async () => { + const user = userEvent.setup(); + const checkoutUrl = 'https://shopify.com/checkout'; + + render( + + Checkout + , + {wrapper: ShopifyTestProviders} + ); + + Object.defineProperty(window, 'location', { + value: { + href: '', + }, + }); + + await user.click(screen.getByRole('button')); + + expect(window.location.href).toBe(checkoutUrl); + }); +}); From 02b61c5a238fe5c333a983eee38da0baf832001b Mon Sep 17 00:00:00 2001 From: Anthony Frehner Date: Thu, 28 Jul 2022 09:24:13 -0600 Subject: [PATCH 2/2] remove unnecessary clearmock --- .../src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx b/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx index 8a2c16688e..0f7b72f9a7 100644 --- a/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx +++ b/packages/hydrogen/src/components/BuyNowButton/tests/BuyNowButton.vitest.tsx @@ -24,10 +24,6 @@ describe('', () => { }); }); - afterEach(() => { - vi.clearAllMocks(); - }); - it('renders a button', () => { render(Buy now, { wrapper: ShopifyTestProviders,