generated from NHSDigital/repository-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest-setup.ts
More file actions
154 lines (134 loc) · 5.63 KB
/
test-setup.ts
File metadata and controls
154 lines (134 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Provide a minimal process polyfill for browser-like test environments (e.g. Storybook + Vitest) where process may be undefined
if (typeof (globalThis as any).process === 'undefined') {
(globalThis as any).process = { env: {} } as any;
}
import { afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import '@testing-library/jest-dom/vitest';
// Accessibility matcher (jest-axe) is imported indirectly via test utils when used.
// Import React globally for JSX in tests
import React from 'react';
// Make React available globally for tests that don't import it explicitly
(globalThis as any).React = React;
// Import fonts to ensure they're available during testing
import './styles/fonts.css';
// Ensure jest-dom matchers are available
import { expect, vi } from 'vitest';
import * as matchers from '@testing-library/jest-dom/matchers';
expect.extend(matchers);
// Cleanup after each test case
afterEach(() => {
cleanup();
});
// Flag to allow hydration tests to ignore known React 19 act() environment warnings
(globalThis as any).__ALLOW_ACT_WARNING__ = true;
// Enhanced DOM environment setup for CI/CD environments
// This addresses issues where jsdom may not be fully initialized
if (typeof global !== 'undefined') {
// Ensure window and document are available
if (typeof window === 'undefined') {
// This should not happen with jsdom, but provides a fallback
console.warn('Warning: window not available in test environment');
}
if (typeof document === 'undefined') {
// This should not happen with jsdom, but provides a fallback
console.warn('Warning: document not available in test environment');
}
// Ensure document is available globally for @testing-library/react
// This fixes "document is not defined" errors in React 19 with @testing-library/react
if (typeof globalThis !== 'undefined' && typeof document !== 'undefined') {
globalThis.document = document;
globalThis.window = window;
}
}
// React 19: ensure window.event exists with minimal shape { type }
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'event', {
get() {
return { type: 'synthetic' } as any; // minimal object so code can read .type
},
configurable: true,
});
// Provide a lightweight ResizeObserver mock for components using it (e.g. GanttChart)
if (!('ResizeObserver' in window)) {
(window as any).ResizeObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}));
}
// Polyfill scrollIntoView used in tab/data grid components (noop for jsdom)
if (!HTMLElement.prototype.scrollIntoView) {
(HTMLElement.prototype as any).scrollIntoView = function() { /* noop */ } as any;
} else {
// Wrap existing to swallow unexpected calls in tests
const original = HTMLElement.prototype.scrollIntoView;
(HTMLElement.prototype as any).scrollIntoView = function(...args: any[]) {
try { return original.apply(this, args as any); } catch { /* ignore */ }
};
}
// Polyfill HTMLFormElement.requestSubmit (jsdom not implemented)
if (typeof (HTMLFormElement.prototype as any).requestSubmit !== 'function') {
(HTMLFormElement.prototype as any).requestSubmit = function(submitter?: HTMLElement) {
const evt = new Event('submit', { bubbles: true, cancelable: true });
// If submitter provided set it on form for handlers that read it
(this as any)._requestSubmitter = submitter;
this.dispatchEvent(evt);
if (!evt.defaultPrevented) {
// Basic no-op to simulate native submission path
}
};
}
}
// Provide jest global alias for tests still using jest.fn etc.
if (!(globalThis as any).jest) {
(globalThis as any).jest = {
fn: vi.fn.bind(vi),
spyOn: vi.spyOn.bind(vi),
};
}
// Mock document.fonts API for testing
if (typeof document !== 'undefined') {
Object.defineProperty(document, 'fonts', {
value: {
load: vi.fn().mockResolvedValue([]),
check: vi.fn().mockReturnValue(false), // Initially fonts are not loaded
ready: Promise.resolve(new Set()),
},
writable: true,
});
// Mock window.getComputedStyle to better handle font fallbacks in tests
const originalGetComputedStyle = window.getComputedStyle;
window.getComputedStyle = function(element: Element, pseudoElement?: string | null) {
const style = originalGetComputedStyle(element, pseudoElement);
// Create a proxy to better handle font-family fallbacks
return new Proxy(style, {
get(target: CSSStyleDeclaration, property: string | symbol) {
if (property === 'fontFamily') {
const fontFamily = target.fontFamily;
// If no inline style is set, check if Frutiger should be applied
if (!fontFamily || fontFamily === '' || fontFamily === 'Times' || fontFamily === 'serif') {
// Check if element has our font stack applied via inline styles
const htmlElement = element as HTMLElement;
if (htmlElement.style && htmlElement.style.fontFamily) {
return htmlElement.style.fontFamily;
}
// In test environment, fall back to system default
return 'arial, sans-serif';
}
return fontFamily;
}
return (target as any)[property];
}
});
};
}
// Silence AriaTabsDataGrid scroll debug logs by default in test runs unless explicitly disabled
try {
if (!(process as any).env.SILENCE_SCROLL_DEBUG) {
(process as any).env.SILENCE_SCROLL_DEBUG = 'true';
}
if (!(process as any).env.CI_SILENCE_PERF_WARN) {
(process as any).env.CI_SILENCE_PERF_WARN = 'true';
}
} catch { /* ignore if polyfill missing */ }