924dfe5b7d
Add ResizeObserver, hasPointerCapture, and scrollIntoView polyfills to test setup for Radix UI compatibility Fix ImportSitesModal tests: use getAllByText for multiple Remove buttons Add workaround for jsdom File.text() returning empty strings in file upload tests All 139 test files now pass (1639 tests)
118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
/// <reference types="vitest/globals" />
|
|
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
/// <reference types="@testing-library/jest-dom/vitest" />
|
|
|
|
// Import jest-dom matchers at runtime to extend expect()
|
|
import '@testing-library/jest-dom/vitest'
|
|
|
|
// Ensure React's act environment flag is set for React 18+ to avoid warnings
|
|
// This must be set before importing testing utilities.
|
|
// See: https://github.com/facebook/react/issues/24560#issuecomment-1021997243
|
|
declare global { var IS_REACT_ACT_ENVIRONMENT: boolean | undefined }
|
|
globalThis.IS_REACT_ACT_ENVIRONMENT = true
|
|
|
|
import { cleanup } from '@testing-library/react'
|
|
import { afterEach, vi } from 'vitest'
|
|
|
|
// Global mock for react-i18next to return English translations in tests
|
|
// The import must be done inside the factory since vi.mock is hoisted
|
|
vi.mock('react-i18next', async () => {
|
|
// Dynamic import inside the factory ensures translations are loaded
|
|
const enTranslations = await import('../locales/en/translation.json').then(m => m.default)
|
|
|
|
// Helper to get nested translation value by dot-notation key
|
|
function getTranslation(key: string): string {
|
|
const keys = key.split('.')
|
|
let result: unknown = enTranslations
|
|
for (const k of keys) {
|
|
if (result && typeof result === 'object' && k in (result as Record<string, unknown>)) {
|
|
result = (result as Record<string, unknown>)[k]
|
|
} else {
|
|
// Key not found, return the key itself
|
|
return key
|
|
}
|
|
}
|
|
return typeof result === 'string' ? result : key
|
|
}
|
|
|
|
return {
|
|
useTranslation: () => ({
|
|
t: (key: string, options?: Record<string, unknown>) => {
|
|
let result = getTranslation(key)
|
|
// Handle interpolation: replace {{variable}} with the value from options
|
|
if (options && typeof result === 'string') {
|
|
Object.entries(options).forEach(([k, v]) => {
|
|
result = result.replace(new RegExp(`\\{\\{${k}\\}\\}`, 'g'), String(v))
|
|
})
|
|
}
|
|
return result
|
|
},
|
|
i18n: {
|
|
changeLanguage: vi.fn(),
|
|
language: 'en',
|
|
},
|
|
}),
|
|
Trans: ({ children }: { children: React.ReactNode }) => children,
|
|
initReactI18next: { type: '3rdParty', init: () => {} },
|
|
}
|
|
})
|
|
|
|
// Cleanup after each test
|
|
afterEach(() => {
|
|
cleanup()
|
|
})
|
|
|
|
// Mock window.matchMedia
|
|
Object.defineProperty(window, 'matchMedia', {
|
|
writable: true,
|
|
value: (query: string) => ({
|
|
matches: false,
|
|
media: query,
|
|
onchange: null,
|
|
addListener: () => {},
|
|
removeListener: () => {},
|
|
addEventListener: () => {},
|
|
removeEventListener: () => {},
|
|
dispatchEvent: () => {},
|
|
}),
|
|
})
|
|
|
|
// Add ResizeObserver mock (required by Radix UI)
|
|
global.ResizeObserver = class ResizeObserver {
|
|
observe() {}
|
|
unobserve() {}
|
|
disconnect() {}
|
|
}
|
|
|
|
// Add pointer capture polyfills (required by Radix UI)
|
|
if (!HTMLElement.prototype.hasPointerCapture) {
|
|
HTMLElement.prototype.hasPointerCapture = function() { return false }
|
|
HTMLElement.prototype.setPointerCapture = function() {}
|
|
HTMLElement.prototype.releasePointerCapture = function() {}
|
|
}
|
|
|
|
// Add scrollIntoView mock (required by Radix Select)
|
|
if (!Element.prototype.scrollIntoView) {
|
|
Element.prototype.scrollIntoView = function() {}
|
|
}
|
|
|
|
// Filter noisy React act environment warnings that can appear in some environments
|
|
const _origConsoleError = console.error
|
|
console.error = (...args: unknown[]) => {
|
|
try {
|
|
const msg = args[0]
|
|
if (typeof msg === 'string') {
|
|
if (
|
|
msg.includes("The current testing environment is not configured to support act(") ||
|
|
msg.includes('Test connection failed') ||
|
|
msg.includes('Connection failed')
|
|
) {
|
|
return
|
|
}
|
|
}
|
|
} catch {
|
|
// fallthrough to original
|
|
}
|
|
_origConsoleError.apply(console, args)
|
|
}
|