Skip to content

Commit 03652e3

Browse files
semikolonclaude
andcommitted
test: add tests for token optimization features
- Add maxLength truncation tests to snapshotFormatter.test.ts - Add new image-processor.test.ts with tests for resize and format conversion - Use sharp to generate valid test images (more reliable than manual PNG bytes) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 7db3bf1 commit 03652e3

2 files changed

Lines changed: 197 additions & 0 deletions

File tree

tests/formatters/snapshotFormatter.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,74 @@ describe('snapshotFormatter', () => {
292292
],
293293
});
294294
});
295+
296+
describe('maxLength truncation', () => {
297+
it('truncates output when exceeding maxLength', () => {
298+
const node: TextSnapshotNode = {
299+
id: '1_1',
300+
role: 'root',
301+
name: 'root',
302+
children: [
303+
{
304+
id: '1_2',
305+
role: 'button',
306+
name: 'This is a very long button name that will cause the output to exceed the maxLength limit',
307+
children: [],
308+
elementHandle: async () => null,
309+
},
310+
{
311+
id: '1_3',
312+
role: 'textbox',
313+
name: 'Another element with a long name',
314+
children: [],
315+
elementHandle: async () => null,
316+
},
317+
],
318+
elementHandle: async () => null,
319+
};
320+
321+
const formatter = new SnapshotFormatter(
322+
{root: node} as TextSnapshot,
323+
{maxLength: 50},
324+
);
325+
const formatted = formatter.toString();
326+
327+
assert.ok(formatted.length <= 50);
328+
assert.ok(formatted.includes('[truncated'));
329+
});
330+
331+
it('does not truncate when under maxLength', () => {
332+
const node: TextSnapshotNode = {
333+
id: '1_1',
334+
role: 'button',
335+
name: 'btn',
336+
children: [],
337+
elementHandle: async () => null,
338+
};
339+
340+
const formatter = new SnapshotFormatter(
341+
{root: node} as TextSnapshot,
342+
{maxLength: 1000},
343+
);
344+
const formatted = formatter.toString();
345+
346+
assert.ok(!formatted.includes('[truncated'));
347+
});
348+
349+
it('works without maxLength option', () => {
350+
const node: TextSnapshotNode = {
351+
id: '1_1',
352+
role: 'button',
353+
name: 'button',
354+
children: [],
355+
elementHandle: async () => null,
356+
};
357+
358+
const formatter = new SnapshotFormatter({root: node} as TextSnapshot);
359+
const formatted = formatter.toString();
360+
361+
assert.ok(formatted.includes('button'));
362+
assert.ok(!formatted.includes('[truncated'));
363+
});
364+
});
295365
});
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import assert from 'node:assert';
8+
import {describe, it, before} from 'node:test';
9+
10+
import sharp from 'sharp';
11+
12+
import {processImage} from '../../src/utils/image-processor.js';
13+
14+
// Create a valid test PNG using sharp (100x100 red square)
15+
async function createTestPng(): Promise<Uint8Array> {
16+
const buffer = await sharp({
17+
create: {
18+
width: 100,
19+
height: 100,
20+
channels: 3,
21+
background: {r: 255, g: 0, b: 0},
22+
},
23+
})
24+
.png()
25+
.toBuffer();
26+
return new Uint8Array(buffer);
27+
}
28+
29+
// Cache the test image to avoid regenerating for each test
30+
let testPngCache: Uint8Array | null = null;
31+
async function getTestPng(): Promise<Uint8Array> {
32+
if (!testPngCache) {
33+
testPngCache = await createTestPng();
34+
}
35+
return testPngCache;
36+
}
37+
38+
describe('image-processor', () => {
39+
describe('processImage', () => {
40+
it('returns original image when no options provided', async () => {
41+
const testPng = await getTestPng();
42+
const result = await processImage(testPng, 'image/png');
43+
44+
assert.strictEqual(result.mimeType, 'image/png');
45+
assert.strictEqual(result.compressionRatio, 1.0);
46+
assert.strictEqual(result.originalSize.width, result.processedSize.width);
47+
assert.strictEqual(result.originalSize.height, result.processedSize.height);
48+
});
49+
50+
it('returns original image when empty options provided', async () => {
51+
const testPng = await getTestPng();
52+
const result = await processImage(testPng, 'image/png', {});
53+
54+
assert.strictEqual(result.mimeType, 'image/png');
55+
assert.strictEqual(result.compressionRatio, 1.0);
56+
});
57+
58+
it('respects maxWidth option', async () => {
59+
const testPng = await getTestPng();
60+
const result = await processImage(testPng, 'image/png', {maxWidth: 50});
61+
62+
// 100x100 image resized to max 50 width
63+
assert.strictEqual(result.processedSize.width, 50);
64+
assert.strictEqual(result.processedSize.height, 50);
65+
});
66+
67+
it('respects maxHeight option', async () => {
68+
const testPng = await getTestPng();
69+
const result = await processImage(testPng, 'image/png', {maxHeight: 50});
70+
71+
// 100x100 image resized to max 50 height
72+
assert.strictEqual(result.processedSize.width, 50);
73+
assert.strictEqual(result.processedSize.height, 50);
74+
});
75+
76+
it('converts format when specified', async () => {
77+
const testPng = await getTestPng();
78+
const result = await processImage(testPng, 'image/png', {format: 'jpeg'});
79+
80+
assert.strictEqual(result.mimeType, 'image/jpeg');
81+
});
82+
83+
it('applies quality setting for jpeg', async () => {
84+
const testPng = await getTestPng();
85+
const result = await processImage(testPng, 'image/png', {
86+
format: 'jpeg',
87+
quality: 50,
88+
});
89+
90+
assert.strictEqual(result.mimeType, 'image/jpeg');
91+
assert.ok(result.data.length > 0);
92+
});
93+
94+
it('applies quality setting for webp', async () => {
95+
const testPng = await getTestPng();
96+
const result = await processImage(testPng, 'image/png', {
97+
format: 'webp',
98+
quality: 80,
99+
});
100+
101+
assert.strictEqual(result.mimeType, 'image/webp');
102+
assert.ok(result.data.length > 0);
103+
});
104+
105+
it('returns metadata about processing', async () => {
106+
const testPng = await getTestPng();
107+
const result = await processImage(testPng, 'image/png', {maxWidth: 50});
108+
109+
assert.ok('originalSize' in result);
110+
assert.ok('processedSize' in result);
111+
assert.ok('compressionRatio' in result);
112+
assert.strictEqual(result.originalSize.width, 100);
113+
assert.strictEqual(result.originalSize.height, 100);
114+
assert.strictEqual(result.processedSize.width, 50);
115+
assert.strictEqual(result.processedSize.height, 50);
116+
});
117+
118+
it('calculates compression ratio correctly', async () => {
119+
const testPng = await getTestPng();
120+
const result = await processImage(testPng, 'image/png', {maxWidth: 50});
121+
122+
// Resized image should be smaller
123+
assert.ok(result.compressionRatio < 1.0);
124+
assert.ok(result.data.length < testPng.length);
125+
});
126+
});
127+
});

0 commit comments

Comments
 (0)