// Run with: node tests/test_product_pagination.js const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); const source = fs.readFileSync(process.argv[2] || 'static/js/app.js', 'utf8'); const requests = []; const nodes = {}; for (const id of ['prodCodeName', 'prodSupplier', 'prodBrandFilter', 'prodTypeFilter', 'prodTbody', 'prodCount', 'prodPagination']) { nodes[id] = {value: '', innerHTML: '', textContent: ''}; } nodes.prodSupplier.value = '瑞沣'; const renderedPages = []; const context = { window: {}, document: {getElementById: id => nodes[id]}, PROD_COLUMNS: [], escHtml: String, inlineJsString: JSON.stringify, renderPaginationWithSize: (el, page, total, size) => renderedPages.push({page, total, size}), fetch: url => new Promise(resolve => requests.push({url, resolve})), }; vm.createContext(context); vm.runInContext(source.slice(source.indexOf('let prodCurrentPage ='), source.indexOf('function loadProductsPage(')), context); vm.runInContext(source.slice(source.indexOf('function loadProducts(page)'), source.indexOf('window.searchProducts =')), context); vm.runInContext(source.slice(source.indexOf('function loadRecycleProducts(page)'), source.indexOf('\nwindow.', source.indexOf('function loadRecycleProducts(page)'))), context); const tick = () => new Promise(resolve => setImmediate(resolve)); function finish(index) { requests[index].resolve({json: () => Promise.resolve({code: 0, data: {rows: [], total: 194}})}); } async function run() { for (const page of [1, 2, 3, 4]) context.loadProducts(page); for (let i = 0; i < 4; i++) { const url = new URL(requests[i].url, 'http://localhost'); assert.equal(url.searchParams.get('supplier'), '瑞沣'); assert.equal(url.searchParams.get('page'), String(i + 1)); } finish(3); await tick(); for (const i of [2, 1, 0]) { finish(i); await tick(); } assert.deepEqual(renderedPages.map(x => x.page), [4], 'Older responses must not change the last requested page'); // A pending normal-list response cannot overwrite the recycle tab. context.loadProducts(2); vm.runInContext("prodActiveTab = '回收站'", context); context.loadProducts(1); finish(5); await tick(); finish(4); await tick(); assert.deepEqual(renderedPages.map(x => x.page), [4, 1]); // A pending response must not render into a newly mounted products page. context.loadProducts(1); nodes.prodTbody = {innerHTML: 'new page'}; finish(6); await tick(); assert.equal(nodes.prodTbody.innerHTML, 'new page'); assert.equal(renderedPages.length, 2); console.log('Product pagination: reverse response order, supplier filter, tab switch and page remount passed'); } run().catch(error => { console.error(error); process.exitCode = 1; });