All checks were successful
Quality gates / quality (pull_request) Successful in 1m26s
51 lines
3.4 KiB
JavaScript
51 lines
3.4 KiB
JavaScript
import { chromium } from 'playwright';
|
|
import assert from 'node:assert/strict';
|
|
import { mkdir } from 'node:fs/promises';
|
|
|
|
await mkdir('artifacts', { recursive: true });
|
|
const browser = await chromium.launch({ headless: true });
|
|
const context = await browser.newContext({ viewport: { width: 390, height: 844 }, deviceScaleFactor: 2, serviceWorkers: 'block' });
|
|
const page = await context.newPage();
|
|
const errors = [];
|
|
page.on('console', message => { if (message.type() === 'error') errors.push(message.text()); });
|
|
page.on('pageerror', error => errors.push(error.message));
|
|
|
|
await page.route('**/api/vision-status', route => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ enabled: true, profile: 'selfhost', providerReady: true, model: 'SmolVLM2-2.2B-Instruct' }) }));
|
|
await page.route('**/api/agent/status', route => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ enabled: true, configured: true, authenticated: true, mode: 'hermes-agent' }) }));
|
|
let chatRequest;
|
|
await page.route('**/api/agent/chat', async route => {
|
|
chatRequest = route.request().postDataJSON();
|
|
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ connected: true, reply: 'Your confirmed logs are mostly Type 4 this week. I can explain the pattern, but I cannot diagnose a cause.' }) });
|
|
});
|
|
|
|
await page.goto('http://127.0.0.1:4173');
|
|
await page.waitForLoadState('networkidle');
|
|
assert.equal(await page.locator('.bottom-nav .nav-btn').count(), 3, 'primary navigation must have exactly three destinations');
|
|
assert.equal(await page.locator('main .btn-primary:visible').count(), 1, 'home must expose one dominant primary action');
|
|
assert.equal(await page.locator('[data-log]:visible').count(), 1, 'manual fallback remains available once without competing styling');
|
|
assert.match(await page.locator('main').innerText(), /photo/i);
|
|
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true, 'home must not overflow horizontally');
|
|
await page.screenshot({ path: 'artifacts/sleek-home-mobile.png', fullPage: true });
|
|
|
|
await page.locator('[data-view="timmy"]').click();
|
|
await page.waitForSelector('#chat-message');
|
|
assert.equal(await page.locator('[data-prompt]').count(), 0, 'preset prompt button cluster is removed');
|
|
assert.match(await page.locator('.agent-status').innerText(), /Hermes Agent connected/i);
|
|
await page.locator('#chat-message').fill('What pattern do you see?');
|
|
await page.locator('#send-chat').click();
|
|
await page.waitForSelector('.bubble.timmy >> text=mostly Type 4');
|
|
assert.equal(chatRequest.message, 'What pattern do you see?');
|
|
assert.ok(Array.isArray(chatRequest.ledger));
|
|
assert.equal(JSON.stringify(chatRequest).includes('photoDataUrl'), false, 'photos never enter chat context');
|
|
const previousRequest = chatRequest;
|
|
await page.locator('#chat-message').fill('I threw up');
|
|
await page.locator('#send-chat').click();
|
|
await page.waitForSelector('.bubble.timmy >> text=Pause and get medical help');
|
|
assert.equal(chatRequest, previousRequest, 'urgent language must be intercepted before the Hermes request');
|
|
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true, 'chat must not overflow horizontally');
|
|
await page.screenshot({ path: 'artifacts/sleek-hermes-chat-mobile.png', fullPage: true });
|
|
|
|
assert.deepEqual(errors, []);
|
|
await browser.close();
|
|
console.log('Sleek shell + Hermes chat mobile acceptance passed.');
|