fix(util): detect Cloudflare Workers in shouldUseGlobalFetchAndWebSocket (#11456)

Co-authored-by: Muhammad Ali <muhammadali@cloudflare.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Muhammad Bin Ali
2026-03-26 11:46:57 -04:00
committed by GitHub
parent 9ade8dcc71
commit 22b820fbf2
2 changed files with 55 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
import { afterEach, describe, expect, test, vi } from 'vitest';
import { shouldUseGlobalFetchAndWebSocket } from '../src/index.js';
describe('shouldUseGlobalFetchAndWebSocket', () => {
afterEach(() => {
vi.unstubAllGlobals();
});
test('GIVEN browser env with fetch and WebSocket THEN returns true', () => {
vi.stubGlobal('process', undefined);
vi.stubGlobal('fetch', () => void 0);
vi.stubGlobal('WebSocket', class {});
expect(shouldUseGlobalFetchAndWebSocket()).toBe(true);
});
test('GIVEN browser env without fetch or WebSocket THEN returns false', () => {
vi.stubGlobal('process', undefined);
vi.stubGlobal('fetch', globalThis.fetch);
vi.stubGlobal('WebSocket', globalThis.WebSocket);
// @ts-expect-error Testing missing globals
delete globalThis.fetch;
// @ts-expect-error Testing missing globals
delete globalThis.WebSocket;
expect(shouldUseGlobalFetchAndWebSocket()).toBe(false);
});
test('GIVEN Cloudflare Workers with nodejs_compat THEN returns true', () => {
vi.stubGlobal('process', { versions: { node: '22.19.0' } });
vi.stubGlobal('WebSocketPair', class {});
expect(shouldUseGlobalFetchAndWebSocket()).toBe(true);
});
test('GIVEN Node.js THEN returns false', () => {
vi.stubGlobal('process', { versions: { node: '22.19.0' } });
expect(shouldUseGlobalFetchAndWebSocket()).toBe(false);
});
test('GIVEN Deno THEN returns true', () => {
vi.stubGlobal('process', { versions: { deno: '1.0.0' } });
expect(shouldUseGlobalFetchAndWebSocket()).toBe(true);
});
test('GIVEN Bun THEN returns true', () => {
vi.stubGlobal('process', { versions: { bun: '1.0.0' } });
expect(shouldUseGlobalFetchAndWebSocket()).toBe(true);
});
});

View File

@@ -6,6 +6,14 @@ export function shouldUseGlobalFetchAndWebSocket() {
return 'fetch' in globalThis && 'WebSocket' in globalThis;
}
// Cloudflare Workers with nodejs_compat polyfills process (including
// process.versions.node), but natively supports the Web WebSocket API.
// WebSocketPair is a Workers-only global; no other runtime exposes it.
// @ts-expect-error WebSocketPair is not in the globalThis type
if (typeof globalThis.WebSocketPair !== 'undefined') {
return true;
}
if ('versions' in globalThis.process) {
return 'deno' in globalThis.process.versions || 'bun' in globalThis.process.versions;
}