Files
AtreidesAssetsFree/tests/ui/alert.test.mjs
T
2026-10-29 11:57:29 +01:00

66 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Generated, do not edit. sha256:c59345089e27fb5a471d676d1783b760f5131e156f381aef6e04e76979a27c21
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
const { alertHtml } = await import('../../client/ui/alert.js');
describe('alertHtml: the four kinds', () => {
it('renders kind, icon, title and body in the shape the stylesheet expects', () => {
const html = alertHtml({ kind: 'error', title: 'Mislukt', body: 'Bestand onleesbaar.' });
assert.match(html, /^<div class="alert alert-error"><span class="alert-icon">⚠️<\/span>/);
assert.match(html, /<div class="alert-content"><div class="alert-title">Mislukt<\/div>/);
assert.match(html, /<div class="alert-body">Bestand onleesbaar\.<\/div><\/div><\/div>$/);
});
it('gives each kind its own icon, and neutral none', () => {
assert.match(alertHtml({ kind: 'info', body: 'x' }), /alert-icon">ℹ️</);
assert.match(alertHtml({ kind: 'success', body: 'x' }), /alert-icon">✓</);
assert.match(alertHtml({ kind: 'error', body: 'x' }), /alert-icon">⚠️</);
assert.doesNotMatch(alertHtml({ kind: 'neutral', body: 'x' }), /alert-icon/);
});
it('lets a caller override the icon, and suppress it with null', () => {
assert.match(alertHtml({ kind: 'info', icon: '✨', body: 'x' }), /alert-icon">✨</);
assert.doesNotMatch(alertHtml({ kind: 'error', icon: null, body: 'x' }), /alert-icon/);
});
it('REFUSES a kind that does not exist', () => {
assert.throws(() => alertHtml({ kind: 'warning', body: 'x' }), /Unknown alert kind/);
});
});
describe('alertHtml: what is left out leaves nothing behind', () => {
it('writes no title element without a title', () => {
assert.doesNotMatch(alertHtml({ kind: 'error', body: 'x' }), /alert-title/);
});
it('writes no body element without a body', () => {
assert.doesNotMatch(alertHtml({ kind: 'error', title: 'x' }), /alert-body/);
});
it('still renders the content wrapper, because the flex layout needs it', () => {
assert.match(alertHtml({ kind: 'neutral', body: 'x' }), /<div class="alert-content">/);
});
it('adds an extra class only when asked', () => {
assert.match(alertHtml({ kind: 'info', className: 'mt-lg', body: 'x' }), /"alert alert-info mt-lg"/);
assert.match(alertHtml({ kind: 'info', body: 'x' }), /"alert alert-info"/);
});
});
describe('alertHtml: title and body are text, extra is markup', () => {
it('escapes the title and the body', () => {
const html = alertHtml({ kind: 'error', title: '<b>t</b>', body: '<img src=x onerror=alert(1)>' });
assert.doesNotMatch(html, /<b>|<img/);
});
it('escapes a database message put in the body', () => {
assert.doesNotMatch(alertHtml({ kind: 'error', body: 'no such column: <script>' }), /<script>/);
});
it('does NOT escape extra', () => {
assert.match(alertHtml({ kind: 'info', body: 'x', extra: '<button id="go">Go</button>' }),
/<button id="go">Go<\/button>/);
});
});