From 5578fe2a32f8c11c32b564a6233be245aefe29fc Mon Sep 17 00:00:00 2001
From: Bastien Caudan <1331991+bcaudan@users.noreply.github.com>
Date: Wed, 29 Mar 2023 14:16:14 +0200
Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F[RUMF-1517]=20split=20core=20?=
=?UTF-8?q?specHelper=20(#2111)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* ♻️ move clearAllCookies to its usage
* ♻️ extract browserChecks
* ♻️ extract buildEnv
* ♻️ extract requests.specHelper
* ♻️ extract createNewEvent
* ♻️ extract location.specHelper
* ♻️ extract mockClock
* ♻️ rename specHelper to simpleTestDoubles
* ♻️ move capturedExceptions to tracekit
* 👌 remove specHelper prefix for files under test directory
* 👌 extract test/emulate directory
* 👌 split simpleTestDoubles
---
.../capturedExceptions.specHelper.ts} | 0
.../domain/tracekit/computeStackTrace.spec.ts | 2 +-
packages/core/test/browserChecks.ts | 11 +
packages/core/test/buildEnv.ts | 4 +
packages/core/test/emulate/cookie.ts | 13 +
packages/core/test/emulate/createNewEvent.ts | 26 ++
packages/core/test/emulate/eventBridge.ts | 14 +
packages/core/test/emulate/location.ts | 32 ++
packages/core/test/emulate/mockClock.ts | 20 ++
packages/core/test/emulate/navigatorOnLine.ts | 12 +
.../core/test/{ => emulate}/stubReportApis.ts | 4 +-
.../core/test/{ => emulate}/stubZoneJs.ts | 2 +-
.../{ => emulate}/syntheticsWorkerValues.ts | 8 +-
packages/core/test/emulate/visibilityState.ts | 12 +
packages/core/test/emulate/windowOnError.ts | 13 +
packages/core/test/forEach.spec.ts | 9 +-
packages/core/test/index.ts | 21 +-
.../core/test/{specHelper.ts => requests.ts} | 296 ++++--------------
18 files changed, 256 insertions(+), 243 deletions(-)
rename packages/core/{test/capturedExceptions.ts => src/domain/tracekit/capturedExceptions.specHelper.ts} (100%)
create mode 100644 packages/core/test/browserChecks.ts
create mode 100644 packages/core/test/buildEnv.ts
create mode 100644 packages/core/test/emulate/cookie.ts
create mode 100644 packages/core/test/emulate/createNewEvent.ts
create mode 100644 packages/core/test/emulate/eventBridge.ts
create mode 100644 packages/core/test/emulate/location.ts
create mode 100644 packages/core/test/emulate/mockClock.ts
create mode 100644 packages/core/test/emulate/navigatorOnLine.ts
rename packages/core/test/{ => emulate}/stubReportApis.ts (95%)
rename packages/core/test/{ => emulate}/stubZoneJs.ts (89%)
rename packages/core/test/{ => emulate}/syntheticsWorkerValues.ts (85%)
create mode 100644 packages/core/test/emulate/visibilityState.ts
create mode 100644 packages/core/test/emulate/windowOnError.ts
rename packages/core/test/{specHelper.ts => requests.ts} (64%)
diff --git a/packages/core/test/capturedExceptions.ts b/packages/core/src/domain/tracekit/capturedExceptions.specHelper.ts
similarity index 100%
rename from packages/core/test/capturedExceptions.ts
rename to packages/core/src/domain/tracekit/capturedExceptions.specHelper.ts
diff --git a/packages/core/src/domain/tracekit/computeStackTrace.spec.ts b/packages/core/src/domain/tracekit/computeStackTrace.spec.ts
index 2426ddeb2e..1ccc14980c 100644
--- a/packages/core/src/domain/tracekit/computeStackTrace.spec.ts
+++ b/packages/core/src/domain/tracekit/computeStackTrace.spec.ts
@@ -1,5 +1,5 @@
-import * as CapturedExceptions from '../../../test'
import { isSafari } from '../../../test'
+import * as CapturedExceptions from './capturedExceptions.specHelper'
import { computeStackTrace } from './computeStackTrace'
describe('computeStackTrace', () => {
diff --git a/packages/core/test/browserChecks.ts b/packages/core/test/browserChecks.ts
new file mode 100644
index 0000000000..fbf38bba55
--- /dev/null
+++ b/packages/core/test/browserChecks.ts
@@ -0,0 +1,11 @@
+export function isSafari() {
+ return /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
+}
+
+export function isFirefox() {
+ return navigator.userAgent.toLowerCase().indexOf('firefox') > -1
+}
+
+export function isAdoptedStyleSheetsSupported() {
+ return Boolean((document as any).adoptedStyleSheets)
+}
diff --git a/packages/core/test/buildEnv.ts b/packages/core/test/buildEnv.ts
new file mode 100644
index 0000000000..b258cecc60
--- /dev/null
+++ b/packages/core/test/buildEnv.ts
@@ -0,0 +1,4 @@
+// to simulate different build env behavior
+export interface BuildEnvWindow {
+ __BUILD_ENV__SDK_VERSION__: string
+}
diff --git a/packages/core/test/emulate/cookie.ts b/packages/core/test/emulate/cookie.ts
new file mode 100644
index 0000000000..a053a560c8
--- /dev/null
+++ b/packages/core/test/emulate/cookie.ts
@@ -0,0 +1,13 @@
+export function stubCookie() {
+ let cookie = ''
+ return {
+ getSpy: spyOnProperty(Document.prototype, 'cookie', 'get').and.callFake(() => cookie),
+ setSpy: spyOnProperty(Document.prototype, 'cookie', 'set').and.callFake((newCookie) => {
+ cookie = newCookie
+ }),
+ currentValue: () => cookie,
+ setCurrentValue: (newCookie: string) => {
+ cookie = newCookie
+ },
+ }
+}
diff --git a/packages/core/test/emulate/createNewEvent.ts b/packages/core/test/emulate/createNewEvent.ts
new file mode 100644
index 0000000000..e5a9089000
--- /dev/null
+++ b/packages/core/test/emulate/createNewEvent.ts
@@ -0,0 +1,26 @@
+import { objectEntries } from '../../src'
+
+export function createNewEvent
>(eventName: 'click', properties?: P): MouseEvent & P
+export function createNewEvent
>(
+ eventName: 'pointerup',
+ properties?: P
+): PointerEvent & P
+export function createNewEvent(eventName: string, properties?: { [name: string]: unknown }): Event
+export function createNewEvent(eventName: string, properties: { [name: string]: unknown } = {}) {
+ let event: Event
+ if (typeof Event === 'function') {
+ event = new Event(eventName)
+ } else {
+ event = document.createEvent('Event')
+ event.initEvent(eventName, true, true)
+ }
+ objectEntries(properties).forEach(([name, value]) => {
+ // Setting values directly or with a `value` descriptor seems unsupported in IE11
+ Object.defineProperty(event, name, {
+ get() {
+ return value
+ },
+ })
+ })
+ return event
+}
diff --git a/packages/core/test/emulate/eventBridge.ts b/packages/core/test/emulate/eventBridge.ts
new file mode 100644
index 0000000000..178d84cc2c
--- /dev/null
+++ b/packages/core/test/emulate/eventBridge.ts
@@ -0,0 +1,14 @@
+import type { BrowserWindowWithEventBridge } from '../../src/transport'
+
+export function initEventBridgeStub(allowedWebViewHosts: string[] = [window.location.hostname]) {
+ const eventBridgeStub = {
+ send: (_msg: string) => undefined,
+ getAllowedWebViewHosts: () => JSON.stringify(allowedWebViewHosts),
+ }
+ ;(window as BrowserWindowWithEventBridge).DatadogEventBridge = eventBridgeStub
+ return eventBridgeStub
+}
+
+export function deleteEventBridgeStub() {
+ delete (window as BrowserWindowWithEventBridge).DatadogEventBridge
+}
diff --git a/packages/core/test/emulate/location.ts b/packages/core/test/emulate/location.ts
new file mode 100644
index 0000000000..866a2ecc21
--- /dev/null
+++ b/packages/core/test/emulate/location.ts
@@ -0,0 +1,32 @@
+import { assign, buildUrl } from '../../src'
+
+export function mockLocation(initialUrl: string) {
+ const fakeLocation = buildLocation(initialUrl)
+ spyOn(history, 'pushState').and.callFake((_: any, __: string, pathname: string) => {
+ assign(fakeLocation, buildLocation(pathname, fakeLocation.href))
+ })
+
+ function hashchangeCallBack() {
+ fakeLocation.hash = window.location.hash
+ fakeLocation.href = fakeLocation.href.replace(/#.*/, '') + window.location.hash
+ }
+
+ window.addEventListener('hashchange', hashchangeCallBack)
+ return {
+ location: fakeLocation,
+ cleanup: () => {
+ window.removeEventListener('hashchange', hashchangeCallBack)
+ window.location.hash = ''
+ },
+ }
+}
+
+export function buildLocation(url: string, base = location.href) {
+ const urlObject = buildUrl(url, base)
+ return {
+ hash: urlObject.hash,
+ href: urlObject.href,
+ pathname: urlObject.pathname,
+ search: urlObject.search,
+ } as Location
+}
diff --git a/packages/core/test/emulate/mockClock.ts b/packages/core/test/emulate/mockClock.ts
new file mode 100644
index 0000000000..a0ce1ba31c
--- /dev/null
+++ b/packages/core/test/emulate/mockClock.ts
@@ -0,0 +1,20 @@
+import { resetNavigationStart } from '../../src/tools/timeUtils'
+
+export type Clock = ReturnType
+
+export function mockClock(date?: Date) {
+ jasmine.clock().install()
+ jasmine.clock().mockDate(date)
+ const start = Date.now()
+ spyOn(performance, 'now').and.callFake(() => Date.now() - start)
+ spyOnProperty(performance.timing, 'navigationStart', 'get').and.callFake(() => start)
+ resetNavigationStart()
+ return {
+ tick: (ms: number) => jasmine.clock().tick(ms),
+ setDate: (date: Date) => jasmine.clock().mockDate(date),
+ cleanup: () => {
+ jasmine.clock().uninstall()
+ resetNavigationStart()
+ },
+ }
+}
diff --git a/packages/core/test/emulate/navigatorOnLine.ts b/packages/core/test/emulate/navigatorOnLine.ts
new file mode 100644
index 0000000000..2e915cc568
--- /dev/null
+++ b/packages/core/test/emulate/navigatorOnLine.ts
@@ -0,0 +1,12 @@
+export function setNavigatorOnLine(onLine: boolean) {
+ Object.defineProperty(navigator, 'onLine', {
+ get() {
+ return onLine
+ },
+ configurable: true,
+ })
+}
+
+export function restoreNavigatorOnLine() {
+ delete (navigator as any).onLine
+}
diff --git a/packages/core/test/stubReportApis.ts b/packages/core/test/emulate/stubReportApis.ts
similarity index 95%
rename from packages/core/test/stubReportApis.ts
rename to packages/core/test/emulate/stubReportApis.ts
index 4db46b59a0..dd9d940961 100644
--- a/packages/core/test/stubReportApis.ts
+++ b/packages/core/test/emulate/stubReportApis.ts
@@ -4,8 +4,8 @@ import type {
Report,
ReportingObserverConstructor,
ReportingObserverOption,
-} from '../src/domain/report/browser.types'
-import { noop } from '../src/tools/utils'
+} from '../../src/domain/report/browser.types'
+import { noop } from '../../src/tools/utils'
export function stubReportingObserver() {
const originalReportingObserver = (window as BrowserWindow).ReportingObserver
diff --git a/packages/core/test/stubZoneJs.ts b/packages/core/test/emulate/stubZoneJs.ts
similarity index 89%
rename from packages/core/test/stubZoneJs.ts
rename to packages/core/test/emulate/stubZoneJs.ts
index 53242c2d23..dccd7070c1 100644
--- a/packages/core/test/stubZoneJs.ts
+++ b/packages/core/test/emulate/stubZoneJs.ts
@@ -1,4 +1,4 @@
-import type { BrowserWindowWithZoneJs } from '../src/tools/getZoneJsOriginalValue'
+import type { BrowserWindowWithZoneJs } from '../../src/tools/getZoneJsOriginalValue'
export function stubZoneJs() {
const browserWindow = window as BrowserWindowWithZoneJs
diff --git a/packages/core/test/syntheticsWorkerValues.ts b/packages/core/test/emulate/syntheticsWorkerValues.ts
similarity index 85%
rename from packages/core/test/syntheticsWorkerValues.ts
rename to packages/core/test/emulate/syntheticsWorkerValues.ts
index 48443ed70e..47fb7c564a 100644
--- a/packages/core/test/syntheticsWorkerValues.ts
+++ b/packages/core/test/emulate/syntheticsWorkerValues.ts
@@ -1,11 +1,11 @@
-import { deleteCookie, setCookie } from '../src/browser/cookie'
-import type { BrowserWindow } from '../src/domain/synthetics/syntheticsWorkerValues'
+import { deleteCookie, setCookie } from '../../src/browser/cookie'
+import type { BrowserWindow } from '../../src/domain/synthetics/syntheticsWorkerValues'
import {
SYNTHETICS_INJECTS_RUM_COOKIE_NAME,
SYNTHETICS_RESULT_ID_COOKIE_NAME,
SYNTHETICS_TEST_ID_COOKIE_NAME,
-} from '../src/domain/synthetics/syntheticsWorkerValues'
-import { ONE_MINUTE } from '../src/tools/utils'
+} from '../../src/domain/synthetics/syntheticsWorkerValues'
+import { ONE_MINUTE } from '../../src/tools/utils'
// Duration to create a cookie lasting at least until the end of the test
const COOKIE_DURATION = ONE_MINUTE
diff --git a/packages/core/test/emulate/visibilityState.ts b/packages/core/test/emulate/visibilityState.ts
new file mode 100644
index 0000000000..4586a97bca
--- /dev/null
+++ b/packages/core/test/emulate/visibilityState.ts
@@ -0,0 +1,12 @@
+export function setPageVisibility(visibility: 'visible' | 'hidden') {
+ Object.defineProperty(document, 'visibilityState', {
+ get() {
+ return visibility
+ },
+ configurable: true,
+ })
+}
+
+export function restorePageVisibility() {
+ delete (document as any).visibilityState
+}
diff --git a/packages/core/test/emulate/windowOnError.ts b/packages/core/test/emulate/windowOnError.ts
new file mode 100644
index 0000000000..e2d237aacc
--- /dev/null
+++ b/packages/core/test/emulate/windowOnError.ts
@@ -0,0 +1,13 @@
+import { instrumentMethod, noop } from '../../src'
+
+/**
+ * Opt out of jasmine uncaught error interception during test. This is useful for tests that are
+ * instrumenting `window.onerror`. See https://github.com/jasmine/jasmine/pull/1860 for more
+ * information.
+ */
+export function disableJasmineUncaughtErrorHandler() {
+ const { stop } = instrumentMethod(window, 'onerror', () => noop)
+ return {
+ reset: stop,
+ }
+}
diff --git a/packages/core/test/forEach.spec.ts b/packages/core/test/forEach.spec.ts
index 1b3b535384..2c9eeb3acc 100644
--- a/packages/core/test/forEach.spec.ts
+++ b/packages/core/test/forEach.spec.ts
@@ -1,5 +1,4 @@
-import type { BuildEnvWindow } from './specHelper'
-import { clearAllCookies } from './specHelper'
+import type { BuildEnvWindow } from './buildEnv'
beforeEach(() => {
;(window as unknown as BuildEnvWindow).__BUILD_ENV__SDK_VERSION__ = 'test'
@@ -13,3 +12,9 @@ beforeEach(() => {
afterEach(() => {
clearAllCookies()
})
+
+function clearAllCookies() {
+ document.cookie.split(';').forEach((c) => {
+ document.cookie = c.replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/;samesite=strict`)
+ })
+}
diff --git a/packages/core/test/index.ts b/packages/core/test/index.ts
index 38a780b548..cdffa284cc 100644
--- a/packages/core/test/index.ts
+++ b/packages/core/test/index.ts
@@ -1,6 +1,17 @@
-export * from './capturedExceptions'
+export * from './browserChecks'
+export * from './buildEnv'
export * from './collectAsyncCalls'
-export * from './stubReportApis'
-export * from './stubZoneJs'
-export * from './syntheticsWorkerValues'
-export * from './specHelper'
+export * from './requests'
+export * from './emulate/createNewEvent'
+export * from './emulate/location'
+export * from './emulate/mockClock'
+export * from './emulate/stubReportApis'
+export * from './emulate/stubZoneJs'
+export * from './emulate/syntheticsWorkerValues'
+export * from './emulate/visibilityState'
+export * from './emulate/navigatorOnLine'
+export * from './emulate/navigatorOnLine'
+export * from './emulate/eventBridge'
+export * from './emulate/eventBridge'
+export * from './emulate/windowOnError'
+export * from './emulate/cookie'
diff --git a/packages/core/test/specHelper.ts b/packages/core/test/requests.ts
similarity index 64%
rename from packages/core/test/specHelper.ts
rename to packages/core/test/requests.ts
index a5ecc57553..35b1c22874 100644
--- a/packages/core/test/specHelper.ts
+++ b/packages/core/test/requests.ts
@@ -1,18 +1,5 @@
-import type { EndpointBuilder } from '../src/domain/configuration'
-import { instrumentMethod } from '../src/tools/instrumentMethod'
-import { resetNavigationStart } from '../src/tools/timeUtils'
-import { buildUrl } from '../src/tools/urlPolyfill'
-import { noop, objectEntries, assign } from '../src/tools/utils'
-import type { BrowserWindowWithEventBridge } from '../src/transport'
-
-// to simulate different build env behavior
-export interface BuildEnvWindow {
- __BUILD_ENV__SDK_VERSION__: string
-}
-
-export function stubEndpointBuilder(url: string) {
- return { build: (_: any) => url } as EndpointBuilder
-}
+import type { EndpointBuilder } from '../src'
+import { noop } from '../src'
export const SPEC_ENDPOINTS = {
logsEndpointBuilder: stubEndpointBuilder('https://logs-intake.com/v1/input/abcde?foo=bar'),
@@ -24,70 +11,79 @@ export const SPEC_ENDPOINTS = {
},
}
-export function isSafari() {
- return /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
-}
-
-export function isFirefox() {
- return navigator.userAgent.toLowerCase().indexOf('firefox') > -1
+export function stubEndpointBuilder(url: string) {
+ return { build: (_: any) => url } as EndpointBuilder
}
-export function clearAllCookies() {
- document.cookie.split(';').forEach((c) => {
- document.cookie = c.replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/;samesite=strict`)
- })
+export interface Request {
+ type: 'xhr' | 'sendBeacon' | 'fetch'
+ url: string
+ body: string
}
-export type Clock = ReturnType
+export function interceptRequests() {
+ const requests: Request[] = []
+ const originalSendBeacon = isSendBeaconSupported() && navigator.sendBeacon.bind(navigator)
+ const originalRequest = window.Request
+ const originalFetch = window.fetch
+ let stubXhrManager: { reset(): void } | undefined
-export function mockClock(date?: Date) {
- jasmine.clock().install()
- jasmine.clock().mockDate(date)
- const start = Date.now()
- spyOn(performance, 'now').and.callFake(() => Date.now() - start)
- spyOnProperty(performance.timing, 'navigationStart', 'get').and.callFake(() => start)
- resetNavigationStart()
- return {
- tick: (ms: number) => jasmine.clock().tick(ms),
- setDate: (date: Date) => jasmine.clock().mockDate(date),
- cleanup: () => {
- jasmine.clock().uninstall()
- resetNavigationStart()
- },
+ spyOn(XMLHttpRequest.prototype, 'open').and.callFake((_, url) => requests.push({ type: 'xhr', url } as Request))
+ spyOn(XMLHttpRequest.prototype, 'send').and.callFake((body) => (requests[requests.length - 1].body = body as string))
+ if (isSendBeaconSupported()) {
+ spyOn(navigator, 'sendBeacon').and.callFake((url, body) => {
+ requests.push({ type: 'sendBeacon', url: url as string, body: body as string })
+ return true
+ })
+ }
+ if (isFetchKeepAliveSupported()) {
+ spyOn(window, 'fetch').and.callFake((url, config) => {
+ requests.push({ type: 'fetch', url: url as string, body: config!.body as string })
+ return new Promise(() => undefined)
+ })
}
-}
-export function mockLocation(initialUrl: string) {
- const fakeLocation = buildLocation(initialUrl)
- spyOn(history, 'pushState').and.callFake((_: any, __: string, pathname: string) => {
- assign(fakeLocation, buildLocation(pathname, fakeLocation.href))
- })
+ function isSendBeaconSupported() {
+ return !!navigator.sendBeacon
+ }
- function hashchangeCallBack() {
- fakeLocation.hash = window.location.hash
- fakeLocation.href = fakeLocation.href.replace(/#.*/, '') + window.location.hash
+ function isFetchKeepAliveSupported() {
+ return 'fetch' in window && 'keepalive' in new window.Request('')
}
- window.addEventListener('hashchange', hashchangeCallBack)
return {
- location: fakeLocation,
- cleanup: () => {
- window.removeEventListener('hashchange', hashchangeCallBack)
- window.location.hash = ''
+ requests,
+ isSendBeaconSupported,
+ isFetchKeepAliveSupported,
+ withSendBeacon(newSendBeacon: any) {
+ navigator.sendBeacon = newSendBeacon
+ },
+ withRequest(newRequest: any) {
+ window.Request = newRequest
+ },
+ withFetch(newFetch: any) {
+ window.fetch = newFetch
+ },
+ withStubXhr(onSend: (xhr: StubXhr) => void) {
+ stubXhrManager = stubXhr()
+ StubXhr.onSend = onSend
+ },
+ restore() {
+ if (originalSendBeacon) {
+ navigator.sendBeacon = originalSendBeacon
+ }
+ if (originalRequest) {
+ window.Request = originalRequest
+ }
+ if (originalFetch) {
+ window.fetch = originalFetch
+ }
+ stubXhrManager?.reset()
+ StubXhr.onSend = noop
},
}
}
-export function buildLocation(url: string, base = location.href) {
- const urlObject = buildUrl(url, base)
- return {
- hash: urlObject.hash,
- href: urlObject.href,
- pathname: urlObject.pathname,
- search: urlObject.search,
- } as Location
-}
-
export interface FetchStubManager {
reset: () => void
whenAllComplete: (callback: () => void) => void
@@ -149,9 +145,6 @@ export interface ResponseStubOptions {
bodyUsed?: boolean
bodyDisturbed?: boolean
}
-function notYetImplemented(): never {
- throw new Error('not yet implemented')
-}
export class ResponseStub implements Response {
private _body: ReadableStream | undefined
@@ -220,22 +213,28 @@ export class ResponseStub implements Response {
blob = notYetImplemented
formData = notYetImplemented
json = notYetImplemented
+
/* eslint-enable @typescript-eslint/member-ordering */
get ok() {
return notYetImplemented()
}
+
get headers() {
return notYetImplemented()
}
+
get redirected() {
return notYetImplemented()
}
+
get statusText() {
return notYetImplemented()
}
+
get trailer() {
return notYetImplemented()
}
+
get url() {
return notYetImplemented()
}
@@ -328,31 +327,6 @@ class StubXhr extends StubEventEmitter {
}
}
-export function createNewEvent>(eventName: 'click', properties?: P): MouseEvent & P
-export function createNewEvent
>(
- eventName: 'pointerup',
- properties?: P
-): PointerEvent & P
-export function createNewEvent(eventName: string, properties?: { [name: string]: unknown }): Event
-export function createNewEvent(eventName: string, properties: { [name: string]: unknown } = {}) {
- let event: Event
- if (typeof Event === 'function') {
- event = new Event(eventName)
- } else {
- event = document.createEvent('Event')
- event.initEvent(eventName, true, true)
- }
- objectEntries(properties).forEach(([name, value]) => {
- // Setting values directly or with a `value` descriptor seems unsupported in IE11
- Object.defineProperty(event, name, {
- get() {
- return value
- },
- })
- })
- return event
-}
-
export function stubXhr() {
const originalXhr = XMLHttpRequest
@@ -383,140 +357,6 @@ export function withXhr({
setup(xhr as unknown as StubXhr)
}
-export function setPageVisibility(visibility: 'visible' | 'hidden') {
- Object.defineProperty(document, 'visibilityState', {
- get() {
- return visibility
- },
- configurable: true,
- })
-}
-
-export function restorePageVisibility() {
- delete (document as any).visibilityState
-}
-
-export function setNavigatorOnLine(onLine: boolean) {
- Object.defineProperty(navigator, 'onLine', {
- get() {
- return onLine
- },
- configurable: true,
- })
-}
-
-export function restoreNavigatorOnLine() {
- delete (navigator as any).onLine
-}
-
-export function initEventBridgeStub(allowedWebViewHosts: string[] = [window.location.hostname]) {
- const eventBridgeStub = {
- send: (msg: string) => undefined,
- getAllowedWebViewHosts: () => JSON.stringify(allowedWebViewHosts),
- }
- ;(window as BrowserWindowWithEventBridge).DatadogEventBridge = eventBridgeStub
- return eventBridgeStub
-}
-
-export function deleteEventBridgeStub() {
- delete (window as BrowserWindowWithEventBridge).DatadogEventBridge
-}
-
-/**
- * Opt out of jasmine uncaught error interception during test. This is useful for tests that are
- * instrumenting `window.onerror`. See https://github.com/jasmine/jasmine/pull/1860 for more
- * information.
- */
-export function disableJasmineUncaughtErrorHandler() {
- const { stop } = instrumentMethod(window, 'onerror', () => noop)
- return {
- reset: stop,
- }
-}
-
-export function stubCookie() {
- let cookie = ''
- return {
- getSpy: spyOnProperty(Document.prototype, 'cookie', 'get').and.callFake(() => cookie),
- setSpy: spyOnProperty(Document.prototype, 'cookie', 'set').and.callFake((newCookie) => {
- cookie = newCookie
- }),
- currentValue: () => cookie,
- setCurrentValue: (newCookie: string) => {
- cookie = newCookie
- },
- }
-}
-
-export interface Request {
- type: 'xhr' | 'sendBeacon' | 'fetch'
- url: string
- body: string
-}
-
-export function interceptRequests() {
- const requests: Request[] = []
- const originalSendBeacon = isSendBeaconSupported() && navigator.sendBeacon.bind(navigator)
- const originalRequest = window.Request
- const originalFetch = window.fetch
- let stubXhrManager: { reset(): void } | undefined
-
- spyOn(XMLHttpRequest.prototype, 'open').and.callFake((_, url) => requests.push({ type: 'xhr', url } as Request))
- spyOn(XMLHttpRequest.prototype, 'send').and.callFake((body) => (requests[requests.length - 1].body = body as string))
- if (isSendBeaconSupported()) {
- spyOn(navigator, 'sendBeacon').and.callFake((url, body) => {
- requests.push({ type: 'sendBeacon', url: url as string, body: body as string })
- return true
- })
- }
- if (isFetchKeepAliveSupported()) {
- spyOn(window, 'fetch').and.callFake((url, config) => {
- requests.push({ type: 'fetch', url: url as string, body: config!.body as string })
- return new Promise(() => undefined)
- })
- }
-
- function isSendBeaconSupported() {
- return !!navigator.sendBeacon
- }
-
- function isFetchKeepAliveSupported() {
- return 'fetch' in window && 'keepalive' in new window.Request('')
- }
-
- return {
- requests,
- isSendBeaconSupported,
- isFetchKeepAliveSupported,
- withSendBeacon(newSendBeacon: any) {
- navigator.sendBeacon = newSendBeacon
- },
- withRequest(newRequest: any) {
- window.Request = newRequest
- },
- withFetch(newFetch: any) {
- window.fetch = newFetch
- },
- withStubXhr(onSend: (xhr: StubXhr) => void) {
- stubXhrManager = stubXhr()
- StubXhr.onSend = onSend
- },
- restore() {
- if (originalSendBeacon) {
- navigator.sendBeacon = originalSendBeacon
- }
- if (originalRequest) {
- window.Request = originalRequest
- }
- if (originalFetch) {
- window.fetch = originalFetch
- }
- stubXhrManager?.reset()
- StubXhr.onSend = noop
- },
- }
-}
-
-export function isAdoptedStyleSheetsSupported() {
- return Boolean((document as any).adoptedStyleSheets)
+function notYetImplemented(): never {
+ throw new Error('not yet implemented')
}