Ctrl K
ComunidadGuías…

scripts/test_ui_icons.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Run: node scripts/test_ui_icons.mjs
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import vm from 'node:vm';

class Element {
  constructor(tag, attributes = {}, children = []) {
    this.localName = tag;
    this.attrs = new Map(Object.entries(attributes));
    this.children = children;
    this.dataset = {};
    this.classList = {
      add: (...names) => this.attrs.set('class', [...new Set([...(this.attrs.get('class') || '').split(' '), ...names])].join(' ').trim()),
      remove: name => this.attrs.set('class', (this.attrs.get('class') || '').split(' ').filter(value => value !== name).join(' '))
    };
  }
  get attributes() { return [...this.attrs].map(([name, value]) => ({ name, value })); }
  getAttribute(name) { return this.attrs.get(name); }
  setAttribute(name, value) { this.attrs.set(name, String(value)); }
  hasAttribute(name) { return this.attrs.has(name); }
  replaceWith(node) { nodes.splice(nodes.indexOf(this), 1, node); replacements++; }
}
const defaults = { viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor' };
const nodes = [new Element('i', { 'data-lucide': 'play', width: '32', class: 'transport', style: 'color:red' }), new Element('i', { 'data-lucide': 'search' })];
let replacements = 0;
const document = { documentElement: { dataset: { theme: 'classic' } }, querySelectorAll: () => [...nodes] };
const library = { icons: { Play: ['svg', defaults, []], Search: ['svg', defaults, []], Menu: ['svg', defaults, []] }, createElement: ([tag, attributes, children]) => new Element(tag, attributes, children) };
vm.runInNewContext(readFileSync(new URL('../Aoede/assets/js/ui_icons.js', import.meta.url), 'utf8'), { window: { lucide: library }, document });

library.createIcons({ nodes: [nodes[0]] });
assert.equal(replacements, 1);
assert.equal(nodes[1].localName, 'i'); // Scoped refresh cannot redraw the rest of the feed.
assert.equal(nodes[0].getAttribute('width'), '32');
assert.equal(nodes[0].getAttribute('style'), 'color:red');
assert.ok(nodes[0].getAttribute('class').includes('transport'));
assert.equal(nodes[0].getAttribute('aria-hidden'), 'true');
assert.equal(nodes[0].getAttribute('focusable'), 'false');
const play = nodes[0];
library.createIcons();
assert.equal(nodes[0], play); // Same SVG is retained even during legacy global refreshes.
assert.equal(replacements, 2);
for (const theme of ['vitrine', 'glass', 'classic', 'glass']) {
  document.documentElement.dataset.theme = theme;
  library.createIcons();
  assert.equal(nodes[0].getAttribute('data-lucide'), 'play');
  assert.equal(nodes[0].getAttribute('width'), '32');
  if (theme === 'glass') {
    assert.equal(nodes[0].getAttribute('viewBox'), '0 0 24 24');
    assert.equal(nodes[0].getAttribute('stroke'), 'currentColor');
    assert.equal(nodes[0].getAttribute('fill'), 'none');
    assert.ok(!nodes[0].getAttribute('class').includes('aoede-glyph'));
  }
}
const retained = nodes[0];
for (let repeat = 0; repeat < 100; repeat++) library.createIcons();
assert.equal(nodes[0], retained);
nodes.push(new Element('i', { 'data-lucide': 'menu', 'aria-label': 'Navigation' }));
library.createIcons();
assert.equal(nodes.at(-1).getAttribute('aria-label'), 'Navigation');
assert.equal(nodes.at(-1).hasAttribute('aria-hidden'), false);
nodes.push(new Element('i', { 'data-lucide': 'heart', fill: 'var(--accent)' }));
document.documentElement.dataset.theme = 'classic';
library.createIcons();
assert.ok(nodes.at(-1).children.length); // Filled recovered heart rather than the outline glyph.
document.documentElement.dataset.theme = 'glass';
library.icons.Heart = ['svg', defaults, []];
library.createIcons();
assert.equal(nodes.at(-1).getAttribute('fill'), 'var(--accent)'); // A theme change keeps a saved track visibly saved.
nodes.push(new Element('i', { 'data-lucide': 'unknown' }));
library.createIcons();
assert.equal(nodes.at(-1).localName, 'i');
console.log('PASS: scoped, idempotent UI icon rendering, theme coordinate changes, attributes and accessibility.');