/
utils.ts
82 lines (67 loc) · 1.84 KB
/
utils.ts
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
import { KEYS } from './jsdom-keys'
const skipKeys = [
'window',
'self',
'top',
'parent',
]
export function getWindowKeys(global: any, win: any) {
const keys = new Set(KEYS.concat(Object.getOwnPropertyNames(win))
.filter((k) => {
if (skipKeys.includes(k))
return false
if (k in global)
return KEYS.includes(k)
return true
}))
return keys
}
function isClassLikeName(name: string) {
return name[0] === name[0].toUpperCase()
}
interface PopulateOptions {
// we bind functions such as addEventListener and others
// because they rely on `this` in happy-dom, and in jsdom it
// has a priority for getting implementation from symbols
// (global doesn't have these symbols, but window - does)
bindFunctions?: boolean
}
export function populateGlobal(global: any, win: any, options: PopulateOptions = {}) {
const { bindFunctions = false } = options
const keys = getWindowKeys(global, win)
const originals = new Map<string | symbol, any>()
const overrideObject = new Map<string | symbol, any>()
for (const key of keys) {
const boundFunction = bindFunctions
&& typeof win[key] === 'function'
&& !isClassLikeName(key)
&& win[key].bind(win)
if (KEYS.includes(key) && key in global)
originals.set(key, global[key])
Object.defineProperty(global, key, {
get() {
if (overrideObject.has(key))
return overrideObject.get(key)
if (boundFunction)
return boundFunction
return win[key]
},
set(v) {
overrideObject.set(key, v)
},
configurable: true,
})
}
global.window = global
global.self = global
global.top = global
global.parent = global
if (global.global)
global.global = global
skipKeys.forEach(k => keys.add(k))
return {
keys,
skipKeys,
originals,
}
}