import { isIE } from '@datadog/browser-core' import { NodePrivacyLevel, PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_HIDDEN, PRIVACY_ATTR_VALUE_MASK, PRIVACY_ATTR_VALUE_MASK_USER_INPUT, } from '../../constants' import { getNodeSelfPrivacyLevel, reducePrivacyLevel, getNodePrivacyLevel, shouldMaskNode } from './privacy' describe('getNodePrivacyLevel', () => { beforeEach(() => { if (isIE()) { pending('IE not supported') } }) it('returns the element privacy mode if it has one', () => { const node = document.createElement('div') node.setAttribute(PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_MASK) expect(getNodePrivacyLevel(node, NodePrivacyLevel.ALLOW)).toBe(NodePrivacyLevel.MASK) }) it('fallbacks to the default privacy mode if the element has none', () => { const node = document.createElement('div') expect(getNodePrivacyLevel(node, NodePrivacyLevel.ALLOW)).toBe(NodePrivacyLevel.ALLOW) expect(getNodePrivacyLevel(node, NodePrivacyLevel.IGNORE)).toBe(NodePrivacyLevel.IGNORE) expect(getNodePrivacyLevel(node, NodePrivacyLevel.MASK)).toBe(NodePrivacyLevel.MASK) expect(getNodePrivacyLevel(node, NodePrivacyLevel.MASK_USER_INPUT)).toBe(NodePrivacyLevel.MASK_USER_INPUT) expect(getNodePrivacyLevel(node, NodePrivacyLevel.HIDDEN)).toBe(NodePrivacyLevel.HIDDEN) }) describe('inheritance', () => { it('returns an ancestor privacy mode if the element has none', () => { const ancestor = document.createElement('div') const node = document.createElement('div') ancestor.setAttribute(PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_MASK) ancestor.appendChild(node) expect(getNodePrivacyLevel(node, NodePrivacyLevel.ALLOW)).toBe(NodePrivacyLevel.MASK) }) it('fallbacks to the default privacy mode if no ancestor has one', () => { const ancestor = document.createElement('div') const node = document.createElement('div') ancestor.appendChild(node) expect(getNodePrivacyLevel(node, NodePrivacyLevel.ALLOW)).toBe(NodePrivacyLevel.ALLOW) }) it('overrides the ancestor privacy mode', () => { const ancestor = document.createElement('div') ancestor.setAttribute(PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_MASK) const node = document.createElement('div') node.setAttribute(PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_MASK_USER_INPUT) ancestor.appendChild(node) expect(getNodePrivacyLevel(node, NodePrivacyLevel.ALLOW)).toBe(NodePrivacyLevel.MASK_USER_INPUT) }) it('does not override the ancestor privacy mode if it is HIDDEN', () => { const ancestor = document.createElement('div') ancestor.setAttribute(PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_HIDDEN) const node = document.createElement('div') node.setAttribute(PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_MASK_USER_INPUT) ancestor.appendChild(node) expect(getNodePrivacyLevel(node, NodePrivacyLevel.ALLOW)).toBe(NodePrivacyLevel.HIDDEN) }) it('overrides the ancestor privacy mode if the element should be IGNORE', () => { const ancestor = document.createElement('div') ancestor.setAttribute(PRIVACY_ATTR_NAME, PRIVACY_ATTR_VALUE_MASK) const node = document.createElement('script') ancestor.appendChild(node) expect(getNodePrivacyLevel(node, NodePrivacyLevel.ALLOW)).toBe(NodePrivacyLevel.IGNORE) }) }) }) describe('getNodeSelfPrivacyLevel', () => { beforeEach(() => { if (isIE()) { pending('IE not supported') } }) ;[ { msg: 'is not an element', html: 'foo', expected: undefined, }, // Overrules { msg: 'has no privacy attribute or class', html: '', expected: undefined, }, { msg: 'is a "base" element (forced override)', html: '', expected: NodePrivacyLevel.ALLOW, }, { msg: 'is an "input" element of type "password" (forced override)', html: '', expected: NodePrivacyLevel.MASK, }, { msg: 'is an "input" element of type "tel" (forced override)', html: '', expected: NodePrivacyLevel.MASK, }, { msg: 'is an "input" element of type "email" (forced override)', html: '', expected: NodePrivacyLevel.MASK, }, { msg: 'is an "input" element of type "hidden" (forced override)', html: '', expected: NodePrivacyLevel.MASK, }, { msg: 'is an "input" element and has an autocomplete attribute starting with "cc-" (forced override)', html: '', expected: NodePrivacyLevel.MASK, }, { msg: 'is an "input" element and has an autocomplete attribute not starting with "cc-"', html: '', expected: undefined, }, // Class { msg: 'has a dd-privacy-allow class', html: '', expected: NodePrivacyLevel.ALLOW, }, { msg: 'has a dd-privacy-hidden class', html: '', expected: NodePrivacyLevel.HIDDEN, }, { msg: 'has a dd-privacy-mask class', html: '', expected: NodePrivacyLevel.MASK, }, { msg: 'has a dd-privacy-mask-user-input class', html: '', expected: NodePrivacyLevel.MASK_USER_INPUT, }, { msg: 'has an unknown class starting with dd-privacy-', html: '', expected: undefined, }, // Attributes { msg: 'has a data-dd-privacy="allow" attribute', html: '', expected: NodePrivacyLevel.ALLOW, }, { msg: 'has a data-dd-privacy="hidden" attribute', html: '', expected: NodePrivacyLevel.HIDDEN, }, { msg: 'has a data-dd-privacy="mask" attribute', html: '', expected: NodePrivacyLevel.MASK, }, { msg: 'has a data-dd-privacy="mask-user-input" attribute', html: '', expected: NodePrivacyLevel.MASK_USER_INPUT, }, { msg: 'has an unknown data-dd-privacy attribute value', html: '', expected: undefined, }, // Ignored elements { msg: 'should be ignored', html: '