Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions packages/app/e2e/model-picker-height.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { test, expect } from "./fixtures"
import { promptModelSelector } from "./selectors"

const pickerContentSelector = '[data-picker-content=""]'
const thinkingTriggerSelector = '[data-action="prompt-model-thinking-trigger"]'

test("model picker height fits content, no empty bottom space", async ({ page, gotoSession }, testInfo) => {
await gotoSession()

const chip = page.locator(promptModelSelector).locator('[data-action="prompt-model"]').first()
await expect(chip).toBeVisible()
await chip.click()

const picker = page.locator(pickerContentSelector).first()
Comment thread
Astro-Han marked this conversation as resolved.
Resolved
await expect(picker).toBeVisible()

const thinking = page.locator(thinkingTriggerSelector)
await expect(thinking).toBeVisible()

const items = picker.locator('[data-slot="list-item"]')
const itemCount = await items.count()
expect(itemCount, "expected at least one model in the picker").toBeGreaterThan(0)
const lastItem = items.nth(itemCount - 1)

const pickerBox = await picker.boundingBox()
const lastItemBox = await lastItem.boundingBox()
const thinkingBox = await thinking.boundingBox()
if (!pickerBox || !lastItemBox || !thinkingBox) throw new Error("picker layout box missing")

// The model list and the Thinking row are stacked in a flex-col. Between the last
// visible model and the Thinking row only the list's own gap (12px) plus the
// section's border + padding belong. When the popover is forced to a fixed 400px
// and the model list happens to be short, the list-scroll grows to fill flex-1
// and an empty band appears above the Thinking row.
const scrollHeight = await picker
.locator('[data-slot="list-scroll"]')
.evaluate((el) => el.scrollHeight)
const clientHeight = await picker
.locator('[data-slot="list-scroll"]')
.evaluate((el) => el.clientHeight)
const listOverflowing = scrollHeight > clientHeight + 1

const lastItemBottom = lastItemBox.y + lastItemBox.height
const gapBelowLastItem = thinkingBox.y - lastItemBottom

// If the list scrolls, the last DOM item may be clipped offscreen, so we only
// require the no-empty-band invariant when the content fits without scrolling.
if (!listOverflowing) {
expect(
gapBelowLastItem,
"no empty band should appear between last model and Thinking row",
).toBeLessThan(40)
}

expect(pickerBox.height, "popover height should not exceed the 400px cap").toBeLessThanOrEqual(400)

const screenshotPath = testInfo.outputPath("model-picker.png")
await picker.screenshot({ path: screenshotPath })
await testInfo.attach("model-picker", { path: screenshotPath, contentType: "image/png" })
})
2 changes: 1 addition & 1 deletion packages/app/src/components/prompt-input/model-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export function ModelSelectorPopover(props: {
<Kobalte.Portal>
<Kobalte.Content
data-picker-content=""
class="w-[240px] h-[400px] flex flex-col z-50 outline-none overflow-hidden"
class="w-[240px] max-h-[400px] flex flex-col z-50 outline-none overflow-hidden"
onEscapeKeyDown={(event) => {
close("escape")
event.preventDefault()
Expand Down
Loading