Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import { globalObject } from '@datadog/browser-core'
* denied without Permissions Policy delegation), but the SDK only catches an async rejection.
* - `getPristineWindow()` creates a nested iframe to read an unpatched `URL` constructor; that
* nested iframe's `contentWindow` is cross-origin here, and reading a property off it throws.
* - `document.hasFocus()` always returns `false`: the pixel iframe has no focusable UI, so it can
* never hold browser focus regardless of whether the customer is actively looking at the page.
* Shimming these away makes the SDK fall back to code paths that do work in this context
* (`document.cookie`, same-document promise chaining, `globalObject.URL`).
* (`document.cookie`, same-document promise chaining, `globalObject.URL`, always-focused state).
*/
export function patchSandboxedIframeApis() {
disableProperty(globalObject, 'cookieStore')
Expand All @@ -24,6 +26,12 @@ export function patchSandboxedIframeApis() {
},
configurable: true,
})

Object.defineProperty(document, 'hasFocus', {
value: () => true,
configurable: true,
writable: true,
})
}

function disableProperty(target: object, key: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe('initShopifyBindings', () => {
expect(stopAction).toHaveBeenCalledWith('element-without-id', { type: 'click' })
})

it('maps "ui_extension_errored" to addError with the extension context', () => {
it('maps "ui_extension_errored" to addError with the flattened extension context', () => {
const { rumPublicApi, addError } = createFakeRumPublicApi()
const { analytics, emit } = createFakeAnalytics()

Expand All @@ -138,18 +138,20 @@ describe('initShopifyBindings', () => {
extensionName: 'my-extension',
extensionTarget: 'purchase.checkout.block.render',
type: 'RUNTIME',
appId: 'gid://shopify/App/1',
appName: 'my-app',
appVersion: '1.2.3',
},
},
})

expect(addError).toHaveBeenCalledWith(jasmine.objectContaining({ message: 'Boom', stack: 'stack trace' }), {
extension: {
name: 'my-extension',
target: 'purchase.checkout.block.render',
type: 'RUNTIME',
appName: 'my-app',
},
extensionName: 'my-extension',
extensionTarget: 'purchase.checkout.block.render',
extensionErrorType: 'RUNTIME',
appId: 'gid://shopify/App/1',
appName: 'my-app',
appVersion: '1.2.3',
})
})
})
14 changes: 8 additions & 6 deletions packages/browser-rum-shopify/src/domain/shopifyBindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ export interface ErrorData {
extensionName?: string
extensionTarget?: string
type?: string
appId?: string
appName?: string
appVersion?: string
}

// Matches /checkouts/*, /checkout, including locale-prefixed paths.
Expand Down Expand Up @@ -54,12 +56,12 @@ export function initShopifyBindings(rumPublicApi: RumPublicApi, analytics: Shopi
const err = new Error(error?.message)
err.stack = error?.trace
rumPublicApi.addError(err, {
extension: {
name: error?.extensionName,
target: error?.extensionTarget,
type: error?.type,
appName: error?.appName,
},
extensionName: error?.extensionName,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: usually we use snake_case for attributes

extensionTarget: error?.extensionTarget,
extensionErrorType: error?.type,
appId: error?.appId,
appName: error?.appName,
appVersion: error?.appVersion,
})
})
}
Loading