Skip to content

Commit f618283

Browse files
Copilotmattieruth
andcommitted
Add comprehensive tests for messageSizeWithinLimit utility function
Co-authored-by: mattieruth <[email protected]>
1 parent 52e9d21 commit f618283

3 files changed

Lines changed: 182 additions & 1 deletion

File tree

client-js/eslint.config.mjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,15 @@ export default [
3131
...tsRecommended.configs.recommended.rules,
3232
},
3333
},
34+
{
35+
files: ["jest.setup.js"],
36+
languageOptions: {
37+
globals: {
38+
...globals.node,
39+
},
40+
},
41+
rules: {
42+
"@typescript-eslint/no-require-imports": "off",
43+
},
44+
},
3445
];

client-js/tests/jest.setup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* SPDX-License-Identifier: BSD-2-Clause
55
*/
66

7-
import { TextEncoder, TextDecoder } from "util";
7+
import { TextDecoder, TextEncoder } from "util";
88

99
// Polyfill TextEncoder and TextDecoder for jsdom environment
1010
global.TextEncoder = TextEncoder;

client-js/tests/utils.spec.ts

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/**
2+
* Copyright (c) 2024, Daily.
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
import { describe, expect, test } from "@jest/globals";
8+
9+
import { messageSizeWithinLimit } from "./../client/utils";
10+
11+
describe("messageSizeWithinLimit", () => {
12+
test("returns true for simple string within limit", () => {
13+
const message = "Hello";
14+
// "Hello" as JSON is "\"Hello\"" (7 bytes)
15+
expect(messageSizeWithinLimit(message, 10)).toBe(true);
16+
});
17+
18+
test("returns false for simple string exceeding limit", () => {
19+
const message = "Hello World";
20+
// "Hello World" as JSON is "\"Hello World\"" (13 bytes)
21+
expect(messageSizeWithinLimit(message, 10)).toBe(false);
22+
});
23+
24+
test("returns true when size equals limit exactly", () => {
25+
const message = "Hi";
26+
// "Hi" as JSON is "\"Hi\"" (4 bytes)
27+
expect(messageSizeWithinLimit(message, 4)).toBe(true);
28+
});
29+
30+
test("handles Unicode characters correctly", () => {
31+
// "🎉" is a 4-byte UTF-8 character
32+
const message = "🎉";
33+
// "🎉" as JSON is "\"🎉\"" (2 quotes + 4 bytes for emoji = 6 bytes)
34+
const size = new TextEncoder().encode(JSON.stringify(message)).length;
35+
expect(messageSizeWithinLimit(message, size)).toBe(true);
36+
expect(messageSizeWithinLimit(message, size - 1)).toBe(false);
37+
});
38+
39+
test("handles multi-byte Unicode characters in strings", () => {
40+
const message = "Hello 世界";
41+
// Each Chinese character is typically 3 bytes in UTF-8
42+
const size = new TextEncoder().encode(JSON.stringify(message)).length;
43+
expect(messageSizeWithinLimit(message, size)).toBe(true);
44+
expect(messageSizeWithinLimit(message, size - 1)).toBe(false);
45+
});
46+
47+
test("handles simple objects", () => {
48+
const message = { name: "test", value: 123 };
49+
// {"name":"test","value":123} = 27 bytes
50+
expect(messageSizeWithinLimit(message, 30)).toBe(true);
51+
expect(messageSizeWithinLimit(message, 20)).toBe(false);
52+
});
53+
54+
test("handles nested objects", () => {
55+
const message = {
56+
outer: {
57+
inner: {
58+
deep: "value",
59+
},
60+
},
61+
};
62+
const size = new TextEncoder().encode(JSON.stringify(message)).length;
63+
expect(messageSizeWithinLimit(message, size)).toBe(true);
64+
expect(messageSizeWithinLimit(message, size - 1)).toBe(false);
65+
});
66+
67+
test("handles arrays", () => {
68+
const message = [1, 2, 3, 4, 5];
69+
// [1,2,3,4,5] = 11 bytes
70+
expect(messageSizeWithinLimit(message, 15)).toBe(true);
71+
expect(messageSizeWithinLimit(message, 10)).toBe(false);
72+
});
73+
74+
test("handles arrays of objects", () => {
75+
const message = [
76+
{ id: 1, name: "first" },
77+
{ id: 2, name: "second" },
78+
];
79+
const size = new TextEncoder().encode(JSON.stringify(message)).length;
80+
expect(messageSizeWithinLimit(message, size)).toBe(true);
81+
expect(messageSizeWithinLimit(message, size - 1)).toBe(false);
82+
});
83+
84+
test("handles null", () => {
85+
const message = null;
86+
// null as JSON is "null" (4 bytes)
87+
expect(messageSizeWithinLimit(message, 4)).toBe(true);
88+
expect(messageSizeWithinLimit(message, 3)).toBe(false);
89+
});
90+
91+
test("handles empty objects", () => {
92+
const message = {};
93+
// {} = 2 bytes
94+
expect(messageSizeWithinLimit(message, 2)).toBe(true);
95+
expect(messageSizeWithinLimit(message, 1)).toBe(false);
96+
});
97+
98+
test("handles empty arrays", () => {
99+
const message = [];
100+
// [] = 2 bytes
101+
expect(messageSizeWithinLimit(message, 2)).toBe(true);
102+
expect(messageSizeWithinLimit(message, 1)).toBe(false);
103+
});
104+
105+
test("handles empty strings", () => {
106+
const message = "";
107+
// "" as JSON is "\"\"" (2 bytes)
108+
expect(messageSizeWithinLimit(message, 2)).toBe(true);
109+
expect(messageSizeWithinLimit(message, 1)).toBe(false);
110+
});
111+
112+
test("handles numbers", () => {
113+
const message = 12345;
114+
// 12345 as JSON is "12345" (5 bytes)
115+
expect(messageSizeWithinLimit(message, 5)).toBe(true);
116+
expect(messageSizeWithinLimit(message, 4)).toBe(false);
117+
});
118+
119+
test("handles booleans", () => {
120+
const trueMessage = true;
121+
// true as JSON is "true" (4 bytes)
122+
expect(messageSizeWithinLimit(trueMessage, 4)).toBe(true);
123+
expect(messageSizeWithinLimit(trueMessage, 3)).toBe(false);
124+
125+
const falseMessage = false;
126+
// false as JSON is "false" (5 bytes)
127+
expect(messageSizeWithinLimit(falseMessage, 5)).toBe(true);
128+
expect(messageSizeWithinLimit(falseMessage, 4)).toBe(false);
129+
});
130+
131+
test("handles complex nested structures with Unicode", () => {
132+
const message = {
133+
user: {
134+
name: "Test User",
135+
emoji: "🎉🎊",
136+
location: "東京",
137+
},
138+
data: [1, 2, 3],
139+
meta: {
140+
timestamp: 1234567890,
141+
tags: ["tag1", "tag2"],
142+
},
143+
};
144+
const size = new TextEncoder().encode(JSON.stringify(message)).length;
145+
expect(messageSizeWithinLimit(message, size)).toBe(true);
146+
expect(messageSizeWithinLimit(message, size - 1)).toBe(false);
147+
});
148+
149+
test("handles large objects exceeding typical limits", () => {
150+
// Create a large object
151+
const largeArray = Array(1000)
152+
.fill(null)
153+
.map((_, i) => ({ id: i, value: `item-${i}` }));
154+
const message = { data: largeArray };
155+
const size = new TextEncoder().encode(JSON.stringify(message)).length;
156+
157+
// Should be within a very large limit
158+
expect(messageSizeWithinLimit(message, size)).toBe(true);
159+
// Should exceed a small limit
160+
expect(messageSizeWithinLimit(message, 100)).toBe(false);
161+
});
162+
163+
test("handles special characters and escapes", () => {
164+
const message = { text: 'Line 1\nLine 2\t"quoted"' };
165+
// JSON.stringify will escape special characters
166+
const size = new TextEncoder().encode(JSON.stringify(message)).length;
167+
expect(messageSizeWithinLimit(message, size)).toBe(true);
168+
expect(messageSizeWithinLimit(message, size - 1)).toBe(false);
169+
});
170+
});

0 commit comments

Comments
 (0)