From fc1ca90b38cccaf37c5037108d3d90058df92c51 Mon Sep 17 00:00:00 2001 From: juanatsap Date: Tue, 14 Apr 2026 03:13:04 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20chat=20bubbles=20crushed=20to=206px=20?= =?UTF-8?q?=E2=80=94=20flex-shrink:=200=20prevents=20row=20collapse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit overflow: hidden on .chat-row made min-height resolve to 0 (CSS Flexbox §4.5), so the flex column container crushed rows instead of scrolling. Also fix all test selectors (.chat-agent→.chat-row-bot .chat-msg) and add bubble dimension assertions. --- static/css/04-interactive/_chat.css | 6 +- tests/mjs/83-chat-mascot.test.mjs | 90 ++++++++++++++++++++--------- 2 files changed, 65 insertions(+), 31 deletions(-) diff --git a/static/css/04-interactive/_chat.css b/static/css/04-interactive/_chat.css index 984fb7c..df5a87d 100644 --- a/static/css/04-interactive/_chat.css +++ b/static/css/04-interactive/_chat.css @@ -330,14 +330,10 @@ align-items: flex-start; max-width: 100%; overflow: hidden; -} - -.chat-row-bot { - align-self: flex-start; + flex-shrink: 0; } .chat-row-user { - align-self: flex-end; justify-content: flex-end; } diff --git a/tests/mjs/83-chat-mascot.test.mjs b/tests/mjs/83-chat-mascot.test.mjs index b7e5ac9..e8341f2 100644 --- a/tests/mjs/83-chat-mascot.test.mjs +++ b/tests/mjs/83-chat-mascot.test.mjs @@ -74,9 +74,9 @@ async function testChatMascot() { // ====================================================================== console.log("\n3️⃣ Help Modal"); - record('Help button (?) visible', await page.locator('.chat-help-btn').isVisible()); + record('Help button (?) visible', await page.locator('button[command="show-modal"][commandfor="chat-help-modal"]').isVisible()); - await page.click('.chat-help-btn'); + await page.click('button[command="show-modal"][commandfor="chat-help-modal"]'); await page.waitForTimeout(500); const modalOpen = await page.locator('#chat-help-modal').evaluate(el => el.open); record('Help modal opens', modalOpen); @@ -99,7 +99,7 @@ async function testChatMascot() { // ====================================================================== console.log("\n4️⃣ Welcome Message"); - const welcome = await page.locator('#chat-messages .chat-agent').first().textContent(); + const welcome = await page.locator('#chat-messages .chat-row-bot .chat-msg').first().textContent(); record('Welcome message present', welcome.includes('Ask me anything') || welcome.includes('Pregúntame')); // ====================================================================== @@ -115,22 +115,60 @@ async function testChatMascot() { // ====================================================================== console.log("\n6️⃣ Chip Click → Response"); - const msgsBefore = await page.locator('#chat-messages .chat-message').count(); + const msgsBefore = await page.locator('#chat-messages .chat-row').count(); await page.locator('.chat-chip').first().click(); // Wait for response await page.waitForFunction( - (before) => document.querySelectorAll('#chat-messages .chat-message').length > before + 1, + (before) => document.querySelectorAll('#chat-messages .chat-row').length > before + 1, msgsBefore, { timeout: CHAT_TIMEOUT } ); - const userMsg = await page.locator('#chat-messages .chat-user').last().textContent(); + const userMsg = await page.locator('#chat-messages .chat-row-user .chat-msg').last().textContent(); record('User message appears', userMsg.length > 5, userMsg.substring(0, 40)); - const agentMsg = await page.locator('#chat-messages .chat-agent').last().textContent(); + const agentMsg = await page.locator('#chat-messages .chat-row-bot .chat-msg').last().textContent(); record('Agent response appears', agentMsg.length > 30, `${agentMsg.substring(0, 50)}...`); + // ====================================================================== + // 6b. BUBBLE RENDERING — user and bot bubbles must have proper dimensions + // ====================================================================== + console.log("\n6️⃣b Bubble Rendering"); + + // Scroll to make last user bubble visible + await page.locator('#chat-messages .chat-row-user').last().scrollIntoViewIfNeeded(); + await page.waitForTimeout(200); + + const lastUserBubble = page.locator('#chat-messages .chat-row-user .chat-msg').last(); + const userBubbleBox = await lastUserBubble.boundingBox(); + record('User bubble width > 80px', userBubbleBox && userBubbleBox.width > 80, + `${Math.round(userBubbleBox?.width || 0)}px`); + record('User bubble height > 15px', userBubbleBox && userBubbleBox.height > 15, + `${Math.round(userBubbleBox?.height || 0)}px`); + + const lastBotBubble = page.locator('#chat-messages .chat-row-bot .chat-msg').last(); + await lastBotBubble.scrollIntoViewIfNeeded(); + await page.waitForTimeout(200); + const botBubbleBox = await lastBotBubble.boundingBox(); + record('Bot bubble width > 100px', botBubbleBox && botBubbleBox.width > 100, + `${Math.round(botBubbleBox?.width || 0)}px`); + record('Bot bubble height > 15px', botBubbleBox && botBubbleBox.height > 15, + `${Math.round(botBubbleBox?.height || 0)}px`); + + // User bubble must be ABOVE bot response — use DOM offsets (scroll-independent) + const noOverlap = await page.evaluate(() => { + const userRows = document.querySelectorAll('#chat-messages .chat-row-user'); + const botRows = document.querySelectorAll('#chat-messages .chat-row-bot'); + const lastUser = userRows[userRows.length - 1]; + const lastBot = botRows[botRows.length - 1]; + if (!lastUser || !lastBot) return { ok: false, detail: 'elements not found' }; + const userBottom = lastUser.offsetTop + lastUser.offsetHeight; + const botTop = lastBot.offsetTop; + return { ok: userBottom <= botTop, detail: 'user ends=' + userBottom + ', bot starts=' + botTop }; + }); + record('Bubbles don\'t overlap vertically', noOverlap.ok, noOverlap.detail); + // ====================================================================== // 7. NAVIGATION LINKS IN RESPONSE // ====================================================================== @@ -149,20 +187,20 @@ async function testChatMascot() { // ====================================================================== console.log("\n8️⃣ Typed Question"); - const msgsBeforeType = await page.locator('#chat-messages .chat-user').count(); + const msgsBeforeType = await page.locator('#chat-messages .chat-row-user .chat-msg').count(); await page.fill('#chat-input', 'What certifications does he have?'); await page.click('.chat-send-btn'); await page.waitForFunction( - (count) => document.querySelectorAll('#chat-messages .chat-user').length > count, + (count) => document.querySelectorAll('#chat-messages .chat-row-user .chat-msg').length > count, msgsBeforeType, { timeout: CHAT_TIMEOUT } ); - const typedMsg = await page.locator('#chat-messages .chat-user').last().textContent(); + const typedMsg = await page.locator('#chat-messages .chat-row-user .chat-msg').last().textContent(); record('Typed message appears', typedMsg.includes('certifications')); - const certResponse = await page.locator('#chat-messages .chat-agent').last().textContent(); + const certResponse = await page.locator('#chat-messages .chat-row-bot .chat-msg').last().textContent(); record('Certifications response', certResponse.toLowerCase().includes('sap') || certResponse.toLowerCase().includes('certif')); // ====================================================================== @@ -189,14 +227,14 @@ async function testChatMascot() { await page.fill('#chat-input', 'What is Juan\'s experience with Go?'); await page.click('.chat-send-btn'); - const agentsBefore11 = await page.locator('#chat-messages .chat-agent').count(); + const agentsBefore11 = await page.locator('#chat-messages .chat-row-bot .chat-msg').count(); await page.waitForFunction( - (c) => document.querySelectorAll('#chat-messages .chat-agent').length > c, + (c) => document.querySelectorAll('#chat-messages .chat-row-bot .chat-msg').length > c, agentsBefore11, { timeout: CHAT_TIMEOUT } ); - const goResp = (await page.locator('#chat-messages .chat-agent').last().textContent()).toLowerCase(); + const goResp = (await page.locator('#chat-messages .chat-row-bot .chat-msg').last().textContent()).toLowerCase(); record('Go: finds projects', goResp.includes('immich') || goResp.includes('cmux')); record('Go: finds skills', goResp.includes('skill') || goResp.includes('proficiency') || goResp.includes('programming')); @@ -208,14 +246,14 @@ async function testChatMascot() { await page.fill('#chat-input', 'What Java experience does he have?'); await page.click('.chat-send-btn'); - const agentsBefore12 = await page.locator('#chat-messages .chat-agent').count(); + const agentsBefore12 = await page.locator('#chat-messages .chat-row-bot .chat-msg').count(); await page.waitForFunction( - (c) => document.querySelectorAll('#chat-messages .chat-agent').length > c, + (c) => document.querySelectorAll('#chat-messages .chat-row-bot .chat-msg').length > c, agentsBefore12, { timeout: CHAT_TIMEOUT } ); - const javaResp = (await page.locator('#chat-messages .chat-agent').last().textContent()).toLowerCase(); + const javaResp = (await page.locator('#chat-messages .chat-row-bot .chat-msg').last().textContent()).toLowerCase(); record('Java: finds Insa', javaResp.includes('insa')); record('Java: finds multiple companies', javaResp.includes('homeria') || javaResp.includes('webratio') || javaResp.includes('penta')); @@ -227,14 +265,14 @@ async function testChatMascot() { await page.fill('#chat-input', 'List all companies he worked at'); await page.click('.chat-send-btn'); - const agentsBefore13 = await page.locator('#chat-messages .chat-agent').count(); + const agentsBefore13 = await page.locator('#chat-messages .chat-row-bot .chat-msg').count(); await page.waitForFunction( - (c) => document.querySelectorAll('#chat-messages .chat-agent').length > c, + (c) => document.querySelectorAll('#chat-messages .chat-row-bot .chat-msg').length > c, agentsBefore13, { timeout: CHAT_TIMEOUT } ); - const compResp = (await page.locator('#chat-messages .chat-agent').last().textContent()).toLowerCase(); + const compResp = (await page.locator('#chat-messages .chat-row-bot .chat-msg').last().textContent()).toLowerCase(); record('Lists Olympic', compResp.includes('olympic')); record('Lists SAP', compResp.includes('sap')); record('Lists Insa', compResp.includes('insa')); @@ -283,7 +321,7 @@ async function testChatMascot() { const esChip = await page.locator('.chat-chip').first().textContent(); record('Spanish chips', esChip.includes('Go') || esChip.includes('Proyectos')); - const esWelcome = await page.locator('#chat-messages .chat-agent').first().textContent(); + const esWelcome = await page.locator('#chat-messages .chat-row-bot .chat-msg').first().textContent(); record('Spanish welcome', esWelcome.includes('Pregúntame')); // ====================================================================== @@ -294,14 +332,14 @@ async function testChatMascot() { await page.fill('#chat-input', '¿Cuántos años de experiencia tiene?'); await page.click('.chat-send-btn'); - const agentsBefore16 = await page.locator('#chat-messages .chat-agent').count(); + const agentsBefore16 = await page.locator('#chat-messages .chat-row-bot .chat-msg').count(); await page.waitForFunction( - (c) => document.querySelectorAll('#chat-messages .chat-agent').length > c, + (c) => document.querySelectorAll('#chat-messages .chat-row-bot .chat-msg').length > c, agentsBefore16, { timeout: CHAT_TIMEOUT } ); - const esResp = await page.locator('#chat-messages .chat-agent').last().textContent(); + const esResp = await page.locator('#chat-messages .chat-row-bot .chat-msg').last().textContent(); record('Responds in Spanish', esResp.includes('años') || esResp.includes('experiencia')); record('Reports 21 years', esResp.includes('21')); @@ -321,9 +359,9 @@ async function testChatMascot() { await page.fill('#chat-input', 'How many years of experience?'); await page.click('.chat-send-btn'); - const agentsBefore17 = await page.locator('#chat-messages .chat-agent').count(); + const agentsBefore17 = await page.locator('#chat-messages .chat-row-bot .chat-msg').count(); await page.waitForFunction( - (c) => document.querySelectorAll('#chat-messages .chat-agent').length > c, + (c) => document.querySelectorAll('#chat-messages .chat-row-bot .chat-msg').length > c, agentsBefore17, { timeout: CHAT_TIMEOUT } );