Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Refactor GDPR stuff into a more readable consent class #1176

Merged
merged 11 commits into from
May 28, 2024
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
184 changes: 184 additions & 0 deletions src/__tests__/consent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import _posthog, { PostHog, PostHogConfig } from '../loader-module'
import { uuidv7 } from '../uuidv7'

import { isNull } from '../utils/type-utils'
import { document, assignableWindow, navigator } from '../utils/globals'

const DEFAULT_PERSISTENCE_PREFIX = `__ph_opt_in_out_`
const CUSTOM_PERSISTENCE_PREFIX = `𝓶𝓶𝓶𝓬𝓸𝓸𝓴𝓲𝓮𝓼`

function deleteAllCookies() {
const cookies = document!.cookie.split(';')

for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i]
const eqPos = cookie.indexOf('=')
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie
document!.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT'
}
}

describe('consentManager', () => {
const createPostHog = (config: Partial<PostHogConfig> = {}) => {
const posthog = _posthog.init('testtoken', { ...config }, uuidv7())!
posthog.debug()
return posthog
}

let posthog: PostHog

beforeEach(() => {
posthog = createPostHog()
posthog.reset()
})

afterEach(() => {
document!.getElementsByTagName('html')[0].innerHTML = ''
assignableWindow.localStorage.clear()
deleteAllCookies()
})

it('should start default opted in', () => {
expect(posthog.has_opted_in_capturing()).toBe(true)
expect(posthog.has_opted_out_capturing()).toBe(false)

expect(posthog.persistence?.disabled).toBe(false)
expect(posthog.sessionPersistence?.disabled).toBe(false)
})

it('should start default opted out if setting given', () => {
posthog = createPostHog({ opt_out_capturing_by_default: true })
expect(posthog.has_opted_in_capturing()).toBe(false)
expect(posthog.has_opted_out_capturing()).toBe(true)

expect(posthog.persistence?.disabled).toBe(false)
expect(posthog.sessionPersistence?.disabled).toBe(false)
})

it('should start default opted out if setting given and disable storage', () => {
posthog = createPostHog({ opt_out_capturing_by_default: true, opt_out_persistence_by_default: true })
expect(posthog.has_opted_in_capturing()).toBe(false)
expect(posthog.has_opted_out_capturing()).toBe(true)

expect(posthog.persistence?.disabled).toBe(true)
expect(posthog.sessionPersistence?.disabled).toBe(true)
})

it('should enable or disable persistence when changing opt out status', () => {
posthog = createPostHog({ opt_out_capturing_by_default: true, opt_out_persistence_by_default: true })
expect(posthog.has_opted_in_capturing()).toBe(false)
expect(posthog.persistence?.disabled).toBe(true)

posthog.opt_in_capturing()
expect(posthog.has_opted_in_capturing()).toBe(true)
expect(posthog.persistence?.disabled).toBe(false)

posthog.opt_out_capturing()
expect(posthog.has_opted_in_capturing()).toBe(false)
expect(posthog.persistence?.disabled).toBe(true)
})

describe('with do not track setting', () => {
beforeEach(() => {
;(navigator as any).doNotTrack = '1'
})

it('should respect it if explicitly set', () => {
posthog = createPostHog({ respect_dnt: true })
expect(posthog.has_opted_in_capturing()).toBe(false)
})

it('should not respect it if not explicitly set', () => {
expect(posthog.has_opted_in_capturing()).toBe(true)
})
})

describe.each([`cookie`, `localStorage`] as PostHogConfig['opt_out_capturing_persistence_type'][])(
`%s`,
(persistenceType) => {
function assertPersistenceValue(
value: string | number | null,
persistencePrefix = DEFAULT_PERSISTENCE_PREFIX
) {
const token = posthog.config.token
const expected = persistencePrefix + token
if (persistenceType === `cookie`) {
if (isNull(value)) {
expect(document!.cookie).not.toContain(expected + `=`)
} else {
expect(document!.cookie).toContain(expected + `=${value}`)
}
} else {
if (isNull(value)) {
expect(assignableWindow.localStorage.getItem(expected)).toBeNull()
} else {
expect(assignableWindow.localStorage.getItem(expected)).toBe(`${value}`)
}
}
}

beforeEach(() => {
posthog = createPostHog({
opt_out_capturing_persistence_type: persistenceType,
persistence: persistenceType,
})
})

describe(`common consent functions`, () => {
it(`should set a persistent value marking the user as opted-in for a given token`, () => {
posthog.opt_in_capturing()
assertPersistenceValue(1)
})

it(`should set a persistent value marking the user as opted-out for a given token`, () => {
posthog.opt_out_capturing()
assertPersistenceValue(0)
})

it(`should capture an event recording the opt-in action`, () => {
const onCapture = jest.fn()
posthog.on('eventCaptured', onCapture)

posthog.opt_in_capturing()
expect(onCapture).toHaveBeenCalledWith(expect.objectContaining({ event: '$opt_in' }))

onCapture.mockClear()
const captureEventName = `єνєηт`
const captureProperties = { '𝖕𝖗𝖔𝖕𝖊𝖗𝖙𝖞': `𝓿𝓪𝓵𝓾𝓮` }
benjackwhite marked this conversation as resolved.
Show resolved Hide resolved

posthog.opt_in_capturing({ captureEventName, captureProperties })
expect(onCapture).toHaveBeenCalledWith(
expect.objectContaining({
event: captureEventName,
properties: expect.objectContaining(captureProperties),
})
)
})

it(`should allow use of a custom "persistence prefix" string (with correct default behavior)`, () => {
posthog = createPostHog({
opt_out_capturing_persistence_type: persistenceType,
opt_out_capturing_cookie_prefix: CUSTOM_PERSISTENCE_PREFIX,
})
posthog.opt_out_capturing()
posthog.opt_in_capturing()

assertPersistenceValue(null)
assertPersistenceValue(1, CUSTOM_PERSISTENCE_PREFIX)

posthog.opt_out_capturing()

assertPersistenceValue(null)
assertPersistenceValue(0, CUSTOM_PERSISTENCE_PREFIX)
})

it(`should clear the persisted value`, () => {
posthog.opt_in_capturing()
assertPersistenceValue(1)
posthog.reset()
assertPersistenceValue(null)
})
})
}
)
})
1 change: 1 addition & 0 deletions src/__tests__/extensions/replay/sessionrecording.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ describe('SessionRecording', () => {
sessionManager: sessionManager,
requestRouter: new RequestRouter({ config } as any),
_addCaptureHook: jest.fn(),
consent: { isOptedOut: () => false },
} as unknown as PostHog

// defaults
Expand Down
Loading
Loading