Skip to content

Commit 9019898

Browse files
committed
fix undefined and null values when fallback is true
1 parent 0a298b5 commit 9019898

File tree

2 files changed

+108
-4
lines changed

2 files changed

+108
-4
lines changed

packages/core/src/attributes.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export function attributeValueToTypedAttributeValue(
8484
return { ...attributeValue, ...checkedUnit };
8585
}
8686

87-
if (!useFallback) {
87+
if (!useFallback || value === undefined) {
8888
return;
8989
}
9090

@@ -113,9 +113,12 @@ export function attributeValueToTypedAttributeValue(
113113
*
114114
* @returns The serialized attributes.
115115
*/
116-
export function serializeAttributes<T>(attributes: RawAttributes<T>, fallback: boolean = false): Attributes {
116+
export function serializeAttributes<T>(
117+
attributes: RawAttributes<T> | undefined,
118+
fallback: boolean = false,
119+
): Attributes {
117120
const serializedAttributes: Attributes = {};
118-
for (const [key, value] of Object.entries(attributes)) {
121+
for (const [key, value] of Object.entries(attributes ?? {})) {
119122
const typedValue = attributeValueToTypedAttributeValue(value, fallback);
120123
if (typedValue) {
121124
serializedAttributes[key] = typedValue;

packages/core/test/lib/attributes.test.ts

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from 'vitest';
2-
import { attributeValueToTypedAttributeValue, isAttributeObject } from '../../src/attributes';
2+
import { attributeValueToTypedAttributeValue, isAttributeObject, serializeAttributes } from '../../src/attributes';
33

44
describe('attributeValueToTypedAttributeValue', () => {
55
describe('without fallback (default behavior)', () => {
@@ -267,6 +267,19 @@ describe('attributeValueToTypedAttributeValue', () => {
267267
type: 'string',
268268
});
269269
});
270+
271+
it.each([null, { value: null }, { value: null, unit: 'byte' }])('stringifies %s values', value => {
272+
const result = attributeValueToTypedAttributeValue(value, true);
273+
expect(result).toMatchObject({
274+
value: 'null',
275+
type: 'string',
276+
});
277+
});
278+
279+
it.each([undefined, { value: undefined }, { value: undefined, unit: 'byte' }])('ignores %s values', value => {
280+
const result = attributeValueToTypedAttributeValue(value, true);
281+
expect(result).toBeUndefined();
282+
});
270283
});
271284
});
272285
});
@@ -297,3 +310,91 @@ describe('isAttributeObject', () => {
297310
},
298311
);
299312
});
313+
314+
describe('serializeAttributes', () => {
315+
it('returns an empty object for undefined attributes', () => {
316+
const result = serializeAttributes(undefined);
317+
expect(result).toStrictEqual({});
318+
});
319+
320+
it('returns an empty object for an empty object', () => {
321+
const result = serializeAttributes({});
322+
expect(result).toStrictEqual({});
323+
});
324+
325+
it('serializes valid, non-primitive values', () => {
326+
const result = serializeAttributes({ foo: 'bar', bar: { value: 123 }, baz: { value: 456, unit: 'byte' } });
327+
expect(result).toStrictEqual({
328+
bar: {
329+
type: 'integer',
330+
value: 123,
331+
},
332+
baz: {
333+
type: 'integer',
334+
unit: 'byte',
335+
value: 456,
336+
},
337+
foo: {
338+
type: 'string',
339+
value: 'bar',
340+
},
341+
});
342+
});
343+
344+
it.each([true, false])('ignores undefined values if fallback is %s', fallback => {
345+
const result = serializeAttributes(
346+
{ foo: undefined, bar: { value: undefined }, baz: { value: undefined, unit: 'byte' } },
347+
fallback,
348+
);
349+
expect(result).toStrictEqual({});
350+
});
351+
352+
it('ignores null values by default', () => {
353+
const result = serializeAttributes({ foo: null, bar: { value: null }, baz: { value: null, unit: 'byte' } });
354+
expect(result).toStrictEqual({});
355+
});
356+
357+
it('stringifies to `"null"` if fallback is true', () => {
358+
const result = serializeAttributes({ foo: null, bar: { value: null }, baz: { value: null, unit: 'byte' } }, true);
359+
expect(result).toStrictEqual({
360+
foo: {
361+
type: 'string',
362+
value: 'null',
363+
},
364+
bar: {
365+
type: 'string',
366+
value: 'null',
367+
},
368+
baz: {
369+
type: 'string',
370+
unit: 'byte',
371+
value: 'null',
372+
},
373+
});
374+
});
375+
376+
describe('invalid (non-primitive) values', () => {
377+
it("doesn't fall back to stringification by default", () => {
378+
const result = serializeAttributes({ foo: { some: 'object' }, bar: [1, 2, 3], baz: () => {} });
379+
expect(result).toStrictEqual({});
380+
});
381+
382+
it('falls back to stringification of unsupported non-primitive values if fallback is true', () => {
383+
const result = serializeAttributes({ foo: { some: 'object' }, bar: [1, 2, 3], baz: () => {} }, true);
384+
expect(result).toStrictEqual({
385+
bar: {
386+
type: 'string',
387+
value: '[1,2,3]',
388+
},
389+
baz: {
390+
type: 'string',
391+
value: '',
392+
},
393+
foo: {
394+
type: 'string',
395+
value: '{"some":"object"}',
396+
},
397+
});
398+
});
399+
});
400+
});

0 commit comments

Comments
 (0)