const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); const ts = require('typescript'); // Render the actual pages with cached React Query responses; no onSuccess call. function pageHarness(filename, data) { const state = { data: { data }, isSuccess: true, isLoading: false, isError: false, dataUpdatedAt: 1 }; const module = { exports: {} }; let options; const source = ts.transpileModule(fs.readFileSync(filename, 'utf8'), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020, esModuleInterop: true, jsx: ts.JsxEmit.ReactJSX, } }).outputText; const requireStub = name => { if (name === 'react/jsx-runtime') return require(name); if (name === 'react') return { useEffect() {}, useState: () => [undefined, () => {}] }; if (name === '@tanstack/react-query') return { useQuery: value => { options = value; return state; } }; if (name === 'next/navigation') return { useRouter: () => ({ push() {} }) }; if (name === '@/axios/axiosInstance') return { __esModule: true, default: { get() {} } }; if (name === '@/components/ui/table') return Object.fromEntries(['Table', 'TableBody', 'TableCaption', 'TableCell', 'TableFooter', 'TableHead', 'TableHeader', 'TableRow'].map(key => [key, key])); return { __esModule: true, default: name.endsWith('products-cat') ? 'CategoryCard' : name.endsWith('products') ? 'ProductCard' : 'Image' }; }; vm.runInNewContext('(function(require,module,exports){' + source + '\n})', {})(requireStub, module, module.exports); return { state, render: () => module.exports.default({ params: { id: '9' } }), get options() { return options; } }; } function elements(tree, type) { if (tree == null || typeof tree !== 'object') return []; if (Array.isArray(tree)) return tree.flatMap(item => elements(item, type)); return [...(tree.type === type ? [tree] : []), ...elements(tree.props?.children, type)]; } const categoryPage = 'src/app/(index)/shop/page.tsx'; const productPage = 'src/app/(index)/shop/product/[id]/page.tsx'; test('shop displays cached categories in the API order, including after updated data', () => { const h = pageHarness(categoryPage, [{ id: 8, name: 'Second alphabetically' }, { id: 1, name: 'First alphabetically' }]); assert.deepEqual(elements(h.render(), 'CategoryCard').map(card => card.props.iteam.id), [8, 1]); h.state.data = { data: [{ id: 1 }, { id: 8 }] }; h.state.dataUpdatedAt++; assert.deepEqual(elements(h.render(), 'CategoryCard').map(card => card.props.iteam.id), [1, 8]); assert.equal(h.options.refetchOnWindowFocus, true); }); test('category page preserves cached and refreshed product order for both product groups', () => { const data = { category_name: 'Category', category_img: null, products: [{ id: 20, name: 'Z', view_only: false }, { id: 2, name: 'A', view_only: false }], view_only_products: [{ id: 19, name: 'Custom Z' }, { id: 1, name: 'Custom A' }] }; const h = pageHarness(productPage, data); assert.deepEqual(elements(h.render(), 'ProductCard').map(card => card.props.iteam.id), [20, 2]); assert.deepEqual(elements(h.render(), 'TableCell').filter(cell => cell.props.children !== '-----').map(cell => cell.props.children), ['Custom Z', 'Custom A']); h.state.data = { data: { ...data, products: [...data.products].reverse(), view_only_products: [...data.view_only_products].reverse() } }; assert.deepEqual(elements(h.render(), 'ProductCard').map(card => card.props.iteam.id), [2, 20]); assert.deepEqual(elements(h.render(), 'TableCell').filter(cell => cell.props.children !== '-----').map(cell => cell.props.children), ['Custom A', 'Custom Z']); }); test('a category without custom products renders its ordered ordinary products', () => { const h = pageHarness(productPage, { category_name: 'Category', category_img: null, products: [{ id: 3, view_only: false }], view_only_products: null }); assert.deepEqual(elements(h.render(), 'ProductCard').map(card => card.props.iteam.id), [3]); assert.equal(elements(h.render(), 'TableRow').length, 0); });