fix: chat bubbles crushed to 6px — flex-shrink: 0 prevents row collapse

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.
This commit is contained in:
juanatsap
2026-04-14 03:13:04 +01:00
parent 9164344375
commit fc1ca90b38
2 changed files with 65 additions and 31 deletions
+1 -5
View File
@@ -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;
}
+64 -26
View File
@@ -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 }
);