diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index c5d948a14f2..ccee66cc8a8 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -14,6 +14,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 * fix(sdk-logs): allow AnyValue attributes for logs and handle circular references [#6210](https://github.com/open-telemetry/opentelemetry-js/pull/6210) @david-luna * based on [#5765](https://github.com/open-telemetry/opentelemetry-js/pull/5765) from @alec2435 +* fix(browser-detector): use window feature detection to avoid false positives in Node.js 21+ and Bun [#6271](https://github.com/open-telemetry/opentelemetry-js/pull/6271) @fiyinfoluwa001 @overbalance ### :books: Documentation diff --git a/experimental/packages/opentelemetry-browser-detector/src/BrowserDetector.ts b/experimental/packages/opentelemetry-browser-detector/src/BrowserDetector.ts index 3cfc05ca80d..2c482901a80 100644 --- a/experimental/packages/opentelemetry-browser-detector/src/BrowserDetector.ts +++ b/experimental/packages/opentelemetry-browser-detector/src/BrowserDetector.ts @@ -28,7 +28,9 @@ import { BROWSER_ATTRIBUTES, UserAgentData } from './types'; */ class BrowserDetector implements ResourceDetector { detect(config?: ResourceDetectionConfig): DetectedResource { - const isBrowser = typeof navigator !== 'undefined'; + const isBrowser = + typeof window !== 'undefined' && typeof document !== 'undefined'; + if (!isBrowser) { return emptyResource(); } diff --git a/experimental/packages/opentelemetry-browser-detector/test/BrowserDetector.test.ts b/experimental/packages/opentelemetry-browser-detector/test/BrowserDetector.test.ts index 758ca395819..73e1b4ba4f1 100644 --- a/experimental/packages/opentelemetry-browser-detector/test/BrowserDetector.test.ts +++ b/experimental/packages/opentelemetry-browser-detector/test/BrowserDetector.test.ts @@ -15,7 +15,12 @@ */ import * as sinon from 'sinon'; import { browserDetector } from '../src/BrowserDetector'; -import { assertEmptyResource, assertResource, describeBrowser } from './util'; +import { + assertEmptyResource, + assertResource, + describeBrowser, + describeNode, +} from './util'; describeBrowser('browserDetector()', () => { afterEach(() => { @@ -69,7 +74,7 @@ describeBrowser('browserDetector()', () => { }); }); - it('should return empty resources if user agent is missing', async () => { + it('should return empty resource if userAgent is missing', async () => { sinon.stub(globalThis, 'navigator').value({ userAgent: '', }); @@ -77,3 +82,20 @@ describeBrowser('browserDetector()', () => { assertEmptyResource(resource); }); }); + +describeNode('browserDetector()', () => { + it('should return empty resource even if navigator is present', () => { + // Cannot use sinon.stub for non-existent properties (Node.js <=20) + Object.defineProperty(globalThis, 'navigator', { + value: { + userAgent: 'dddd', + language: 'en-US', + userAgentData: undefined, + }, + configurable: true, + }); + + const resource = browserDetector.detect(); + assertEmptyResource(resource); + }); +}); diff --git a/experimental/packages/opentelemetry-browser-detector/test/util.ts b/experimental/packages/opentelemetry-browser-detector/test/util.ts index c51862adc1c..f5ffdb0ff49 100644 --- a/experimental/packages/opentelemetry-browser-detector/test/util.ts +++ b/experimental/packages/opentelemetry-browser-detector/test/util.ts @@ -18,9 +18,20 @@ import * as assert from 'assert'; import { BROWSER_ATTRIBUTES } from '../src/types'; import { DetectedResource } from '@opentelemetry/resources'; +const isBrowser = + typeof window !== 'undefined' && typeof document !== 'undefined'; + export function describeBrowser(title: string, fn: (this: Suite) => void) { title = `Browser: ${title}`; - if (typeof process === 'object' && process.release?.name === 'node') { + if (isBrowser) { + return describe(title, fn); + } + return describe.skip(title, fn); +} + +export function describeNode(title: string, fn: (this: Suite) => void) { + title = `Node.js: ${title}`; + if (isBrowser) { return describe.skip(title, fn); } return describe(title, fn);