Files
tolaria/src/lib/telemetry.test.ts
2026-05-07 22:22:29 +02:00

111 lines
3.3 KiB
TypeScript

import { afterEach, describe, it, expect, vi } from 'vitest'
const sentryMocks = vi.hoisted(() => ({
close: vi.fn(),
init: vi.fn(),
setTag: vi.fn(),
setUser: vi.fn(),
}))
vi.mock('@sentry/react', () => sentryMocks)
import {
_scrubPathsForTest as scrubPaths,
initSentry,
isFeatureEnabled,
setReleaseChannel,
teardownSentry,
trackEvent,
} from './telemetry'
afterEach(() => {
teardownSentry()
vi.unstubAllEnvs()
sentryMocks.close.mockClear()
sentryMocks.init.mockClear()
sentryMocks.setTag.mockClear()
sentryMocks.setUser.mockClear()
})
describe('telemetry scrubPaths', () => {
it('redacts macOS absolute paths', () => {
expect(scrubPaths('Error in /Users/luca/Laputa/note.md')).toBe(
'Error in [redacted-path]'
)
})
it('redacts Linux absolute paths', () => {
expect(scrubPaths('Error in /home/user/vault/note.md')).toBe(
'Error in [redacted-path]'
)
})
it('redacts Windows paths', () => {
expect(scrubPaths('Error in C:\\Users\\luca\\docs\\file.md')).toBe(
'Error in [redacted-path]'
)
})
it('leaves non-path strings untouched', () => {
expect(scrubPaths('Something went wrong')).toBe('Something went wrong')
})
it('redacts multiple paths in one string', () => {
const input = 'Failed copying /a/b/c to /x/y/z'
expect(scrubPaths(input)).toBe('Failed copying [redacted-path] to [redacted-path]')
})
})
describe('trackEvent', () => {
it('does not throw when PostHog is not initialized', () => {
expect(() => trackEvent('test_event', { count: 1 })).not.toThrow()
})
it('accepts event name with no properties', () => {
expect(() => trackEvent('note_created')).not.toThrow()
})
it('accepts event name with string and number properties', () => {
expect(() => trackEvent('note_created', { has_type: 1, creation_path: 'cmd_n' })).not.toThrow()
})
})
describe('initSentry', () => {
it.each([
['stable builds', '2026.4.23', '2026.4.23', 'stable'],
['alpha builds', '2026.4.28-alpha.7', undefined, 'prerelease'],
['local builds', '0.1.0', undefined, 'internal'],
])('sets release metadata for %s', (_name, buildVersion, sentryRelease, releaseKind) => {
vi.stubEnv('VITE_SENTRY_DSN', 'https://public@example.ingest.sentry.io/123456')
vi.stubEnv('VITE_SENTRY_RELEASE', buildVersion)
initSentry('anonymous-user')
expect(sentryMocks.init).toHaveBeenCalledWith(expect.objectContaining({
dsn: 'https://public@example.ingest.sentry.io/123456',
release: sentryRelease,
}))
expect(sentryMocks.setUser).toHaveBeenCalledWith({ id: 'anonymous-user' })
expect(sentryMocks.setTag).toHaveBeenCalledWith('tolaria.build_version', buildVersion)
expect(sentryMocks.setTag).toHaveBeenCalledWith('tolaria.release_kind', releaseKind)
})
})
describe('isFeatureEnabled', () => {
it('returns true for alpha channel regardless of flag state', () => {
setReleaseChannel('alpha')
expect(isFeatureEnabled('any_flag')).toBe(true)
expect(isFeatureEnabled('nonexistent_flag')).toBe(true)
})
it('returns false for stable channel when PostHog is not initialized', () => {
setReleaseChannel('stable')
expect(isFeatureEnabled('some_flag')).toBe(false)
})
it('returns false for beta channel when PostHog is not initialized', () => {
setReleaseChannel('beta')
expect(isFeatureEnabled('some_flag')).toBe(false)
})
})