64 lines
3.1 KiB
JavaScript
64 lines
3.1 KiB
JavaScript
#!/usr/bin/env node
|
|
// JS-only regression of the Stored Logs sorting interaction (no Rust server).
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import vm from 'node:vm';
|
|
const read = name => fs.readFileSync(name, 'utf8');
|
|
const ui = read('src/admin/web/file-logs.js');
|
|
const css = read('src/admin/web/style.css');
|
|
const api = JSON.parse(read('src/admin/openapi.json'));
|
|
const params = api.paths['/api/file-logs/query'].get.parameters.map(param => param.name);
|
|
assert.ok(params.includes('sort_by') && params.includes('sort_descending'));
|
|
assert.ok(api.components.schemas.AdminPreferences.properties.file_log_sort);
|
|
assert.ok(api.components.schemas.AdminPreferences.properties.file_log_descending);
|
|
assert.match(ui, /params\.set\("sort_by", sortBy\)/);
|
|
assert.match(ui, /params\.set\("sort_descending", String\(sortDescending\)\)/);
|
|
assert.match(css, /file-log-sort-button/);
|
|
|
|
class FakeNode {
|
|
constructor(tag, text = '', cls = '') { this.tag = tag; this.textContent = text; this.className = cls; this.children = []; this.dataset = {}; this.attrs = {}; this.events = {}; }
|
|
setAttribute(name, value) { this.attrs[name] = value; }
|
|
append(...nodes) { this.children.push(...nodes); }
|
|
replaceChildren(...nodes) { this.children = nodes; }
|
|
addEventListener(name, handler) { this.events[name] = handler; }
|
|
click() { this.events.click?.(); }
|
|
}
|
|
const row = new FakeNode('tr');
|
|
const sort = ui.slice(ui.indexOf(' function syncHeaders() {'), ui.indexOf(' function syncColumnPicker()'));
|
|
assert.ok(sort.startsWith(' function syncHeaders() {') && sort.includes('file-log-sort-button'));
|
|
const ctx = {
|
|
el: (tag, text, cls) => new FakeNode(tag, text, cls),
|
|
$: () => ({querySelector: () => row}),
|
|
orderedColumns: () => ['time', 'status'],
|
|
visibleColumns: new Set(['time', 'status']),
|
|
specialLabels: new Map([['time', 'time'], ['status', 'status']]),
|
|
columnLabel: id => id,
|
|
t: key => key,
|
|
sortBy: 'time', sortDescending: true, selectedIndex: 3, offset: 100,
|
|
saved: 0, refreshed: 0,
|
|
savePreferences() { this.saved++; },
|
|
refresh() { this.refreshed++; },
|
|
};
|
|
// Methods capture explicit counters rather than relying on vm's `this` binding.
|
|
ctx.savePreferences = () => { ctx.saved++; };
|
|
ctx.refresh = reset => { if (reset) ctx.refreshed++; };
|
|
vm.createContext(ctx);
|
|
vm.runInContext(`${sort}\nglobalThis.draw = syncHeaders;`, ctx);
|
|
ctx.draw();
|
|
assert.equal(row.children.length, 2);
|
|
assert.equal(row.children[0].attrs['aria-sort'], 'descending');
|
|
assert.equal(row.children[1].attrs['aria-sort'], 'none');
|
|
row.children[1].children[0].click();
|
|
assert.equal(ctx.sortBy, 'status');
|
|
assert.equal(ctx.sortDescending, false);
|
|
assert.equal(ctx.offset, 0);
|
|
assert.equal(ctx.saved, 1);
|
|
assert.equal(ctx.refreshed, 1);
|
|
assert.equal(row.children[1].attrs['aria-sort'], 'ascending');
|
|
row.children[1].children[0].click();
|
|
assert.equal(ctx.sortDescending, true);
|
|
assert.equal(row.children[1].attrs['aria-sort'], 'descending');
|
|
assert.equal(ctx.saved, 2);
|
|
assert.equal(ctx.refreshed, 2);
|
|
console.log('PASS: 0.31.9 Stored Logs headers sort by column, toggle direction, reset pagination, persist preferences and request server sorting.');
|