cdnV2

git clone https://github.com/notamitgamer/cdnV2.git
· rebuilt hourlyOpen on GitHub
root / tests / turbo_e2e.js

turbo_e2e.js (5813B)


      1 // End-to-end check of instant folder navigation with the REAL Turbo and the REAL server-rendered pages.
      2 // Not run directly: tests/test_fast_tree.py writes fixtures to a directory and calls
      3 //   node tests/turbo_e2e.js <fixtures-dir>
      4 // Needs jsdom and @hotwired/turbo@8.0.4 (CI installs both; locally: npm i --no-save --no-package-lock jsdom @hotwired/turbo@8.0.4).
      5 const fs = require('node:fs');
      6 const path = require('node:path');
      7 const { JSDOM, VirtualConsole } = require('jsdom');
      8 const { boot } = require('../app/static/fasttree.js');
      9 
     10 const dir = process.argv[2];
     11 const read = (f) => fs.readFileSync(path.join(dir, f), 'utf8');
     12 const tree = JSON.parse(read('tree.json'));
     13 const shell = JSON.parse(read('shell.json'));
     14 const turboSrc = fs.readFileSync(require.resolve('@hotwired/turbo/dist/turbo.es2017-umd.js'), 'utf8');
     15 
     16 const failures = [];
     17 const check = (cond, msg) => { if (!cond) failures.push(msg); console.log((cond ? 'ok   - ' : 'FAIL - ') + msg); };
     18 const norm = (s) => s.replace(/\s+/g, ' ').trim();
     19 // The parts of a listing page that depend on the folder. (Whole-page equality is checked elsewhere.)
     20 const region = (doc) => ['.breadcrumb-container', '.listing-toolbar', '#file-list', 'footer']
     21   .map((sel) => { const el = doc.querySelector(sel); return norm(el ? el.outerHTML : '(none)'); }).join('\n');
     22 const waitFor = async (cond, ms = 4000) => { const end = Date.now() + ms; while (Date.now() < end) { if (cond()) return true; await new Promise((r) => setTimeout(r, 10)); } return cond(); };
     23 const parse = (html) => new JSDOM(html).window.document;
     24 
     25 (async () => {
     26   // The page the user is on: the server's own rendering of /bsc (external scripts are not loaded in jsdom).
     27   const stripExternal = (h) => h.replace(/<script[^>]*\bsrc="[^"]*"[^>]*><\/script>/g, '');
     28   const dom = new JSDOM(stripExternal(read('from.html')), {
     29     url: 'https://cdn.example.com/bsc', runScripts: 'dangerously', pretendToBeVisual: true, virtualConsole: new VirtualConsole(),
     30   });
     31   const win = dom.window;
     32   win.eval(turboSrc);                       // the real Turbo (what the CDN <script type=module> provides)
     33   check(typeof win.Turbo.visit === 'function', 'real Turbo 8.0.4 is loaded');
     34   win.localStorage.setItem('cdn_fast_v1', JSON.stringify({ tree: { v: tree.v, files: tree.files }, shell }));
     35   let networkCalls = 0;
     36   const requested = [];
     37   win.fetch = (u, o) => {
     38     const url = String(u && u.url || u);
     39     // the tree/shell revalidating in the background is expected; a page request is not
     40     if (url !== '/api/tree' && url !== '/api/shell') { networkCalls++; requested.push(`${url} (during step ${step})`); } return Promise.reject(new Error('the test forbids network requests')); };
     41   let step = 'start';
     42   const origPush = win.history.pushState.bind(win.history);
     43   const pushed = [];
     44   win.history.pushState = (...a) => { pushed.push(a[2]); return origPush(...a); };
     45   boot(win);
     46 
     47   step = 'click';
     48   const link = win.document.querySelector('#file-list a[href="/bsc/semester_1"]');
     49   check(!!link, 'the page has a link to the sub-folder');
     50   await waitFor(() => win.document.readyState === 'complete');
     51   await new Promise((r) => setTimeout(r, 100));   // let Turbo's own start-up settle
     52   link.dispatchEvent(new win.MouseEvent('click', { bubbles: true, cancelable: true, button: 0 }));
     53   await waitFor(() => win.location.pathname === '/bsc/semester_1' && win.document.querySelector('a[href="/bsc/semester_1/deep"]'));
     54 
     55   check(win.location.pathname === '/bsc/semester_1', `the address changed to /bsc/semester_1 (is ${win.location.pathname})`);
     56   check(pushed.length === 1, 'Turbo added a history entry');
     57   check(networkCalls === 0, 'no page was requested from the server for the navigation');
     58   const got = region(win.document);
     59   const want = region(parse(read('to.html')));
     60   check(got === want, 'the page now on screen equals the server-rendered page for that folder');
     61   if (got !== want) {
     62     const i = [...got].findIndex((c, k) => c !== want[k]);
     63     console.log('   got : ...' + got.slice(Math.max(0, i - 80), i + 120) + '\n   want: ...' + want.slice(Math.max(0, i - 80), i + 120));
     64   }
     65   const visited = JSON.parse(win.localStorage.getItem('cdn_visited_v1') || '[]');
     66   check(visited.some((e) => e.type === 'folder' && e.path === 'bsc/semester_1'), "the page's own script recorded the visit in History");
     67 
     68   // Back to the page we came from (Turbo restores it), then forward again.
     69   step = 'back';
     70   win.history.back();
     71   await waitFor(() => win.location.pathname === '/bsc' && win.document.querySelector('#file-list a[href="/bsc/semester_1"]'));
     72   check(win.location.pathname === '/bsc', 'Back returns to /bsc');
     73   check(win.document.querySelector('#file-list a[href="/bsc/semester_1"]') !== null, '...and shows that folder\'s listing');
     74 
     75   // Going to the root from a deep page: header appears, breadcrumb disappears.
     76   step = 'root';
     77   win.document.querySelector('.wordmark').dispatchEvent(new win.MouseEvent('click', { bubbles: true, cancelable: true, button: 0 }));
     78   await waitFor(() => win.location.pathname === '/' && win.document.querySelector('h1'));
     79   check(win.location.pathname === '/', 'the logo link goes to the root locally');
     80   check(win.document.querySelector('h1') !== null && win.document.querySelector('.breadcrumb-container') === null, 'root shows its header and no breadcrumb');
     81   check(region(win.document) === region(parse(read('root.html'))), 'the root page equals the server-rendered root page');
     82   check(networkCalls === 0, 'still no page requests (Back, logo link)' + (requested.length ? ': ' + requested.join(', ') : ''));
     83 
     84   console.log(failures.length ? `\n${failures.length} FAILURE(S)` : '\nend-to-end navigation works');
     85   process.exit(failures.length ? 1 : 0);
     86 })().catch((e) => { console.error('FAIL - exception:', e); process.exit(1); });