RSS Git Download  Clone
Raw Blame History 4kB 116 lines
import { describe, it } from 'node:test';
import { strict as assert } from 'node:assert';

import {
    extractTables,
    stripHtml,
    strikeHtml,
    parseNumber,
    buildPatchReplace,
    buildPatchAppend,
} from '../lib/table.mjs';

const sampleHtml = `
<html><body>
<table data-id="t1">
  <tr data-id="r1"><td data-id="c11"><p>Apple</p></td><td data-id="c12">1 234,56 Ft</td></tr>
  <tr data-id="r2"><td data-id="c21"><p>Pear</p></td><td data-id="c22">2 000 Ft</td></tr>
  <tr data-id="r3"><td data-id="c31"><p>Total</p></td><td data-id="c32">&nbsp;</td></tr>
</table>
<p data-id="p1">not a table</p>
</body></html>
`;

describe('extractTables', () => {
    it('parses table id, row ids, cell ids, cell html and text', () => {
        const tables = extractTables(sampleHtml);
        assert.equal(tables.length, 1);
        const [t] = tables;
        assert.equal(t.id, 't1');
        assert.equal(t.rows.length, 3);
        assert.deepEqual(t.rows.map(r => r.id), ['r1', 'r2', 'r3']);
        assert.deepEqual(t.rows[0].cells.map(c => c.id), ['c11', 'c12']);
        assert.equal(t.rows[0].cells[0].text, 'Apple');
        assert.equal(t.rows[0].cells[1].text, '1 234,56 Ft');
    });

    it('returns empty array when no tables present', () => {
        assert.deepEqual(extractTables('<p>nothing here</p>'), []);
    });
});

describe('stripHtml', () => {
    it('removes tags, decodes entities, collapses whitespace', () => {
        assert.equal(stripHtml('<p>Hello&nbsp;&amp; <b>world</b></p>'), 'Hello & world');
    });

    it('decodes numeric entities (Hungarian á é ő)', () => {
        assert.equal(stripHtml('Lak&#225;s biztos&#237;t&#225;s'), 'Lakás biztosítás');
        assert.equal(stripHtml('Mez&#337;f&#246;ldi'), 'Mezőföldi');
    });

    it('decodes hex entities', () => {
        assert.equal(stripHtml('&#xE1;&#xE9;'), 'áé');
    });
});

describe('strikeHtml', () => {
    it('wraps plain content in <s>', () => {
        assert.equal(strikeHtml('<p>Paid</p>'), '<s><p>Paid</p></s>');
    });

    it('is idempotent when already struck', () => {
        assert.equal(strikeHtml('<s>already</s>'), '<s>already</s>');
    });
});

describe('parseNumber', () => {
    it('parses Hungarian-style "1 234,56 Ft"', () => {
        assert.equal(parseNumber('1 234,56 Ft'), 1234.56);
    });

    it('parses plain integers', () => {
        assert.equal(parseNumber('13 519'), 13519);
    });

    it('parses US-style "1,234.56"', () => {
        assert.equal(parseNumber('1,234.56'), 1234.56);
    });

    it('returns NaN for non-numeric text', () => {
        assert.ok(Number.isNaN(parseNumber('paid')));
    });

    it('parses "k" suffix as thousands (rounded OneNote style)', () => {
        assert.equal(parseNumber('5k'), 5000);
        assert.equal(parseNumber('508k'), 508_000);
        assert.equal(parseNumber('1094k'), 1_094_000);
    });

    it('parses "M" suffix as millions', () => {
        assert.equal(parseNumber('1.2M'), 1_200_000);
        assert.equal(parseNumber('2m'), 2_000_000);
    });

    it('ignores "k" inside longer words (e.g. "kb", "Ft")', () => {
        // "13 519" + "Ft" — no suffix, Ft stripped
        assert.equal(parseNumber('13 519 Ft'), 13_519);
    });
});

describe('buildPatch helpers', () => {
    it('buildPatchReplace returns a single replace command array', () => {
        assert.deepEqual(
            buildPatchReplace('c32', '3 234,56 Ft'),
            [{ target: 'c32', action: 'replace', content: '3 234,56 Ft' }],
        );
    });

    it('buildPatchAppend returns a single append command array', () => {
        assert.deepEqual(
            buildPatchAppend('body', '<p>new</p>'),
            [{ target: 'body', action: 'append', content: '<p>new</p>' }],
        );
    });
});