-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjest.polyfills.js
More file actions
145 lines (137 loc) · 5.18 KB
/
Copy pathjest.polyfills.js
File metadata and controls
145 lines (137 loc) · 5.18 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
// Jest polyfills file - runs before any tests or modules are loaded
// This ensures timer globals are available immediately
// Force override timer globals to ensure they're available
global.setInterval = setInterval;
global.clearInterval = clearInterval;
global.setTimeout = setTimeout;
global.clearTimeout = clearTimeout;
// Also ensure they're available on globalThis for modern environments
/* global globalThis */
if (typeof globalThis !== 'undefined') {
globalThis.setInterval = setInterval;
globalThis.clearInterval = clearInterval;
globalThis.setTimeout = setTimeout;
globalThis.clearTimeout = clearTimeout;
}
// Ensure setImmediate resolves in tests even with fake timers by delegating to process.nextTick
// This avoids tests hanging on `await new Promise(r => setImmediate(r))`
try {
const impl = function (cb, ...args) {
if (typeof process !== 'undefined' && typeof process.nextTick === 'function') {
return process.nextTick(() => cb(...args));
}
return setTimeout(() => cb(...args), 0);
};
// Define only if not already defined, and keep it writable/configurable to avoid conflicts with Jest
const hasSetImmediate = typeof globalThis !== 'undefined' && typeof globalThis.setImmediate === 'function';
if (!hasSetImmediate) {
Object.defineProperty(globalThis, 'setImmediate', {
value: impl,
writable: true,
configurable: true,
enumerable: false,
});
}
} catch (_) {
// Fallback assignment if defineProperty fails
// eslint-disable-next-line no-global-assign
// Only assign if it's not already a function
if (typeof setImmediate !== 'function') {
// eslint-disable-next-line no-global-assign
setImmediate = function (cb, ...args) {
if (typeof process !== 'undefined' && typeof process.nextTick === 'function') {
return process.nextTick(() => cb(...args));
}
return setTimeout(() => cb(...args), 0);
};
}
}
// ---- DOM safety shims for jsdom tests ----
(function applyDocumentShims(root) {
if (!root) return;
const ensureDoc = (doc) => {
// Only patch existing jsdom documents; never replace or redefine
if (!doc) return doc;
try {
if (typeof doc.addEventListener !== 'function') {
// Provide a no-op to satisfy consumers that attach listeners
doc.addEventListener = function () { return undefined; };
}
if (typeof doc.removeEventListener !== 'function') {
doc.removeEventListener = function () { return undefined; };
}
if (typeof doc.createElement !== 'function') {
// Do not synthesize a full element; return minimal object
doc.createElement = function () {
return {
click: function () { return undefined; },
setAttribute: function () { return undefined; },
style: {},
};
};
}
if (!doc.body) {
// Add minimal body with required methods
doc.body = {
appendChild: function () { return undefined; },
removeChild: function () { return undefined; },
};
} else {
if (typeof doc.body.appendChild !== 'function') {
doc.body.appendChild = function () { return undefined; };
}
if (typeof doc.body.removeChild !== 'function') {
doc.body.removeChild = function () { return undefined; };
}
}
} catch (_) {
// ignore
}
return doc;
};
// Patch existing document only; do not override property descriptors
if (root.document) {
ensureDoc(root.document);
}
})(typeof globalThis !== 'undefined' ? globalThis : (typeof global !== 'undefined' ? global : undefined));
// ---- Event polyfills for Node test env ----
(function applyEventPolyfills(root) {
if (!root) return;
try {
if (typeof root.CloseEvent === 'undefined') {
class CloseEventPolyfill {
constructor(type, init = {}) {
this.type = type;
this.code = init.code ?? 1000;
this.reason = init.reason ?? '';
this.wasClean = !!init.wasClean;
}
}
Object.defineProperty(root, 'CloseEvent', { value: CloseEventPolyfill, writable: true, configurable: true });
}
if (typeof root.MessageEvent === 'undefined') {
class MessageEventPolyfill {
constructor(type, init = {}) {
this.type = type;
this.data = init.data;
this.origin = init.origin ?? '';
this.lastEventId = init.lastEventId ?? '';
this.ports = init.ports ?? [];
this.source = init.source ?? null;
}
}
Object.defineProperty(root, 'MessageEvent', { value: MessageEventPolyfill, writable: true, configurable: true });
}
if (typeof root.Event === 'undefined') {
class EventPolyfill { constructor(type) { this.type = type; } }
Object.defineProperty(root, 'Event', { value: EventPolyfill, writable: true, configurable: true });
}
} catch (_) {
// ignore
}
})(typeof globalThis !== 'undefined' ? globalThis : (typeof global !== 'undefined' ? global : undefined));
// Debug: Log that polyfills were loaded
// Commented out to reduce test output noise
// if (process.env.NODE_ENV === 'test') {
// console.log('Jest polyfills loaded: timers and DOM shims available');
// }