From 6f9e4a0dfd4aa69e3e8605f996c1dd91fa828151 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 13 Aug 2024 16:10:42 +0100 Subject: [PATCH 1/7] Run ts on test files --- package.json | 3 ++- src/__tests__/autocapture-utils.test.ts | 5 ++++- src/__tests__/autocapture.test.ts | 8 -------- src/__tests__/featureflags.ts | 4 ++-- src/__tests__/posthog-core.test.ts | 2 +- src/__tests__/posthog-core.ts | 13 ++++++++----- src/autocapture.ts | 2 +- src/posthog-core.ts | 2 ++ tsconfig.test.json | 9 +++++++++ 9 files changed, 29 insertions(+), 19 deletions(-) create mode 100644 tsconfig.test.json diff --git a/package.json b/package.json index 93fc11efa..b5ec5b880 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,13 @@ "lint": "eslint src && eslint cypress", "prettier": "prettier --write src/ functional_tests/", "prepublishOnly": "pnpm lint && pnpm test && pnpm build && pnpm test:react", - "test": "pnpm test:unit && pnpm test:custom-eslint-rules && pnpm test:functional", + "test": "pnpm typecheck && pnpm test:unit && pnpm test:custom-eslint-rules && pnpm test:functional", "test:unit": "jest src", "test:custom-eslint-rules": "jest eslint-rules", "test:react": "cd react; pnpm test", "test:functional": "jest functional_tests", "test-watch": "jest --watch src", + "typecheck": "tsc --noEmit --project tsconfig.test.json", "cypress": "cypress open", "prepare": "husky install", "deprecate-old-versions": "node scripts/deprecate-old-versions.mjs" diff --git a/src/__tests__/autocapture-utils.test.ts b/src/__tests__/autocapture-utils.test.ts index cb2e354d6..59c2ffb8e 100644 --- a/src/__tests__/autocapture-utils.test.ts +++ b/src/__tests__/autocapture-utils.test.ts @@ -16,6 +16,7 @@ import { } from '../autocapture-utils' import { document } from '../utils/globals' import { makeMouseEvent } from './autocapture.test' +import { AutocaptureConfig } from '../types' describe(`Autocapture utility functions`, () => { afterEach(() => { @@ -252,7 +253,9 @@ describe(`Autocapture utility functions`, () => { true, ], ])('correctly respects the allow list: %s', (_, clickTarget, autoCaptureConfig, shouldCapture) => { - expect(shouldCaptureDomEvent(clickTarget, makeMouseEvent({}), autoCaptureConfig)).toBe(shouldCapture) + expect( + shouldCaptureDomEvent(clickTarget, makeMouseEvent({}), autoCaptureConfig as AutocaptureConfig) + ).toBe(shouldCapture) }) }) }) diff --git a/src/__tests__/autocapture.test.ts b/src/__tests__/autocapture.test.ts index 9458381f7..ff540f84e 100644 --- a/src/__tests__/autocapture.test.ts +++ b/src/__tests__/autocapture.test.ts @@ -400,8 +400,6 @@ describe('Autocapture system', () => { it('should capture copy', () => { const fakeEvent = makeCopyEvent({ target: elTarget, - clientX: 5, - clientY: 5, }) setWindowTextSelection('copy this test') @@ -417,8 +415,6 @@ describe('Autocapture system', () => { it('should capture cut', () => { const fakeEvent = makeCutEvent({ target: elTarget, - clientX: 5, - clientY: 5, }) setWindowTextSelection('cut this test') @@ -435,8 +431,6 @@ describe('Autocapture system', () => { it('ignores empty selection', () => { const fakeEvent = makeCopyEvent({ target: elTarget, - clientX: 5, - clientY: 5, }) setWindowTextSelection('') @@ -450,8 +444,6 @@ describe('Autocapture system', () => { it('runs selection through the safe text before capture', () => { const fakeEvent = makeCopyEvent({ target: elTarget, - clientX: 5, - clientY: 5, }) // oh no, a social security number! diff --git a/src/__tests__/featureflags.ts b/src/__tests__/featureflags.ts index d97f92db4..1531e2d39 100644 --- a/src/__tests__/featureflags.ts +++ b/src/__tests__/featureflags.ts @@ -8,8 +8,8 @@ jest.useFakeTimers() jest.spyOn(global, 'setTimeout') describe('featureflags', () => { - let instance - let featureFlags + let instance: any + let featureFlags: any const config = { token: 'random fake token', diff --git a/src/__tests__/posthog-core.test.ts b/src/__tests__/posthog-core.test.ts index c60a699b9..7b8047c56 100644 --- a/src/__tests__/posthog-core.test.ts +++ b/src/__tests__/posthog-core.test.ts @@ -59,7 +59,7 @@ describe('posthog core', () => { }) // act - const actual = posthog._calculate_event_properties(eventName, eventProperties) + const actual = posthog._calculate_event_properties(eventName, eventProperties, new Date()) // assert expect(actual['event']).toBe('prop') diff --git a/src/__tests__/posthog-core.ts b/src/__tests__/posthog-core.ts index 2ce103037..0fee2c072 100644 --- a/src/__tests__/posthog-core.ts +++ b/src/__tests__/posthog-core.ts @@ -27,8 +27,11 @@ describe('posthog core', () => { _send_request: jest.fn(), } - const posthogWith = (config: Partial, overrides?: Partial) => { + const posthogWith = (config: Partial, overrides?: Partial): PostHog => { const posthog = defaultPostHog().init('testtoken', config, uuidv7()) + if (!posthog) { + throw new Error('PostHog failed to initialize') + } return Object.assign(posthog, overrides || {}) } @@ -47,7 +50,7 @@ describe('posthog core', () => { }) it('adds system time to events', () => { - const captureData = posthogWith(defaultConfig, defaultOverrides).capture(eventName, {}, {}) + const captureData = posthogWith(defaultConfig, defaultOverrides).capture(eventName, {}, {})! expect(captureData).toHaveProperty('timestamp') // timer is fixed at 2020-01-01 @@ -59,7 +62,7 @@ describe('posthog core', () => { eventName, {}, { timestamp: new Date(2020, 0, 2, 12, 34) } - ) + )! expect(captureData).toHaveProperty('timestamp') expect(captureData.timestamp).toEqual(new Date(2020, 0, 2, 12, 34)) expect(captureData.properties['$event_time_override_provided']).toEqual(true) @@ -115,8 +118,8 @@ describe('posthog core', () => { posthog.capture(eventName, {}, {}) - expect(posthog.sessionPersistence.update_campaign_params).toHaveBeenCalled() - expect(posthog.sessionPersistence.update_referrer_info).toHaveBeenCalled() + expect(posthog.sessionPersistence?.update_campaign_params).toHaveBeenCalled() + expect(posthog.sessionPersistence?.update_referrer_info).toHaveBeenCalled() }) it('errors with undefined event name', () => { diff --git a/src/autocapture.ts b/src/autocapture.ts index dbef30693..14880f75b 100644 --- a/src/autocapture.ts +++ b/src/autocapture.ts @@ -57,7 +57,7 @@ export class Autocapture { return config } - private _addDomEventHandlers(): void { + _addDomEventHandlers(): void { if (!this.isBrowserSupported()) { logger.info('Disabling Automatic Event Collection because this browser is not supported') return diff --git a/src/posthog-core.ts b/src/posthog-core.ts index bf69c5c68..d40760d0c 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -234,6 +234,7 @@ class DeprecatedWebPerformanceObserver { export class PostHog { __loaded: boolean config: PostHogConfig + lib_version: string rateLimiter: RateLimiter scrollManager: ScrollManager @@ -286,6 +287,7 @@ export class PostHog { this.__request_queue = [] this.__loaded = false this.analyticsDefaultEndpoint = '/e/' + this.lib_version = Config.LIB_VERSION this.featureFlags = new PostHogFeatureFlags(this) this.toolbar = new Toolbar(this) diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 000000000..69cb9894a --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "strict": false, + "noImplicitAny": false + }, + "include": ["src/**/*.ts*", "src/__tests__/**/*.ts*"], + "exclude": [] +} From ad28d9cce2a2700e7b9828f67c103c6b0fea5be9 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 13 Aug 2024 18:14:32 +0100 Subject: [PATCH 2/7] Move tsconfig to test folder, get tests passing type checking --- package.json | 9 +++-- pnpm-lock.yaml | 7 ++++ .../error-conversion.test.ts | 2 +- src/__tests__/featureflags.ts | 22 +++++----- src/__tests__/helpers/script-utils.ts | 2 +- src/__tests__/posthog-core.ts | 40 +++++++++---------- src/__tests__/surveys.test.ts | 26 ++++++------ src/__tests__/tsconfig.json | 13 ++++++ src/__tests__/utils/event-utils.test.ts | 8 ++-- .../utils/survey-event-receiver.test.ts | 21 ++++------ src/autocapture-utils.ts | 4 +- .../replay/sessionrecording-utils.ts | 3 +- src/extensions/web-vitals/index.ts | 2 +- src/heatmaps.ts | 2 +- src/posthog-core.ts | 7 ++-- src/web-types.d.ts | 1 + tsconfig.json | 6 +-- tsconfig.test.json | 9 ----- 18 files changed, 100 insertions(+), 84 deletions(-) create mode 100644 src/__tests__/tsconfig.json create mode 100644 src/web-types.d.ts delete mode 100644 tsconfig.test.json diff --git a/package.json b/package.json index b5ec5b880..ce8d3ecb2 100644 --- a/package.json +++ b/package.json @@ -13,16 +13,18 @@ "lint": "eslint src && eslint cypress", "prettier": "prettier --write src/ functional_tests/", "prepublishOnly": "pnpm lint && pnpm test && pnpm build && pnpm test:react", - "test": "pnpm typecheck && pnpm test:unit && pnpm test:custom-eslint-rules && pnpm test:functional", + "test": "pnpm test:unit && pnpm test:custom-eslint-rules && pnpm test:functional", "test:unit": "jest src", "test:custom-eslint-rules": "jest eslint-rules", "test:react": "cd react; pnpm test", "test:functional": "jest functional_tests", "test-watch": "jest --watch src", - "typecheck": "tsc --noEmit --project tsconfig.test.json", + "test:typecheck": "cd src/__tests__ && tsc --noEmit --project tsconfig.json", + "typecheck": "tsc --noEmit --project tsconfig.json", "cypress": "cypress open", "prepare": "husky install", - "deprecate-old-versions": "node scripts/deprecate-old-versions.mjs" + "deprecate-old-versions": "node scripts/deprecate-old-versions.mjs", + "tsc": "tsc" }, "main": "dist/main.js", "module": "dist/module.js", @@ -34,6 +36,7 @@ "react/package.json" ], "dependencies": { + "@types/web": "^0.0.154", "fflate": "^0.4.8", "preact": "^10.19.3", "web-vitals": "^4.0.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5384b46a..dc8b54121 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,9 @@ patchedDependencies: path: patches/rrweb@2.0.0-alpha.13.patch dependencies: + '@types/web': + specifier: ^0.0.154 + version: 0.0.154 fflate: specifier: ^0.4.8 version: 0.4.8 @@ -3018,6 +3021,10 @@ packages: resolution: {integrity: sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==} dev: true + /@types/web@0.0.154: + resolution: {integrity: sha512-Tc10Nkpbb8AgM3iGnrvpKVb6x8pzrZpMCPqMJe8htXoEdNDKojEevNAkCjxkjCLZF2p1ZB+gknAwdbkypxwxKg==} + dev: false + /@types/yargs-parser@15.0.0: resolution: {integrity: sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==} dev: true diff --git a/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts b/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts index d7b557a2f..181ff01c4 100644 --- a/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts +++ b/src/__tests__/extensions/exception-autocapture/error-conversion.test.ts @@ -2,12 +2,12 @@ import { errorToProperties, - ErrorProperties, unhandledRejectionToProperties, } from '../../../extensions/exception-autocapture/error-conversion' import { isNull } from '../../../utils/type-utils' import { expect } from '@jest/globals' +import { ErrorProperties } from '../../../types' // ugh, jest // can't reference PromiseRejectionEvent to construct it 🤷 diff --git a/src/__tests__/featureflags.ts b/src/__tests__/featureflags.ts index 1531e2d39..7dd295c6c 100644 --- a/src/__tests__/featureflags.ts +++ b/src/__tests__/featureflags.ts @@ -3,19 +3,22 @@ import { filterActiveFeatureFlags, parseFeatureFlagDecideResponse, PostHogFeatureFlags } from '../posthog-featureflags' import { PostHogPersistence } from '../posthog-persistence' import { RequestRouter } from '../utils/request-router' +import { PostHogConfig } from '../types' jest.useFakeTimers() jest.spyOn(global, 'setTimeout') describe('featureflags', () => { - let instance: any - let featureFlags: any + let instance + let featureFlags const config = { token: 'random fake token', persistence: 'memory', api_host: 'https://app.posthog.com', - } + } as PostHogConfig + + let mockWarn beforeEach(() => { instance = { @@ -23,7 +26,7 @@ describe('featureflags', () => { get_distinct_id: () => 'blah id', getGroups: () => {}, persistence: new PostHogPersistence(config), - requestRouter: new RequestRouter({ config }), + requestRouter: new RequestRouter({ config } as any), register: (props) => instance.persistence.register(props), unregister: (key) => instance.persistence.unregister(key), get_property: (key) => instance.persistence.props[key], @@ -40,8 +43,8 @@ describe('featureflags', () => { featureFlags = new PostHogFeatureFlags(instance) - jest.spyOn(instance, 'capture').mockReturnValue() - jest.spyOn(window.console, 'warn').mockImplementation() + jest.spyOn(instance, 'capture').mockReturnValue(undefined) + mockWarn = jest.spyOn(window.console, 'warn').mockImplementation() instance.persistence.register({ $feature_flag_payloads: { @@ -76,7 +79,7 @@ describe('featureflags', () => { }) it('should warn if decide endpoint was not hit and no flags exist', () => { - window.POSTHOG_DEBUG = true + ;(window as any).POSTHOG_DEBUG = true featureFlags.instance.decideEndpointWasHit = false instance.persistence.unregister('$enabled_feature_flags') instance.persistence.unregister('$active_feature_flags') @@ -88,7 +91,7 @@ describe('featureflags', () => { 'isFeatureEnabled for key "beta-feature" failed. Feature flags didn\'t load in time.' ) - window.console.warn.mockClear() + mockWarn.mockClear() expect(featureFlags.getFeatureFlag('beta-feature')).toEqual(undefined) expect(window.console.warn).toHaveBeenCalledWith( @@ -249,7 +252,7 @@ describe('featureflags', () => { ) // Clear the mock to reset call count - window.console.warn.mockClear() + mockWarn.mockClear() // Test with suppressing warning (new behavior) featureFlags.override( @@ -1031,6 +1034,7 @@ describe('parseFeatureFlagDecideResponse', () => { // checks that nothing fails when asking for ?v=2 and getting a ?v=1 response const decideResponse = { featureFlags: ['beta-feature', 'alpha-feature-2'] } + // @ts-expect-error testing backwards compatibility parseFeatureFlagDecideResponse(decideResponse, persistence) expect(persistence.register).toHaveBeenLastCalledWith({ diff --git a/src/__tests__/helpers/script-utils.ts b/src/__tests__/helpers/script-utils.ts index 0e44118c5..d3ed34c3c 100644 --- a/src/__tests__/helpers/script-utils.ts +++ b/src/__tests__/helpers/script-utils.ts @@ -2,7 +2,7 @@ const checkScriptsForSrcExists = (src: string): boolean => { const scripts = document.querySelectorAll('body > script') let foundScript = false for (let i = 0; i < scripts.length; i++) { - if (scripts[i].src === src) { + if ((scripts[i] as any).src === src) { foundScript = true break } diff --git a/src/__tests__/posthog-core.ts b/src/__tests__/posthog-core.ts index 0fee2c072..865c228ba 100644 --- a/src/__tests__/posthog-core.ts +++ b/src/__tests__/posthog-core.ts @@ -7,7 +7,7 @@ import * as globals from '../utils/globals' import { USER_STATE } from '../constants' import { createPosthogInstance, defaultPostHog } from './helpers/posthog-instance' import { logger } from '../utils/logger' -import { PostHogConfig } from '../types' +import { DecideResponse, PostHogConfig } from '../types' import { PostHog } from '../posthog-core' import { PostHogPersistence } from '../posthog-persistence' import { SessionIdManager } from '../sessionid' @@ -141,6 +141,7 @@ describe('posthog core', () => { const posthog = posthogWith(defaultConfig, defaultOverrides) posthog._addCaptureHook(hook) + // @ts-expect-error - testing invalid input expect(() => posthog.capture({ event: 'object as name' })).not.toThrow() expect(hook).not.toHaveBeenCalled() expect(logger.error).toHaveBeenCalledWith('No event name provided to posthog.capture') @@ -298,7 +299,7 @@ describe('posthog core', () => { it('sends payloads to alternative endpoint if given', () => { const posthog = posthogWith({ ...defaultConfig, request_batching: false }, defaultOverrides) - posthog._afterDecideResponse({ analytics: { endpoint: '/i/v0/e/' } }) + posthog._afterDecideResponse({ analytics: { endpoint: '/i/v0/e/' } } as DecideResponse) posthog.capture('event-name', { foo: 'bar', length: 0 }) @@ -323,7 +324,7 @@ describe('posthog core', () => { it('sends payloads to overriden _url, even if alternative endpoint is set', () => { const posthog = posthogWith({ ...defaultConfig, request_batching: false }, defaultOverrides) - posthog._afterDecideResponse({ analytics: { endpoint: '/i/v0/e/' } }) + posthog._afterDecideResponse({ analytics: { endpoint: '/i/v0/e/' } } as DecideResponse) posthog.capture('event-name', { foo: 'bar', length: 0 }, { _url: 'https://app.posthog.com/s/' }) @@ -339,7 +340,7 @@ describe('posthog core', () => { it('enables compression from decide response', () => { const posthog = posthogWith({}) - posthog._afterDecideResponse({ supportedCompression: ['gzip-js', 'base64'] }) + posthog._afterDecideResponse({ supportedCompression: ['gzip-js', 'base64'] } as DecideResponse) expect(posthog.compression).toEqual('gzip-js') }) @@ -347,7 +348,7 @@ describe('posthog core', () => { it('enables compression from decide response when only one received', () => { const posthog = posthogWith({}) - posthog._afterDecideResponse({ supportedCompression: ['base64'] }) + posthog._afterDecideResponse({ supportedCompression: ['base64'] } as DecideResponse) expect(posthog.compression).toEqual('base64') }) @@ -355,7 +356,7 @@ describe('posthog core', () => { it('does not enable compression from decide response if compression is disabled', () => { const posthog = posthogWith({ disable_compression: true, persistence: 'memory' }) - posthog._afterDecideResponse({ supportedCompression: ['gzip-js', 'base64'] }) + posthog._afterDecideResponse({ supportedCompression: ['gzip-js', 'base64'] } as DecideResponse) expect(posthog.compression).toEqual(undefined) }) @@ -363,7 +364,7 @@ describe('posthog core', () => { it('defaults to /e if no endpoint is given', () => { const posthog = posthogWith({}) - posthog._afterDecideResponse({}) + posthog._afterDecideResponse({} as DecideResponse) expect(posthog.analyticsDefaultEndpoint).toEqual('/e/') }) @@ -371,7 +372,7 @@ describe('posthog core', () => { it('uses the specified analytics endpoint if given', () => { const posthog = posthogWith({}) - posthog._afterDecideResponse({ analytics: { endpoint: '/i/v0/e/' } }) + posthog._afterDecideResponse({ analytics: { endpoint: '/i/v0/e/' } } as DecideResponse) expect(posthog.analyticsDefaultEndpoint).toEqual('/i/v0/e/') }) @@ -414,7 +415,7 @@ describe('posthog core', () => { }) it('returns calculated properties', () => { - expect(posthog._calculate_event_properties('custom_event', { event: 'prop' })).toEqual({ + expect(posthog._calculate_event_properties('custom_event', { event: 'prop' }, new Date())).toEqual({ token: 'testtoken', event: 'prop', $lib: 'web', @@ -435,7 +436,7 @@ describe('posthog core', () => { overrides ) - expect(posthog._calculate_event_properties('custom_event', { event: 'prop' })).toEqual({ + expect(posthog._calculate_event_properties('custom_event', { event: 'prop' }, new Date())).toEqual({ token: 'testtoken', event: 'prop', $lib: 'web', @@ -460,7 +461,9 @@ describe('posthog core', () => { ) expect( - posthog._calculate_event_properties('custom_event', { event: 'prop' })['$process_person_profile'] + posthog._calculate_event_properties('custom_event', { event: 'prop' }, new Date())[ + '$process_person_profile' + ] ).toEqual(true) }) @@ -472,7 +475,7 @@ describe('posthog core', () => { overrides ) - expect(posthog._calculate_event_properties('$snapshot', { event: 'prop' })).toEqual({ + expect(posthog._calculate_event_properties('$snapshot', { event: 'prop' }, new Date())).toEqual({ token: 'testtoken', event: 'prop', distinct_id: 'abc', @@ -489,7 +492,7 @@ describe('posthog core', () => { overrides ) - expect(posthog._calculate_event_properties('custom_event', { event: 'prop' })).toEqual({ + expect(posthog._calculate_event_properties('custom_event', { event: 'prop' }, new Date())).toEqual({ event_name: 'custom_event', token: 'testtoken', $process_person_profile: true, @@ -499,7 +502,7 @@ describe('posthog core', () => { it('saves $snapshot data and token for $snapshot events', () => { posthog = posthogWith({}, overrides) - expect(posthog._calculate_event_properties('$snapshot', { $snapshot_data: {} })).toEqual({ + expect(posthog._calculate_event_properties('$snapshot', { $snapshot_data: {} }, new Date())).toEqual({ token: 'testtoken', $snapshot_data: {}, distinct_id: 'abc', @@ -509,7 +512,7 @@ describe('posthog core', () => { it("doesn't modify properties passed into it", () => { const properties = { prop1: 'val1', prop2: 'val2' } - posthog._calculate_event_properties('custom_event', properties) + posthog._calculate_event_properties('custom_event', properties, new Date()) expect(Object.keys(properties)).toEqual(['prop1', 'prop2']) }) @@ -517,7 +520,7 @@ describe('posthog core', () => { it('adds page title to $pageview', () => { document!.title = 'test' - expect(posthog._calculate_event_properties('$pageview', {})).toEqual( + expect(posthog._calculate_event_properties('$pageview', {}, new Date())).toEqual( expect.objectContaining({ title: 'test' }) ) }) @@ -772,13 +775,10 @@ describe('posthog core', () => { }) describe('init()', () => { - // @ts-expect-error - it's fine to spy on window jest.spyOn(window, 'window', 'get') beforeEach(() => { - // @ts-expect-error - it's fine to spy on window jest.spyOn(window.console, 'warn').mockImplementation() - // @ts-expect-error - it's fine to spy on window jest.spyOn(window.console, 'error').mockImplementation() }) @@ -794,7 +794,7 @@ describe('posthog core', () => { // TODO this didn't make a tonne of sense in the given form // it makes no sense now // of course mocks added _after_ init will not be called - const posthog = defaultPostHog().init('testtoken', defaultConfig, uuidv7())! + const posthog = defaultPostHog().init('testtoken', defaultConfig, uuidv7()) posthog.sessionRecording = { afterDecideResponse: jest.fn(), diff --git a/src/__tests__/surveys.test.ts b/src/__tests__/surveys.test.ts index 38708612c..6c0bc7820 100644 --- a/src/__tests__/surveys.test.ts +++ b/src/__tests__/surveys.test.ts @@ -8,6 +8,7 @@ import { MultipleSurveyQuestion, SurveyQuestionBranchingType, SurveyQuestion, + RatingSurveyQuestion, } from '../posthog-surveys-types' import { canActivateRepeatedly, @@ -614,11 +615,12 @@ describe('surveys', () => { }) it('returns event based surveys that observed an event', () => { + // TODO this test fails when run in isolation + surveysResponse = { surveys: [surveyWithEnabledInternalFlag, surveyWithEvents], } - - surveys._surveyEventReceiver?.on('user_subscribed') + ;(surveys._surveyEventReceiver as any)?.on('user_subscribed') surveys.getActiveMatchingSurveys((data) => { expect(data).toEqual([surveyWithEnabledInternalFlag]) }) @@ -840,7 +842,7 @@ describe('surveys', () => { { type: SurveyQuestionType.Open, question: 'Why yes?' }, { type: SurveyQuestionType.Open, question: 'Why no?' }, { type: SurveyQuestionType.Open, question: 'Why maybe?' }, - ] as SurveyQuestion[] + ] as unknown[] as SurveyQuestion[] expect(surveys.getNextSurveyStep(survey, 0, 'Yes')).toEqual(1) expect(surveys.getNextSurveyStep(survey, 0, 'No')).toEqual(2) expect(surveys.getNextSurveyStep(survey, 0, 'Maybe')).toEqual(3) @@ -861,7 +863,7 @@ describe('surveys', () => { { type: SurveyQuestionType.Open, question: 'Sorry to hear that. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' }, - ] as SurveyQuestion[] + ] as unknown[] as SurveyQuestion[] expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1) expect(surveys.getNextSurveyStep(survey, 0, 2)).toEqual(2) @@ -883,7 +885,7 @@ describe('surveys', () => { { type: SurveyQuestionType.Open, question: 'Sorry to hear that. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' }, - ] as SurveyQuestion[] + ] as unknown as SurveyQuestion[] expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1) expect(surveys.getNextSurveyStep(survey, 0, 3)).toEqual(2) @@ -905,7 +907,7 @@ describe('surveys', () => { { type: SurveyQuestionType.Open, question: 'Sorry to hear that. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' }, - ] as SurveyQuestion[] + ] as unknown as SurveyQuestion[] expect(surveys.getNextSurveyStep(survey, 0, 1)).toEqual(1) expect(surveys.getNextSurveyStep(survey, 0, 8)).toEqual(2) @@ -1085,7 +1087,7 @@ describe('surveys', () => { { type: SurveyQuestionType.Open, question: 'Sorry to hear that. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' }, - ] as SurveyQuestion[] + ] as unknown as SurveyQuestion[] expect(() => surveys.getNextSurveyStep(survey, 0, 1)).toThrow('The scale must be one of: 3, 5, 10') }) @@ -1103,13 +1105,11 @@ describe('surveys', () => { { type: SurveyQuestionType.Open, question: 'Sorry to hear that. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' }, - ] as SurveyQuestion[] + ] as unknown as SurveyQuestion[] expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-3') - - survey.questions[0].scale = 5 + ;(survey.questions[0] as RatingSurveyQuestion).scale = 5 expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 1-5') - - survey.questions[0].scale = 10 + ;(survey.questions[0] as RatingSurveyQuestion).scale = 10 expect(() => surveys.getNextSurveyStep(survey, 0, 20)).toThrow('The response must be in range 0-10') }) @@ -1127,7 +1127,7 @@ describe('surveys', () => { { type: SurveyQuestionType.Open, question: 'Sorry to hear that. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Seems you are not completely happy. Tell us more!' }, { type: SurveyQuestionType.Open, question: 'Glad to hear that. Tell us more!' }, - ] as SurveyQuestion[] + ] as unknown as SurveyQuestion[] expect(() => surveys.getNextSurveyStep(survey, 0, '2')).toThrow('The response type must be an integer') expect(() => surveys.getNextSurveyStep(survey, 0, 'some_string')).toThrow( 'The response type must be an integer' diff --git a/src/__tests__/tsconfig.json b/src/__tests__/tsconfig.json new file mode 100644 index 000000000..f51de4b32 --- /dev/null +++ b/src/__tests__/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "skipLibCheck": true, + "allowJs": true, + "checkJs": true, + "strict": false, + "noImplicitReturns": false, + "typeRoots": ["../../node_modules/@types", "../..//src/types"] + }, + "include": ["./**/*.ts*"], + "exclude": [] +} diff --git a/src/__tests__/utils/event-utils.test.ts b/src/__tests__/utils/event-utils.test.ts index 863df9cf8..19024430e 100644 --- a/src/__tests__/utils/event-utils.test.ts +++ b/src/__tests__/utils/event-utils.test.ts @@ -39,7 +39,7 @@ describe(`event-utils`, () => { const browserTestcases: { name: string userAgent: string - vendor: string + vendor?: string expectedVersion: number | null expectedBrowser: string }[] = [ @@ -238,11 +238,11 @@ describe(`event-utils`, () => { ] test.each(browserTestcases)('browser version %s', ({ userAgent, vendor, expectedVersion }) => { - expect(Info.browserVersion(userAgent, vendor, '')).toBe(expectedVersion) + expect(Info.browserVersion(userAgent, vendor)).toBe(expectedVersion) }) test.each(browserTestcases)('browser %s', ({ userAgent, vendor, expectedBrowser }) => { - expect(Info.browser(userAgent, vendor, '')).toBe(expectedBrowser) + expect(Info.browser(userAgent, vendor)).toBe(expectedBrowser) }) /** @@ -287,7 +287,7 @@ describe(`event-utils`, () => { test('can rely on vendor string to detect safari', () => { const ua = 'Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.7.0' const vendor = 'Apple Computer, Inc.' - expect(detectBrowser(ua, vendor, '')).toBe('Safari') + expect(detectBrowser(ua, vendor)).toBe('Safari') }) test('osVersion', () => { diff --git a/src/__tests__/utils/survey-event-receiver.test.ts b/src/__tests__/utils/survey-event-receiver.test.ts index f24b4b3ba..d36ff33e4 100644 --- a/src/__tests__/utils/survey-event-receiver.test.ts +++ b/src/__tests__/utils/survey-event-receiver.test.ts @@ -16,6 +16,7 @@ describe('survey-event-receiver', () => { describe('event based surveys', () => { let config: PostHogConfig let instance: PostHog + let mockAddCaptureHook: jest.Mock const surveysWithEvents: Survey[] = [ { @@ -75,6 +76,7 @@ describe('survey-event-receiver', () => { ] beforeEach(() => { + mockAddCaptureHook = jest.fn() config = { token: 'testtoken', api_host: 'https://app.posthog.com', @@ -84,7 +86,7 @@ describe('survey-event-receiver', () => { instance = { config: config, persistence: new PostHogPersistence(config), - _addCaptureHook: jest.fn(), + _addCaptureHook: mockAddCaptureHook, } as unknown as PostHog }) @@ -106,7 +108,7 @@ describe('survey-event-receiver', () => { it('receiver activates survey on event', () => { const surveyEventReceiver = new SurveyEventReceiver(instance) surveyEventReceiver.register(surveysWithEvents) - const registeredHook = instance._addCaptureHook.mock.calls[0][0] + const registeredHook = mockAddCaptureHook.mock.calls[0][0] registeredHook('billing_changed') const activatedSurveys = surveyEventReceiver.getSurveys() expect(activatedSurveys).toContain('first-survey') @@ -120,7 +122,7 @@ describe('survey-event-receiver', () => { } surveyEventReceiver.register(surveysWithEvents) - const registeredHook = instance._addCaptureHook.mock.calls[0][0] + const registeredHook = mockAddCaptureHook.mock.calls[0][0] registeredHook('billing_changed') const activatedSurveys = surveyEventReceiver.getSurveys() expect(activatedSurveys).toContain('first-survey') @@ -142,7 +144,7 @@ describe('survey-event-receiver', () => { it('receiver activates same survey on multiple event', () => { const surveyEventReceiver = new SurveyEventReceiver(instance) surveyEventReceiver.register(surveysWithEvents) - const registeredHook = instance._addCaptureHook.mock.calls[0][0] + const registeredHook = mockAddCaptureHook.mock.calls[0][0] registeredHook('billing_changed') expect(surveyEventReceiver.getSurveys()).toEqual(['first-survey']) registeredHook('billing_removed') @@ -152,7 +154,7 @@ describe('survey-event-receiver', () => { it('receiver activates multiple surveys on same event', () => { const surveyEventReceiver = new SurveyEventReceiver(instance) surveyEventReceiver.register(surveysWithEvents) - const registeredHook = instance._addCaptureHook.mock.calls[0][0] + const registeredHook = mockAddCaptureHook.mock.calls[0][0] registeredHook('user_subscribed') expect(surveyEventReceiver.getSurveys()).toEqual(['first-survey', 'third-survey']) }) @@ -160,7 +162,7 @@ describe('survey-event-receiver', () => { it('receiver activates multiple surveys on different events', () => { const surveyEventReceiver = new SurveyEventReceiver(instance) surveyEventReceiver.register(surveysWithEvents) - const registeredHook = instance._addCaptureHook.mock.calls[0][0] + const registeredHook = mockAddCaptureHook.mock.calls[0][0] registeredHook('billing_changed') expect(surveyEventReceiver.getSurveys()).toEqual(['first-survey']) registeredHook('address_changed') @@ -211,13 +213,9 @@ describe('survey-event-receiver', () => { return { id: id, name: `${eventName || 'user defined '} action`, - description: '', - post_to_slack: false, - slack_message_format: '', steps: [ { event: eventName, - properties: null, text: null, text_matching: null, href: null, @@ -228,10 +226,7 @@ describe('survey-event-receiver', () => { ], created_at: '2024-06-20T14:39:23.616676Z', deleted: false, - is_calculating: false, - last_calculated_at: '2024-06-20T14:39:23.616051Z', is_action: true, - bytecode_error: null, tags: [], } } diff --git a/src/autocapture-utils.ts b/src/autocapture-utils.ts index 94b85b69e..8dec1bd3e 100644 --- a/src/autocapture-utils.ts +++ b/src/autocapture-utils.ts @@ -29,7 +29,9 @@ export function getClassNames(el: Element): string[] { // TODO: when is this ever used? case 'object': // handle cases where className might be SVGAnimatedString or some other type className = - ('baseVal' in el.className ? (el.className as any).baseVal : null) || el.getAttribute('class') || '' + (el.className && 'baseVal' in el.className ? (el.className as any).baseVal : null) || + el.getAttribute('class') || + '' break default: className = '' diff --git a/src/extensions/replay/sessionrecording-utils.ts b/src/extensions/replay/sessionrecording-utils.ts index 91eff8d04..87087b3e6 100644 --- a/src/extensions/replay/sessionrecording-utils.ts +++ b/src/extensions/replay/sessionrecording-utils.ts @@ -17,11 +17,10 @@ import { SnapshotBuffer } from './sessionrecording' // taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references function circularReferenceReplacer() { const ancestors: any[] = [] - return function (_key: string, value: any) { + return function (this: any, _key: string, value: any) { if (isObject(value)) { // `this` is the object that value is contained in, // i.e., its direct parent. - // @ts-expect-error - TS was unhappy with `this` on the next line but the code is copied in from MDN while (ancestors.length > 0 && ancestors.at(-1) !== this) { ancestors.pop() } diff --git a/src/extensions/web-vitals/index.ts b/src/extensions/web-vitals/index.ts index d4b9a9155..eb6a5e186 100644 --- a/src/extensions/web-vitals/index.ts +++ b/src/extensions/web-vitals/index.ts @@ -119,7 +119,7 @@ export class WebVitalsAutocapture { return } - this.buffer = this.buffer || {} + this.buffer = this.buffer || { url: undefined, metrics: [], firstMetricTimestamp: undefined } const $currentUrl = this._currentURL() if (isUndefined($currentUrl)) { diff --git a/src/heatmaps.ts b/src/heatmaps.ts index bd8689330..257ff9c5e 100644 --- a/src/heatmaps.ts +++ b/src/heatmaps.ts @@ -47,7 +47,7 @@ export class Heatmaps { rageclicks = new RageClick() _enabledServerSide: boolean = false _initialized = false - _mouseMoveTimeout: number | undefined + _mouseMoveTimeout: ReturnType | undefined // TODO: Periodically flush this if no other event has taken care of it private buffer: HeatmapEventBuffer diff --git a/src/posthog-core.ts b/src/posthog-core.ts index d40760d0c..fae28639f 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -337,7 +337,7 @@ export class PostHog { token: string, config?: OnlyValidKeys, Partial>, name?: string - ): PostHog | void { + ): PostHog | undefined { if (!name || name === PRIMARY_INSTANCE_NAME) { // This means we are initializing the primary instance (i.e. this) return this._init(token, config, name) @@ -757,11 +757,12 @@ export class PostHog { * @param {String} [config.transport] Transport method for network request ('XHR' or 'sendBeacon'). * @param {Date} [config.timestamp] Timestamp is a Date object. If not set, it'll automatically be set to the current time. */ - capture(event_name: string, properties?: Properties | null, options?: CaptureOptions): CaptureResult | void { + capture(event_name: string, properties?: Properties | null, options?: CaptureOptions): CaptureResult | undefined { // While developing, a developer might purposefully _not_ call init(), // in this case, we would like capture to be a noop. if (!this.__loaded || !this.persistence || !this.sessionPersistence || !this._requestQueue) { - return logger.uninitializedWarning('posthog.capture') + logger.uninitializedWarning('posthog.capture') + return } if (this.consent.isOptedOut()) { diff --git a/src/web-types.d.ts b/src/web-types.d.ts new file mode 100644 index 000000000..a49a5ac69 --- /dev/null +++ b/src/web-types.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.json b/tsconfig.json index 4a1f28762..07e5b9c4c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "checkJs": true, - "skipLibCheck": false, + "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, @@ -24,6 +24,6 @@ "jsxFactory": "h", "jsxFragmentFactory": "Fragment" }, - "include": ["src/**/*.ts*"], - "exclude": ["src/__tests__/**/*.ts*"] + "include": ["./src/**/*.ts*"], + "exclude": ["./src/__tests__/**/*.ts*"] } diff --git a/tsconfig.test.json b/tsconfig.test.json deleted file mode 100644 index 69cb9894a..000000000 --- a/tsconfig.test.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "strict": false, - "noImplicitAny": false - }, - "include": ["src/**/*.ts*", "src/__tests__/**/*.ts*"], - "exclude": [] -} From 619540295de3d5f708f499dbe9ec92741df2c544 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 13 Aug 2024 18:39:19 +0100 Subject: [PATCH 3/7] Add test for circularReferenceReplacer --- .../replay/sessionrecording-utils.test.ts | 19 +++++++++++++++++++ .../replay/sessionrecording-utils.ts | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/__tests__/extensions/replay/sessionrecording-utils.test.ts b/src/__tests__/extensions/replay/sessionrecording-utils.test.ts index 8e27f55b4..d0faef5b1 100644 --- a/src/__tests__/extensions/replay/sessionrecording-utils.test.ts +++ b/src/__tests__/extensions/replay/sessionrecording-utils.test.ts @@ -8,6 +8,7 @@ import { splitBuffer, SEVEN_MEGABYTES, estimateSize, + circularReferenceReplacer, } from '../../../extensions/replay/sessionrecording-utils' import { largeString, threeMBAudioURI, threeMBImageURI } from '../test_data/sessionrecording-utils-test-data' import { eventWithTime } from '@rrweb/types' @@ -333,4 +334,22 @@ describe(`SessionRecording utility functions`, () => { expect(result).toEqual([buffer]) }) }) + + describe('circularReferenceReplacer', () => { + it('should handle circular references', () => { + const obj: any = {} + obj.obj = obj + const result = JSON.stringify(obj, circularReferenceReplacer()) + expect(result).toEqual('{"obj":"[Circular]"}') + }) + + it('should handle nested circular references', () => { + const a: any = {} + const b: any = {} + a.b = b + b.a = a + const result = JSON.stringify(a, circularReferenceReplacer()) + expect(result).toEqual('{"b":{"a":"[Circular]"}}') + }) + }) }) diff --git a/src/extensions/replay/sessionrecording-utils.ts b/src/extensions/replay/sessionrecording-utils.ts index 87087b3e6..a08ba24ca 100644 --- a/src/extensions/replay/sessionrecording-utils.ts +++ b/src/extensions/replay/sessionrecording-utils.ts @@ -15,7 +15,7 @@ import { isObject } from '../../utils/type-utils' import { SnapshotBuffer } from './sessionrecording' // taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references -function circularReferenceReplacer() { +export function circularReferenceReplacer() { const ancestors: any[] = [] return function (this: any, _key: string, value: any) { if (isObject(value)) { From dd56022f7cb651a679ec28e9cf108c31cfb9b0a4 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Wed, 14 Aug 2024 10:10:51 +0100 Subject: [PATCH 4/7] Undo some changes now we're not using strict --- src/__tests__/posthog-core.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/__tests__/posthog-core.ts b/src/__tests__/posthog-core.ts index 865c228ba..2aa0307df 100644 --- a/src/__tests__/posthog-core.ts +++ b/src/__tests__/posthog-core.ts @@ -29,9 +29,6 @@ describe('posthog core', () => { const posthogWith = (config: Partial, overrides?: Partial): PostHog => { const posthog = defaultPostHog().init('testtoken', config, uuidv7()) - if (!posthog) { - throw new Error('PostHog failed to initialize') - } return Object.assign(posthog, overrides || {}) } @@ -50,7 +47,7 @@ describe('posthog core', () => { }) it('adds system time to events', () => { - const captureData = posthogWith(defaultConfig, defaultOverrides).capture(eventName, {}, {})! + const captureData = posthogWith(defaultConfig, defaultOverrides).capture(eventName, {}, {}) expect(captureData).toHaveProperty('timestamp') // timer is fixed at 2020-01-01 @@ -62,7 +59,7 @@ describe('posthog core', () => { eventName, {}, { timestamp: new Date(2020, 0, 2, 12, 34) } - )! + ) expect(captureData).toHaveProperty('timestamp') expect(captureData.timestamp).toEqual(new Date(2020, 0, 2, 12, 34)) expect(captureData.properties['$event_time_override_provided']).toEqual(true) @@ -118,8 +115,8 @@ describe('posthog core', () => { posthog.capture(eventName, {}, {}) - expect(posthog.sessionPersistence?.update_campaign_params).toHaveBeenCalled() - expect(posthog.sessionPersistence?.update_referrer_info).toHaveBeenCalled() + expect(posthog.sessionPersistence.update_campaign_params).toHaveBeenCalled() + expect(posthog.sessionPersistence.update_referrer_info).toHaveBeenCalled() }) it('errors with undefined event name', () => { @@ -480,7 +477,7 @@ describe('posthog core', () => { event: 'prop', distinct_id: 'abc', }) - expect(posthog.sessionManager!.checkAndGetSessionAndWindowId).not.toHaveBeenCalled() + expect(posthog.sessionManager.checkAndGetSessionAndWindowId).not.toHaveBeenCalled() }) it('calls sanitize_properties', () => { @@ -794,7 +791,7 @@ describe('posthog core', () => { // TODO this didn't make a tonne of sense in the given form // it makes no sense now // of course mocks added _after_ init will not be called - const posthog = defaultPostHog().init('testtoken', defaultConfig, uuidv7()) + const posthog = defaultPostHog().init('testtoken', defaultConfig, uuidv7())! posthog.sessionRecording = { afterDecideResponse: jest.fn(), From a3da4565be4b0d98ed8103427bc3963646ba4d33 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Wed, 14 Aug 2024 10:35:18 +0100 Subject: [PATCH 5/7] Tidy up tsconfig --- src/__tests__/tsconfig.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/__tests__/tsconfig.json b/src/__tests__/tsconfig.json index f51de4b32..fb50b07eb 100644 --- a/src/__tests__/tsconfig.json +++ b/src/__tests__/tsconfig.json @@ -2,11 +2,9 @@ "extends": "../../tsconfig.json", "compilerOptions": { "skipLibCheck": true, - "allowJs": true, - "checkJs": true, "strict": false, "noImplicitReturns": false, - "typeRoots": ["../../node_modules/@types", "../..//src/types"] + "typeRoots": ["../../node_modules/@types", "../../src/types"] }, "include": ["./**/*.ts*"], "exclude": [] From 033386f6c5196c10d0097be09f645e920526cd5f Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Wed, 14 Aug 2024 10:46:30 +0100 Subject: [PATCH 6/7] Remove tsc script --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index ce8d3ecb2..fd2aed7a2 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,7 @@ "typecheck": "tsc --noEmit --project tsconfig.json", "cypress": "cypress open", "prepare": "husky install", - "deprecate-old-versions": "node scripts/deprecate-old-versions.mjs", - "tsc": "tsc" + "deprecate-old-versions": "node scripts/deprecate-old-versions.mjs" }, "main": "dist/main.js", "module": "dist/module.js", From f030c70247c874e59ff0975977cb20502708790e Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 15 Aug 2024 17:15:24 +0100 Subject: [PATCH 7/7] Remove duplicate lib version --- src/posthog-core.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index fae28639f..382cbb978 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -234,7 +234,6 @@ class DeprecatedWebPerformanceObserver { export class PostHog { __loaded: boolean config: PostHogConfig - lib_version: string rateLimiter: RateLimiter scrollManager: ScrollManager @@ -287,7 +286,6 @@ export class PostHog { this.__request_queue = [] this.__loaded = false this.analyticsDefaultEndpoint = '/e/' - this.lib_version = Config.LIB_VERSION this.featureFlags = new PostHogFeatureFlags(this) this.toolbar = new Toolbar(this)