import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { compileFunction } from 'node:vm'; import { createRequire } from 'node:module'; import ts from 'typescript'; const require = createRequire(import.meta.url); function nodes(tree) { if (Array.isArray(tree)) return tree.flatMap(nodes); if (!tree || typeof tree !== 'object') return []; return [tree, ...nodes(tree.props?.children)]; } function text(tree) { if (typeof tree === 'string') return tree; if (Array.isArray(tree)) return tree.map(text).join(''); return tree?.props ? text(tree.props.children) : ''; } function harness() { const memory = [], effects = [], calls = [], reloads = []; let cursor = 0, pending = [], dirty = false, serial = 0, handler; let props = { record: { id: 1, title: 'QA first', featured: false }, etag: 'a'.repeat(64), history: { data: [], current_page: 1 }, basePath: '/management/opportunities' }; const code = ts.transpileModule(fs.readFileSync(new URL('../../resources/js/pages/management/opportunity-curation.tsx', import.meta.url), 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS, jsx: ts.JsxEmit.ReactJSX, target: ts.ScriptTarget.ES2022 }, }).outputText; const module = { exports: {} }; const mocks = { react: { useState(initial) { const i = cursor++; if (!(i in memory)) memory[i] = typeof initial === 'function' ? initial() : initial; return [memory[i], (value) => { const next = typeof value === 'function' ? value(memory[i]) : value; if (!Object.is(next, memory[i])) { memory[i] = next; dirty = true; } }]; }, useRef(initial) { const i = cursor++; memory[i] ??= { current: initial }; return memory[i]; }, useEffect(effect, dependencies) { const i = cursor++; if (!effects[i] || dependencies.some((value, index) => value !== effects[i][index])) { effects[i] = dependencies; pending.push(effect); } }, }, '@inertiajs/react': { Link: 'a', router: { reload: (options) => reloads.push(options) } }, '@/lib/operation-key': { createOperationKey: () => `aaaaaaaa-aaaa-4aaa-8aaa-${String(++serial).padStart(12, '0')}` }, '@/lib/profile-json': { ProfileValidationError: class extends Error {}, profileJson: (url, data) => { calls.push({ url, data: structuredClone(data) }); return handler(url, data); }, }, './shared': { Management: 'main', button: '', control: '' }, }; compileFunction(code, ['require', 'module', 'exports'])((name) => mocks[name] ?? require(name), module, module.exports); let tree; function render() { do { dirty = false; cursor = 0; pending = []; tree = module.exports.default(props); for (const effect of pending) effect(); } while (dirty); return tree; } return { calls, reloads, render, setHandler(fn) { handler = fn; }, setProps(next) { props = next; return render(); }, button(label) { return nodes(render()).find(node => node.type === 'button' && text(node) === label); }, input(type) { return nodes(render()).find(node => node.type === type); }, get props() { return props; }, }; } test('editing rationale invalidates both the preview and its confirmation without submitting', async () => { const h = harness(); h.setHandler(async () => ({ hash: 'b'.repeat(64), title: 'QA first', before: false, featured: true, reason: 'Rationale for QA editorial selection' })); h.input('textarea').props.onChange({ target: { value: 'Rationale for QA editorial selection' } }); await h.button('Conferir prévia').props.onClick(); assert.equal(h.button('Confirmar decisão de destaque').props.disabled, true); h.input('input').props.onChange({ target: { checked: true } }); assert.equal(h.button('Confirmar decisão de destaque').props.disabled, false); h.input('textarea').props.onChange({ target: { value: 'Changed editorial rationale must be reviewed again' } }); assert.equal(h.button('Confirmar decisão de destaque'), undefined); assert.equal(h.calls.length, 1); assert.equal(h.calls[0].data.featured, true); }); test('in-flight preview is single; uncertain confirmation keeps the same intent for recovery', async () => { const h = harness(); let release; h.setHandler(() => new Promise(resolve => { release = resolve; })); h.input('textarea').props.onChange({ target: { value: 'Rationale for QA editorial selection' } }); const first = h.button('Conferir prévia').props.onClick(); await h.button('Conferir prévia').props.onClick(); assert.equal(h.calls.length, 1); assert.equal(h.input('fieldset').props.disabled, true); release({ hash: 'b'.repeat(64), title: 'QA first', before: false, featured: true, reason: 'Rationale for QA editorial selection' }); await first; h.input('input').props.onChange({ target: { checked: true } }); h.setHandler(async () => { throw new Error('Response lost'); }); await h.button('Confirmar decisão de destaque').props.onClick(); const uncertain = h.calls.at(-1).data; h.setHandler(async () => ({ replayed: true, featured: true, etag: 'c'.repeat(64) })); await h.button('Confirmar decisão de destaque').props.onClick(); assert.deepEqual(h.calls.at(-1).data, uncertain); assert.equal(h.reloads.length, 1); assert.deepEqual(h.reloads[0].only, ['record', 'etag', 'history']); assert.match(text(h.render()), /Decisão já registada/); }); test('a delayed preview cannot be adopted after another record and version arrive', async () => { const h = harness(); let release; h.setHandler(() => new Promise(resolve => { release = resolve; })); h.input('textarea').props.onChange({ target: { value: 'Rationale for QA editorial selection' } }); const request = h.button('Conferir prévia').props.onClick(); h.setProps({ ...h.props, record: { id: 2, title: 'QA second', featured: false }, etag: 'd'.repeat(64) }); release({ hash: 'b'.repeat(64), title: 'QA first', before: false, featured: true, reason: 'Old rationale' }); await request; assert.equal(h.button('Confirmar decisão de destaque'), undefined); assert.match(text(h.render()), /QA second/); assert.doesNotMatch(text(h.render()), /Old rationale/); assert.equal(h.input('textarea').props.value, ''); }); test('changing only the history page retains the unsubmitted rationale and reviewed decision', async () => { const h = harness(); h.setHandler(async () => ({ hash: 'b'.repeat(64), title: 'QA first', before: false, featured: true, reason: 'Reviewed QA rationale retained during paging' })); h.input('textarea').props.onChange({ target: { value: 'Reviewed QA rationale retained during paging' } }); await h.button('Conferir prévia').props.onClick(); h.input('input').props.onChange({ target: { checked: true } }); h.setProps({ ...h.props, history: { data: [], current_page: 2, prev_page_url: '/management/opportunities/1/destaque?page=1' } }); assert.equal(h.input('textarea').props.value, 'Reviewed QA rationale retained during paging'); assert.equal(h.button('Confirmar decisão de destaque').props.disabled, false); const link = nodes(h.render()).find(node => node.type === 'a' && text(node) === 'Anterior'); assert.equal(link.props.preserveState, true); assert.equal(link.props.preserveScroll, true); });