From a46f7fcafd6e8cf7104313222370ab8c2c57e631 Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 08:48:29 +0200 Subject: [PATCH 1/8] fix: Remove complex get_config --- src/__tests__/posthog-core.js | 2 +- src/autocapture.ts | 12 +- src/config.ts | 2 +- src/decide.ts | 18 +-- .../exceptions/exception-autocapture.ts | 4 +- src/extensions/sessionrecording.ts | 25 ++-- src/extensions/toolbar.ts | 10 +- src/extensions/web-performance.ts | 8 +- src/gdpr-utils.ts | 10 +- src/posthog-core.ts | 107 ++++++++---------- src/posthog-featureflags.ts | 10 +- src/posthog-surveys.ts | 2 +- src/types.ts | 1 - 13 files changed, 98 insertions(+), 113 deletions(-) diff --git a/src/__tests__/posthog-core.js b/src/__tests__/posthog-core.js index 87a2a2ac2..fe2e93dc2 100644 --- a/src/__tests__/posthog-core.js +++ b/src/__tests__/posthog-core.js @@ -576,7 +576,7 @@ describe('init()', () => { 'a-name' ) ) - expect(given.subject.get_config('on_xhr_error')).toBe(fakeOnXHRError) + expect(given.subject.config.on_xhr_error).toBe(fakeOnXHRError) }) it('does not load decide endpoint on advanced_disable_decide', () => { diff --git a/src/autocapture.ts b/src/autocapture.ts index 5913d7070..09941d3ce 100644 --- a/src/autocapture.ts +++ b/src/autocapture.ts @@ -46,7 +46,7 @@ const autocapture = { this._isDisabledServerSide === null ? !!instance.persistence?.props[AUTOCAPTURE_DISABLED_SERVER_SIDE] : this._isDisabledServerSide - const enabled_client_side = !!instance.get_config('autocapture') + const enabled_client_side = !!instance.config.autocapture this._isAutocaptureEnabled = enabled_client_side && !disabled_server_side }, @@ -233,8 +233,8 @@ const autocapture = { elementsJson.push( this._getPropertiesFromElement( el, - instance.get_config('mask_all_element_attributes'), - instance.get_config('mask_all_text') + instance.config.mask_all_element_attributes, + instance.config.mask_all_text ) ) @@ -242,7 +242,7 @@ const autocapture = { _extend(autocaptureAugmentProperties, augmentProperties) }) - if (!instance.get_config('mask_all_text')) { + if (!instance.config.mask_all_text) { // if the element is a button or anchor tag get the span text from any // children and include it as/with the text property on the parent element if (target.tagName.toLowerCase() === 'a' || target.tagName.toLowerCase() === 'button') { @@ -305,11 +305,11 @@ const autocapture = { this.config.url_allowlist = this.config.url_allowlist.map((url) => new RegExp(url)) } - this.rageclicks = new RageClick(instance.get_config('rageclick')) + this.rageclicks = new RageClick(instance.config.rageclick) }, afterDecideResponse: function (response: DecideResponse, instance: PostHog): void { - const token = instance.get_config('token') + const token = instance.config.token if (this._initializedTokens.indexOf(token) > -1) { logger.log('autocapture already initialized for token "' + token + '"') return diff --git a/src/config.ts b/src/config.ts index 7da572bd8..fcd2b741c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,7 +1,7 @@ import { version } from '../package.json' // overriden in posthog-core, -// e.g. Config.DEBUG = Config.DEBUG || instance.get_config('debug') +// e.g. Config.DEBUG = Config.DEBUG || instance.config.debug const Config = { DEBUG: false, LIB_VERSION: version, diff --git a/src/decide.ts b/src/decide.ts index 49d434e86..3362a2124 100644 --- a/src/decide.ts +++ b/src/decide.ts @@ -18,20 +18,20 @@ export class Decide { Calls /decide endpoint to fetch options for autocapture, session recording, feature flags & compression. */ const json_data = JSON.stringify({ - token: this.instance.get_config('token'), + token: this.instance.config.token, distinct_id: this.instance.get_distinct_id(), groups: this.instance.getGroups(), person_properties: this.instance.get_property(STORED_PERSON_PROPERTIES_KEY), group_properties: this.instance.get_property(STORED_GROUP_PROPERTIES_KEY), disable_flags: - this.instance.get_config('advanced_disable_feature_flags') || - this.instance.get_config('advanced_disable_feature_flags_on_first_load') || + this.instance.config.advanced_disable_feature_flags || + this.instance.config.advanced_disable_feature_flags_on_first_load || undefined, }) const encoded_data = _base64Encode(json_data) this.instance._send_request( - `${this.instance.get_config('api_host')}/decide/?v=3`, + `${this.instance.config.api_host}/decide/?v=3`, { data: encoded_data, verbose: true }, { method: 'POST' }, (response) => this.parseDecideResponse(response as DecideResponse) @@ -61,12 +61,12 @@ export class Decide { this.instance.webPerformance?.afterDecideResponse(response) this.instance.exceptionAutocapture?.afterDecideResponse(response) - if (!this.instance.get_config('advanced_disable_feature_flags_on_first_load')) { + if (!this.instance.config.advanced_disable_feature_flags_on_first_load) { this.instance.featureFlags.receivedFeatureFlags(response) } this.instance['compression'] = {} - if (response['supportedCompression'] && !this.instance.get_config('disable_compression')) { + if (response['supportedCompression'] && !this.instance.config.disable_compression) { const compression: Partial> = {} for (const method of response['supportedCompression']) { compression[method] = true @@ -80,7 +80,7 @@ export class Decide { const surveysGenerator = window?.extendPostHogWithSurveys if (response['surveys'] && !surveysGenerator) { - loadScript(this.instance.get_config('api_host') + `/static/surveys.js`, (err) => { + loadScript(this.instance.config.api_host + `/static/surveys.js`, (err) => { if (err) { return console.error(`Could not load surveys script`, err) } @@ -92,8 +92,8 @@ export class Decide { } if (response['siteApps']) { - if (this.instance.get_config('opt_in_site_apps')) { - const apiHost = this.instance.get_config('api_host') + if (this.instance.config.opt_in_site_apps) { + const apiHost = this.instance.config.api_host for (const { id, url } of response['siteApps']) { const scriptUrl = [ apiHost, diff --git a/src/extensions/exceptions/exception-autocapture.ts b/src/extensions/exceptions/exception-autocapture.ts index 4b31ee9b3..18ac96b90 100644 --- a/src/extensions/exceptions/exception-autocapture.ts +++ b/src/extensions/exceptions/exception-autocapture.ts @@ -19,7 +19,7 @@ export class ExceptionObserver { } private debugLog(...args: any[]) { - if (this.instance.get_config('debug')) { + if (this.instance.config.debug) { console.log('PostHog.js [PostHog.ExceptionObserver]', ...args) } } @@ -125,7 +125,7 @@ export class ExceptionObserver { const propertiesToSend = { ...properties, ...errorProperties } - const posthogHost = this.instance.get_config('ui_host') || this.instance.get_config('api_host') + const posthogHost = this.instance.config.ui_host || this.instance.config.api_host errorProperties.$exception_personURL = posthogHost + '/person/' + this.instance.get_distinct_id() this.sendExceptionEvent(propertiesToSend) diff --git a/src/extensions/sessionrecording.ts b/src/extensions/sessionrecording.ts index 54e583bd0..e8d193beb 100644 --- a/src/extensions/sessionrecording.ts +++ b/src/extensions/sessionrecording.ts @@ -132,19 +132,19 @@ export class SessionRecording { isRecordingEnabled() { const enabled_server_side = !!this.instance.get_property(SESSION_RECORDING_ENABLED_SERVER_SIDE) - const enabled_client_side = !this.instance.get_config('disable_session_recording') + const enabled_client_side = !this.instance.config.disable_session_recording return enabled_server_side && enabled_client_side } isConsoleLogCaptureEnabled() { const enabled_server_side = !!this.instance.get_property(CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE) - const enabled_client_side = this.instance.get_config('enable_recording_console_log') + const enabled_client_side = this.instance.config.enable_recording_console_log return enabled_client_side ?? enabled_server_side } getRecordingVersion() { const recordingVersion_server_side = this.instance.get_property(SESSION_RECORDING_RECORDER_VERSION_SERVER_SIDE) - const recordingVersion_client_side = this.instance.get_config('session_recording')?.recorderVersion + const recordingVersion_client_side = this.instance.config.session_recording?.recorderVersion return recordingVersion_client_side || recordingVersion_server_side || 'v1' } @@ -210,7 +210,7 @@ export class SessionRecording { } // We do not switch recorder versions midway through a recording. - if (this.captureStarted || this.instance.get_config('disable_session_recording')) { + if (this.captureStarted || this.instance.config.disable_session_recording) { return } @@ -224,16 +224,13 @@ export class SessionRecording { // imported) or matches the requested recorder version, don't load script. Otherwise, remotely import // recorder.js from cdn since it hasn't been loaded. if (this.instance.__loaded_recorder_version !== this.getRecordingVersion()) { - loadScript( - this.instance.get_config('api_host') + `/static/${recorderJS}?v=${Config.LIB_VERSION}`, - (err) => { - if (err) { - return logger.error(`Could not load ${recorderJS}`, err) - } - - this._onScriptLoaded() + loadScript(this.instance.config.api_host + `/static/${recorderJS}?v=${Config.LIB_VERSION}`, (err) => { + if (err) { + return logger.error(`Could not load ${recorderJS}`, err) } - ) + + this._onScriptLoaded() + }) } else { this._onScriptLoaded() } @@ -330,7 +327,7 @@ export class SessionRecording { this.rrwebRecord = window.rrweb ? window.rrweb.record : window.rrwebRecord // only allows user to set our 'allowlisted' options - const userSessionRecordingOptions = this.instance.get_config('session_recording') + const userSessionRecordingOptions = this.instance.config.session_recording for (const [key, value] of Object.entries(userSessionRecordingOptions || {})) { if (key in sessionRecordingOptions) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/src/extensions/toolbar.ts b/src/extensions/toolbar.ts index 111a69cbf..f4e2af8ee 100644 --- a/src/extensions/toolbar.ts +++ b/src/extensions/toolbar.ts @@ -79,7 +79,7 @@ export class Toolbar { delete toolbarParams.userIntent } - if (toolbarParams['token'] && this.instance.get_config('token') === toolbarParams['token']) { + if (toolbarParams['token'] && this.instance.config.token === toolbarParams['token']) { this.loadToolbar(toolbarParams) return true } else { @@ -97,7 +97,7 @@ export class Toolbar { // only load the toolbar once, even if there are multiple instances of PostHogLib ;(window as any)['_postHogToolbarLoaded'] = true - const host = this.instance.get_config('api_host') + const host = this.instance.config.api_host // toolbar.js is served from the PostHog CDN, this has a TTL of 24 hours. // the toolbar asset includes a rotating "token" that is valid for 5 minutes. const fiveMinutesInMillis = 5 * 60 * 1000 @@ -105,11 +105,11 @@ export class Toolbar { const timestampToNearestFiveMinutes = Math.floor(Date.now() / fiveMinutesInMillis) * fiveMinutesInMillis const toolbarUrl = `${host}${host.endsWith('/') ? '' : '/'}static/toolbar.js?t=${timestampToNearestFiveMinutes}` const disableToolbarMetrics = - !POSTHOG_MANAGED_HOSTS.includes(this.instance.get_config('api_host')) && - this.instance.get_config('advanced_disable_toolbar_metrics') + !POSTHOG_MANAGED_HOSTS.includes(this.instance.config.api_host) && + this.instance.config.advanced_disable_toolbar_metrics const toolbarParams = { - token: this.instance.get_config('token'), + token: this.instance.config.token, ...params, apiURL: host, // defaults to api_host from the instance config if nothing else set ...(disableToolbarMetrics ? { instrument: false } : {}), diff --git a/src/extensions/web-performance.ts b/src/extensions/web-performance.ts index fa2f39afd..dab51fa6b 100644 --- a/src/extensions/web-performance.ts +++ b/src/extensions/web-performance.ts @@ -147,7 +147,7 @@ export class WebPerformanceObserver { } isEnabled() { - return this.instance.get_config('capture_performance') ?? this.remoteEnabled ?? false + return this.instance.config.capture_performance ?? this.remoteEnabled ?? false } afterDecideResponse(response: DecideResponse) { @@ -160,8 +160,8 @@ export class WebPerformanceObserver { _capturePerformanceEvent(event: PerformanceEntry) { // NOTE: We don't want to capture our own request events. - if (event.name.indexOf(this.instance.get_config('api_host')) === 0) { - const path = event.name.replace(this.instance.get_config('api_host'), '') + if (event.name.indexOf(this.instance.config.api_host) === 0) { + const path = event.name.replace(this.instance.config.api_host, '') if (POSTHOG_PATHS_TO_IGNORE.find((x) => path.indexOf(x) === 0)) { return @@ -174,7 +174,7 @@ export class WebPerformanceObserver { url: event.name, } - const userSessionRecordingOptions = this.instance.get_config('session_recording') + const userSessionRecordingOptions = this.instance.config.session_recording if (userSessionRecordingOptions.maskNetworkRequestFn) { networkRequest = userSessionRecordingOptions.maskNetworkRequestFn(networkRequest) diff --git a/src/gdpr-utils.ts b/src/gdpr-utils.ts index 51246f4f1..6d40f0a56 100644 --- a/src/gdpr-utils.ts +++ b/src/gdpr-utils.ts @@ -214,11 +214,11 @@ export function userOptedOut(posthog: PostHog, silenceErrors: boolean | undefine let optedOut = false try { - const token = posthog.get_config('token') - const respectDnt = posthog.get_config('respect_dnt') - const persistenceType = posthog.get_config('opt_out_capturing_persistence_type') - const persistencePrefix = posthog.get_config('opt_out_capturing_cookie_prefix') || undefined - const win = posthog.get_config('window' as any) as Window | undefined // used to override window during browser tests + const token = posthog.config.token + const respectDnt = posthog.config.respect_dnt + const persistenceType = posthog.config.opt_out_capturing_persistence_type + const persistencePrefix = posthog.config.opt_out_capturing_cookie_prefix || undefined + const win = (posthog.config as any).window as Window | undefined // used to override window during browser tests if (token) { // if there was an issue getting the token, continue method execution as normal diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 02899a09d..e17e27e99 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -117,8 +117,6 @@ const defaultConfig = (): PostHogConfig => ({ custom_campaign_params: [], custom_blocked_useragents: [], save_referrer: true, - test: false, - verbose: false, capture_pageview: true, capture_pageleave: true, // We'll only capture pageleave events if capture_pageview is also true debug: false, @@ -217,19 +215,19 @@ const create_phlib = function ( instance.webPerformance = new WebPerformanceObserver(instance) instance.webPerformance.startObservingIfEnabled() - if (instance.get_config('__preview_measure_pageview_stats')) { + if (instance.config.__preview_measure_pageview_stats) { instance.pageViewManager.startMeasuringScrollPosition() } instance.exceptionAutocapture = new ExceptionObserver(instance) - instance.__autocapture = instance.get_config('autocapture') + instance.__autocapture = instance.config.autocapture autocapture._setIsAutocaptureEnabled(instance) if (autocapture._isAutocaptureEnabled) { - instance.__autocapture = instance.get_config('autocapture') + instance.__autocapture = instance.config.autocapture const num_buckets = 100 const num_enabled_buckets = 100 - if (!autocapture.enabledForProject(instance.get_config('token'), num_buckets, num_enabled_buckets)) { + if (!autocapture.enabledForProject(instance.config.token, num_buckets, num_enabled_buckets)) { instance.__autocapture = false logger.log('Not in active bucket: disabling Automatic Event Collection.') } else if (!autocapture.isBrowserSupported()) { @@ -242,7 +240,7 @@ const create_phlib = function ( // if any instance on the page has debug = true, we set the // global debug to be true - Config.DEBUG = Config.DEBUG || instance.get_config('debug') + Config.DEBUG = Config.DEBUG || instance.config.debug // if target is not defined, we called init after the lib already // loaded, so there won't be an array of things to execute @@ -434,7 +432,7 @@ export class PostHog { this.persistence = new PostHogPersistence(this.config) this._requestQueue = new RequestQueue(this._handle_queued_event.bind(this)) - this._retryQueue = new RetryQueue(this.get_config('on_xhr_error'), this.rateLimiter) + this._retryQueue = new RetryQueue(this.config.on_xhr_error, this.rateLimiter) this.__captureHooks = [] this.__request_queue = [] @@ -464,7 +462,7 @@ export class PostHog { } if (config.bootstrap?.distinctID !== undefined) { - const uuid = this.get_config('get_device_id')(uuidv7()) + const uuid = this.config.get_device_id(uuidv7()) const deviceID = config.bootstrap?.isIdentifiedID ? uuid : config.bootstrap.distinctID this.persistence.set_user_state(config.bootstrap?.isIdentifiedID ? 'identified' : 'anonymous') this.register({ @@ -498,7 +496,7 @@ export class PostHog { // There is no need to set the distinct id // or the device id if something was already stored // in the persitence - const uuid = this.get_config('get_device_id')(uuidv7()) + const uuid = this.config.get_device_id(uuidv7()) this.register_once( { distinct_id: uuid, @@ -525,13 +523,13 @@ export class PostHog { // Pause `reloadFeatureFlags` calls in config.loaded callback. // These feature flags are loaded in the decide call made right // afterwards - const disableDecide = this.get_config('advanced_disable_decide') + const disableDecide = this.config.advanced_disable_decide if (!disableDecide) { this.featureFlags.setReloadingPaused(true) } try { - this.get_config('loaded')(this) + this.config.loaded(this) } catch (err) { console.error('`loaded` function failed', err) } @@ -540,7 +538,7 @@ export class PostHog { // this happens after so a user can call identify in // the loaded callback - if (this.get_config('capture_pageview')) { + if (this.config.capture_pageview) { this.capture('$pageview', { title: document.title }, { send_instantly: true }) } @@ -558,7 +556,7 @@ export class PostHog { _start_queue_if_opted_in(): void { if (!this.has_opted_out_capturing()) { - if (this.get_config('request_batching')) { + if (this.config.request_batching) { this._requestQueue?.poll() } } @@ -601,7 +599,7 @@ export class PostHog { // callback string to reflect that. const jsc = this._jsc const randomized_cb = '' + Math.floor(Math.random() * 100000000) - const callback_string = this.get_config('callback_fn') + '[' + randomized_cb + ']' + const callback_string = this.config.callback_fn + '[' + randomized_cb + ']' jsc[randomized_cb] = function (response: any) { delete jsc[randomized_cb] callback(response, data) @@ -611,14 +609,14 @@ export class PostHog { } _handle_unload(): void { - if (!this.get_config('request_batching')) { - if (this.get_config('capture_pageview') && this.get_config('capture_pageleave')) { + if (!this.config.request_batching) { + if (this.config.capture_pageview && this.config.capture_pageleave) { this.capture('$pageleave', null, { transport: 'sendBeacon' }) } return } - if (this.get_config('capture_pageview') && this.get_config('capture_pageleave')) { + if (this.config.capture_pageview && this.config.capture_pageleave) { this.capture('$pageleave') } @@ -655,9 +653,9 @@ export class PostHog { } const DEFAULT_OPTIONS = { - method: this.get_config('api_method'), - transport: this.get_config('api_transport'), - verbose: this.get_config('verbose'), + method: this.config.api_method, + transport: this.config.api_transport, + verbose: this.config.verbose, } options = _extend(DEFAULT_OPTIONS, options || {}) @@ -667,7 +665,7 @@ export class PostHog { const useSendBeacon = 'sendBeacon' in window.navigator && options.transport === 'sendBeacon' url = addParamsToURL(url, options.urlQueryArgs || {}, { - ip: this.get_config('ip'), + ip: this.config.ip, }) if (useSendBeacon) { @@ -684,12 +682,12 @@ export class PostHog { xhr({ url: url, data: data, - headers: this.get_config('xhr_headers'), + headers: this.config.xhr_headers, options: options, callback, retriesPerformedSoFar: 0, retryQueue: this._retryQueue, - onXHRError: this.get_config('on_xhr_error'), + onXHRError: this.config.on_xhr_error, onResponse: this.rateLimiter.checkForLimiting, }) } catch (e) { @@ -854,17 +852,17 @@ export class PostHog { return } - if (_isBlockedUA(userAgent, this.get_config('custom_blocked_useragents'))) { + if (_isBlockedUA(userAgent, this.config.custom_blocked_useragents)) { return } // update persistence this.sessionPersistence.update_search_keyword() - if (this.get_config('store_google')) { + if (this.config.store_google) { this.sessionPersistence.update_campaign_params() } - if (this.get_config('save_referrer')) { + if (this.config.save_referrer) { this.sessionPersistence.update_referrer_info() } @@ -879,26 +877,19 @@ export class PostHog { data['$set_once'] = options['$set_once'] } - data = _copyAndTruncateStrings( - data, - options._noTruncate ? null : this.get_config('properties_string_max_length') - ) + data = _copyAndTruncateStrings(data, options._noTruncate ? null : this.config.properties_string_max_length) data.timestamp = options.timestamp || new Date() - if (this.get_config('debug')) { + if (this.config.debug) { logger.log('PostHog.js send', data) } const jsonData = JSON.stringify(data) - const url = this.get_config('api_host') + (options.endpoint || '/e/') + const url = this.config.api_host + (options.endpoint || '/e/') const has_unique_traits = options !== __NOOPTIONS - if ( - this.get_config('request_batching') && - (!has_unique_traits || options._batchKey) && - !options.send_instantly - ) { + if (this.config.request_batching && (!has_unique_traits || options._batchKey) && !options.send_instantly) { this._requestQueue.enqueue(url, data, options) } else { this.__compress_and_send_json_request(url, jsonData, options) @@ -926,7 +917,7 @@ export class PostHog { // set defaults const start_timestamp = this.persistence.remove_event_timer(event_name) let properties = { ...event_properties } - properties['token'] = this.get_config('token') + properties['token'] = this.config.token if (event_name === '$snapshot') { const persistenceProps = { ...this.persistence.properties(), ...this.sessionPersistence.properties() } @@ -942,7 +933,7 @@ export class PostHog { properties['$window_id'] = windowId } - if (this.get_config('__preview_measure_pageview_stats')) { + if (this.config.__preview_measure_pageview_stats) { let performanceProperties: Record = {} if (event_name === '$pageview') { performanceProperties = this.pageViewManager.doPageView() @@ -983,7 +974,7 @@ export class PostHog { properties ) - const property_blacklist = this.get_config('property_blacklist') + const property_blacklist = this.config.property_blacklist if (_isArray(property_blacklist)) { _each(property_blacklist, function (blacklisted_prop) { delete properties[blacklisted_prop] @@ -992,7 +983,7 @@ export class PostHog { console.error('Invalid value for property_blacklist config: ' + property_blacklist) } - const sanitize_properties = this.get_config('sanitize_properties') + const sanitize_properties = this.config.sanitize_properties if (sanitize_properties) { properties = sanitize_properties(properties, event_name) } @@ -1432,7 +1423,7 @@ export class PostHog { this.sessionPersistence?.clear() this.persistence?.set_user_state('anonymous') this.sessionManager?.resetSessionId() - const uuid = this.get_config('get_device_id')(uuidv7()) + const uuid = this.config.get_device_id(uuidv7()) this.register_once( { distinct_id: uuid, @@ -1687,10 +1678,10 @@ export class PostHog { if (_isObject(config)) { _extend(this.config, config) - if (!this.get_config('persistence_name')) { + if (!this.config.persistence_name) { this.config.persistence_name = this.config.cookie_name } - if (!this.get_config('disable_persistence')) { + if (!this.config.disable_persistence) { this.config.disable_persistence = this.config.disable_cookie } @@ -1700,7 +1691,7 @@ export class PostHog { if (localStore.is_supported() && localStore.get('ph_debug') === 'true') { this.config.debug = true } - if (this.get_config('debug')) { + if (this.config.debug) { Config.DEBUG = true } @@ -1802,7 +1793,7 @@ export class PostHog { } toString(): string { - let name = this.get_config('name') ?? PRIMARY_INSTANCE_NAME + let name = this.config.name ?? PRIMARY_INSTANCE_NAME if (name !== PRIMARY_INSTANCE_NAME) { name = PRIMARY_INSTANCE_NAME + '.' + name } @@ -1811,7 +1802,7 @@ export class PostHog { // perform some housekeeping around GDPR opt-in/out state _gdpr_init(): void { - const is_localStorage_requested = this.get_config('opt_out_capturing_persistence_type') === 'localStorage' + const is_localStorage_requested = this.config.opt_out_capturing_persistence_type === 'localStorage' // try to convert opt-in/out cookies to localStorage if possible if (is_localStorage_requested && localStore.is_supported()) { @@ -1836,11 +1827,11 @@ export class PostHog { // used as an initial state while GDPR information is being collected } else if ( !this.has_opted_in_capturing() && - (this.get_config('opt_out_capturing_by_default') || cookieStore.get('ph_optout')) + (this.config.opt_out_capturing_by_default || cookieStore.get('ph_optout')) ) { cookieStore.remove('ph_optout') this.opt_out_capturing({ - clear_persistence: this.get_config('opt_out_persistence_by_default'), + clear_persistence: this.config.opt_out_persistence_by_default, }) } } @@ -1861,10 +1852,10 @@ export class PostHog { return } - if (!this.get_config('disable_persistence') && this.persistence?.disabled !== disabled) { + if (!this.config.disable_persistence && this.persistence?.disabled !== disabled) { this.persistence?.set_disabled(disabled) } - if (!this.get_config('disable_persistence') && this.sessionPersistence?.disabled !== disabled) { + if (!this.config.disable_persistence && this.sessionPersistence?.disabled !== disabled) { this.sessionPersistence?.set_disabled(disabled) } } @@ -1877,11 +1868,11 @@ export class PostHog { options = _extend( { capture: this.capture.bind(this), - persistence_type: this.get_config('opt_out_capturing_persistence_type'), - cookie_prefix: this.get_config('opt_out_capturing_cookie_prefix'), - cookie_expiration: this.get_config('cookie_expiration'), - cross_subdomain_cookie: this.get_config('cross_subdomain_cookie'), - secure_cookie: this.get_config('secure_cookie'), + persistence_type: this.config.opt_out_capturing_persistence_type, + cookie_prefix: this.config.opt_out_capturing_cookie_prefix, + cookie_expiration: this.config.cookie_expiration, + cross_subdomain_cookie: this.config.cross_subdomain_cookie, + secure_cookie: this.config.secure_cookie, }, options || {} ) @@ -1891,7 +1882,7 @@ export class PostHog { options['persistence_type'] = 'cookie' } - return func(this.get_config('token'), { + return func(this.config.token, { capture: options['capture'], captureEventName: options['capture_event_name'], captureProperties: options['capture_properties'], diff --git a/src/posthog-featureflags.ts b/src/posthog-featureflags.ts index 0e3a40a0f..07aa1d02f 100644 --- a/src/posthog-featureflags.ts +++ b/src/posthog-featureflags.ts @@ -168,7 +168,7 @@ export class PostHogFeatureFlags { _reloadFeatureFlagsRequest(): void { this.setReloadingPaused(true) - const token = this.instance.get_config('token') + const token = this.instance.config.token const personProperties = this.instance.get_property(STORED_PERSON_PROPERTIES_KEY) const groupProperties = this.instance.get_property(STORED_GROUP_PROPERTIES_KEY) const json_data = JSON.stringify({ @@ -178,12 +178,12 @@ export class PostHogFeatureFlags { $anon_distinct_id: this.$anon_distinct_id, person_properties: personProperties, group_properties: groupProperties, - disable_flags: this.instance.get_config('advanced_disable_feature_flags') || undefined, + disable_flags: this.instance.config.advanced_disable_feature_flags || undefined, }) const encoded_data = _base64Encode(json_data) this.instance._send_request( - this.instance.get_config('api_host') + '/decide/?v=3', + this.instance.config.api_host + '/decide/?v=3', { data: encoded_data }, { method: 'POST' }, this.instance._prepare_callback((response) => { @@ -350,9 +350,7 @@ export class PostHogFeatureFlags { if (!existing_early_access_features || force_reload) { this.instance._send_request( - `${this.instance.get_config('api_host')}/api/early_access_features/?token=${this.instance.get_config( - 'token' - )}`, + `${this.instance.config.api_host}/api/early_access_features/?token=${this.config. 'token )}`, {}, { method: 'GET' }, (response) => { diff --git a/src/posthog-surveys.ts b/src/posthog-surveys.ts index aab07708e..a050b5349 100644 --- a/src/posthog-surveys.ts +++ b/src/posthog-surveys.ts @@ -13,7 +13,7 @@ export class PostHogSurveys { const existingSurveys = this.instance.get_property(SURVEYS) if (!existingSurveys || forceReload) { this.instance._send_request( - `${this.instance.get_config('api_host')}/api/surveys/?token=${this.instance.get_config('token')}`, + `${this.instance.config.api_host}/api/surveys/?token=${this.instance.config.token}`, {}, { method: 'GET' }, (response) => { diff --git a/src/types.ts b/src/types.ts index 7f6df8399..7fd90f86e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,7 +75,6 @@ export interface PostHogConfig { // defaults to the empty array custom_blocked_useragents: string[] save_referrer: boolean - test: boolean verbose: boolean capture_pageview: boolean capture_pageleave: boolean From 7e0a259b865db8aba1f59efa45dc7168a0afd6fe Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 08:49:48 +0200 Subject: [PATCH 2/8] Fix --- src/posthog-core.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index e17e27e99..11df7e41c 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -120,6 +120,7 @@ const defaultConfig = (): PostHogConfig => ({ capture_pageview: true, capture_pageleave: true, // We'll only capture pageleave events if capture_pageview is also true debug: false, + verbose: false, cookie_expiration: 365, upgrade: false, disable_session_recording: false, From f87eb5d20e335bad7737e77596418d7c6f2f759a Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 08:52:40 +0200 Subject: [PATCH 3/8] Fix --- src/posthog-featureflags.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posthog-featureflags.ts b/src/posthog-featureflags.ts index 07aa1d02f..4b9e3f873 100644 --- a/src/posthog-featureflags.ts +++ b/src/posthog-featureflags.ts @@ -350,7 +350,7 @@ export class PostHogFeatureFlags { if (!existing_early_access_features || force_reload) { this.instance._send_request( - `${this.instance.config.api_host}/api/early_access_features/?token=${this.config. 'token )}`, + `${this.instance.config.api_host}/api/early_access_features/?token=${this.instance.config.token}`, {}, { method: 'GET' }, (response) => { From be0acb828becfad5a099b249f110165df7eab59e Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 09:15:03 +0200 Subject: [PATCH 4/8] Fix tests --- src/__tests__/autocapture.js | 97 ++++++------- src/__tests__/compression.js | 12 +- src/__tests__/decide.js | 132 ++++++++---------- .../exceptions/exception-observer.test.ts | 2 +- src/__tests__/extensions/sessionrecording.js | 2 +- src/__tests__/extensions/toolbar.js | 2 +- .../extensions/web-performance.test.ts | 2 +- src/__tests__/featureflags.js | 2 +- src/__tests__/gdpr-utils.js | 25 ++-- src/__tests__/posthog-core.js | 9 +- src/__tests__/posthog-core.loaded.js | 4 +- src/__tests__/surveys.js | 2 +- src/posthog-core.ts | 7 - 13 files changed, 123 insertions(+), 175 deletions(-) diff --git a/src/__tests__/autocapture.js b/src/__tests__/autocapture.js index b8ef31643..f40e3ac4f 100644 --- a/src/__tests__/autocapture.js +++ b/src/__tests__/autocapture.js @@ -474,14 +474,10 @@ describe('Autocapture system', () => { return 'distinctid' }, capture: sandbox.spy(), - get_config: sandbox.spy(function (key) { - switch (key) { - case 'mask_all_element_attributes': - return false - case 'rageclick': - return true - } - }), + config: { + mask_all_element_attributes: false, + rageclick: true, + }, } }) @@ -506,18 +502,12 @@ describe('Autocapture system', () => { it('should add the custom property when an element matching any of the event selectors is clicked', () => { lib = { _prepare_callback: sandbox.spy((callback) => callback), - get_config: sandbox.spy(function (key) { - switch (key) { - case 'api_host': - return 'https://test.com' - case 'token': - return 'testtoken' - case 'mask_all_element_attributes': - return false - case 'autocapture': - return true - } - }), + config: { + api_host: 'https://test.com', + token: 'testtoken', + mask_all_element_attributes: false, + autocapture: true, + }, token: 'testtoken', capture: sandbox.spy(), get_distinct_id() { @@ -614,21 +604,15 @@ describe('Autocapture system', () => { expect(captureProperties).toHaveProperty('parent-augment', 'the parent') }) - it('should not capture events when get_config returns false, when an element matching any of the event selectors is clicked', () => { + it('should not capture events when config returns false, when an element matching any of the event selectors is clicked', () => { lib = { _prepare_callback: sandbox.spy((callback) => callback), - get_config: sandbox.spy(function (key) { - switch (key) { - case 'api_host': - return 'https://test.com' - case 'token': - return 'testtoken' - case 'mask_all_element_attributes': - return false - case 'autocapture': - return false - } - }), + config: { + api_host: 'https://test.com', + token: 'testtoken', + mask_all_element_attributes: false, + autocapture: false, + }, token: 'testtoken', capture: sandbox.spy(), get_distinct_id() { @@ -666,21 +650,15 @@ describe('Autocapture system', () => { lib.capture.resetHistory() }) - it('should not capture events when get_config returns true but server setting is disabled', () => { + it('should not capture events when config returns true but server setting is disabled', () => { lib = { _prepare_callback: sandbox.spy((callback) => callback), - get_config: sandbox.spy(function (key) { - switch (key) { - case 'api_host': - return 'https://test.com' - case 'token': - return 'testtoken' - case 'mask_all_element_attributes': - return false - case 'autocapture': - return true - } - }), + config: { + api_host: 'https://test.com', + token: 'testtoken', + mask_all_element_attributes: false, + autocapture: true, + }, token: 'testtoken', capture: sandbox.spy(), get_distinct_id() { @@ -1035,7 +1013,12 @@ describe('Autocapture system', () => { ` - const newLib = { ...lib, get_config: jest.fn(() => true) } + const newLib = { + ...lib, + config: { + // TODO + }, + } document.body.innerHTML = dom const button1 = document.getElementById('button1') @@ -1057,7 +1040,12 @@ describe('Autocapture system', () => { ` - const newLib = { ...lib, get_config: jest.fn(() => true) } + const newLib = { + ...lib, + config: { + // TODO: Return true + }, + } document.body.innerHTML = dom const a = document.getElementById('a1') @@ -1075,19 +1063,14 @@ describe('Autocapture system', () => { }) describe('_addDomEventHandlers', () => { - const sandbox = sinon.createSandbox() - const lib = { capture: sinon.spy(), get_distinct_id() { return 'distinctid' }, - get_config: sandbox.spy(function (key) { - switch (key) { - case 'mask_all_element_attributes': - return false - } - }), + config: { + mask_all_element_attributes: false, + }, } let navigateSpy @@ -1125,7 +1108,7 @@ describe('Autocapture system', () => { given('persistence', () => ({ props: {}, register: jest.fn() })) given('posthog', () => ({ - get_config: jest.fn().mockImplementation((key) => given.config[key]), + config: given.config, token: 'testtoken', capture: jest.fn(), get_distinct_id: () => 'distinctid', diff --git a/src/__tests__/compression.js b/src/__tests__/compression.js index 2904fe5bd..53a5b6688 100644 --- a/src/__tests__/compression.js +++ b/src/__tests__/compression.js @@ -69,14 +69,10 @@ describe('Payload Compression', () => { throw new Error('Should not get here') } }), - get_config: sandbox.spy(function (key) { - switch (key) { - case 'api_host': - return 'https://test.com' - case 'token': - return 'testtoken' - } - }), + config: { + api_host: 'https://test.com', + token: 'testtoken', + }, token: 'testtoken', get_distinct_id() { return 'distinctid' diff --git a/src/__tests__/decide.js b/src/__tests__/decide.js index 20122a342..ca88dfa4f 100644 --- a/src/__tests__/decide.js +++ b/src/__tests__/decide.js @@ -3,10 +3,28 @@ import { Decide } from '../decide' import { _base64Encode } from '../utils' import { PostHogPersistence } from '../posthog-persistence' +const expectDecodedSendRequest = (send_request, data) => { + const lastCall = send_request.mock.calls[send_request.mock.calls.length - 1] + + const decoded = JSON.parse(atob(lastCall[1].data)) + // Helper to give us more accurate error messages + expect(decoded).toEqual(data) + + expect(given.posthog._send_request).toHaveBeenCalledWith( + 'https://test.com/decide/?v=3', + { + data: _base64Encode(JSON.stringify(data)), + verbose: true, + }, + { method: 'POST' }, + expect.any(Function) + ) +} + describe('Decide', () => { given('decide', () => new Decide(given.posthog)) given('posthog', () => ({ - get_config: jest.fn().mockImplementation((key) => given.config[key]), + config: given.config, persistence: new PostHogPersistence(given.config), register: (props) => given.posthog.persistence.register(props), unregister: (key) => given.posthog.persistence.unregister(key), @@ -54,21 +72,11 @@ describe('Decide', () => { it('should call instance._send_request on constructor', () => { given.subject() - expect(given.posthog._send_request).toHaveBeenCalledWith( - 'https://test.com/decide/?v=3', - { - data: _base64Encode( - JSON.stringify({ - token: 'testtoken', - distinct_id: 'distinctid', - groups: { organization: '5' }, - }) - ), - verbose: true, - }, - { method: 'POST' }, - expect.any(Function) - ) + expectDecodedSendRequest(given.posthog._send_request, { + token: 'testtoken', + distinct_id: 'distinctid', + groups: { organization: '5' }, + }) }) it('should send all stored properties with decide request', () => { @@ -78,89 +86,59 @@ describe('Decide', () => { }) given.subject() - expect(given.posthog._send_request).toHaveBeenCalledWith( - 'https://test.com/decide/?v=3', - { - data: _base64Encode( - JSON.stringify({ - token: 'testtoken', - distinct_id: 'distinctid', - groups: { organization: '5' }, - person_properties: { key: 'value' }, - group_properties: { organization: { orgName: 'orgValue' } }, - }) - ), - verbose: true, - }, - { method: 'POST' }, - expect.any(Function) - ) + expectDecodedSendRequest(given.posthog._send_request, { + token: 'testtoken', + distinct_id: 'distinctid', + groups: { organization: '5' }, + person_properties: { key: 'value' }, + group_properties: { organization: { orgName: 'orgValue' } }, + }) }) it('should send disable flags with decide request when config is set', () => { - given.posthog.register({ - $stored_person_properties: { key: 'value' }, - $stored_group_properties: { organization: { orgName: 'orgValue' } }, - }) given('config', () => ({ api_host: 'https://test.com', token: 'testtoken', persistence: 'memory', advanced_disable_feature_flags: true, })) + given.posthog.register({ + $stored_person_properties: { key: 'value' }, + $stored_group_properties: { organization: { orgName: 'orgValue' } }, + }) given.subject() - expect(given.posthog._send_request).toHaveBeenCalledWith( - 'https://test.com/decide/?v=3', - { - data: _base64Encode( - JSON.stringify({ - token: 'testtoken', - distinct_id: 'distinctid', - groups: { organization: '5' }, - person_properties: { key: 'value' }, - group_properties: { organization: { orgName: 'orgValue' } }, - disable_flags: true, - }) - ), - verbose: true, - }, - { method: 'POST' }, - expect.any(Function) - ) + expectDecodedSendRequest(given.posthog._send_request, { + token: 'testtoken', + distinct_id: 'distinctid', + groups: { organization: '5' }, + person_properties: { key: 'value' }, + group_properties: { organization: { orgName: 'orgValue' } }, + disable_flags: true, + }) }) it('should send disable flags with decide request when config for advanced_disable_feature_flags_on_first_load is set', () => { - given.posthog.register({ - $stored_person_properties: { key: 'value' }, - $stored_group_properties: { organization: { orgName: 'orgValue' } }, - }) given('config', () => ({ api_host: 'https://test.com', token: 'testtoken', persistence: 'memory', advanced_disable_feature_flags_on_first_load: true, })) + given.posthog.register({ + $stored_person_properties: { key: 'value' }, + $stored_group_properties: { organization: { orgName: 'orgValue' } }, + }) given.subject() - expect(given.posthog._send_request).toHaveBeenCalledWith( - 'https://test.com/decide/?v=3', - { - data: _base64Encode( - JSON.stringify({ - token: 'testtoken', - distinct_id: 'distinctid', - groups: { organization: '5' }, - person_properties: { key: 'value' }, - group_properties: { organization: { orgName: 'orgValue' } }, - disable_flags: true, - }) - ), - verbose: true, - }, - { method: 'POST' }, - expect.any(Function) - ) + expectDecodedSendRequest(given.posthog._send_request, { + token: 'testtoken', + distinct_id: 'distinctid', + groups: { organization: '5' }, + person_properties: { key: 'value' }, + group_properties: { organization: { orgName: 'orgValue' } }, + disable_flags: true, + }) }) }) diff --git a/src/__tests__/extensions/exceptions/exception-observer.test.ts b/src/__tests__/extensions/exceptions/exception-observer.test.ts index 9bbb49f5c..42833cf46 100644 --- a/src/__tests__/extensions/exceptions/exception-observer.test.ts +++ b/src/__tests__/extensions/exceptions/exception-observer.test.ts @@ -13,7 +13,7 @@ describe('Exception Observer', () => { beforeEach(() => { mockPostHogInstance = { - get_config: jest.fn((key: string) => mockConfig[key as keyof PostHogConfig]), + config: mockConfig, get_distinct_id: jest.fn(() => 'mock-distinct-id'), capture: mockCapture, } diff --git a/src/__tests__/extensions/sessionrecording.js b/src/__tests__/extensions/sessionrecording.js index bc68b1108..b23080336 100644 --- a/src/__tests__/extensions/sessionrecording.js +++ b/src/__tests__/extensions/sessionrecording.js @@ -45,7 +45,7 @@ describe('SessionRecording', () => { : property_key === SESSION_RECORDING_ENABLED_SERVER_SIDE ? given.$session_recording_enabled_server_side : given.$console_log_enabled_server_side, - get_config: jest.fn().mockImplementation((key) => given.config[key]), + config: given.config, capture: jest.fn(), persistence: { register: jest.fn() }, sessionManager: given.sessionManager, diff --git a/src/__tests__/extensions/toolbar.js b/src/__tests__/extensions/toolbar.js index b18a4f01e..91445dcf3 100644 --- a/src/__tests__/extensions/toolbar.js +++ b/src/__tests__/extensions/toolbar.js @@ -10,7 +10,7 @@ describe('Toolbar', () => { given('toolbar', () => new Toolbar(given.lib)) given('lib', () => ({ - get_config: jest.fn().mockImplementation((key) => given.config[key]), + config: given.config, set_config: jest.fn(), })) diff --git a/src/__tests__/extensions/web-performance.test.ts b/src/__tests__/extensions/web-performance.test.ts index 5e666a51a..96af1146c 100644 --- a/src/__tests__/extensions/web-performance.test.ts +++ b/src/__tests__/extensions/web-performance.test.ts @@ -35,7 +35,7 @@ describe('WebPerformance', () => { beforeEach(() => { mockPostHogInstance = { - get_config: jest.fn((key: string) => mockConfig[key as keyof PostHogConfig]), + config: mockConfig, sessionRecording: { onRRwebEmit: jest.fn(), }, diff --git a/src/__tests__/featureflags.js b/src/__tests__/featureflags.js index e7a46cd81..170f159c4 100644 --- a/src/__tests__/featureflags.js +++ b/src/__tests__/featureflags.js @@ -13,7 +13,7 @@ describe('featureflags', () => { persistence: 'memory', })), given('instance', () => ({ - get_config: jest.fn().mockImplementation((key) => given.config[key]), + config: given.config, get_distinct_id: () => 'blah id', getGroups: () => {}, _prepare_callback: (callback) => callback, diff --git a/src/__tests__/gdpr-utils.js b/src/__tests__/gdpr-utils.js index c8b02e2cc..64433a340 100644 --- a/src/__tests__/gdpr-utils.js +++ b/src/__tests__/gdpr-utils.js @@ -473,13 +473,12 @@ describe(`GDPR utils`, () => { describe(`addOptOutCheckPostHogLib`, () => { const captureEventName = `єνєηт` const captureProperties = { '𝖕𝖗𝖔𝖕𝖊𝖗𝖙𝖞': `𝓿𝓪𝓵𝓾𝓮` } - let getConfig, capture, postHogLib + let capture, postHogLib - function setupMocks(getConfigFunc, silenceErrors = false) { - getConfig = sinon.spy((name) => getConfigFunc()[name]) + function setupMocks(config, silenceErrors = false) { capture = sinon.spy() postHogLib = { - get_config: getConfig, + config, capture: undefined, } postHogLib.capture = gdpr.addOptOutCheck(postHogLib, capture, silenceErrors) @@ -488,7 +487,7 @@ describe(`GDPR utils`, () => { forPersistenceTypes(function (persistenceType) { it(`should call the wrapped method if the user is neither opted in or opted out`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ token, opt_out_capturing_persistence_type: persistenceType })) + setupMocks({ token, opt_out_capturing_persistence_type: persistenceType }) postHogLib.capture(captureEventName, captureProperties) @@ -498,7 +497,7 @@ describe(`GDPR utils`, () => { it(`should call the wrapped method if the user is opted in`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ token, opt_out_capturing_persistence_type: persistenceType })) + setupMocks({ token, opt_out_capturing_persistence_type: persistenceType }) gdpr.optIn(token, { persistenceType }) postHogLib.capture(captureEventName, captureProperties) @@ -509,7 +508,7 @@ describe(`GDPR utils`, () => { it(`should not call the wrapped method if the user is opted out`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ token, opt_out_capturing_persistence_type: persistenceType })) + setupMocks({ token, opt_out_capturing_persistence_type: persistenceType }) gdpr.optOut(token, { persistenceType }) postHogLib.capture(captureEventName, captureProperties) @@ -520,7 +519,7 @@ describe(`GDPR utils`, () => { it(`should not invoke the callback directly if the user is neither opted in or opted out`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ token, opt_out_capturing_persistence_type: persistenceType })) + setupMocks({ token, opt_out_capturing_persistence_type: persistenceType }) const callback = sinon.spy() postHogLib.capture(captureEventName, captureProperties, callback) @@ -531,7 +530,7 @@ describe(`GDPR utils`, () => { it(`should not invoke the callback directly if the user is opted in`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ token, opt_out_capturing_persistence_type: persistenceType })) + setupMocks({ token, opt_out_capturing_persistence_type: persistenceType }) const callback = sinon.spy() gdpr.optIn(token, { persistenceType }) @@ -543,7 +542,7 @@ describe(`GDPR utils`, () => { it(`should invoke the callback directly if the user is opted out`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ token, opt_out_capturing_persistence_type: persistenceType })) + setupMocks({ token, opt_out_capturing_persistence_type: persistenceType }) const callback = sinon.spy() gdpr.optOut(token, { persistenceType }) @@ -555,7 +554,7 @@ describe(`GDPR utils`, () => { it(`should call the wrapped method if there is no token available`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ token: null, opt_out_capturing_persistence_type: persistenceType })) + setupMocks({ token: null, opt_out_capturing_persistence_type: persistenceType }) gdpr.optIn(token, { persistenceType }) postHogLib.capture(captureEventName, captureProperties) @@ -593,11 +592,11 @@ describe(`GDPR utils`, () => { it(`should allow use of a custom "persistence prefix" string`, () => { TOKENS.forEach((token) => { - setupMocks(() => ({ + setupMocks({ token, opt_out_capturing_persistence_type: persistenceType, opt_out_capturing_cookie_prefix: CUSTOM_PERSISTENCE_PREFIX, - })) + }) gdpr.optOut(token, { persistenceType, persistencePrefix: CUSTOM_PERSISTENCE_PREFIX }) postHogLib.capture(captureEventName, captureProperties) diff --git a/src/__tests__/posthog-core.js b/src/__tests__/posthog-core.js index fe2e93dc2..4991c86cb 100644 --- a/src/__tests__/posthog-core.js +++ b/src/__tests__/posthog-core.js @@ -38,7 +38,6 @@ describe('capture()', () => { given('overrides', () => ({ __loaded: true, - get_config: (key) => given.config?.[key], config: given.config, persistence: { remove_event_timer: jest.fn(), @@ -187,7 +186,7 @@ describe('_calculate_event_properties()', () => { given('options', () => ({})) given('overrides', () => ({ - get_config: (key) => given.config[key], + config: given.config, persistence: { properties: () => ({ distinct_id: 'abc', persistent: 'prop' }), remove_event_timer: jest.fn(), @@ -298,7 +297,7 @@ describe('_handle_unload()', () => { given('subject', () => () => given.lib._handle_unload()) given('overrides', () => ({ - get_config: (key) => given.config[key], + config: given.config, capture: jest.fn(), compression: {}, _requestQueue: { @@ -369,7 +368,7 @@ describe('__compress_and_send_json_request', () => { given('overrides', () => ({ compression: {}, _send_request: jest.fn(), - get_config: () => false, + config: {}, })) it('handles base64 compression', () => { @@ -888,7 +887,7 @@ describe('_loaded()', () => { given('subject', () => () => given.lib._loaded()) given('overrides', () => ({ - get_config: (key) => given.config?.[key], + config: given.config, capture: jest.fn(), featureFlags: { setReloadingPaused: jest.fn(), diff --git a/src/__tests__/posthog-core.loaded.js b/src/__tests__/posthog-core.loaded.js index 4f7ce5e8b..99f7da655 100644 --- a/src/__tests__/posthog-core.loaded.js +++ b/src/__tests__/posthog-core.loaded.js @@ -13,7 +13,7 @@ describe('loaded() with flags', () => { given('subject', () => () => given.lib._loaded()) given('overrides', () => ({ - get_config: (key) => given.config?.[key], + config: given.config, capture: jest.fn(), featureFlags: { setReloadingPaused: jest.fn(), @@ -39,7 +39,7 @@ describe('loaded() with flags', () => { })) given('overrides', () => ({ - get_config: (key) => given.config?.[key], + config: given.config, capture: jest.fn(), _send_request: jest.fn((host, data, header, callback) => setTimeout(() => callback({ status: 200 }), 1000)), _start_queue_if_opted_in: jest.fn(), diff --git a/src/__tests__/surveys.js b/src/__tests__/surveys.js index 20024e24b..073e21a11 100644 --- a/src/__tests__/surveys.js +++ b/src/__tests__/surveys.js @@ -9,7 +9,7 @@ describe('surveys', () => { persistence: 'memory', })) given('instance', () => ({ - get_config: jest.fn().mockImplementation((key) => given.config[key]), + config: given.config, _prepare_callback: (callback) => callback, persistence: new PostHogPersistence(given.config), register: (props) => given.instance.persistence.register(props), diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 11df7e41c..58b39b775 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -1741,13 +1741,6 @@ export class PostHog { return this.toolbar.loadToolbar(params) } - /** - * returns the current config object for the library. - */ - get_config(prop_name: K): PostHogConfig[K] { - return this.config?.[prop_name] - } - /** * Returns the value of the super property named property_name. If no such * property is set, get_property() will return the undefined value. From 1d7ced148484ba164902ee843efffa41aa98b66b Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 09:27:12 +0200 Subject: [PATCH 5/8] Fix tests --- src/__tests__/featureflags.js | 80 ++++++++++++----------------------- 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/src/__tests__/featureflags.js b/src/__tests__/featureflags.js index 170f159c4..26f6ec5e8 100644 --- a/src/__tests__/featureflags.js +++ b/src/__tests__/featureflags.js @@ -8,26 +8,25 @@ jest.spyOn(global, 'setTimeout') describe('featureflags', () => { given('decideEndpointWasHit', () => false) - given('config', () => ({ - token: 'testtoken', + + const config = { + token: 'random fake token', persistence: 'memory', - })), - given('instance', () => ({ - config: given.config, - get_distinct_id: () => 'blah id', - getGroups: () => {}, - _prepare_callback: (callback) => callback, - persistence: new PostHogPersistence(given.config), - register: (props) => given.instance.persistence.register(props), - unregister: (key) => given.instance.persistence.unregister(key), - get_property: (key) => given.instance.persistence.props[key], - capture: () => {}, - decideEndpointWasHit: given.decideEndpointWasHit, - _send_request: jest - .fn() - .mockImplementation((url, data, headers, callback) => callback(given.decideResponse)), - reloadFeatureFlags: () => given.featureFlags.reloadFeatureFlags(), - })) + } + given('instance', () => ({ + config, + get_distinct_id: () => 'blah id', + getGroups: () => {}, + _prepare_callback: (callback) => callback, + persistence: new PostHogPersistence(config), + register: (props) => given.instance.persistence.register(props), + unregister: (key) => given.instance.persistence.unregister(key), + get_property: (key) => given.instance.persistence.props[key], + capture: () => {}, + decideEndpointWasHit: given.decideEndpointWasHit, + _send_request: jest.fn().mockImplementation((url, data, headers, callback) => callback(given.decideResponse)), + reloadFeatureFlags: () => given.featureFlags.reloadFeatureFlags(), + })) given('featureFlags', () => new PostHogFeatureFlags(given.instance)) @@ -216,11 +215,6 @@ describe('featureflags', () => { }, })) - given('config', () => ({ - token: 'random fake token', - persistence: 'memory', - })) - it('onFeatureFlags should not be called immediately if feature flags not loaded', () => { var called = false let _flags = [] @@ -323,10 +317,12 @@ describe('featureflags', () => { earlyAccessFeatures: [EARLY_ACCESS_FEATURE_FIRST], })) - given('config', () => ({ - token: 'random fake token', - api_host: 'https://decide.com', - })) + beforeEach(() => { + given.instance.config = { + ...given.instance.config, + api_host: 'https://decide.com', + } + }) it('getEarlyAccessFeatures requests early access features if not present', () => { given.featureFlags.getEarlyAccessFeatures((data) => { @@ -467,11 +463,6 @@ describe('featureflags', () => { }, })) - given('config', () => ({ - token: 'random fake token', - persistence: 'memory', - })) - it('on providing anonDistinctId', () => { given.featureFlags.setAnonymousDistinctId('rando_id') given.featureFlags.reloadFeatureFlags() @@ -561,11 +552,11 @@ describe('featureflags', () => { }) it('on providing config advanced_disable_feature_flags', () => { - given('config', () => ({ - token: 'random fake token', - persistence: 'memory', + given.instance.config = { + ...given.instance.config, advanced_disable_feature_flags: true, - })) + } + given.featureFlags.reloadFeatureFlags() jest.runAllTimers() @@ -595,11 +586,6 @@ describe('featureflags', () => { }, })) - given('config', () => ({ - token: 'random fake token', - persistence: 'memory', - })) - it('on providing personProperties updates properties successively', () => { given.featureFlags.setPersonPropertiesForFlags({ a: 'b', c: 'd' }) given.featureFlags.setPersonPropertiesForFlags({ x: 'y', c: 'e' }) @@ -736,11 +722,6 @@ describe('featureflags', () => { errorsWhileComputingFlags: true, })) - given('config', () => ({ - token: 'random fake token', - persistence: 'memory', - })) - it('should return combined results', () => { given.featureFlags.reloadFeatureFlags() @@ -763,11 +744,6 @@ describe('featureflags', () => { errorsWhileComputingFlags: false, })) - given('config', () => ({ - token: 'random fake token', - persistence: 'memory', - })) - it('should return combined results', () => { given.featureFlags.reloadFeatureFlags() From e993516e24940c64f178d88e08e08f55b4012c28 Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 09:38:04 +0200 Subject: [PATCH 6/8] Fix? --- src/__tests__/autocapture.js | 22 ++++++++------------ src/__tests__/extensions/sessionrecording.js | 9 ++++---- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/__tests__/autocapture.js b/src/__tests__/autocapture.js index f40e3ac4f..940917c11 100644 --- a/src/__tests__/autocapture.js +++ b/src/__tests__/autocapture.js @@ -1108,7 +1108,11 @@ describe('Autocapture system', () => { given('persistence', () => ({ props: {}, register: jest.fn() })) given('posthog', () => ({ - config: given.config, + config: { + api_host: 'https://test.com', + token: 'testtoken', + autocapture: true, + }, token: 'testtoken', capture: jest.fn(), get_distinct_id: () => 'distinctid', @@ -1117,14 +1121,6 @@ describe('Autocapture system', () => { persistence: given.persistence, })) - given('clientSideEnabled', () => true) - - given('config', () => ({ - api_host: 'https://test.com', - token: 'testtoken', - autocapture: given.clientSideEnabled, - })) - given('decideResponse', () => ({ config: { enable_collect_everything: true } })) beforeEach(() => { @@ -1149,7 +1145,7 @@ describe('Autocapture system', () => { }) it('should be disabled before the decide response if client side opted out', () => { - given('clientSideEnabled', () => false) + given.posthog.config.autocapture = false // _setIsAutocaptureEnabled is called during init autocapture._setIsAutocaptureEnabled(given.posthog) @@ -1166,7 +1162,7 @@ describe('Autocapture system', () => { ])( 'when client side config is %p and remote opt out is %p - autocapture enabled should be %p', (clientSideOptIn, serverSideOptOut, expected) => { - given('clientSideEnabled', () => clientSideOptIn) + given.posthog.config.autocapture = clientSideOptIn given('decideResponse', () => ({ config: { enable_collect_everything: true }, autocapture_opt_out: serverSideOptOut, @@ -1184,11 +1180,11 @@ describe('Autocapture system', () => { }) it('should not call _addDomEventHandlders if autocapture is disabled', () => { - given('config', () => ({ + given.posthog.config = { api_host: 'https://test.com', token: 'testtoken', autocapture: false, - })) + } given('$autocapture_disabled_server_side', () => true) given.subject() expect(autocapture._addDomEventHandlers).not.toHaveBeenCalled() diff --git a/src/__tests__/extensions/sessionrecording.js b/src/__tests__/extensions/sessionrecording.js index b23080336..b847e9ccc 100644 --- a/src/__tests__/extensions/sessionrecording.js +++ b/src/__tests__/extensions/sessionrecording.js @@ -55,7 +55,7 @@ describe('SessionRecording', () => { given('config', () => ({ api_host: 'https://test.com', - disable_session_recording: given.disabled, + disable_session_recording: false, enable_recording_console_log: given.enable_recording_console_log_client_side, autocapture: false, // Assert that session recording works even if `autocapture = false` session_recording: { @@ -68,7 +68,6 @@ describe('SessionRecording', () => { given('$session_recording_enabled_server_side', () => true) given('$console_log_enabled_server_side', () => false) given('$session_recording_recorder_version_server_side', () => undefined) - given('disabled', () => false) given('__loaded_recorder_version', () => undefined) beforeEach(() => { @@ -90,7 +89,7 @@ describe('SessionRecording', () => { }) it('is disabled if the client config is disabled', () => { - given('disabled', () => true) + given.posthog.config.disable_session_recording = true given.subject() expect(given.subject()).toBe(false) }) @@ -164,7 +163,7 @@ describe('SessionRecording', () => { }) it('call stopRecording if its not enabled', () => { - given('disabled', () => true) + given.posthog.config.disable_session_recording = true given.subject() expect(given.sessionRecording.stopRecording).toHaveBeenCalled() }) @@ -427,7 +426,7 @@ describe('SessionRecording', () => { }) it('does not load script if disable_session_recording passed', () => { - given('disabled', () => true) + given.posthog.config.disable_session_recording = true given.sessionRecording.startRecordingIfEnabled() given.sessionRecording.startCaptureAndTrySendingQueuedSnapshots() From a34dd1e8976cf130bcbf5242af364668bb2892ea Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 09:40:24 +0200 Subject: [PATCH 7/8] Fix more tests --- src/__tests__/autocapture.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/__tests__/autocapture.js b/src/__tests__/autocapture.js index 940917c11..5e5d6c9b9 100644 --- a/src/__tests__/autocapture.js +++ b/src/__tests__/autocapture.js @@ -1016,7 +1016,8 @@ describe('Autocapture system', () => { const newLib = { ...lib, config: { - // TODO + ...lib.config, + mask_all_element_attributes: true, }, } @@ -1043,7 +1044,8 @@ describe('Autocapture system', () => { const newLib = { ...lib, config: { - // TODO: Return true + ...lib.config, + mask_all_text: true, }, } @@ -1212,7 +1214,7 @@ describe('Autocapture system', () => { autocapture.afterDecideResponse(given.decideResponse, given.posthog) expect(autocapture._addDomEventHandlers).toHaveBeenCalledTimes(1) - given('config', () => ({ api_host: 'https://test.com', token: 'anotherproject', autocapture: true })) + given.posthog.config = { api_host: 'https://test.com', token: 'anotherproject', autocapture: true } autocapture.afterDecideResponse(given.decideResponse, given.posthog) expect(autocapture._addDomEventHandlers).toHaveBeenCalledTimes(2) }) From b8080d807d22e401224594bc2a74c29573119404 Mon Sep 17 00:00:00 2001 From: Ben White Date: Wed, 27 Sep 2023 09:42:31 +0200 Subject: [PATCH 8/8] Fix tests --- src/__tests__/gdpr-utils.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/__tests__/gdpr-utils.js b/src/__tests__/gdpr-utils.js index 64433a340..df419bd17 100644 --- a/src/__tests__/gdpr-utils.js +++ b/src/__tests__/gdpr-utils.js @@ -563,22 +563,9 @@ describe(`GDPR utils`, () => { }) }) - it(`should call the wrapped method if an unexpected error occurs`, () => { - TOKENS.forEach((token) => { - setupMocks(() => { - throw new Error(`Unexpected error!`) - }, true) - - gdpr.optIn(token, { persistenceType }) - postHogLib.capture(captureEventName, captureProperties) - - expect(capture.calledOnceWith(captureEventName, captureProperties)).toBe(true) - }) - }) - it(`should call the wrapped method if config is undefined`, () => { TOKENS.forEach((token) => { - setupMocks(() => undefined, false) + setupMocks(undefined, false) console.error = jest.fn() gdpr.optIn(token, { persistenceType })