Download app/tests/space-embedded.mjs from Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP: direct link, hf CLI and curl.
- Browser
- Download file 5.98 kB
-
https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/space-embedded.mjs
- Command line
-
hf download hf://spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/app/tests/space-embedded.mjs
-
curl -L -o space-embedded.mjs https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi-HTTP/resolve/main/app/tests/space-embedded.mjs
5.98 kB
| import { chromium } from 'playwright'; | |
| import fs from 'node:fs/promises'; | |
| import assert from 'node:assert/strict'; | |
| import { createRequire } from 'node:module'; | |
| import path from 'node:path'; | |
| // Playwright 1.58 disables ThirdPartyStoragePartitioning by default. Restore | |
| // Chromium's normal partitioning for a representative cross-site iframe test. | |
| const require = createRequire(import.meta.url); | |
| const { chromiumSwitches } = require(path.join(path.dirname(require.resolve('playwright-core/package.json')), 'lib/server/chromium/chromiumSwitches.js')); | |
| const disabledFeatures = chromiumSwitches(false).find(arg => arg.startsWith('--disable-features=')); | |
| const url = 'https://huggingface.co/spaces/Mike0021/MiniCPM5-2B-WebGPU-Pi'; | |
| const label = process.argv[2] ?? 'agent-space-embedded'; | |
| const firstMessage = process.argv.includes('--first-message'); | |
| const result = { date: new Date().toISOString(), url, firstMessage }; | |
| const context = await chromium.launchPersistentContext('../validation/agent-browser-profile/space', { | |
| executablePath: '/usr/bin/chromium', headless: true, viewport: { width: 1440, height: 1080 }, | |
| ignoreDefaultArgs: [disabledFeatures], | |
| args: [disabledFeatures.replace('ThirdPartyStoragePartitioning,', ''), '--enable-unsafe-webgpu', '--use-angle=vulkan', '--enable-features=Vulkan', '--disable-vulkan-surface'], | |
| }); | |
| context.setDefaultTimeout(240_000); | |
| try { | |
| const page = await context.newPage(); | |
| await page.goto(url, { waitUntil: 'domcontentloaded' }); | |
| console.log('Hugging Face page opened'); | |
| await page.waitForFunction(() => [...document.querySelectorAll('iframe')].some(frame => frame.src.includes('minicpm5-2b-webgpu-pi'))); | |
| // Hugging Face can replace its initial iframe while the parent initializes. | |
| let app; | |
| for (let attempt = 0; attempt < 4; attempt++) { | |
| const element = await page.waitForSelector('iframe[src*="minicpm5-2b-webgpu-pi"]'); | |
| app = await element.contentFrame(); | |
| assert(app, 'The deployed Hugging Face app frame must exist.'); | |
| try { | |
| await app.waitForFunction(() => window.browserPi?.terminal); | |
| await app.evaluate(() => window.browserPi.ready); | |
| break; | |
| } catch (error) { | |
| if (attempt === 3 || !/detached|context was destroyed/i.test(error.message)) throw error; | |
| } | |
| } | |
| result.frameUrl = app.url(); | |
| result.cachedBeforeSend = await app.evaluate(() => window.browserPi.rpc('cache_status')); | |
| console.log('App initialized'); | |
| const task = 'Read sales.csv, calculate total revenue using bash, and save a short report to report.md. Verify the file.'; | |
| if (firstMessage) { | |
| await app.evaluate(() => document.querySelector('#new-chat').onclick()); | |
| await app.evaluate(() => window.browserPi.rpc('shell', { command: 'rm -f /workspace/report.md' })); | |
| // Activate the iframe with a real click before sending keyboard events. | |
| await app.locator('#pi-terminal').click(); | |
| await app.locator('.xterm-helper-textarea').focus(); await page.keyboard.type(task); | |
| await app.waitForFunction(text => window.browserPi.terminal.text === text, task, { timeout: 15_000 }); | |
| console.log('First message typed'); | |
| await app.locator('#send').click(); | |
| if (!result.cachedBeforeSend) { | |
| await app.waitForFunction(() => document.querySelector('#model-dialog').open); | |
| console.log('First-message modal opened'); | |
| assert.equal(await app.locator('#model-preview').textContent(), task); | |
| await page.screenshot({ path: `../validation/${label}-modal.png`, fullPage: true }); | |
| } | |
| } | |
| const start = Date.now(); | |
| if (!firstMessage || !result.cachedBeforeSend) await app.locator(firstMessage ? '#model-confirm' : '#load').click(); | |
| await app.waitForFunction(() => window.browserPi.loaded || (!window.browserPi.busy && (document.querySelector('#notice').textContent || !document.querySelector('#model-error').hidden))); | |
| assert.equal(await app.evaluate(() => window.browserPi.loaded), true, await app.locator('#load-status').textContent()); | |
| result.loadMs = Date.now() - start; | |
| result.device = await app.evaluate(() => window.browserPi.diagnostics.device); | |
| if (!firstMessage) { | |
| await app.waitForFunction(() => !window.browserPi.busy); | |
| // Await the async UI handler: checking !busy immediately after a click can | |
| // precede the worker's busy event and race the next setup command. | |
| await app.evaluate(() => document.querySelector('#new-chat').onclick()); | |
| await app.evaluate(() => window.browserPi.rpc('shell', { command: 'rm -f /workspace/report.md' })); | |
| await app.locator('.xterm-helper-textarea').focus(); | |
| await page.keyboard.type(task); | |
| await app.locator('#send').click(); | |
| await app.waitForFunction(() => window.browserPi.busy); | |
| await app.waitForFunction(() => !window.browserPi.busy); | |
| } else { | |
| await app.waitForFunction(() => window.browserPi.diagnostics.events.includes('agent_end') && !window.browserPi.busy); | |
| assert.equal(await app.locator('#model-dialog').evaluate(el => el.open), false); | |
| } | |
| const state = await app.evaluate(() => window.browserPi.rpc('snapshot')); | |
| result.messages = state.messages; result.report = state.files['/workspace/report.md']; | |
| result.terminalScreen = await app.evaluate(() => window.browserPi.terminal.readScreen()); | |
| assert.equal(state.messages.filter(m => m.role === 'user').length, 1); | |
| assert.match(result.report ?? '', /144/); | |
| assert(state.messages.some(m => m.role === 'toolResult' && m.toolName === 'bash' && !m.isError)); | |
| assert(state.messages.filter(m => m.role === 'assistant').at(-1).content.some(c => c.type === 'text' && c.text.includes('144'))); | |
| await page.screenshot({ path: `../validation/${label}.png`, fullPage: true }); | |
| result.passed = true; | |
| console.log('Embedded Hugging Face Space: real UI → Pi → WebGPU → bash → verified report passed.'); | |
| } catch (error) { result.failure = error.stack; throw error; } | |
| finally { await fs.writeFile(`../validation/${label}.json`, JSON.stringify(result, null, 2)); await context.close(); } | |