158 lines
4.3 KiB
JavaScript
158 lines
4.3 KiB
JavaScript
/**
|
||
* Tests for js/utils/helpers.js
|
||
*/
|
||
|
||
import { test, describe, assertEquals, assertTrue } from './test-runner.js'
|
||
import { escapeHTML, formatPrice, formatRelativeTime, debounce, truncate } from '../js/utils/helpers.js'
|
||
|
||
describe('escapeHTML', () => {
|
||
test('escapes < and >', () => {
|
||
assertEquals(escapeHTML('<script>'), '<script>')
|
||
})
|
||
|
||
test('escapes quotes', () => {
|
||
assertEquals(escapeHTML('"hello"'), '"hello"')
|
||
})
|
||
|
||
test('escapes ampersand', () => {
|
||
assertEquals(escapeHTML('a & b'), 'a & b')
|
||
})
|
||
|
||
test('escapes single quotes', () => {
|
||
assertEquals(escapeHTML("it's"), "it's")
|
||
})
|
||
|
||
test('handles null', () => {
|
||
assertEquals(escapeHTML(null), '')
|
||
})
|
||
|
||
test('handles undefined', () => {
|
||
assertEquals(escapeHTML(undefined), '')
|
||
})
|
||
|
||
test('handles numbers by converting to string', () => {
|
||
assertEquals(escapeHTML(123), '123')
|
||
})
|
||
|
||
test('handles complex XSS attempt', () => {
|
||
const xss = '<img src="x" onerror="alert(1)">'
|
||
assertTrue(!escapeHTML(xss).includes('<'))
|
||
})
|
||
})
|
||
|
||
describe('formatPrice', () => {
|
||
test('formats EUR correctly', () => {
|
||
assertEquals(formatPrice(99.5, 'EUR'), '€ 99.50')
|
||
})
|
||
|
||
test('formats USD correctly', () => {
|
||
assertEquals(formatPrice(99.5, 'USD'), '$ 99.50')
|
||
})
|
||
|
||
test('formats CHF correctly', () => {
|
||
assertEquals(formatPrice(99.5, 'CHF'), 'CHF 99.50')
|
||
})
|
||
|
||
test('formats XMR with 4 decimals', () => {
|
||
assertEquals(formatPrice(0.5, 'XMR'), '0.5000 ɱ')
|
||
})
|
||
|
||
test('handles null price', () => {
|
||
assertEquals(formatPrice(null, 'EUR'), '–')
|
||
})
|
||
|
||
test('handles undefined price', () => {
|
||
assertEquals(formatPrice(undefined, 'EUR'), '–')
|
||
})
|
||
|
||
test('defaults to EUR', () => {
|
||
assertEquals(formatPrice(10), '€ 10.00')
|
||
})
|
||
|
||
test('handles unknown currency', () => {
|
||
assertEquals(formatPrice(10, 'GBP'), 'GBP 10.00')
|
||
})
|
||
})
|
||
|
||
describe('formatRelativeTime', () => {
|
||
test('formats seconds ago', () => {
|
||
const date = new Date(Date.now() - 30000) // 30 seconds ago
|
||
const result = formatRelativeTime(date, 'en')
|
||
assertTrue(result.includes('second'))
|
||
})
|
||
|
||
test('formats minutes ago', () => {
|
||
const date = new Date(Date.now() - 5 * 60000) // 5 minutes ago
|
||
const result = formatRelativeTime(date, 'en')
|
||
assertTrue(result.includes('minute'))
|
||
})
|
||
|
||
test('formats hours ago', () => {
|
||
const date = new Date(Date.now() - 2 * 3600000) // 2 hours ago
|
||
const result = formatRelativeTime(date, 'en')
|
||
assertTrue(result.includes('hour'))
|
||
})
|
||
|
||
test('formats days ago', () => {
|
||
const date = new Date(Date.now() - 3 * 86400000) // 3 days ago
|
||
const result = formatRelativeTime(date, 'en')
|
||
assertTrue(result.includes('day'))
|
||
})
|
||
|
||
test('accepts string date', () => {
|
||
const date = new Date(Date.now() - 60000).toISOString()
|
||
const result = formatRelativeTime(date, 'en')
|
||
assertTrue(result.includes('minute'))
|
||
})
|
||
|
||
test('respects locale de', () => {
|
||
const date = new Date(Date.now() - 60000)
|
||
const result = formatRelativeTime(date, 'de')
|
||
assertTrue(result.includes('Minute'))
|
||
})
|
||
})
|
||
|
||
describe('truncate', () => {
|
||
test('truncates long strings', () => {
|
||
assertEquals(truncate('Hello World', 6), 'Hello…')
|
||
})
|
||
|
||
test('does not truncate short strings', () => {
|
||
assertEquals(truncate('Hi', 10), 'Hi')
|
||
})
|
||
|
||
test('handles exact length', () => {
|
||
assertEquals(truncate('Hello', 5), 'Hello')
|
||
})
|
||
|
||
test('handles null', () => {
|
||
assertEquals(truncate(null, 10), null)
|
||
})
|
||
|
||
test('handles empty string', () => {
|
||
assertEquals(truncate('', 10), '')
|
||
})
|
||
|
||
test('uses default maxLength of 100', () => {
|
||
const long = 'a'.repeat(150)
|
||
const result = truncate(long)
|
||
assertEquals(result.length, 100)
|
||
assertTrue(result.endsWith('…'))
|
||
})
|
||
})
|
||
|
||
describe('debounce', () => {
|
||
test('returns a function', () => {
|
||
const fn = debounce(() => {})
|
||
assertEquals(typeof fn, 'function')
|
||
})
|
||
|
||
test('delays execution', (done) => {
|
||
let called = false
|
||
const fn = debounce(() => { called = true }, 50)
|
||
|
||
fn()
|
||
assertEquals(called, false)
|
||
})
|
||
})
|