111 lines
3.3 KiB
TypeScript
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)
|
|
})
|
|
})
|