test: cover dom + emoji pure helpers; fix syntaxErrorPosition regex

Test-coverage expansion (2-agent reviewed, both SHIP). The named candidates
(roomToUnread, markedUnread, serverAcl, plaintextCaches, recent*) were already
tested, so this targets genuinely-untested pure logic.

- dom.test.ts: getThumbnailDimensions (scaling math incl. just-over-cap
  boundaries), tryDecodeURIComponent, syntaxErrorPosition, and the three
  scroll-view geometry helpers (via duck-typed element mocks — no jsdom).
- emoji.test.ts: getHexcodeForEmoji (astral codepoints, 4-digit zero-pad,
  FE0F/FE0E/200D stripping on and off, keycap sequences, degenerate inputs)
  and the pre-load `undefined` contract for getShortcode(s)For.

Fix (found while writing the tests): syntaxErrorPosition required whitespace
AFTER the digits (`/position\s(\d+)\s/`), but real V8/Node JSON.parse errors
put the number at end-of-string ("... at position N"), so it returned
undefined for every real error and the three dev-tools JSON editors silently
pointed their cursor at position 0. Dropped the trailing `\s`; tests now assert
extraction at end-of-string.

Gates: tsc 0, eslint 0, prettier clean, 891 tests, build ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 16:49:51 -04:00
co-authored by Claude Opus 4.8
parent 015495c77d
commit 36369926ca
3 changed files with 226 additions and 1 deletions
+63
View File
@@ -0,0 +1,63 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { getHexcodeForEmoji, getShortcodeFor, getShortcodesFor } from './emoji';
describe('getHexcodeForEmoji', () => {
it('converts a single astral codepoint to an uppercase hexcode', () => {
// 😀 = U+1F600
assert.equal(getHexcodeForEmoji('😀'), '1F600');
});
it('zero-pads BMP codepoints to at least four hex digits', () => {
// ☺ = U+263A ; # = U+0023 (must pad "23" -> "0023")
assert.equal(getHexcodeForEmoji('☺'), '263A');
assert.equal(getHexcodeForEmoji('#'), '0023');
});
it('strips the FE0F variation selector by default', () => {
// ❤️ = U+2764 U+FE0F
assert.equal(getHexcodeForEmoji('❤️'), '2764');
});
it('keeps the variation selector when strip is false', () => {
assert.equal(getHexcodeForEmoji('❤️', false), '2764-FE0F');
});
it('strips ZWJ (200D) joiners from a sequence by default', () => {
// 👨‍👩‍👧 = 1F468 200D 1F469 200D 1F467
assert.equal(getHexcodeForEmoji('👨‍👩‍👧'), '1F468-1F469-1F467');
});
it('keeps ZWJ joiners when strip is false', () => {
assert.equal(getHexcodeForEmoji('👨‍👩‍👧', false), '1F468-200D-1F469-200D-1F467');
});
it('strips the FE0E text-presentation selector too', () => {
// ▶ = U+25B6 ; ▶︎ = U+25B6 U+FE0E (text presentation)
assert.equal(getHexcodeForEmoji('▶︎'), '25B6');
assert.equal(getHexcodeForEmoji('▶︎', false), '25B6-FE0E');
});
it('handles a keycap sequence (padding + selector strip together)', () => {
// #️⃣ = U+0023 U+FE0F U+20E3 -> "0023" + (FE0F stripped) + "20E3"
assert.equal(getHexcodeForEmoji('#️⃣'), '0023-20E3');
});
it('handles degenerate inputs (empty string, plain ASCII per codepoint)', () => {
assert.equal(getHexcodeForEmoji(''), '');
assert.equal(getHexcodeForEmoji('ab'), '0061-0062');
});
});
describe('getShortcodesFor / getShortcodeFor before emoji data is loaded', () => {
// These gracefully degrade to `undefined` until loadEmojiData() has populated
// the shortcode maps — the contract that lets tooltips/aria-labels render
// eagerly without pulling the emojibase runtime into the eager graph.
it('returns undefined for getShortcodesFor', () => {
assert.equal(getShortcodesFor('1F600'), undefined);
});
it('returns undefined for getShortcodeFor', () => {
assert.equal(getShortcodeFor('1F600'), undefined);
});
});