fix(assistant): #91 question positionnee au bord haut de la fenetre (padding dynamique, overflow-anchor, passe de correction)
CI / lint (push) Successful in 1m27s
CI / security (push) Successful in 1m0s
CI / test (push) Successful in 3m23s
CI / build (push) Successful in 51s
CI / e2e (push) Successful in 10m56s

This commit is contained in:
2026-09-15 20:29:01 -04:00
parent 1ed0d52619
commit daf9ff3b2d
6 changed files with 130 additions and 24 deletions
+39
View File
@@ -235,6 +235,45 @@ async function main() {
panel.remove();
});
await test("a short answer still rolls the post up: bottom padding is grown", () => {
// jsdom has no layout, so the geometry is stubbed: the post sits 500px
// down the thread while only 300px of scroll room exist. Without the
// padding trick the browser clamps and the post stops mid-window.
const b = new BooksLM();
b._messages = [
{ role: "user", content: "question" },
{ role: "assistant", content: "réponse courte" },
];
const panel = document.createElement("div");
panel.innerHTML = `<div class="bookslm-messages"></div>`;
document.body.appendChild(panel);
b._panel = panel;
const raf = globalThis.requestAnimationFrame;
globalThis.requestAnimationFrame = (fn) => fn();
try {
// Render the messages, then fake the geometry and re-anchor.
b._renderMessages();
const c = panel.querySelector(".bookslm-messages");
const post = panel.querySelector(".bookslm-msg.user");
Object.defineProperty(c, "clientHeight", { value: 400, configurable: true });
Object.defineProperty(c, "scrollHeight", { value: 700, configurable: true, writable: true });
c.getBoundingClientRect = () => ({ top: 0, left: 0, right: 0, bottom: 400, width: 400, height: 400 });
post.getBoundingClientRect = () => ({ top: 500, left: 0, right: 0, bottom: 560, width: 300, height: 60 });
b._anchorLatestUser({ instant: true });
// target (500) - max (300) = 200px of missing room.
assert.equal(c.style.paddingBottom, "200px", "padding grown by the missing room");
// Plenty of room below the post → no padding at all.
Object.defineProperty(c, "scrollHeight", { value: 2000, configurable: true, writable: true });
c.scrollTop = 0;
b._anchorLatestUser({ instant: true });
assert.equal(c.style.paddingBottom, "", "no padding when the thread already scrolls far enough");
} finally {
globalThis.requestAnimationFrame = raf;
panel.remove();
}
});
await test("the placeholder render keeps the anchor (no scroll reset before first token)", async () => {
// Regression: the assistant placeholder used to be rendered while
// `_isLoading` was still false, so it took the "restore previous