From d32a758d963a2a0b5acdd76e410043793f8f6628 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Fri, 20 May 2022 11:49:42 +0300 Subject: [PATCH] fix: simplify globals access, fix global != global (#1340) --- .../vitest/src/integrations/env/happy-dom.ts | 6 +- packages/vitest/src/integrations/env/jsdom.ts | 6 +- packages/vitest/src/integrations/env/utils.ts | 100 +++--------------- test/core/test/dom.test.ts | 7 ++ test/core/test/happy-dom.test.ts | 7 ++ 5 files changed, 28 insertions(+), 98 deletions(-) diff --git a/packages/vitest/src/integrations/env/happy-dom.ts b/packages/vitest/src/integrations/env/happy-dom.ts index b8232bc5c..328139fc7 100644 --- a/packages/vitest/src/integrations/env/happy-dom.ts +++ b/packages/vitest/src/integrations/env/happy-dom.ts @@ -10,11 +10,7 @@ export default ({ const { Window, GlobalWindow } = await importModule('happy-dom') as typeof import('happy-dom') const win = new (GlobalWindow || Window)() - const { keys, allowRewrite } = populateGlobal(global, win, { bindFunctions: true }) - - const originals = new Map( - allowRewrite.map(([key]) => [key, global[key]]), - ) + const { keys, originals } = populateGlobal(global, win, { bindFunctions: true }) return { teardown(global) { diff --git a/packages/vitest/src/integrations/env/jsdom.ts b/packages/vitest/src/integrations/env/jsdom.ts index 5b8324ea1..238a668db 100644 --- a/packages/vitest/src/integrations/env/jsdom.ts +++ b/packages/vitest/src/integrations/env/jsdom.ts @@ -40,11 +40,7 @@ export default ({ }, ) - const { keys, allowRewrite } = populateGlobal(global, dom.window) - - const originals = new Map( - allowRewrite.map(([key]) => [key, global[key]]), - ) + const { keys, originals } = populateGlobal(global, dom.window, { bindFunctions: true }) return { teardown(global) { diff --git a/packages/vitest/src/integrations/env/utils.ts b/packages/vitest/src/integrations/env/utils.ts index efe4b597d..7906247a4 100644 --- a/packages/vitest/src/integrations/env/utils.ts +++ b/packages/vitest/src/integrations/env/utils.ts @@ -34,15 +34,19 @@ export function populateGlobal(global: any, win: any, options: PopulateOptions = const { bindFunctions = false } = options const keys = getWindowKeys(global, win) + const originals = new Map( + allowRewrite.map(([key]) => [key, global[key]]), + ) + const overrideObject = new Map() for (const key of keys) { - const shouldBind = bindFunctions && typeof win[key] === 'function' + const bindedFunction = bindFunctions && typeof win[key] === 'function' && win[key].bind(win) Object.defineProperty(global, key, { get() { if (overrideObject.has(key)) return overrideObject.get(key) - if (shouldBind) - return win[key].bind(win) + if (bindedFunction) + return bindedFunction return win[key] }, set(v) { @@ -52,98 +56,18 @@ export function populateGlobal(global: any, win: any, options: PopulateOptions = }) } - const globalKeys = new Set(['window', 'self', 'top', 'parent']) - - // we are creating a proxy that intercepts all access to the global object, - // stores new value on `override`, and returns only these values, - // so it actually shares only values defined inside tests - const globalProxy = new Proxy(win.window, { - get(target, p, receiver) { - if (overrideObject.has(p)) - return overrideObject.get(p) - return Reflect.get(target, p, receiver) - }, - set(target, p, value, receiver) { - try { - // if property is defined with "configurable: false", - // this will throw an error, but `self.prop = value` should not throw - // this matches browser behaviour where it silently ignores the error - // and returns previously defined value, which is a hell for debugging - Object.defineProperty(global, p, { - get: () => overrideObject.get(p), - set: value => overrideObject.set(p, value), - configurable: true, - }) - overrideObject.set(p, value) - Reflect.set(target, p, value, receiver) - } - catch { - // ignore - } - return true - }, - deleteProperty(target, p) { - Reflect.deleteProperty(global, p) - overrideObject.delete(p) - return Reflect.deleteProperty(target, p) - }, - defineProperty(target, p, attributes) { - if (attributes.writable && 'value' in attributes) { - // skip - already covered by "set" - } - else if (attributes.get) { - overrideObject.delete(p) - Reflect.defineProperty(global, p, attributes) - } - return Reflect.defineProperty(target, p, attributes) - }, - }) - - globalKeys.forEach((key) => { - if (!win[key]) - return - - Object.defineProperty(global, key, { - get() { - return globalProxy - }, - configurable: true, - }) - }) - - const globalThisProxy = new Proxy(global.globalThis, { - set(target, key, value, receiver) { - overrideObject.set(key, value) - return Reflect.set(target, key, value, receiver) - }, - deleteProperty(target, key) { - overrideObject.delete(key) - return Reflect.deleteProperty(target, key) - }, - defineProperty(target, p, attributes) { - if (attributes.writable && 'value' in attributes) { - // skip - already covered by "set" - } - else if (attributes.get && !globalKeys.has(p)) { - globalKeys.forEach((key) => { - if (win[key]) - Object.defineProperty(win[key], p, attributes) - }) - } - return Reflect.defineProperty(target, p, attributes) - }, - }) - - global.globalThis = globalThisProxy + global.window = global + global.self = global + global.top = global if (global.global) - global.global = globalThisProxy + global.global = global skipKeys.forEach(k => keys.add(k)) return { keys, skipKeys, - allowRewrite, + originals, } } diff --git a/test/core/test/dom.test.ts b/test/core/test/dom.test.ts index df55887ab..ae1bd7105 100644 --- a/test/core/test/dom.test.ts +++ b/test/core/test/dom.test.ts @@ -119,3 +119,10 @@ it('can call global functions without window works as expected', async () => { expect(() => self.requestAnimationFrame(noop)).not.toThrow() expect(() => globalThis.requestAnimationFrame(noop)).not.toThrow() }) + +it('globals are the same', () => { + expect(window.globalThis).toBe(globalThis) + expect(window.Blob).toBe(globalThis.Blob) + expect(window.globalThis.Blob).toBe(globalThis.Blob) + expect(Blob).toBe(globalThis.Blob) +}) diff --git a/test/core/test/happy-dom.test.ts b/test/core/test/happy-dom.test.ts index d0cd80494..772b2d060 100644 --- a/test/core/test/happy-dom.test.ts +++ b/test/core/test/happy-dom.test.ts @@ -98,3 +98,10 @@ it('can call global functions without window works as expected', async () => { expect(() => self.requestAnimationFrame(noop)).not.toThrow() expect(() => globalThis.requestAnimationFrame(noop)).not.toThrow() }) + +it('globals are the same', () => { + expect(window.globalThis).toBe(globalThis) + expect(window.Blob).toBe(globalThis.Blob) + expect(window.globalThis.Blob).toBe(globalThis.Blob) + expect(Blob).toBe(globalThis.Blob) +}) -- 2.51.2