const { test } = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); const context = vm.createContext({ URLSearchParams }); vm.runInContext(fs.readFileSync(require('node:path').join(__dirname, '../internal/transport/httpserver/console/console-core.js'), 'utf8'), context); const { listURL, readFilters, ListPage } = context.OrbitConsole; test('精确业务键、筛选和游标跨页保持,不静默扩展查询范围', () => { const page = new ListPage(); page.reset({ business_key: '订单 +%_ ', state: 'NEEDS_REVIEW', created_from: '2026-09-01T00:00:00.000Z' }); assert.ok(page.accept(page.begin(), { next_cursor: 'opaque+/=' })); assert.ok(page.move('next')); const query = new URL(listURL('tasks', 'queue-1', page.filters, page.cursor), 'http://localhost').searchParams; assert.equal(query.get('business_key'), '订单 +%_ '); assert.equal(query.get('state'), 'NEEDS_REVIEW'); assert.equal(query.get('queue_id'), 'queue-1'); assert.equal(query.get('cursor'), 'opaque+/='); assert.equal(page.limit, 10); assert.equal(query.get('limit'), '10'); assert.equal(new URL(listURL('tasks', 'queue-1', page.filters, page.cursor, 50), 'http://localhost').searchParams.get('limit'), '50'); assert.ok(page.move('prev')); assert.equal(page.cursor, ''); assert.equal(page.filters.state, 'NEEDS_REVIEW'); }); test('查询重置后迟到的旧页面不会覆盖新条件和翻页状态', () => { const page = new ListPage(); const slow = page.begin(); page.reset({ state: 'FAILED' }); const latest = page.begin(); assert.equal(page.accept(slow, { next_cursor: 'wrong' }), false); assert.equal(page.loading, true); assert.equal(page.move('next'), false); assert.equal(page.accept(latest, {}), true); assert.equal(page.next, ''); assert.equal(page.filters.state, 'FAILED'); }); test('失败保留原查询与原页,不自动回到无筛选列表', () => { const page = new ListPage(); page.reset({ state: 'RUNNING' }); page.accept(page.begin(), { next_cursor: 'page-2' }); page.move('next'); assert.equal(page.fail(page.begin()), true); assert.equal(page.cursor, 'page-2'); assert.equal(page.history.length, 1); assert.equal(page.filters.state, 'RUNNING'); assert.equal(page.next, ''); }); test('时间边界验证、流程范围与无队列保护', () => { assert.throws(() => readFilters({ created_from: '2026-09-29T12:00', created_before: '2026-09-29T11:00' }), /结束时间/); assert.throws(() => readFilters({ created_from: 'not a date' }), /有效/); const f = readFilters({ created_from: '2026-09-29T12:00:00+08:00', business_key: ' key ' }); assert.equal(f.created_from, '2026-09-29T04:00:00.000Z'); assert.equal(f.business_key, ' key '); assert.throws(() => listURL('tasks', ''), /选择队列/); assert.equal(new URL(listURL('workflows', 'ignored'), 'http://localhost').searchParams.has('queue_id'), false); }); // 用页面原始 HTML 构建轻量 DOM,执行 applications.js 的真实点击与提交处理器。 // 不引入浏览器依赖;网络边界独立模拟,断言最终请求及用户可见状态。 function applicationsHarness({ actions = ['tasks:read', 'workers:connect'], revoked = false, loseApply = false } = {}) { const decode = text => text.replace(/&(amp|lt|gt|quot|#39);/g, (_, key) => ({ amp: '&', lt: '<', gt: '>', quot: '"', '#39': "'" }[key])); class Element { constructor(tag = '', attrs = {}) { this.tag = tag; this.attrs = attrs; this.children = []; this.parent = null; this.listeners = {}; this.value = attrs.value || ''; this.defaultValue = this.value; this.checked = 'checked' in attrs; this.defaultChecked = this.checked; this.disabled = 'disabled' in attrs; this.hidden = 'hidden' in attrs; this.open = false; this.text = ''; this.dataset = Object.fromEntries(Object.entries(attrs).filter(([k]) => k.startsWith('data-')).map(([k, v]) => [k.slice(5).replace(/-([a-z])/g, (_, c) => c.toUpperCase()), v])); this.classList = { toggle() {} }; } matches(selector) { const id = selector.match(/#([\w-]+)/)?.[1], cls = selector.match(/\.([\w-]+)/)?.[1], tag = selector.match(/^[\w-]+/)?.[0]; return (!id || this.attrs.id === id) && (!cls || (this.attrs.class || '').split(' ').includes(cls)) && (!tag || this.tag === tag) && (!selector.includes(':checked') || this.checked) && [...selector.matchAll(/\[([\w-]+)\]/g)].every(([, a]) => a === 'open' ? this.open : a in this.attrs); } querySelectorAll(selector) { const all = this.children.flatMap(c => [c, ...c.querySelectorAll('*')]); return all.filter(el => selector.split(',').some(s => { const parts = s.trim().split(/\s+/); if (!el.matches(parts.pop())) return false; let ancestor = el.parent; while (parts.length) { const part = parts.pop(); while (ancestor && !ancestor.matches(part)) ancestor = ancestor.parent; if (!ancestor) return false; ancestor = ancestor.parent; } return true; })); } querySelector(selector) { return this.querySelectorAll(selector)[0] || null; } closest(selector) { return selector.split(',').some(s => this.matches(s)) ? this : this.parent?.closest(selector); } set innerHTML(html) { this.html = html; this.children = []; parse(html, this); } get innerHTML() { return this.html || ''; } set textContent(text) { this.text = String(text); this.children = []; } get textContent() { return this.text + this.children.map(c => c.textContent).join(''); } get elements() { return this.querySelectorAll('input,select,button,textarea'); } reset() { this.elements.forEach(el => { el.value = el.defaultValue; el.checked = el.defaultChecked; }); } addEventListener(name, handler) { (this.listeners[name] ||= []).push(handler); } async fire(name, target = this) { for (const handler of this.listeners[name] || []) await handler({ target, preventDefault() {} }); } showModal() { this.open = true; } close() { this.open = false; } focus() { document.activeElement = this; } } function parse(html, root) { const stack = [root]; for (const token of html.matchAll(/|<[^>]+>|[^<]+/g)) { const raw = token[0]; if (raw.startsWith('