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
7 changes: 4 additions & 3 deletions packages/browser/src/integrations/breadcrumbs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
/** JSDoc */
interface BreadcrumbsOptions {
console: boolean;
dom: boolean;
dom: boolean | { serializeAttribute: string };
fetch: boolean;
history: boolean;
sentry: boolean;
Expand Down Expand Up @@ -162,12 +162,13 @@ export class Breadcrumbs implements Integration {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private _domBreadcrumb(handlerData: { [key: string]: any }): void {
let target;
const keyAttr = typeof this._options.dom === 'object' ? this._options.dom.serializeAttribute : undefined;

// Accessing event.target can throw (see getsentry/raven-js#838, #768)
try {
target = handlerData.event.target
? htmlTreeAsString(handlerData.event.target as Node)
: htmlTreeAsString((handlerData.event as unknown) as Node);
? htmlTreeAsString(handlerData.event.target as Node, keyAttr)
: htmlTreeAsString((handlerData.event as unknown) as Node, keyAttr);
} catch (e) {
target = '<unknown>';
}
Expand Down
1 change: 1 addition & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"chai": "^4.1.2",
"eslint": "7.6.0",
"jest": "^24.7.1",
"jsdom": "^16.2.2",
"npm-run-all": "^4.1.2",
"prettier": "1.19.0",
"rimraf": "^2.6.3",
Expand Down
30 changes: 18 additions & 12 deletions packages/utils/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { isString } from './is';
* e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
* @returns generated DOM path
*/
export function htmlTreeAsString(elem: unknown): string {
export function htmlTreeAsString(elem: unknown, keyAttr?: string): string {
type SimpleNode = {
parentNode: SimpleNode;
} | null;
Expand All @@ -28,7 +28,7 @@ export function htmlTreeAsString(elem: unknown): string {

// eslint-disable-next-line no-plusplus
while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {
nextStr = _htmlElementAsString(currentElem);
nextStr = _htmlElementAsString(currentElem, keyAttr);
// bail out if
// - nextStr is the 'html' element
// - the length of the string that would be created exceeds MAX_OUTPUT_LEN
Expand All @@ -54,7 +54,7 @@ export function htmlTreeAsString(elem: unknown): string {
* e.g. [HTMLElement] => input#foo.btn[name=baz]
* @returns generated DOM path
*/
function _htmlElementAsString(el: unknown): string {
function _htmlElementAsString(el: unknown, keyAttr?: string): string {
const elem = el as {
tagName?: string;
id?: string;
Expand All @@ -74,16 +74,22 @@ function _htmlElementAsString(el: unknown): string {
}

out.push(elem.tagName.toLowerCase());
if (elem.id) {
out.push(`#${elem.id}`);
}

// eslint-disable-next-line prefer-const
className = elem.className;
if (className && isString(className)) {
classes = className.split(/\s+/);
for (i = 0; i < classes.length; i++) {
out.push(`.${classes[i]}`);
const keyAttrValue = keyAttr ? elem.getAttribute(keyAttr) : null;
if (keyAttrValue) {
out.push(`[${keyAttr}="${keyAttrValue}"]`);
} else {
if (elem.id) {
out.push(`#${elem.id}`);
}

// eslint-disable-next-line prefer-const
className = elem.className;
if (className && isString(className)) {
classes = className.split(/\s+/);
for (i = 0; i < classes.length; i++) {
out.push(`.${classes[i]}`);
}
}
}
const allowedAttrs = ['type', 'name', 'title', 'alt'];
Expand Down
47 changes: 47 additions & 0 deletions packages/utils/test/browser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { JSDOM } from 'jsdom';

import { htmlTreeAsString } from '../src/browser';

beforeAll(() => {
const dom = new JSDOM();
// @ts-ignore need to override global document
global.document = dom.window.document;
});

describe('htmlTreeAsString', () => {
it('generates html tree for a simple element', () => {
const el = document.createElement('ul');
el.innerHTML = `<li class="container">
<button id="err-btn" class="button" />
</li>`;
document.body.appendChild(el);

expect(htmlTreeAsString(document.getElementById('err-btn'))).toBe(
'body > ul > li.container > button#err-btn.button',
);
});

it('inserts pre-defined attribute values by default', () => {
const el = document.createElement('ul');
el.innerHTML = `<li title="container-title" class="container">
<img id="cat" test-id="cat-test-id" alt="kitten" />
</li>`;
document.body.appendChild(el);

expect(htmlTreeAsString(document.getElementById('cat'))).toBe(
'body > ul > li.container[title="container-title"] > img#cat[alt="kitten"]',
);
});

it('insert key attribute instead of class names or ids when serializeAttribute is defined and the element has it', () => {
const el = document.createElement('ul');
el.innerHTML = `<li class="li-class" title="li-title">
<img id="cat-2" class="catimg" test-id="cat-2-test-id"/>
</li>`;
document.body.appendChild(el);

expect(htmlTreeAsString(document.getElementById('cat-2'), 'test-id')).toBe(
'body > ul > li.li-class[title="li-title"] > img[test-id="cat-2-test-id"]',
);
});
});
6 changes: 6 additions & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ if [[ "$(cut -d. -f1 <<<"$NODE_VERSION")" -le 6 ]]; then
cd packages/tracing
yarn add --dev --ignore-engines --ignore-scripts jsdom@11.x
cd ../..
cd packages/utils
yarn add --dev --ignore-engines --ignore-scripts jsdom@11.x
cd ../..

# only test against @sentry/node and its dependencies - node 6 is too old for anything else to work
yarn test --scope="@sentry/core" --scope="@sentry/hub" --scope="@sentry/minimal" --scope="@sentry/node" --scope="@sentry/utils" --scope="@sentry/tracing"
Expand All @@ -23,6 +26,9 @@ elif [[ "$(cut -d. -f1 <<<"$NODE_VERSION")" -le 8 ]]; then
cd packages/tracing
yarn add --dev --ignore-engines --ignore-scripts jsdom@15.x
cd ../..
cd packages/utils
yarn add --dev --ignore-engines --ignore-scripts jsdom@15.x
cd ../..

# ember tests happen separately, and the rest fail on node 8 for various syntax or dependency reasons
yarn test --ignore="@sentry/ember" --ignore="@sentry-internal/eslint-plugin-sdk" --ignore="@sentry/react" --ignore="@sentry/wasm" --ignore="@sentry/gatsby" --ignore="@sentry/serverless"
Expand Down