#!/bin/bash # https://docs.sheetjs.com/docs/demos/frontend/legacy#knockoutjs # Tests both Knockout 2 and Knockout 3 cd /tmp rm -rf sheetjs-knockout-tests mkdir -p sheetjs-knockout-tests cd sheetjs-knockout-tests cat >test.cjs <<'EOF' const puppeteer = require('puppeteer'); const express = require('express'); const fs = require('fs'); (async() => { const app = express(); app.use(express.static('./')); const server = app.listen(7263, async() => { console.log('[START] Server on port 7263'); const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox'] }); const page = await browser.newPage(); page.on('console', msg => console.log('PAGE:', msg.text())); await page.setViewport({ width: 1920, height: 1080 }); const cdp = await page.target().createCDPSession(); await cdp.send('Browser.setDownloadBehavior', { behavior: 'allow', downloadPath: process.cwd() }); await page.goto('http://localhost:7263/', { waitUntil: 'networkidle0' }); /* Verify Knockout binding */ const hasBinding = await page.$('table[data-bind]'); if(!hasBinding) throw new Error('Knockout binding not found'); /* Verify initial data */ const initialRows = await page.$$eval('table tr', rs => rs.length); if(initialRows !== 3) throw new Error('Expected 3 rows, got ' + initialRows); /* Verify SheetJS loaded */ const hasXLSX = await page.evaluate(() => typeof XLSX !== 'undefined'); if(!hasXLSX) throw new Error('SheetJS not loaded'); /* Test file import */ const buf = fs.readFileSync('./pres.xlsx'); await page.evaluate((b64) => { const input = document.getElementById('xlf'); const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0)); const file = new File([bytes], 'pres.xlsx', { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); const dt = new DataTransfer(); dt.items.add(file); input.files = dt.files; input.dispatchEvent(new Event('change', { bubbles: true })); }, buf.toString('base64')); await new Promise(r => setTimeout(r, 2000)); const importedRows = await page.$$eval('table tr', rs => rs.length); if(importedRows <= 3) throw new Error('Import failed: ' + importedRows + ' rows'); /* Cell mutation test */ await page.evaluate(() => { const input = document.querySelector('table input'); if(input) { input.value = 'MODIFIED_TEST_VALUE'; input.dispatchEvent(new Event('change', { bubbles: true })); } }); /* Export test */ const exportPath = './SheetJSKnockoutDemo.xlsx'; if(fs.existsSync(exportPath)) fs.unlinkSync(exportPath); await page.click('#export'); for(let i = 0; i < 10 && !fs.existsSync(exportPath); ++i) await new Promise(r => setTimeout(r, 500)); if(!fs.existsSync(exportPath)) throw new Error('Export failed'); const stats = fs.statSync(exportPath); if(stats.size < 100) throw new Error('Export file too small: ' + stats.size); console.log('[PASS] All tests passed (' + stats.size + ' bytes)'); await browser.close(); server.close(); process.exit(0); }); })(); EOF curl -LO https://docs.sheetjs.com/pres.xlsx npm init -y npm install --save puppeteer express@4 for KNOCKOUT_VERSION in knockout{2,3}; do curl -L -o index.html "https://docs.sheetjs.com/knockout/${KNOCKOUT_VERSION}.html" node test.cjs TEST_EXIT=$? if [ $TEST_EXIT -ne 0 ]; then echo "Puppeteer tests failed with exit code $TEST_EXIT"; exit $TEST_EXIT; fi if [ -f "./SheetJSKnockoutDemo.xlsx" ]; then OUTPUT=$(npx -y xlsx-cli SheetJSKnockoutDemo.xlsx) echo "$OUTPUT" if echo "$OUTPUT" | grep -q "MODIFIED_TEST_VALUE"; then rm SheetJSKnockoutDemo.xlsx else echo "ERROR: Exported file does not contain MODIFIED_TEST_VALUE"; exit 1 fi else echo "ERROR: Exported file not found"; exit 1 fi done