test: add JS test framework using Node built-in test runner

Extracted pure utility functions (esc, sanitize, formatBytes, formatTime)
into web/ui/util.js with CommonJS export for Node testing compatibility.
Added 19 tests across 4 suites using node:test + node:assert (zero deps).

- util.js: browser-compatible utility functions
- util.test.js: 19 tests (5 esc, 3 sanitize, 6 formatBytes, 5 formatTime)
- package.json: 'test' script → node --test util.test.js
- mise.toml: js-test task
- app.js: removed duplicate helper functions (now in util.js)
- index.html: load util.js before app.js
This commit was merged in pull request #14.
This commit is contained in:
2026-06-22 02:23:24 -07:00
parent d7a17eb054
commit b5650c53ba
6 changed files with 125 additions and 28 deletions
+91
View File
@@ -0,0 +1,91 @@
const { describe, it } = require('node:test')
const assert = require('node:assert/strict')
const { esc, sanitize, formatBytes, formatTime } = require('./util.js')
describe('esc', () => {
it('escapes HTML entities', () => {
assert.strictEqual(esc('<script>alert("xss")</script>'),
'&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;')
})
it('handles ampersands', () => {
assert.strictEqual(esc('a & b'), 'a &amp; b')
})
it('handles single quotes', () => {
assert.strictEqual(esc("it's"), 'it&#39;s')
})
it('returns empty string for falsy input', () => {
assert.strictEqual(esc(''), '')
assert.strictEqual(esc(null), '')
assert.strictEqual(esc(undefined), '')
})
it('passes through safe strings', () => {
assert.strictEqual(esc('Hello World'), 'Hello World')
})
})
describe('sanitize', () => {
it('replaces special characters with underscores', () => {
assert.strictEqual(sanitize('hello world!'), 'hello_world_')
})
it('preserves alphanumeric and dashes', () => {
assert.strictEqual(sanitize('test-123_abc'), 'test-123_abc')
})
it('sanitizes dots and slashes', () => {
assert.strictEqual(sanitize('path/to/file.name'),
'path_to_file_name')
})
})
describe('formatBytes', () => {
it('formats zero', () => {
assert.strictEqual(formatBytes(0), '0 B')
})
it('formats bytes', () => {
assert.strictEqual(formatBytes(500), '500 B')
})
it('formats KB', () => {
assert.strictEqual(formatBytes(1024), '1 KB')
})
it('formats MB', () => {
assert.strictEqual(formatBytes(1048576), '1 MB')
})
it('formats GB', () => {
assert.strictEqual(formatBytes(1073741824), '1 GB')
})
it('formats fractional', () => {
assert.strictEqual(formatBytes(1536), '1.5 KB')
})
})
describe('formatTime', () => {
it('formats zero', () => {
assert.strictEqual(formatTime(0), '0:00')
})
it('formats seconds', () => {
assert.strictEqual(formatTime(5), '0:05')
})
it('formats minutes and seconds', () => {
assert.strictEqual(formatTime(65), '1:05')
})
it('formats double-digit seconds', () => {
assert.strictEqual(formatTime(75), '1:15')
})
it('formats large times', () => {
assert.strictEqual(formatTime(3661), '61:01')
})
})