const assert = require('node:assert/strict'); const test = require('node:test'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); const ts = require('typescript'); const root = path.resolve(__dirname, '..'); const source = fs.readFileSync(path.join(root, 'src/shared/ui/grid-cell-tooltip.tsx'), 'utf8'); const css = fs.readFileSync(path.join(root, 'src/app/styles/grid-ellipsis.css'), 'utf8'); function mount() { const handlers = {}; let cleanup; class Cell { constructor(text, overflowing = true) { this.textContent = text; this.title = ''; this.clientWidth = 100; this.scrollWidth = overflowing ? 300 : 100; } closest() { return this; } querySelector() { return null; } querySelectorAll() { return []; } hasAttribute() { return Boolean(this.title); } removeAttribute() { this.title = ''; } } const module = {exports:{}}; vm.runInNewContext(ts.transpileModule(source, {compilerOptions:{module:ts.ModuleKind.CommonJS}}).outputText, { module, exports:module.exports, Element:Cell, require:()=>({useEffect:fn=>{cleanup=fn();}}), document:{addEventListener:(name,handler)=>{handlers[name]=handler;},removeEventListener:name=>{delete handlers[name];}}, }); module.exports.GridCellTooltip(); return {Cell,handlers,cleanup}; } test('CSS and tooltip target the same SN text cells and preserve controls', () => { const selector = source.match(/const CELL_SELECTOR = '([^']+)'/)[1]; assert.ok(css.includes(selector + ' {')); for (const token of ['input','textarea','button','[colspan]','[rowspan]','data-sn-cell-wrap']) assert.ok(selector.includes(token)); }); test('overflow tooltip retains full text and updates reused cells', () => { const {Cell,handlers,cleanup}=mount(); const cell=new Cell('긴 원문\n내용'); handlers.pointerover({target:cell}); assert.equal(cell.title,cell.textContent); cell.textContent='변경된 원문'; handlers.pointerover({target:cell}); assert.equal(cell.title,cell.textContent); cell.scrollWidth=100; handlers.pointerover({target:cell}); assert.equal(cell.title,''); cleanup(); assert.deepEqual(handlers,{}); }); test('existing explicit tooltip and editable-cell exclusions remain authoritative', () => { const {Cell,handlers}=mount(); const cell=new Cell('원문'); cell.title='기존 설명'; handlers.pointerover({target:cell}); assert.equal(cell.title,'기존 설명'); const excluded=new Cell('입력'); excluded.closest=()=>null; handlers.pointerover({target:excluded}); assert.equal(excluded.title,''); });