Download app/tests/local-folder-browser.mjs from Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP: direct link, hf CLI and curl.
- Browser
- Download file 7.65 kB
-
https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/local-folder-browser.mjs
- Command line
-
hf download hf://spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/app/tests/local-folder-browser.mjs
-
curl -L -o local-folder-browser.mjs https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/local-folder-browser.mjs
7.65 kB
| import { chromium, webkit } from 'playwright'; | |
| import assert from 'node:assert/strict'; | |
| import fs from 'node:fs/promises'; | |
| const url = process.argv[2] || 'http://127.0.0.1:4193/'; | |
| const label = process.argv[3] || 'local-folder-browser'; | |
| const result = { url, date: new Date().toISOString(), checks: [], errors: [], picker: 'Test supplies a real OPFS directory handle; native OS picker covered separately.' }; | |
| const browser = await chromium.launch({ executablePath: '/usr/bin/chromium', headless: true }); | |
| const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } }); | |
| const page = await context.newPage(); | |
| page.on('pageerror', e => result.errors.push(e.message)); | |
| const idle = () => page.waitForFunction(() => window.browserPi && !window.browserPi.busy); | |
| const rpc = (action, args) => page.evaluate(({ action, args }) => window.browserPi.rpc(action, args), { action, args }); | |
| const disk = name => page.evaluate(async name => (await (await window.testFolder.getFileHandle(name)).getFile()).text(), name); | |
| async function open() { await page.goto(url); await page.waitForFunction(() => window.browserPi); await page.evaluate(() => window.browserPi.ready); await idle(); } | |
| try { | |
| await open(); | |
| const demo = await rpc('snapshot'); | |
| await page.evaluate(async () => { | |
| const root = await navigator.storage.getDirectory(); | |
| window.testFolder = await root.getDirectoryHandle('project-fixture', { create: true }); | |
| const write = async (name, text) => { const s = await (await window.testFolder.getFileHandle(name, { create: true })).createWritable(); await s.write(text); await s.close(); }; | |
| await write('README.md', '# Local fixture\n'); await write('count.txt', '1\n'); | |
| const modules = await window.testFolder.getDirectoryHandle('node_modules', { create: true }); | |
| const ignored = await (await modules.getFileHandle('ignored.js', { create: true })).createWritable(); await ignored.write('ignore'); await ignored.close(); | |
| window.pickerCalls = 0; | |
| window.showDirectoryPicker = async () => { window.pickerCalls++; window.pickerGesture = navigator.userActivation.isActive; return window.testFolder; }; | |
| }); | |
| await page.locator('#open-folder').click(); | |
| await page.waitForFunction(() => document.querySelector('#editor').value === '# Local fixture\n'); await idle(); | |
| assert.equal(await page.evaluate(() => window.pickerGesture), true); | |
| assert.equal((await rpc('snapshot')).entries, null); | |
| assert.equal(await page.locator('#files').innerText(), 'README.md\ncount.txt'); | |
| result.checks.push('Real directory handle crosses worker boundary; picker called with user activation; existing editor/tree reused; excluded directories omitted'); | |
| await page.locator('#editor').fill('# Edited local fixture\n'); await page.locator('#save').click(); await idle(); | |
| assert.equal(await disk('README.md'), '# Local fixture\n'); | |
| await page.locator('#review-changes').click(); | |
| await page.locator('#local-review').waitFor({ state: 'visible' }); | |
| assert.match(await page.locator('#review-files').innerText(), /\+# Edited local fixture/); | |
| await page.screenshot({ path: `../validation/${label}-review.png` }); | |
| await page.locator('#review-apply').click(); await page.locator('#local-review').waitFor({ state: 'hidden' }); await idle(); | |
| assert.equal(await disk('README.md'), '# Edited local fixture\n'); | |
| result.checks.push('Editor changes are staged; readable diff reviewed; Apply writes through the browser API'); | |
| const shell = await rpc('shell', { command: "printf 'new file\\n' > added.txt; printf '2\\n' > count.txt" }); | |
| assert.equal(shell.exitCode, 0, shell.stderr); await idle(); | |
| assert.equal(await disk('count.txt'), '1\n'); | |
| await page.locator('#disconnect-folder').click(); await page.locator('#open-folder').waitFor({ state: 'visible' }); await idle(); | |
| assert.deepEqual((await rpc('snapshot')).files, demo.files); | |
| assert.deepEqual((await rpc('snapshot')).messages, demo.messages); | |
| await page.reload(); await page.waitForFunction(() => window.browserPi); await page.evaluate(() => window.browserPi.ready); | |
| await page.locator('#reconnect-folder').click(); await page.locator('#local-folder-bar').waitFor({ state: 'visible' }); await idle(); | |
| const staged = await rpc('local_changes'); assert.equal(staged.length, 2); | |
| await page.evaluate(async () => { window.testFolder = await (await navigator.storage.getDirectory()).getDirectoryHandle('project-fixture'); }); | |
| assert.equal(await rpc('read', { path: '/workspace/added.txt' }), 'new file\n'); await idle(); | |
| result.checks.push('Back to demo restores original files/chat; reload + reconnect restores handle, staged edits and local chat from separate IndexedDB record'); | |
| await page.evaluate(async () => { const s = await (await window.testFolder.getFileHandle('count.txt')).createWritable(); await s.write('9\n'); await s.close(); }); | |
| await page.locator('#review-changes').click(); await page.locator('#review-apply').click(); | |
| await page.waitForFunction(() => document.querySelector('#review-error').textContent.includes('Conflict')); | |
| assert.equal(await disk('count.txt'), '9\n'); | |
| assert.equal(await page.evaluate(async () => { try { await window.testFolder.getFileHandle('added.txt'); return true; } catch { return false; } }), false); | |
| page.once('dialog', d => d.accept()); await page.locator('#review-discard').click(); | |
| await page.locator('#local-review').waitFor({ state: 'hidden' }); await idle(); | |
| assert.equal((await rpc('local_changes')).length, 0); | |
| result.checks.push('External edit blocks the whole apply before any disk mutation; Discard leaves external contents intact'); | |
| for (const width of [1440, 390, 320]) { | |
| await page.setViewportSize({ width, height: width === 1440 ? 1000 : 844 }); | |
| assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)); | |
| await page.locator('#local-folder-bar').scrollIntoViewIfNeeded(); | |
| await page.screenshot({ path: `../validation/${label}-${width}.png`, fullPage: true }); | |
| } | |
| result.checks.push('Folder controls and editor fit 1440, 390 and 320px layouts'); | |
| await page.locator('#disconnect-folder').click(); await idle(); | |
| await page.evaluate(() => { window.showDirectoryPicker = async () => { throw new DOMException('Cancelled', 'AbortError'); }; }); | |
| await page.locator('#open-folder').click(); await idle(); | |
| assert.deepEqual((await rpc('snapshot')).files, demo.files); | |
| result.checks.push('Cancelling picker preserves the demo workspace'); | |
| // True cross-origin embedding, not a replaced window.top property. | |
| const embed = await context.newPage(); | |
| await context.grantPermissions(['local-network-access']); | |
| const parent = url.startsWith('http:') ? 'http://localhost:4193/embed-fixture' : 'https://embed.example/'; | |
| await embed.route(parent, route => route.fulfill({ contentType: 'text/html', body: `<iframe src="${url}" style="width:100%;height:900px"></iframe>` })); | |
| await embed.goto(parent); | |
| const frame = embed.frameLocator('iframe'); await frame.locator('#open-folder').click(); | |
| assert.match(await frame.locator('#notice').innerText(), /new tab/); await frame.locator('#open-tab').waitFor({ state: 'visible' }); | |
| await embed.close(); result.checks.push('Cross-origin iframe offers direct app tab instead of a blocked native picker'); | |
| assert.deepEqual(result.errors, []); | |
| result.passed = true; | |
| } catch (e) { result.failure = e.stack; await page.screenshot({ path: `../validation/${label}-failure.png`, fullPage: true }); throw e; } | |
| finally { await fs.writeFile(`../validation/${label}.json`, JSON.stringify(result, null, 2)); await browser.close(); console.log(JSON.stringify(result, null, 2)); } | |