// FILE: _St/IG_StYellow/test_ext_virtual_list.js | ROLE: IG_StYellow 회귀 테스트
const fs = require('fs');
const path = require('path');
const assert = require('assert');

const root = __dirname;
const side = fs.readFileSync(path.join(root, 'side.js'), 'utf8');
const html = fs.readFileSync(path.join(root, 'side.html'), 'utf8');
const manifest = JSON.parse(fs.readFileSync(path.join(root, 'manifest.json'), 'utf8'));

assert.strictEqual(manifest.version, '2.3.8.3130');
assert.strictEqual(manifest.version_name, '2.3.8.313');

// v261: scrolling must never add/remove cards or change the document height.
for (const retired of [
  'TE_SIDE_VIRTUAL_MAX_CARDS',
  'teSideVirtualRange',
  'teSideVirtualMeasuredRowHeight',
  'teSideVirtualCaptureAnchor',
  'teSideVirtualRestoreAnchor',
  'window.scrollBy(0, delta)',
  'igblue-virtual-spacer',
  'window.addEventListener("scroll"'
]) assert.ok(!side.includes(retired), `retired virtual-scroll token remains: ${retired}`);

assert.ok(side.includes('const teSideListState = { items: [], rankCtx: null, cards: new Map() };'));
assert.ok(side.includes('function teSideListRender(items)'));
assert.ok(side.includes('list.forEach((media) => {'));
assert.ok(side.includes('let card = teSideListState.cards.get(code);'));
assert.ok(side.includes('teSideListState.cards.set(code, card);'));
assert.ok(side.includes('if (card !== cursor) box.insertBefore(card, cursor || null);'));
assert.ok(side.includes('if (desired.has(code)) return;'));
assert.ok(side.includes('teSideListReleaseCard(card);'));

// Cards are removed only when the filtered/sorted data no longer contains them.
const renderStart = side.indexOf('function teSideListRender(items)');
const renderEnd = side.indexOf('function ee(items)', renderStart);
const renderBlock = side.slice(renderStart, renderEnd);
assert.ok(renderBlock.includes('const desired = new Set();'));
assert.ok(renderBlock.includes('Array.from(teSideListState.cards.entries())'));
assert.ok(!renderBlock.includes('getBoundingClientRect'));
assert.ok(!renderBlock.includes('scroll'));
assert.ok(!renderBlock.includes('rowHeight'));
assert.ok(!renderBlock.includes('spacer'));

// Stable 16:9 thumbnail boxes keep grid height unchanged while src is unloaded/reloaded.
assert.ok(html.includes('aspect-ratio: 16 / 9;'));
assert.ok(html.includes('content-visibility: auto;'));
assert.ok(html.includes('contain: layout paint style;'));
assert.ok(!html.includes('.igblue-virtual-spacer'));
assert.ok(!html.includes('overflow-anchor: none;'));
assert.ok(!side.includes('img.style.aspectRatio = `${img.naturalWidth} / ${img.naturalHeight}`;'));

console.log('OK test_ext_virtual_list v272 stable DOM');
