import React from 'react' import { render, type RenderOptions, type RenderResult, } from '@testing-library/react' import {vi} from 'vitest' import {createProduct, createShop} from './mocks' import type { Product, ProductVariant, Shop, ProductImage, Money, } from '@shopify/shop-minis-platform' // Create spyable mock SDK functions const createSpyableMockSDK = () => { return { navigateToProduct: vi.fn(), navigateToShop: vi.fn(), saveProduct: vi.fn().mockResolvedValue({ok: true, data: undefined}), unsaveProduct: vi.fn().mockResolvedValue({ok: true, data: undefined}), favorite: vi.fn().mockResolvedValue({ok: true, data: undefined}), unfavorite: vi.fn().mockResolvedValue({ok: true, data: undefined}), followShop: vi.fn().mockResolvedValue({ok: true, data: true}), unfollowShop: vi.fn().mockResolvedValue({ok: true, data: false}), buyProduct: vi.fn(), buyProducts: vi.fn(), addToCart: vi.fn(), getProduct: vi.fn(), getProducts: vi.fn(), getProductSearch: vi.fn(), getRecommendedProducts: vi.fn(), getPopularProducts: vi.fn(), getSavedProducts: vi.fn(), getRecentProducts: vi.fn(), share: vi.fn(), closeMini: vi.fn(), showErrorScreen: vi.fn(), showErrorToast: vi.fn(), getAccountInformation: vi.fn(), getPersistedItem: vi.fn(), setPersistedItem: vi.fn(), removePersistedItem: vi.fn(), clearPersistedItems: vi.fn(), } as any } // Mock window.minisSDK for tests export const mockMinisSDK = createSpyableMockSDK() // Setup minisSDK mock globally if (typeof window !== 'undefined') { ;(window as any).minisSDK = mockMinisSDK } // Custom render with providers if needed export function renderWithProviders( ui: React.ReactElement, options?: Omit ): RenderResult { return render(ui, { ...options, }) } // Re-export mock factories from mocks.ts with backwards compatibility export const mockProduct = (overrides: Partial = {}): Product => { const baseProduct = createProduct( overrides.id || 'product-1', overrides.title || 'Test Product', overrides.price?.amount || '99.99', overrides.compareAtPrice?.amount ) return { ...baseProduct, ...overrides, } } export const mockShop = (overrides: Partial = {}): Shop => { const baseShop = createShop( overrides.id || 'shop-1', overrides.name || 'Test Shop' ) return { ...baseShop, ...overrides, } } // Helper to create multiple products export const mockProducts = (count = 5): Product[] => { return Array.from({length: count}, (_, i) => createProduct( `product-${i + 1}`, `Test Product ${i + 1}`, `${(i + 1) * 50}.00` ) ) } // Export commonly used mock data helpers for backwards compatibility export const mockMoney = (amount = '29.99', currencyCode = 'USD'): Money => ({ amount, currencyCode: currencyCode as any, }) export const mockProductImage = ( overrides: Partial = {} ): ProductImage => ({ url: 'https://example.com/product-image.jpg', altText: 'Product image', width: 1000, height: 1000, sensitive: false, thumbhash: 'someThumbhash', ...overrides, }) export const mockProductVariant = ( overrides: Partial = {} ): ProductVariant => ({ id: 'variant-1', title: 'Default Variant', isFavorited: false, availableForSale: true, price: mockMoney('29.99', 'USD'), compareAtPrice: mockMoney('39.99', 'USD'), image: mockProductImage(), ...overrides, }) // Helper to wait for async updates export const waitForAsync = () => new Promise(resolve => setTimeout(resolve, 0)) // Common test assertions for accessibility export const expectToBeAccessible = (element: HTMLElement) => { // Check for basic accessibility attributes const role = element.getAttribute('role') const ariaLabel = element.getAttribute('aria-label') const ariaLabelledBy = element.getAttribute('aria-labelledby') // At least one of these should be present for interactive elements if (element.tagName === 'BUTTON' || element.onclick) { const hasAccessibility = Boolean( role || ariaLabel || ariaLabelledBy || element.textContent?.trim() ) expect(hasAccessibility).toBe(true) } } // Reset all mocks export const resetAllMocks = () => { Object.values(mockMinisSDK).forEach(mock => { if (typeof mock === 'function' && 'mockReset' in mock) { ;(mock as any).mockReset() } }) } // Export everything from testing library for convenience export * from '@testing-library/react' export {default as userEvent} from '@testing-library/user-event'