← back to Quadrille Showroom
proto/verify-v10.cjs
104 lines
const { chromium } = require('playwright');
const path = require('path');
const fs = require('fs');
(async () => {
const shotsDir = path.join(__dirname, 'shots');
fs.mkdirSync(shotsDir, { recursive: true });
// Serve the proto same-origin (proxies /api -> backend :7690) so CORS isn't an issue,
// exactly as it'll behave behind proto/proxy-server.cjs in real use.
const { spawn } = require('child_process');
const PORT = 7693;
const srv = spawn(process.execPath, [path.join(__dirname, 'proxy-server.cjs')],
{ env: { ...process.env, PROTO_PORT: String(PORT) }, stdio: 'inherit' });
await new Promise(r => setTimeout(r, 700));
const fileUrl = `http://127.0.0.1:${PORT}/v10-concierge.html`;
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } });
const page = await ctx.newPage();
const errors = [];
page.on('console', m => { if (m.type() === 'error') errors.push(m.text()); });
page.on('pageerror', e => errors.push('PAGEERROR: ' + e.message));
await page.goto(fileUrl, { waitUntil: 'networkidle' });
// wait for feed to load (concierge announces board count)
await page.waitForFunction(() => window.PRODUCTS && window.PRODUCTS.length > 0, { timeout: 8000 })
.catch(() => {});
const total = await page.evaluate(() => (window.PRODUCTS || []).length);
console.log('Products loaded:', total);
// ---- Query 1: "show me blues" via API ----
const q1 = await page.evaluate(() => {
const { results } = window.runQuery('show me blues');
const allBlue = results.every(p => /aqua|blue|navy|turquoise|capri/i.test(p.pattern_name));
return { n: results.length, allBlue, sample: results.slice(0,3).map(p=>p.pattern_name) };
});
console.log('Q1 "show me blues":', q1.n, 'results, all blue-named:', q1.allBlue);
console.log(' sample:', q1.sample);
// ---- Query 2: "like Aga but darker" ----
const q2 = await page.evaluate(() => {
const { results } = window.runQuery('like Aga but darker');
const allAga = results.every(p => /^aga/i.test(p.pattern_name));
return { n: results.length, allAga, sample: results.slice(0,4).map(p=>p.pattern_name) };
});
console.log('Q2 "like Aga but darker":', q2.n, 'results, all Aga family:', q2.allAga);
console.log(' sample:', q2.sample);
// ---- Query 3: stripes (style) ----
const q3 = await page.evaluate(() => {
const { results } = window.runQuery('something with stripes');
return { n: results.length, sample: results.slice(0,3).map(p=>p.pattern_name) };
});
console.log('Q3 "stripes":', q3.n, 'results; sample:', q3.sample);
// ---- Drive the UI: click a chip and confirm boards render in DOM ----
await page.click('text=Warm neutrals');
await page.waitForTimeout(900);
const boardsRendered = await page.evaluate(() => document.querySelectorAll('.board').length);
console.log('Warm neutrals chip -> boards in DOM:', boardsRendered);
// ---- Conversational refinement: "show me greens" then "now in blue" ----
const conv = await page.evaluate(() => {
const a = window.runQuery('show me greens');
const greens = a.results.length;
const b = window.runQuery('now in blue'); // refinement carries context, swaps color axis
const allBlue = b.results.every(p => /aqua|blue|navy|turquoise|capri/i.test(p.pattern_name));
return { greens, blueN: b.results.length, allBlue, line: b.line };
});
console.log('Refinement "show greens" -> "now in blue":', conv.greens, '->', conv.blueN,
'| all blue:', conv.allBlue);
console.log(' concierge said:', conv.line.replace(/<[^>]+>/g,''));
// ---- Drive UI for beauty shot: greens, then set aside two, then "now in blue" ----
await page.fill('#askInput', 'fresh greens');
await page.click('.ask button');
await page.waitForTimeout(900);
// set aside the first three boards (dispatch via JS — they may be below the fold)
await page.evaluate(() => {
document.querySelectorAll('.board .setaside').forEach((b,i)=>{ if(i<3) b.click(); });
});
await page.waitForTimeout(300);
const trayN = await page.evaluate(() => document.querySelectorAll('.trayItem').length);
console.log('Set-aside tray items:', trayN);
await page.fill('#askInput', 'now show me those in blue');
await page.click('.ask button');
await page.waitForTimeout(1000);
const finalBoards = await page.evaluate(() => document.querySelectorAll('.board').length);
console.log('Final on-table boards:', finalBoards);
await page.screenshot({ path: path.join(shotsDir, 'v10-concierge.png'), fullPage: false });
console.log('Screenshot -> shots/v10-concierge.png');
console.log('\nConsole errors:', errors.length);
errors.forEach(e => console.log(' ✗', e));
await browser.close();
srv.kill();
process.exit(errors.length ? 2 : 0);
})();