Repository navigation
Expand file tree
/
Copy pathtest_v021_patch.js
More file actions
120 lines (111 loc) · 3.72 KB
/
Copy pathtest_v021_patch.js
File metadata and controls
120 lines (111 loc) · 3.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// =============================================================================
// Chat Archive — Serializer Patch Test (v0.2.1)
// =============================================================================
// Run with: node test_v021_patch.js
// Verifies escapeHtmlForMarkdown handles the cases that caused the turn 20 bug.
// --- Inline the function under test (mirrors serializer.js exactly) ---
function escapeHtmlForMarkdown(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// --- Test harness ---
let passed = 0;
let failed = 0;
function test(description, input, expected) {
const result = escapeHtmlForMarkdown(input);
if (result === expected) {
console.log(` ✅ ${description}`);
passed++;
} else {
console.log(` ❌ ${description}`);
console.log(` Input: ${input}`);
console.log(` Expected: ${expected}`);
console.log(` Got: ${result}`);
failed++;
}
}
// --- Tests ---
console.log('\nChat Archive v0.2.1 — escapeHtmlForMarkdown tests\n');
console.log('Core escaping:');
test(
'Escapes < and > (the primary bug trigger)',
'everything is in the <style> tag',
'everything is in the <style> tag'
);
test(
'Escapes & before < and > (avoids double-escaping)',
'AT&T and <div>',
'AT&T and <div>'
);
test(
'Escapes double quotes',
'aria-label="Copy"',
'aria-label="Copy"'
);
test(
"Escapes single quotes",
"it's a <script>",
"it's a <script>"
);
test(
'No-op on plain text',
'Hello, world! This has no HTML.',
'Hello, world! This has no HTML.'
);
console.log('\nReal content from the bug report (turn 20):');
test(
'The exact sentence that caused the break',
'This uses embedded inline styles - everything is in the <style> tag within the HTML file itself.',
'This uses embedded inline styles - everything is in the <style> tag within the HTML file itself.'
);
console.log('\nCommon technical conversation patterns:');
test(
'CSS rule with selector',
'header.welcome { background-image: url("../images/hero.jpg"); }',
'header.welcome { background-image: url("../images/hero.jpg"); }'
);
test(
'HTML tag discussion',
'Add this to your <head> section: <meta charset="UTF-8">',
'Add this to your <head> section: <meta charset="UTF-8">'
);
test(
'Script tag (high-risk contaminator)',
'<script>alert("xss")</script>',
'<script>alert("xss")</script>'
);
test(
'Markdown links still work (no < > involved)',
'See [SSL Labs](https://www.ssllabs.com/ssltest/) for testing.',
'See [SSL Labs](https://www.ssllabs.com/ssltest/) for testing.'
);
test(
'Emoji and unicode unaffected',
'🎉 SUCCESS! ✅ 488 emails processed — Perfect 100% success rate!',
'🎉 SUCCESS! ✅ 488 emails processed — Perfect 100% success rate!'
);
console.log('\nJSON path (should NOT be escaped — verified by identity):');
// This is a contract test: JSON path uses turn.content directly, no escaping.
// We verify the raw content string is preserved as-is.
const rawContent = 'everything is in the <style> tag';
const jsonParsed = JSON.parse(JSON.stringify({ content: rawContent }));
if (jsonParsed.content === rawContent) {
console.log(' ✅ JSON path preserves raw content unchanged');
passed++;
} else {
console.log(' ❌ JSON path unexpectedly modified content');
failed++;
}
// --- Summary ---
console.log(`\n${'─'.repeat(50)}`);
console.log(`Results: ${passed} passed, ${failed} failed`);
if (failed === 0) {
console.log('All tests passed. Safe to ship v0.2.1. ✅');
} else {
console.log('Fix the failures above before shipping. ❌');
}
console.log('');