import {renderHook} from '@testing-library/react' import {describe, expect, it, vi, beforeEach} from 'vitest' import {useShopIntent} from '../../internal/useShopIntent' import {useBuyNow} from './useBuyNow' vi.mock('../../internal/useShopIntent', () => ({ useShopIntent: vi.fn(), })) const mockUseShopIntent = useShopIntent as unknown as ReturnType const PRODUCT_ID = 'gid://shopify/Product/123' const VARIANT_ID = 'gid://shopify/ProductVariant/456' const VARIANT = { id: VARIANT_ID, title: 'Red / S', isFavorited: false, availableForSale: true, quantityAvailable: 5, selectedOptions: [ {name: 'Color', value: 'Red'}, {name: 'Size', value: 'S'}, ], image: {url: 'https://cdn/v.jpg'}, price: {amount: '10.00', currencyCode: 'USD'}, compareAtPrice: null, } describe('useBuyNow', () => { beforeEach(() => { vi.clearAllMocks() }) it('invokes the buy_now:shopify/ProductVariant intent with productId in data', async () => { const invokeQuery = vi.fn().mockResolvedValue({ code: 'ok', data: { outcome: 'checkout_opened', productVariantId: VARIANT_ID, variant: VARIANT, quantity: 1, source: 'auto', }, }) mockUseShopIntent.mockReturnValue({invokeQuery}) const {result} = renderHook(() => useBuyNow()) await result.current.buyNow({productId: PRODUCT_ID}) expect(invokeQuery).toHaveBeenCalledWith({ action: 'buy_now', type: 'shopify/ProductVariant', data: {productId: PRODUCT_ID}, }) }) it('passes optional params through as the intent data payload', async () => { const invokeQuery = vi.fn().mockResolvedValue({code: 'closed'}) mockUseShopIntent.mockReturnValue({invokeQuery}) const {result} = renderHook(() => useBuyNow()) await result.current.buyNow({ productId: PRODUCT_ID, productVariantId: VARIANT_ID, quantity: 2, discountCode: 'SUMMER20', includedProductVariantGIDs: [VARIANT_ID], initialVariantId: VARIANT_ID, initialQuantity: 2, maxQuantity: 10, showQuantity: false, forceShow: true, }) expect(invokeQuery).toHaveBeenCalledWith({ action: 'buy_now', type: 'shopify/ProductVariant', data: { productId: PRODUCT_ID, productVariantId: VARIANT_ID, quantity: 2, discountCode: 'SUMMER20', includedProductVariantGIDs: [VARIANT_ID], initialVariantId: VARIANT_ID, initialQuantity: 2, maxQuantity: 10, showQuantity: false, forceShow: true, }, }) }) it("returns the ok IntentResult with outcome 'checkout_opened' on direct buy now", async () => { const invokeQuery = vi.fn().mockResolvedValue({ code: 'ok', data: { outcome: 'checkout_opened', productVariantId: VARIANT_ID, variant: VARIANT, quantity: 2, source: 'auto', }, }) mockUseShopIntent.mockReturnValue({invokeQuery}) const {result} = renderHook(() => useBuyNow()) const response = await result.current.buyNow({ productId: PRODUCT_ID, productVariantId: VARIANT_ID, quantity: 2, }) expect(response).toEqual({ code: 'ok', data: { outcome: 'checkout_opened', productVariantId: VARIANT_ID, variant: VARIANT, quantity: 2, source: 'auto', }, }) }) it('returns the ok IntentResult with source user when sheet was shown', async () => { const invokeQuery = vi.fn().mockResolvedValue({ code: 'ok', data: { outcome: 'checkout_opened', productVariantId: VARIANT_ID, variant: VARIANT, quantity: 1, source: 'user', }, }) mockUseShopIntent.mockReturnValue({invokeQuery}) const {result} = renderHook(() => useBuyNow()) const response = await result.current.buyNow({productId: PRODUCT_ID}) if (response.code !== 'ok') throw new Error('expected ok') if (response.data.outcome !== 'checkout_opened') { throw new Error('expected checkout_opened outcome') } expect(response.data.source).toBe('user') }) it("returns the ok IntentResult with outcome 'navigated_to_product' for referrals", async () => { const invokeQuery = vi.fn().mockResolvedValue({ code: 'ok', data: { outcome: 'navigated_to_product', productId: PRODUCT_ID, }, }) mockUseShopIntent.mockReturnValue({invokeQuery}) const {result} = renderHook(() => useBuyNow()) const response = await result.current.buyNow({productId: PRODUCT_ID}) if (response.code !== 'ok') throw new Error('expected ok') if (response.data.outcome !== 'navigated_to_product') { throw new Error('expected navigated_to_product outcome') } expect(response.data.productId).toBe(PRODUCT_ID) }) it('returns closed when the user dismisses the sheet', async () => { const invokeQuery = vi.fn().mockResolvedValue({code: 'closed'}) mockUseShopIntent.mockReturnValue({invokeQuery}) const {result} = renderHook(() => useBuyNow()) const response = await result.current.buyNow({productId: PRODUCT_ID}) expect(response).toEqual({code: 'closed'}) }) it('returns the error IntentResult when the host fails', async () => { const invokeQuery = vi.fn().mockResolvedValue({ code: 'error', message: 'checkout failed', }) mockUseShopIntent.mockReturnValue({invokeQuery}) const {result} = renderHook(() => useBuyNow()) const response = await result.current.buyNow({ productId: PRODUCT_ID, productVariantId: VARIANT_ID, }) expect(response).toEqual({code: 'error', message: 'checkout failed'}) }) })