philipgreat commited on
Commit
87d12bc
·
verified ·
1 Parent(s): c793c14

Retain local and live browser evidence for request-tree TraceChain deployment

Browse files
evidence/live-browser.json ADDED
The diff for this file is too large to render. See raw diff
 
evidence/local-browser.json ADDED
The diff for this file is too large to render. See raw diff
 
source/browser-sqlite/scripts/verify-space.mjs ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import assert from 'node:assert/strict';
2
+ import {writeFileSync} from 'node:fs';
3
+ import puppeteer from 'puppeteer-core';
4
+
5
+ const url = process.env.TEAQL_SPACE_URL || 'https://teaql-browser-sqlite-playground.static.hf.space/';
6
+ const browser = await puppeteer.launch({executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome',
7
+ headless: true, args: ['--no-sandbox', '--disable-dev-shm-usage']});
8
+ try {
9
+ const page = await browser.newPage(), errors = [];
10
+ page.on('pageerror', error => errors.push(error.message));
11
+ page.on('console', event => { if (event.type() === 'error') errors.push(event.text()); });
12
+ page.on('response', response => { if (response.status() >= 400) errors.push(`${response.status()} ${response.url()}`); });
13
+ page.on('requestfailed', request => errors.push(`${request.failure()?.errorText} ${request.url()}`));
14
+ await page.goto(url, {waitUntil: 'networkidle0', timeout: 60_000});
15
+ const waitReady = () => page.waitForFunction(() => document.querySelector('#status')?.textContent?.includes('ready'), {timeout: 45_000});
16
+ await waitReady();
17
+ async function inspect(label) {
18
+ const response = JSON.parse(await page.$eval('#result', element => element.textContent));
19
+ const evidence = JSON.parse(await page.$eval('#sql', element => element.textContent));
20
+ assert.equal(response.resultCode, 0); assert.equal(response.status, 'YES');
21
+ assert.equal(response.recordCount, 3); assert.equal(response.metadata.totalCount, 3);
22
+ assert.equal(response.data[0].orderNumber, 'KEEP-002'); assert.equal(response.data[0].itemCount, 5);
23
+ assert.deepEqual(response.data[0].items.map(item => item.productName), ['Box 1', 'Box 2', 'Box 3']);
24
+ assert.deepEqual(response.facets.statusCounts.map(row => [row.orderCount, row.orderTotalAmount]), [[1, 100], [2, 500], [0, null]]);
25
+ assert.equal(evidence.length, 8);
26
+ const chains = evidence.map(entry => entry.traceChain.filter(node => node.kind === 'comment').map(node => node.detail));
27
+ for (const expected of [
28
+ ['load order list', "countAs('totalOrders')"],
29
+ ['load order list', 'selectStatusWith(...)', 'load status'],
30
+ ['load order list', 'selectOrderItemListWith(...)', 'load item previews'],
31
+ ['load order list', "countOrderItemsAs('itemCount')"],
32
+ ['load order list', "facetByStatusAs('statusCounts')", 'aggregate status'],
33
+ ['load order list', "facetByStatusAs('statusCounts')", 'load status facets'],
34
+ ]) assert.ok(chains.some(chain => JSON.stringify(chain) === JSON.stringify(expected)), JSON.stringify(expected));
35
+ const rendered = await page.$$eval('#evidence-rows tr', rows => rows.map(row => [...row.querySelectorAll('td')].map(cell => cell.textContent)));
36
+ assert.deepEqual(rendered, evidence.map(entry => [`${entry.elapsedMicros} µs`,
37
+ entry.tracePath.find(node => node.kind === 'request')?.name ?? '—',
38
+ `${entry.traceChain.find(node => node.kind === 'purpose').detail}: ${entry.traceChain.filter(node => node.kind === 'comment').map(node => node.detail).join(' → ')}`,
39
+ entry.debugSQL]));
40
+ return {label, response, evidence, rendered};
41
+ }
42
+ const receipts = [await inspect('first')];
43
+ const host = await page.evaluate(() => ({crossOriginIsolated, opfsDisabled: document.querySelector('#persist').disabled}));
44
+ if (!host.crossOriginIsolated) assert.equal(host.opfsDisabled, true);
45
+ await page.click('#logging');
46
+ await page.waitForFunction(() => document.querySelector('#status')?.textContent?.includes('0 diagnostics'));
47
+ receipts.push(await inspect('diagnostics-off'));
48
+ await page.select('#example', 'all');
49
+ await page.waitForFunction(() => { const text = document.querySelector('#result')?.textContent; return text && JSON.parse(text).recordCount === 4; });
50
+ await page.$eval('#search', element => { element.value = 'Q.constructor("return globalThis")'; });
51
+ await page.click('#query');
52
+ await page.waitForFunction(() => document.querySelector('#status')?.textContent?.includes('not allowed'));
53
+ assert.equal(await page.$eval('#sql', element => element.textContent), '[]');
54
+ await page.click('#preset'); await waitReady(); receipts.push(await inspect('restored'));
55
+ await page.click('#reset');
56
+ await page.waitForFunction(() => !document.querySelector('#reset').disabled);
57
+ receipts.push(await inspect('reset'));
58
+ await page.reload({waitUntil: 'networkidle0'}); await waitReady(); receipts.push(await inspect('refresh'));
59
+ assert.deepEqual(errors, []);
60
+ if (process.env.TEAQL_SPACE_EVIDENCE) writeFileSync(process.env.TEAQL_SPACE_EVIDENCE,
61
+ JSON.stringify({url, host, receipts, queryPresetSwitch: true, forbiddenConstructorRejected: true, errors, passed: true}, null, 2) + '\n', {flag: 'wx'});
62
+ console.log(`PASS live Static Space: new TraceChain, 8 SQL records, editor/presets, WebResponse/facets, diagnostics-off, reset/refresh; OPFS disabled=${host.opfsDisabled}`);
63
+ } finally { await browser.close(); }