Skip to content

Commit fccaf0d

Browse files
Add tests to ensure attributes are encoded by copy
1 parent fb33323 commit fccaf0d

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

packages/core/src/sdk/AttributesEncoding/__tests__/attributesEncoding.test.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,122 @@ describe('encodeAttributes', () => {
130130
expect(result).toEqual({ valid: 'ok' });
131131
});
132132

133+
it('does not modify original object when dropping values', () => {
134+
const input = { valid: 'ok', bad: () => {} };
135+
const result = encodeAttributes(input);
136+
expect(result).toEqual({ valid: 'ok' });
137+
expect(input).toHaveProperty('bad');
138+
});
139+
140+
it('does not modify original object when dropping nested invalid values', () => {
141+
const input = { user: { profile: { bad: () => {}, good: 'ok' } } };
142+
const userBefore = { ...input.user };
143+
const profileBefore = { ...input.user.profile };
144+
145+
const result = encodeAttributes(input);
146+
147+
// Encoder should flatten and drop invalid function
148+
expect(result).toEqual({ 'user.profile.good': 'ok' });
149+
150+
// Verify that the original objects were not mutated or replaced
151+
expect(input.user).toEqual(userBefore);
152+
expect(input.user.profile).toEqual(profileBefore);
153+
});
154+
155+
it('does not modify original array inside object', () => {
156+
const arr = [1, 2, () => {}];
157+
const input = { data: arr };
158+
const arrBefore = [...arr];
159+
160+
const result = encodeAttributes(input);
161+
expect(result).toEqual({ data: [1, 2] }); // dropped the function
162+
expect(input.data).toEqual(arrBefore); // original array untouched
163+
});
164+
165+
it('does not modify original nested arrays of objects', () => {
166+
const objA = { val: 1 };
167+
const objB = { bad: () => {} };
168+
const objC = { val: 2 };
169+
170+
const input = {
171+
matrix: [[objA, objB], [objC]]
172+
};
173+
174+
// capture snapshots
175+
const matrixBefore = input.matrix;
176+
const row0Before = input.matrix[0];
177+
const row1Before = input.matrix[1];
178+
const objA_before = { ...objA };
179+
const objB_before = { ...objB };
180+
const objC_before = { ...objC };
181+
182+
const result = encodeAttributes(input);
183+
184+
expect(result).toEqual({
185+
matrix: [
186+
[{ val: 1 }, {}], // objB sanitized
187+
[{ val: 2 }]
188+
]
189+
});
190+
191+
// check original references untouched
192+
expect(input.matrix).toBe(matrixBefore); // same outer array reference
193+
expect(input.matrix[0]).toBe(row0Before); // same row0 reference
194+
expect(input.matrix[1]).toBe(row1Before); // same row1 reference
195+
expect(objA).toEqual(objA_before); // object A unchanged
196+
expect(objB).toEqual(objB_before); // object B unchanged
197+
expect(objC).toEqual(objC_before); // object C unchanged
198+
});
199+
200+
it('does not modify original Map when encoding', () => {
201+
const innerMap = new Map([['x', 1]]);
202+
const outerMap = new Map<any, any>([['inner', innerMap]]);
203+
const input = { outer: outerMap };
204+
205+
const snapshot = new Map(outerMap);
206+
const innerSnapshot = new Map(innerMap);
207+
208+
const result = encodeAttributes(input);
209+
expect(result.outer).toBeInstanceOf(Array);
210+
expect(input.outer).toBe(outerMap); // same reference
211+
expect(Array.from(input.outer.entries())).toEqual(
212+
Array.from(snapshot.entries())
213+
);
214+
expect(Array.from(innerMap.entries())).toEqual(
215+
Array.from(innerSnapshot.entries())
216+
);
217+
});
218+
219+
it('does not modify original object when attribute limit is reached', () => {
220+
const input: Record<string, string> = {};
221+
for (let i = 0; i < 200; i++) {
222+
input[`k${i}`] = `v${i}`;
223+
}
224+
const snapshot = { ...input };
225+
226+
const result = encodeAttributes(input);
227+
expect(Object.keys(result)).toHaveLength(128);
228+
expect(input).toEqual(snapshot); // original still has 200 keys
229+
});
230+
231+
it('does not modify original when sanitizing arrays of objects', () => {
232+
const obj1 = { ok: true };
233+
const obj2 = { bad: () => {} };
234+
const input = [obj1, obj2];
235+
236+
// Capture pre-encode snapshots manually
237+
const obj1Before = { ...obj1 };
238+
const obj2Before = { ...obj2 };
239+
const arrayBefore = [...input];
240+
241+
const result = encodeAttributes(input);
242+
243+
expect(result).toEqual({ context: [{ ok: true }, {}] });
244+
expect(input).toEqual(arrayBefore);
245+
expect(input[0]).toEqual(obj1Before);
246+
expect(input[1]).toEqual(obj2Before);
247+
});
248+
133249
it('handles deeply nested objects', () => {
134250
const deep = { level1: { level2: { level3: { value: 42 } } } };
135251
const result = encodeAttributes(deep);

0 commit comments

Comments
 (0)