light-sentry-sdk/tests/baggage.test.ts

251 lines
8.2 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
serializeBaggage,
parseBaggage,
createBaggageFromTransaction,
} from '../src/utils/baggage';
import type { BaggageFields } from '../src/types';
describe('baggage utils', () => {
describe('serializeBaggage', () => {
it('should serialize empty baggage', () => {
const result = serializeBaggage({});
expect(result).toBe('');
});
it('should serialize baggage with all fields', () => {
const baggage: BaggageFields = {
trace_id: 'abc123',
public_key: 'key123',
sample_rate: '0.5',
sampled: 'true',
user_id: 'user1',
user_segment: 'premium',
release: '1.0.0',
environment: 'production',
};
const result = serializeBaggage(baggage);
expect(result).toContain('sentry-trace_id=abc123');
expect(result).toContain('sentry-public_key=key123');
expect(result).toContain('sentry-sample_rate=0.5');
expect(result).toContain('sentry-sampled=true');
expect(result).toContain('sentry-user_id=user1');
expect(result).toContain('sentry-user_segment=premium');
expect(result).toContain('sentry-release=1.0.0');
expect(result).toContain('sentry-environment=production');
});
it('should skip null, undefined, and empty string values', () => {
const baggage: BaggageFields = {
trace_id: 'abc123',
public_key: undefined as any,
sampled: '',
};
const result = serializeBaggage(baggage);
expect(result).toContain('sentry-trace_id=abc123');
expect(result).not.toContain('public_key');
expect(result).not.toContain('sampled');
});
it('should add sentry- prefix to non-sentry keys', () => {
const baggage: BaggageFields = {
trace_id: 'abc123',
custom_field: 'value',
};
const result = serializeBaggage(baggage);
expect(result).toContain('sentry-trace_id=abc123');
expect(result).toContain('sentry-custom_field=value');
});
it('should preserve sentry- prefix on sentry keys', () => {
const baggage: BaggageFields = {
'sentry-trace_id': 'abc123',
};
const result = serializeBaggage(baggage);
expect(result).toContain('sentry-trace_id=abc123');
// Should not double-prefix
expect(result).not.toContain('sentry-sentry-');
});
it('should truncate long baggage to 8192 characters', () => {
const longBaggage: BaggageFields = {};
// Create a very long value
const longValue = 'a'.repeat(10000);
longBaggage.trace_id = longValue;
const result = serializeBaggage(longBaggage);
expect(result.length).toBeLessThanOrEqual(8192);
});
it('should URL encode values', () => {
const baggage: BaggageFields = {
user_id: 'user with spaces',
custom_field: 'value=special&chars',
};
const result = serializeBaggage(baggage);
expect(result).toContain(encodeURIComponent('user with spaces'));
expect(result).toContain(encodeURIComponent('value=special&chars'));
});
});
describe('parseBaggage', () => {
it('should parse empty baggage', () => {
const result = parseBaggage('');
expect(result).toEqual({});
});
it('should parse valid baggage header', () => {
const header = 'sentry-trace_id=abc123,sentry-sampled=true,sentry-user_id=user1';
const result = parseBaggage(header);
expect(result.trace_id).toBe('abc123');
expect(result.sampled).toBe('true');
expect(result.user_id).toBe('user1');
});
it('should remove sentry- prefix from keys', () => {
const header = 'sentry-public_key=key123,sentry-release=1.0.0';
const result = parseBaggage(header);
expect(result.public_key).toBe('key123');
expect(result.release).toBe('1.0.0');
expect(result['sentry-public_key']).toBeUndefined();
});
it('should handle custom fields without prefix', () => {
const header = 'custom_field=value,another=data';
const result = parseBaggage(header);
expect(result.custom_field).toBe('value');
expect(result.another).toBe('data');
});
it('should URL decode values', () => {
const header = `sentry-user_id=${encodeURIComponent('user with spaces')}`;
const result = parseBaggage(header);
expect(result.user_id).toBe('user with spaces');
});
it('should skip malformed entries', () => {
const header = 'valid=key,invalid-entry-no-equals,sentry-trace_id=abc123';
const result = parseBaggage(header);
expect(result.valid).toBe('key');
expect(result['sentry-trace_id']).toBeUndefined();
expect(result.trace_id).toBe('abc123');
});
it('should handle whitespace around entries', () => {
const header = ' sentry-trace_id=abc123 , sentry-sampled=true ';
const result = parseBaggage(header);
expect(result.trace_id).toBe('abc123');
expect(result.sampled).toBe('true');
});
});
describe('createBaggageFromTransaction', () => {
it('should create baggage with only trace_id', () => {
const result = createBaggageFromTransaction('abc123');
expect(result.trace_id).toBe('abc123');
expect(Object.keys(result)).toHaveLength(1);
});
it('should create baggage with all options', () => {
const result = createBaggageFromTransaction('abc123', {
dsnPublicKey: 'key123',
sampled: true,
sampleRate: 0.5,
user: { id: 'user1', segment: 'premium' },
release: '1.0.0',
environment: 'production',
});
expect(result.trace_id).toBe('abc123');
expect(result.public_key).toBe('key123');
expect(result.sampled).toBe('true');
expect(result.sample_rate).toBe('0.5');
expect(result.user_id).toBe('user1');
expect(result.user_segment).toBe('premium');
expect(result.release).toBe('1.0.0');
expect(result.environment).toBe('production');
});
it('should convert sampled boolean to string', () => {
expect(createBaggageFromTransaction('abc', { sampled: true }).sampled).toBe('true');
expect(createBaggageFromTransaction('abc', { sampled: false }).sampled).toBe('false');
});
it('should convert sampleRate number to string', () => {
const result = createBaggageFromTransaction('abc', { sampleRate: 0.1 });
expect(result.sample_rate).toBe('0.1');
});
it('should handle optional user object', () => {
const result1 = createBaggageFromTransaction('abc', { user: { id: 'user1' } });
expect(result1.user_id).toBe('user1');
expect(result1.user_segment).toBeUndefined();
const result2 = createBaggageFromTransaction('abc', { user: { id: 'user2', segment: 'vip' } });
expect(result2.user_id).toBe('user2');
expect(result2.user_segment).toBe('vip');
});
it('should not include undefined options', () => {
const result = createBaggageFromTransaction('abc', {
dsnPublicKey: 'key',
sampled: undefined,
sampleRate: undefined,
});
expect(result.trace_id).toBe('abc');
expect(result.public_key).toBe('key');
expect(result.sampled).toBeUndefined();
expect(result.sample_rate).toBeUndefined();
});
it('should work without options', () => {
const result = createBaggageFromTransaction('abc');
expect(result.trace_id).toBe('abc');
});
});
describe('serialize/parse roundtrip', () => {
it('should preserve baggage through serialize/parse cycle', () => {
const original: BaggageFields = {
trace_id: 'abc123',
public_key: 'key123',
sampled: 'true',
user_id: 'user1',
release: '1.0.0',
environment: 'production',
custom: 'value',
};
const serialized = serializeBaggage(original);
const parsed = parseBaggage(serialized);
expect(parsed.trace_id).toBe(original.trace_id);
expect(parsed.public_key).toBe(original.public_key);
expect(parsed.sampled).toBe(original.sampled);
expect(parsed.user_id).toBe(original.user_id);
expect(parsed.release).toBe(original.release);
expect(parsed.environment).toBe(original.environment);
expect(parsed.custom).toBe(original.custom);
});
});
});