fix: make code block height content-aware
Engine CI / test (push) Waiting to run

This commit is contained in:
2026-08-31 20:08:32 +08:00
parent e23fa413be
commit 924b1a15f3
8 changed files with 130 additions and 40 deletions
+44 -21
View File
@@ -261,14 +261,14 @@ test('presenter advances animations, switches notes, shows timing, and syncs the
await presenter.getByTitle('Go to next slide').click()
await expect(page.getByRole('heading', { name: '内容优先' })).toBeVisible()
await expect(presenter.getByText('依次介绍四个核心能力')).toBeVisible()
await expect(presenter.getByText('2 / 8', { exact: true })).toBeVisible()
await expect(presenter.getByText('2 / 9', { exact: true })).toBeVisible()
await presenter.getByTitle('Go to next slide').click()
await expect(presenter.getByText('1/4', { exact: true })).toBeVisible()
await expect(page).toHaveURL(/#\/2\?clicks=1$/)
})
test('table and code controls adjust font size while code fills the available height', async ({ page }) => {
test('table and code controls adjust font size while code uses smart height', async ({ page }) => {
await page.goto('/getting-started/#/7')
const table = page.locator('.slidev-layout table').first()
const tablePreset = table.locator('..').locator('..')
@@ -311,15 +311,8 @@ test('table and code controls adjust font size while code fills the available he
await expect.poll(() => code.evaluate(element => Number.parseFloat(getComputedStyle(element).fontSize))).toBe(initialCodeSize)
await expect.poll(() => code.evaluate((element) => {
const region = element.closest('.easy-two-cols-grid > div')!
const layout = element.closest('.slidev-layout') as HTMLElement
const scale = layout.getBoundingClientRect().height / layout.clientHeight
const contentBottom = Math.min(
region.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(region).paddingBottom) * scale,
layout.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(layout).paddingBottom) * scale,
)
return Math.abs(contentBottom - element.getBoundingClientRect().bottom) / scale
})).toBeLessThanOrEqual(3)
return element.scrollHeight - element.clientHeight
})).toBeGreaterThan(0)
const overflow = await code.evaluate(element => ({
horizontal: getComputedStyle(element).overflowX,
lineHeight: Number.parseFloat(getComputedStyle(element).lineHeight),
@@ -365,16 +358,46 @@ test('table and code controls adjust font size while code fills the available he
await layout.evaluate((element) => {
element.classList.remove('easy-code-height-sm', 'easy-code-height-md', 'easy-code-height-lg')
})
await expect.poll(() => code.evaluate(element => element.scrollHeight - element.clientHeight)).toBeGreaterThan(0)
})
test('auto-height code keeps its natural height and reserves room for following content', async ({ page }) => {
await page.goto('/getting-started/#/8')
const layout = page.locator('.slidev-page-8 .slidev-layout')
const code = layout.locator('pre').first()
const following = layout.getByRole('heading', { name: '代码之后的正文仍保留在内容区内' })
await expect(following).toBeVisible()
await expect.poll(() => code.evaluate((element) => {
const region = element.closest('.easy-two-cols-grid > div')!
const layout = element.closest('.slidev-layout') as HTMLElement
const scale = layout.getBoundingClientRect().height / layout.clientHeight
const contentBottom = Math.min(
region.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(region).paddingBottom) * scale,
layout.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(layout).paddingBottom) * scale,
)
return Math.abs(contentBottom - element.getBoundingClientRect().bottom) / scale
})).toBeLessThanOrEqual(3)
const layoutElement = element.closest('.slidev-layout') as HTMLElement
const scale = layoutElement.getBoundingClientRect().height / layoutElement.clientHeight
return Math.abs(element.getBoundingClientRect().height / scale - element.scrollHeight)
})).toBeLessThanOrEqual(1)
const bounds = await layout.evaluate((element) => {
const codeElement = element.querySelector('pre')!
const followingElement = Array.from(element.querySelectorAll('h3')).find(item => item.textContent?.includes('代码之后的正文'))!
return {
codeBottom: codeElement.getBoundingClientRect().bottom,
followingBottom: followingElement.getBoundingClientRect().bottom,
followingTop: followingElement.getBoundingClientRect().top,
layoutBottom: element.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(element).paddingBottom),
}
})
expect(bounds.codeBottom).toBeLessThan(bounds.followingTop)
expect(bounds.followingBottom).toBeLessThanOrEqual(bounds.layoutBottom + 1)
await code.evaluate((element) => {
element.textContent = Array.from({ length: 40 }, (_, index) => `line ${index + 1}: a deliberately long code sample`).join('\n')
})
await expect.poll(() => code.evaluate(element => element.scrollHeight - element.clientHeight)).toBeGreaterThan(100)
const longContentBounds = await layout.evaluate((element) => {
const followingElement = Array.from(element.querySelectorAll('h3')).find(item => item.textContent?.includes('代码之后的正文'))!
return {
followingBottom: followingElement.getBoundingClientRect().bottom,
layoutBottom: element.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(element).paddingBottom),
}
})
expect(longContentBounds.followingBottom).toBeLessThanOrEqual(longContentBounds.layoutBottom + 1)
})
test('image fullscreen preserves layout and table scaling stays out of non-interactive routes', async ({ page }) => {
@@ -601,7 +624,7 @@ test('stacked image layouts constrain wide images by available height', async ({
test('sample slides stay inside the 4:3 canvas', async ({ page }) => {
await page.goto('/getting-started/#/1')
for (let slide = 1; slide <= 8; slide += 1) {
for (let slide = 1; slide <= 9; slide += 1) {
const layout = page.locator('.slidev-layout').first()
await expect(layout).toBeVisible()
const box = await layout.boundingBox()