import { serializeForScriptTag } from '../json.server';
describe('serializeForScriptTag', () => {
it('should serialize basic objects', () => {
const result = serializeForScriptTag({ foo: 'bar', num: 42 });
expect(JSON.parse(result)).toEqual({ foo: 'bar', num: 42 });
});
it('should escape < to prevent injection', () => {
const result = serializeForScriptTag({
html: '',
});
// Should not contain literal < characters
expect(result).not.toContain('<');
// Should contain the escaped version
expect(result).toContain('\\u003c');
// Should still parse back correctly
expect(JSON.parse(result)).toEqual({
html: '',
});
});
it('should escape U+2028 line separator', () => {
const input = { text: 'line1\u2028line2' };
const result = serializeForScriptTag(input);
// Should not contain literal U+2028
expect(result).not.toContain('\u2028');
// Should contain the escaped version
expect(result).toContain('\\u2028');
// Should still parse back correctly
expect(JSON.parse(result)).toEqual(input);
});
it('should escape U+2029 paragraph separator', () => {
const input = { text: 'para1\u2029para2' };
const result = serializeForScriptTag(input);
// Should not contain literal U+2029
expect(result).not.toContain('\u2029');
// Should contain the escaped version
expect(result).toContain('\\u2029');
// Should still parse back correctly
expect(JSON.parse(result)).toEqual(input);
});
it('should NOT HTML-escape > character (must remain as-is for JSON validity)', () => {
const input = { arrow: '->', comparison: 'a > b' };
const result = serializeForScriptTag(input);
// Should contain literal > (NOT >)
expect(result).toContain('>');
expect(result).not.toContain('>');
// Should still parse back correctly
expect(JSON.parse(result)).toEqual(input);
});
it('should NOT HTML-escape & character', () => {
const input = { text: 'foo & bar' };
const result = serializeForScriptTag(input);
expect(result).toContain('&');
expect(result).not.toContain('&');
expect(JSON.parse(result)).toEqual(input);
});
it('should handle complex nested objects', () => {
const input = {
issues: [
{ id: 1, body: 'Fix bug', reactions: { '+1': 5 } },
{ id: 2, body: 'Path: a -> b -> c', reactions: { '-1': 0 } },
],
meta: { total: 2 },
};
const result = serializeForScriptTag(input);
expect(result).not.toContain('<');
expect(JSON.parse(result)).toEqual(input);
});
it('should handle strings with quotes correctly', () => {
const input = { text: 'He said "hello" and \'goodbye\'' };
const result = serializeForScriptTag(input);
// Should be valid JSON (quotes properly escaped by JSON.stringify)
expect(JSON.parse(result)).toEqual(input);
});
it('should handle null values', () => {
expect(serializeForScriptTag(null)).toBe('null');
});
it('should handle arrays', () => {
const input = ['