From 7ce4389323f50688bd815e3952636aacc0a6023c Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Fri, 21 Jan 2022 11:28:29 +0800
Subject: [PATCH 01/14] feat(opentelemetry-resources): add runtime version
 information

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../src/platform/node/detectors/ProcessDetector.ts            | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
index 1df2d9b65fa..779bfc65146 100644
--- a/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
@@ -31,6 +31,7 @@ class ProcessDetector implements Detector {
       [SemanticResourceAttributes.PROCESS_COMMAND]: process.argv[1] || '',
       [SemanticResourceAttributes.PROCESS_COMMAND_LINE]:
         process.argv.join(' ') || '',
+      [SemanticResourceAttributes.PROCESS_RUNTIME_VERSION]: process.versions.node,
     };
     return this._getResourceAttributes(processResource, config);
   }
@@ -51,7 +52,8 @@ class ProcessDetector implements Detector {
       processResource[SemanticResourceAttributes.PROCESS_EXECUTABLE_PATH] ===
         '' ||
       processResource[SemanticResourceAttributes.PROCESS_COMMAND] === '' ||
-      processResource[SemanticResourceAttributes.PROCESS_COMMAND_LINE] === ''
+      processResource[SemanticResourceAttributes.PROCESS_COMMAND_LINE] === '' ||
+      processResource[SemanticResourceAttributes.PROCESS_RUNTIME_VERSION] === ''
     ) {
       diag.debug(
         'ProcessDetector failed: Unable to find required process resources. '

From 7bd392f1c7e86e085fb9ca8dfb92623bff8cd284 Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Fri, 21 Jan 2022 11:46:36 +0800
Subject: [PATCH 02/14] test(opentelemetry-resources): update unit test

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../test/detectors/ProcessDetector.test.ts                 | 4 ++++
 .../test/util/resource-assertions.ts                       | 7 +++++++
 2 files changed, 11 insertions(+)

diff --git a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
index ff4d3fa7a7a..9ca1a7b6209 100644
--- a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
@@ -31,6 +31,9 @@ describe('processDetector()', () => {
     sinon
       .stub(process, 'argv')
       .value(['/tmp/node', '/home/ot/test.js', 'arg1', 'arg2']);
+    sinon
+      .stub(process, 'versions')
+      .value({'node': '1.4.1'});
 
     const resource: Resource = await processDetector.detect();
     assertProcessResource(resource, {
@@ -38,6 +41,7 @@ describe('processDetector()', () => {
       name: 'otProcess',
       command: '/home/ot/test.js',
       commandLine: '/tmp/node /home/ot/test.js arg1 arg2',
+      version: '1.4.1',
     });
   });
   it('should return empty resources if title, command and commondLine is missing', async () => {
diff --git a/packages/opentelemetry-resources/test/util/resource-assertions.ts b/packages/opentelemetry-resources/test/util/resource-assertions.ts
index 9177aea703f..497324ecf64 100644
--- a/packages/opentelemetry-resources/test/util/resource-assertions.ts
+++ b/packages/opentelemetry-resources/test/util/resource-assertions.ts
@@ -270,6 +270,7 @@ export const assertProcessResource = (
     name?: string;
     command?: string;
     commandLine?: string;
+    version?: string;
   }
 ) => {
   assert.strictEqual(
@@ -294,6 +295,12 @@ export const assertProcessResource = (
       validations.commandLine
     );
   }
+  if (validations.version) {
+    assert.strictEqual(
+      resource.attributes[SemanticResourceAttributes.PROCESS_RUNTIME_VERSION],
+      validations.version
+    );
+  }
 };
 
 /**

From 8607046cd4bb3136f66a671a4783e5d0a117c06b Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Mon, 24 Jan 2022 10:35:01 +0800
Subject: [PATCH 03/14] feat(opentelemetry-resources): hardcode the runtime
 name and description

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../src/platform/node/detectors/ProcessDetector.ts |  2 ++
 .../test/detectors/ProcessDetector.test.ts         |  2 ++
 .../test/util/resource-assertions.ts               | 14 ++++++++++++++
 3 files changed, 18 insertions(+)

diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
index 779bfc65146..2424524f988 100644
--- a/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
@@ -32,6 +32,8 @@ class ProcessDetector implements Detector {
       [SemanticResourceAttributes.PROCESS_COMMAND_LINE]:
         process.argv.join(' ') || '',
       [SemanticResourceAttributes.PROCESS_RUNTIME_VERSION]: process.versions.node,
+      [SemanticResourceAttributes.PROCESS_RUNTIME_NAME]: 'nodejs',
+      [SemanticResourceAttributes.PROCESS_RUNTIME_DESCRIPTION]: 'NodeJS',
     };
     return this._getResourceAttributes(processResource, config);
   }
diff --git a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
index 9ca1a7b6209..d0ab1328842 100644
--- a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
@@ -42,6 +42,8 @@ describe('processDetector()', () => {
       command: '/home/ot/test.js',
       commandLine: '/tmp/node /home/ot/test.js arg1 arg2',
       version: '1.4.1',
+      runtimeDescription: 'NodeJS',
+      runtimeName: 'nodejs',
     });
   });
   it('should return empty resources if title, command and commondLine is missing', async () => {
diff --git a/packages/opentelemetry-resources/test/util/resource-assertions.ts b/packages/opentelemetry-resources/test/util/resource-assertions.ts
index 497324ecf64..0b4936349f9 100644
--- a/packages/opentelemetry-resources/test/util/resource-assertions.ts
+++ b/packages/opentelemetry-resources/test/util/resource-assertions.ts
@@ -271,6 +271,8 @@ export const assertProcessResource = (
     command?: string;
     commandLine?: string;
     version?: string;
+    runtimeName?: string;
+    runtimeDescription?: string;
   }
 ) => {
   assert.strictEqual(
@@ -301,6 +303,18 @@ export const assertProcessResource = (
       validations.version
     );
   }
+  if (validations.runtimeName) {
+    assert.strictEqual(
+      resource.attributes[SemanticResourceAttributes.PROCESS_RUNTIME_NAME],
+      validations.runtimeName
+    );
+  }
+  if (validations.runtimeDescription) {
+    assert.strictEqual(
+      resource.attributes[SemanticResourceAttributes.PROCESS_RUNTIME_DESCRIPTION],
+      validations.runtimeDescription
+    );
+  }
 };
 
 /**

From 1827b95d37166890181cf71eeee69c93b7de449e Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Mon, 24 Jan 2022 21:22:28 +0800
Subject: [PATCH 04/14] feat(opentelemetry-resources): add browser detector

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../src/platform/browser/detect-resources.ts  |  7 +-
 .../browser/detectors/BrowserDetector.ts      | 61 ++++++++++++++++
 .../src/platform/browser/detectors/index.ts   | 17 +++++
 .../src/platform/node/detect-resources.ts     | 52 +------------
 .../src/platform/utils.ts                     | 73 +++++++++++++++++++
 .../test/detectors/BrowserDetector.test.ts    | 55 ++++++++++++++
 .../test/detectors/ProcessDetector.test.ts    |  4 +-
 .../test/util/resource-assertions.ts          |  4 +-
 8 files changed, 214 insertions(+), 59 deletions(-)
 create mode 100644 packages/opentelemetry-resources/src/platform/browser/detectors/BrowserDetector.ts
 create mode 100644 packages/opentelemetry-resources/src/platform/browser/detectors/index.ts
 create mode 100644 packages/opentelemetry-resources/src/platform/utils.ts
 create mode 100644 packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts

diff --git a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
index 3a815e8825b..7ca5856a557 100644
--- a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
@@ -13,14 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-import { Resource } from '../../Resource';
+import { detectResources as detect } from '../utils';
 
 /**
  * Detects resources for the browser platform, which is currently only the
  * telemetry SDK resource. More could be added in the future. This method
  * is async to match the signature of corresponding method for node.
  */
-export const detectResources = async (): Promise<Resource> => {
-  return Resource.empty();
-};
+export const detectResources = detect;
diff --git a/packages/opentelemetry-resources/src/platform/browser/detectors/BrowserDetector.ts b/packages/opentelemetry-resources/src/platform/browser/detectors/BrowserDetector.ts
new file mode 100644
index 00000000000..60a11bee2fe
--- /dev/null
+++ b/packages/opentelemetry-resources/src/platform/browser/detectors/BrowserDetector.ts
@@ -0,0 +1,61 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { diag } from '@opentelemetry/api';
+import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
+import { Detector, Resource, ResourceDetectionConfig } from '../../..';
+import { ResourceAttributes } from '../../../types';
+
+/**
+ * BrowserDetector will be used to detect the resources related to browser.
+ */
+class BrowserDetector implements Detector {
+  async detect(config?: ResourceDetectionConfig): Promise<Resource> {
+    const browserResource: ResourceAttributes = {
+      [SemanticResourceAttributes.PROCESS_RUNTIME_NAME]: 'browser',
+      [SemanticResourceAttributes.PROCESS_RUNTIME_DESCRIPTION]: 'Web Browser',
+      [SemanticResourceAttributes.PROCESS_RUNTIME_VERSION]: window.navigator.userAgent
+    };
+    return this._getResourceAttributes(browserResource, config);
+  }
+  /**
+   * Validates process resource attribute map from process variables
+   *
+   * @param browserResource The un-sanitized resource attributes from process as key/value pairs.
+   * @param config: Config
+   * @returns The sanitized resource attributes.
+   */
+  private _getResourceAttributes(
+    browserResource: ResourceAttributes,
+    _config?: ResourceDetectionConfig
+  ) {
+    if (
+      browserResource[SemanticResourceAttributes.PROCESS_RUNTIME_VERSION] === ''
+    ) {
+      diag.debug(
+        'BrowserDetector failed: Unable to find required browser resources. '
+      );
+      return Resource.empty();
+    } else {
+      return new Resource({
+        ...browserResource,
+      });
+    }
+  }
+}
+
+
+export const browserDetector = new BrowserDetector();
diff --git a/packages/opentelemetry-resources/src/platform/browser/detectors/index.ts b/packages/opentelemetry-resources/src/platform/browser/detectors/index.ts
new file mode 100644
index 00000000000..7209990763e
--- /dev/null
+++ b/packages/opentelemetry-resources/src/platform/browser/detectors/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './BrowserDetector';
diff --git a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
index 74a4d337b2e..9e328115f87 100644
--- a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
@@ -14,10 +14,7 @@
  * limitations under the License.
  */
 
-import { Resource } from '../../Resource';
-import { ResourceDetectionConfig } from '../../config';
-import { diag } from '@opentelemetry/api';
-import * as util from 'util';
+import { detectResources as detect } from '../utils';
 
 /**
  * Runs all resource detectors and returns the results merged into a single
@@ -25,49 +22,4 @@ import * as util from 'util';
  *
  * @param config Configuration for resource detection
  */
-export const detectResources = async (
-  config: ResourceDetectionConfig = {}
-): Promise<Resource> => {
-  const internalConfig: ResourceDetectionConfig = Object.assign(config);
-
-  const resources: Array<Resource> = await Promise.all(
-    (internalConfig.detectors || []).map(async d => {
-      try {
-        const resource = await d.detect(internalConfig);
-        diag.debug(`${d.constructor.name} found resource.`, resource);
-        return resource;
-      } catch (e) {
-        diag.debug(`${d.constructor.name} failed: ${e.message}`);
-        return Resource.empty();
-      }
-    })
-  );
-
-  // Future check if verbose logging is enabled issue #1903
-  logResources(resources);
-
-  return resources.reduce(
-    (acc, resource) => acc.merge(resource),
-    Resource.empty()
-  );
-};
-
-/**
- * Writes debug information about the detected resources to the logger defined in the resource detection config, if one is provided.
- *
- * @param resources The array of {@link Resource} that should be logged. Empty entried will be ignored.
- */
-const logResources = (resources: Array<Resource>) => {
-  resources.forEach(resource => {
-    // Print only populated resources
-    if (Object.keys(resource.attributes).length > 0) {
-      const resourceDebugString = util.inspect(resource.attributes, {
-        depth: 2,
-        breakLength: Infinity,
-        sorted: true,
-        compact: false,
-      });
-      diag.verbose(resourceDebugString);
-    }
-  });
-};
+export const detectResources = detect;
diff --git a/packages/opentelemetry-resources/src/platform/utils.ts b/packages/opentelemetry-resources/src/platform/utils.ts
new file mode 100644
index 00000000000..4e368c12ddd
--- /dev/null
+++ b/packages/opentelemetry-resources/src/platform/utils.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Resource } from '../Resource';
+import { ResourceDetectionConfig } from '../config';
+import { diag } from '@opentelemetry/api';
+import * as util from 'util';
+
+/**
+ * Runs all resource detectors and returns the results merged into a single
+ * Resource.
+ *
+ * @param config Configuration for resource detection
+ */
+export const detectResources = async (
+  config: ResourceDetectionConfig = {}
+): Promise<Resource> => {
+  const internalConfig: ResourceDetectionConfig = Object.assign(config);
+
+  const resources: Array<Resource> = await Promise.all(
+    (internalConfig.detectors || []).map(async d => {
+      try {
+        const resource = await d.detect(internalConfig);
+        diag.debug(`${d.constructor.name} found resource.`, resource);
+        return resource;
+      } catch (e) {
+        diag.debug(`${d.constructor.name} failed: ${e.message}`);
+        return Resource.empty();
+      }
+    })
+  );
+
+  // Future check if verbose logging is enabled issue #1903
+  logResources(resources);
+
+  return resources.reduce(
+    (acc, resource) => acc.merge(resource),
+    Resource.empty()
+  );
+};
+
+/**
+ * Writes debug information about the detected resources to the logger defined in the resource detection config, if one is provided.
+ *
+ * @param resources The array of {@link Resource} that should be logged. Empty entries will be ignored.
+ */
+const logResources = (resources: Array<Resource>) => {
+  resources.forEach(resource => {
+    // Print only populated resources
+    if (Object.keys(resource.attributes).length > 0) {
+      const resourceDebugString = util.inspect(resource.attributes, {
+        depth: 2,
+        breakLength: Infinity,
+        sorted: true,
+        compact: false,
+      });
+      diag.verbose(resourceDebugString);
+    }
+  });
+};
diff --git a/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts b/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
new file mode 100644
index 00000000000..e9b79f7fe75
--- /dev/null
+++ b/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
@@ -0,0 +1,55 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import * as sinon from 'sinon';
+import { Resource } from '../../src';
+import { browserDetector } from '../../src/platform/browser/detectors';
+import {
+  assertResource,
+  assertEmptyResource,
+} from '../util/resource-assertions';
+
+
+describe('browserDetector()', () => {
+  beforeEach(() => {
+    global.window = {
+      navigator: {
+        userAgent: '',
+      }
+    };
+  });
+
+  afterEach(() => {
+    sinon.restore();
+  });
+
+  it('should return browser information', async () => {
+    sinon.stub(window, 'navigator').value({
+      userAgent: 'dddd',
+    });
+
+    const resource: Resource = await browserDetector.detect();
+    assertResource(resource, {
+      version: 'dddd',
+      runtimeDescription: 'Web Browser',
+      runtimeName: 'browser',
+    });
+  });
+  it('should return empty resources if version is missing', async () => {
+    const resource: Resource = await browserDetector.detect();
+    assertEmptyResource(resource);
+  });
+});
+
diff --git a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
index d0ab1328842..30147823bff 100644
--- a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
@@ -16,7 +16,7 @@
 import * as sinon from 'sinon';
 import { processDetector, Resource } from '../../src';
 import {
-  assertProcessResource,
+  assertResource,
   assertEmptyResource,
 } from '../util/resource-assertions';
 
@@ -36,7 +36,7 @@ describe('processDetector()', () => {
       .value({'node': '1.4.1'});
 
     const resource: Resource = await processDetector.detect();
-    assertProcessResource(resource, {
+    assertResource(resource, {
       pid: 1234,
       name: 'otProcess',
       command: '/home/ot/test.js',
diff --git a/packages/opentelemetry-resources/test/util/resource-assertions.ts b/packages/opentelemetry-resources/test/util/resource-assertions.ts
index 0b4936349f9..7c8334b0766 100644
--- a/packages/opentelemetry-resources/test/util/resource-assertions.ts
+++ b/packages/opentelemetry-resources/test/util/resource-assertions.ts
@@ -258,12 +258,12 @@ export const assertServiceResource = (
 };
 
 /**
- * Test utility method to validate a process resources
+ * Test utility method to validate a process / browser resources
  *
  * @param resource the Resource to validate
  * @param validations validations for the resource attributes
  */
-export const assertProcessResource = (
+export const assertResource = (
   resource: Resource,
   validations: {
     pid?: number;

From 304edad3a89dd2d3e8a51f7a5eff930ea01619df Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Tue, 25 Jan 2022 22:24:59 +0800
Subject: [PATCH 05/14] fix: strange import and export

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../src/platform/browser/detect-resources.ts                 | 5 +++--
 .../src/platform/node/detect-resources.ts                    | 4 +---
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
index 7ca5856a557..a4bd0b38093 100644
--- a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
@@ -13,11 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { detectResources as detect } from '../utils';
 
 /**
  * Detects resources for the browser platform, which is currently only the
  * telemetry SDK resource. More could be added in the future. This method
  * is async to match the signature of corresponding method for node.
+ *
+ * @param config Configuration for resource detection
  */
-export const detectResources = detect;
+export { detectResources } from '../utils';
diff --git a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
index 9e328115f87..1b2497297e5 100644
--- a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
@@ -14,12 +14,10 @@
  * limitations under the License.
  */
 
-import { detectResources as detect } from '../utils';
-
 /**
  * Runs all resource detectors and returns the results merged into a single
  * Resource.
  *
  * @param config Configuration for resource detection
  */
-export const detectResources = detect;
+ export { detectResources } from '../utils';

From abcf4a0d4c9c430f3de2cb818bbb45041fc427bb Mon Sep 17 00:00:00 2001
From: Will Li <cuichen.li94@gmail.com>
Date: Tue, 25 Jan 2022 22:26:49 +0800
Subject: [PATCH 06/14] fix: improve type

Signed-off-by: Cuichen Li <cuichli@cisco.com>

Co-authored-by: legendecas <legendecas@gmail.com>
---
 packages/opentelemetry-resources/src/platform/utils.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/opentelemetry-resources/src/platform/utils.ts b/packages/opentelemetry-resources/src/platform/utils.ts
index 4e368c12ddd..802bdfdfa3f 100644
--- a/packages/opentelemetry-resources/src/platform/utils.ts
+++ b/packages/opentelemetry-resources/src/platform/utils.ts
@@ -30,7 +30,7 @@ export const detectResources = async (
 ): Promise<Resource> => {
   const internalConfig: ResourceDetectionConfig = Object.assign(config);
 
-  const resources: Array<Resource> = await Promise.all(
+  const resources: Resource[] = await Promise.all(
     (internalConfig.detectors || []).map(async d => {
       try {
         const resource = await d.detect(internalConfig);

From ee76a6cc107c67d88f48bd7111993ee66fa8bf8a Mon Sep 17 00:00:00 2001
From: Will Li <cuichen.li94@gmail.com>
Date: Tue, 25 Jan 2022 22:27:24 +0800
Subject: [PATCH 07/14] fix: improve runtime description

Signed-off-by: Cuichen Li <cuichli@cisco.com>

Co-authored-by: legendecas <legendecas@gmail.com>
---
 .../src/platform/node/detectors/ProcessDetector.ts              | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
index 2424524f988..bf2a2c8bc0e 100644
--- a/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detectors/ProcessDetector.ts
@@ -33,7 +33,7 @@ class ProcessDetector implements Detector {
         process.argv.join(' ') || '',
       [SemanticResourceAttributes.PROCESS_RUNTIME_VERSION]: process.versions.node,
       [SemanticResourceAttributes.PROCESS_RUNTIME_NAME]: 'nodejs',
-      [SemanticResourceAttributes.PROCESS_RUNTIME_DESCRIPTION]: 'NodeJS',
+      [SemanticResourceAttributes.PROCESS_RUNTIME_DESCRIPTION]: 'Node.js',
     };
     return this._getResourceAttributes(processResource, config);
   }

From d25b453deb91999c1a817b5c7c369cdc3d01b186 Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Wed, 26 Jan 2022 10:06:58 +0800
Subject: [PATCH 08/14] test: fix unit test

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../test/detectors/ProcessDetector.test.ts                      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
index 30147823bff..731343cd428 100644
--- a/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/ProcessDetector.test.ts
@@ -42,7 +42,7 @@ describe('processDetector()', () => {
       command: '/home/ot/test.js',
       commandLine: '/tmp/node /home/ot/test.js arg1 arg2',
       version: '1.4.1',
-      runtimeDescription: 'NodeJS',
+      runtimeDescription: 'Node.js',
       runtimeName: 'nodejs',
     });
   });

From 3d36a7ccee19e413e32c51abd99335f179ac3067 Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Wed, 26 Jan 2022 10:24:19 +0800
Subject: [PATCH 09/14] test: improve stub

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../test/detectors/BrowserDetector.test.ts            | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts b/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
index e9b79f7fe75..b31b200c16f 100644
--- a/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
@@ -24,11 +24,12 @@ import {
 
 describe('browserDetector()', () => {
   beforeEach(() => {
-    global.window = {
+    globalThis.window = {};
+    sinon.stub(globalThis, 'window').value({
       navigator: {
         userAgent: '',
       }
-    };
+    });
   });
 
   afterEach(() => {
@@ -36,8 +37,10 @@ describe('browserDetector()', () => {
   });
 
   it('should return browser information', async () => {
-    sinon.stub(window, 'navigator').value({
-      userAgent: 'dddd',
+    sinon.stub(globalThis, 'window').value({
+      navigator: {
+        userAgent: 'dddd',
+      }
     });
 
     const resource: Resource = await browserDetector.detect();

From caea93004c26ea97b1cbeeff1ed8daa00dcffd5a Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Wed, 26 Jan 2022 10:25:24 +0800
Subject: [PATCH 10/14] docs: remove unnecessary inline docs

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../src/platform/browser/detect-resources.ts               | 7 -------
 .../src/platform/node/detect-resources.ts                  | 6 ------
 2 files changed, 13 deletions(-)

diff --git a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
index a4bd0b38093..91f3b97f5ef 100644
--- a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
@@ -14,11 +14,4 @@
  * limitations under the License.
  */
 
-/**
- * Detects resources for the browser platform, which is currently only the
- * telemetry SDK resource. More could be added in the future. This method
- * is async to match the signature of corresponding method for node.
- *
- * @param config Configuration for resource detection
- */
 export { detectResources } from '../utils';
diff --git a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
index 1b2497297e5..6abeb515a52 100644
--- a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
@@ -14,10 +14,4 @@
  * limitations under the License.
  */
 
-/**
- * Runs all resource detectors and returns the results merged into a single
- * Resource.
- *
- * @param config Configuration for resource detection
- */
  export { detectResources } from '../utils';

From b8e73c65d6491de7bf7527fd171835c557d1de46 Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Wed, 26 Jan 2022 21:34:04 +0800
Subject: [PATCH 11/14] fix: hack the type error

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../test/detectors/BrowserDetector.test.ts                      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts b/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
index b31b200c16f..16fa299dfd6 100644
--- a/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
@@ -24,7 +24,7 @@ import {
 
 describe('browserDetector()', () => {
   beforeEach(() => {
-    globalThis.window = {};
+    (globalThis.window as {}) = {};
     sinon.stub(globalThis, 'window').value({
       navigator: {
         userAgent: '',

From 1f1ca09914f537d54506333bb74d829d03a25f93 Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Thu, 3 Mar 2022 11:42:33 +0800
Subject: [PATCH 12/14] chore: move BrowserDetector to detectors directory

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../browser => }/detectors/BrowserDetector.ts |  8 +++-
 .../src/detectors/index.ts                    |  1 +
 .../src/platform/browser/detectors/index.ts   | 17 --------
 .../{ => browser}/BrowserDetector.test.ts     | 10 +++--
 .../detectors/node/BrowserDetector.test.ts    | 43 +++++++++++++++++++
 5 files changed, 56 insertions(+), 23 deletions(-)
 rename packages/opentelemetry-resources/src/{platform/browser => }/detectors/BrowserDetector.ts (88%)
 delete mode 100644 packages/opentelemetry-resources/src/platform/browser/detectors/index.ts
 rename packages/opentelemetry-resources/test/detectors/{ => browser}/BrowserDetector.test.ts (87%)
 create mode 100644 packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts

diff --git a/packages/opentelemetry-resources/src/platform/browser/detectors/BrowserDetector.ts b/packages/opentelemetry-resources/src/detectors/BrowserDetector.ts
similarity index 88%
rename from packages/opentelemetry-resources/src/platform/browser/detectors/BrowserDetector.ts
rename to packages/opentelemetry-resources/src/detectors/BrowserDetector.ts
index 60a11bee2fe..a3568c29584 100644
--- a/packages/opentelemetry-resources/src/platform/browser/detectors/BrowserDetector.ts
+++ b/packages/opentelemetry-resources/src/detectors/BrowserDetector.ts
@@ -16,14 +16,18 @@
 
 import { diag } from '@opentelemetry/api';
 import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
-import { Detector, Resource, ResourceDetectionConfig } from '../../..';
-import { ResourceAttributes } from '../../../types';
+import { Detector, Resource, ResourceDetectionConfig } from '..';
+import { ResourceAttributes } from '../types';
 
 /**
  * BrowserDetector will be used to detect the resources related to browser.
  */
 class BrowserDetector implements Detector {
   async detect(config?: ResourceDetectionConfig): Promise<Resource> {
+    const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
+    if (!isBrowser) {
+      return Resource.empty();
+    }
     const browserResource: ResourceAttributes = {
       [SemanticResourceAttributes.PROCESS_RUNTIME_NAME]: 'browser',
       [SemanticResourceAttributes.PROCESS_RUNTIME_DESCRIPTION]: 'Web Browser',
diff --git a/packages/opentelemetry-resources/src/detectors/index.ts b/packages/opentelemetry-resources/src/detectors/index.ts
index d88f7412d3c..3a69a099bcd 100644
--- a/packages/opentelemetry-resources/src/detectors/index.ts
+++ b/packages/opentelemetry-resources/src/detectors/index.ts
@@ -16,3 +16,4 @@
 
 export * from './EnvDetector';
 export * from './ProcessDetector';
+export * from './BrowserDetector';
diff --git a/packages/opentelemetry-resources/src/platform/browser/detectors/index.ts b/packages/opentelemetry-resources/src/platform/browser/detectors/index.ts
deleted file mode 100644
index 7209990763e..00000000000
--- a/packages/opentelemetry-resources/src/platform/browser/detectors/index.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-export * from './BrowserDetector';
diff --git a/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts b/packages/opentelemetry-resources/test/detectors/browser/BrowserDetector.test.ts
similarity index 87%
rename from packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
rename to packages/opentelemetry-resources/test/detectors/browser/BrowserDetector.test.ts
index 16fa299dfd6..614905cd4b3 100644
--- a/packages/opentelemetry-resources/test/detectors/BrowserDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/browser/BrowserDetector.test.ts
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 import * as sinon from 'sinon';
-import { Resource } from '../../src';
-import { browserDetector } from '../../src/platform/browser/detectors';
+import { Resource } from '../../../src';
+import { browserDetector } from '../../../src/detectors/BrowserDetector';
 import {
   assertResource,
   assertEmptyResource,
-} from '../util/resource-assertions';
+} from '../../util/resource-assertions';
 
 
 describe('browserDetector()', () => {
   beforeEach(() => {
     (globalThis.window as {}) = {};
     sinon.stub(globalThis, 'window').value({
+      document: 'document',
       navigator: {
         userAgent: '',
       }
@@ -40,7 +41,8 @@ describe('browserDetector()', () => {
     sinon.stub(globalThis, 'window').value({
       navigator: {
         userAgent: 'dddd',
-      }
+      },
+      document: 'document'
     });
 
     const resource: Resource = await browserDetector.detect();
diff --git a/packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts b/packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts
new file mode 100644
index 00000000000..d5b51e44359
--- /dev/null
+++ b/packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import * as sinon from 'sinon';
+import { Resource } from '../../../src';
+import { browserDetector } from '../../../src/detectors/BrowserDetector';
+import {
+  assertEmptyResource,
+} from '../../util/resource-assertions';
+
+
+describe('browserDetector()', () => {
+  beforeEach(() => {
+    (globalThis.window as {}) = {};
+    sinon.stub(globalThis, 'window').value({
+      navigator: {
+        userAgent: '',
+      }
+    });
+  });
+
+  afterEach(() => {
+    sinon.restore();
+  });
+
+  it('should return empty resources if window.document is missing', async () => {
+    const resource: Resource = await browserDetector.detect();
+    assertEmptyResource(resource);
+  });
+});
+

From c74961409e2ebe5f3b971098a3d9eb4a7a9145d1 Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Thu, 3 Mar 2022 11:47:21 +0800
Subject: [PATCH 13/14] chore: move detectResources back to different platform

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../src/platform/browser/detect-resources.ts  | 34 ++++++++-
 .../src/platform/node/detect-resources.ts     | 59 ++++++++++++++-
 .../src/platform/utils.ts                     | 73 -------------------
 3 files changed, 91 insertions(+), 75 deletions(-)
 delete mode 100644 packages/opentelemetry-resources/src/platform/utils.ts

diff --git a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
index 91f3b97f5ef..457965fadfa 100644
--- a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts
@@ -14,4 +14,36 @@
  * limitations under the License.
  */
 
-export { detectResources } from '../utils';
+import { Resource } from '../../Resource';
+import { ResourceDetectionConfig } from '../../config';
+import { diag } from '@opentelemetry/api';
+
+/**
+ * Runs all resource detectors and returns the results merged into a single
+ * Resource.
+ *
+ * @param config Configuration for resource detection
+ */
+export const detectResources = async (
+  config: ResourceDetectionConfig = {}
+): Promise<Resource> => {
+  const internalConfig: ResourceDetectionConfig = Object.assign(config);
+
+  const resources: Resource[] = await Promise.all(
+    (internalConfig.detectors || []).map(async d => {
+      try {
+        const resource = await d.detect(internalConfig);
+        diag.debug(`${d.constructor.name} found resource.`, resource);
+        return resource;
+      } catch (e) {
+        diag.debug(`${d.constructor.name} failed: ${e.message}`);
+        return Resource.empty();
+      }
+    })
+  );
+
+  return resources.reduce(
+    (acc, resource) => acc.merge(resource),
+    Resource.empty()
+  );
+};
diff --git a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
index 6abeb515a52..35bf32b4cdd 100644
--- a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
@@ -14,4 +14,61 @@
  * limitations under the License.
  */
 
- export { detectResources } from '../utils';
+import { Resource } from '../../Resource';
+import { ResourceDetectionConfig } from '../../config';
+import { diag } from '@opentelemetry/api';
+import * as util from 'util';
+
+/**
+ * Runs all resource detectors and returns the results merged into a single
+ * Resource.
+ *
+ * @param config Configuration for resource detection
+ */
+export const detectResources = async (
+  config: ResourceDetectionConfig = {}
+): Promise<Resource> => {
+  const internalConfig: ResourceDetectionConfig = Object.assign(config);
+
+  const resources: Resource[] = await Promise.all(
+    (internalConfig.detectors || []).map(async d => {
+      try {
+        const resource = await d.detect(internalConfig);
+        diag.debug(`${d.constructor.name} found resource.`, resource);
+        return resource;
+      } catch (e) {
+        diag.debug(`${d.constructor.name} failed: ${e.message}`);
+        return Resource.empty();
+      }
+    })
+  );
+
+  // Future check if verbose logging is enabled issue #1903
+  logResources(resources);
+
+  return resources.reduce(
+    (acc, resource) => acc.merge(resource),
+    Resource.empty()
+  );
+};
+
+
+/**
+ * Writes debug information about the detected resources to the logger defined in the resource detection config, if one is provided.
+ *
+ * @param resources The array of {@link Resource} that should be logged. Empty entries will be ignored.
+ */
+const logResources = (resources: Array<Resource>) => {
+  resources.forEach(resource => {
+    // Print only populated resources
+    if (Object.keys(resource.attributes).length > 0) {
+      const resourceDebugString = util.inspect(resource.attributes, {
+        depth: 2,
+        breakLength: Infinity,
+        sorted: true,
+        compact: false,
+      });
+      diag.verbose(resourceDebugString);
+    }
+  });
+};
diff --git a/packages/opentelemetry-resources/src/platform/utils.ts b/packages/opentelemetry-resources/src/platform/utils.ts
deleted file mode 100644
index 802bdfdfa3f..00000000000
--- a/packages/opentelemetry-resources/src/platform/utils.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { Resource } from '../Resource';
-import { ResourceDetectionConfig } from '../config';
-import { diag } from '@opentelemetry/api';
-import * as util from 'util';
-
-/**
- * Runs all resource detectors and returns the results merged into a single
- * Resource.
- *
- * @param config Configuration for resource detection
- */
-export const detectResources = async (
-  config: ResourceDetectionConfig = {}
-): Promise<Resource> => {
-  const internalConfig: ResourceDetectionConfig = Object.assign(config);
-
-  const resources: Resource[] = await Promise.all(
-    (internalConfig.detectors || []).map(async d => {
-      try {
-        const resource = await d.detect(internalConfig);
-        diag.debug(`${d.constructor.name} found resource.`, resource);
-        return resource;
-      } catch (e) {
-        diag.debug(`${d.constructor.name} failed: ${e.message}`);
-        return Resource.empty();
-      }
-    })
-  );
-
-  // Future check if verbose logging is enabled issue #1903
-  logResources(resources);
-
-  return resources.reduce(
-    (acc, resource) => acc.merge(resource),
-    Resource.empty()
-  );
-};
-
-/**
- * Writes debug information about the detected resources to the logger defined in the resource detection config, if one is provided.
- *
- * @param resources The array of {@link Resource} that should be logged. Empty entries will be ignored.
- */
-const logResources = (resources: Array<Resource>) => {
-  resources.forEach(resource => {
-    // Print only populated resources
-    if (Object.keys(resource.attributes).length > 0) {
-      const resourceDebugString = util.inspect(resource.attributes, {
-        depth: 2,
-        breakLength: Infinity,
-        sorted: true,
-        compact: false,
-      });
-      diag.verbose(resourceDebugString);
-    }
-  });
-};

From abb3d3a91573c7f1af3a808b3780ec6ddd3e6a1b Mon Sep 17 00:00:00 2001
From: Cuichen Li <cuichli@cisco.com>
Date: Fri, 4 Mar 2022 09:43:11 +0800
Subject: [PATCH 14/14] test: use describeNode and describeBrowser accordingly

Signed-off-by: Cuichen Li <cuichli@cisco.com>
---
 .../detectors/browser/BrowserDetector.test.ts | 22 ++++++-------------
 .../detectors/node/BrowserDetector.test.ts    | 17 ++------------
 2 files changed, 9 insertions(+), 30 deletions(-)

diff --git a/packages/opentelemetry-resources/test/detectors/browser/BrowserDetector.test.ts b/packages/opentelemetry-resources/test/detectors/browser/BrowserDetector.test.ts
index 614905cd4b3..7543d294386 100644
--- a/packages/opentelemetry-resources/test/detectors/browser/BrowserDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/browser/BrowserDetector.test.ts
@@ -16,33 +16,22 @@
 import * as sinon from 'sinon';
 import { Resource } from '../../../src';
 import { browserDetector } from '../../../src/detectors/BrowserDetector';
+import { describeBrowser } from '../../util';
 import {
   assertResource,
   assertEmptyResource,
 } from '../../util/resource-assertions';
 
 
-describe('browserDetector()', () => {
-  beforeEach(() => {
-    (globalThis.window as {}) = {};
-    sinon.stub(globalThis, 'window').value({
-      document: 'document',
-      navigator: {
-        userAgent: '',
-      }
-    });
-  });
+describeBrowser('browserDetector()', () => {
 
   afterEach(() => {
     sinon.restore();
   });
 
   it('should return browser information', async () => {
-    sinon.stub(globalThis, 'window').value({
-      navigator: {
-        userAgent: 'dddd',
-      },
-      document: 'document'
+    sinon.stub(window, 'navigator').value({
+      userAgent: 'dddd',
     });
 
     const resource: Resource = await browserDetector.detect();
@@ -53,6 +42,9 @@ describe('browserDetector()', () => {
     });
   });
   it('should return empty resources if version is missing', async () => {
+    sinon.stub(window, 'navigator').value({
+      userAgent: '',
+    });
     const resource: Resource = await browserDetector.detect();
     assertEmptyResource(resource);
   });
diff --git a/packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts b/packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts
index d5b51e44359..27d7bdfeffb 100644
--- a/packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/node/BrowserDetector.test.ts
@@ -13,28 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import * as sinon from 'sinon';
 import { Resource } from '../../../src';
 import { browserDetector } from '../../../src/detectors/BrowserDetector';
+import { describeNode } from '../../util';
 import {
   assertEmptyResource,
 } from '../../util/resource-assertions';
 
 
-describe('browserDetector()', () => {
-  beforeEach(() => {
-    (globalThis.window as {}) = {};
-    sinon.stub(globalThis, 'window').value({
-      navigator: {
-        userAgent: '',
-      }
-    });
-  });
-
-  afterEach(() => {
-    sinon.restore();
-  });
-
+describeNode('browserDetector()', () => {
   it('should return empty resources if window.document is missing', async () => {
     const resource: Resource = await browserDetector.detect();
     assertEmptyResource(resource);