import { Code } from '@luke-ui/react/code'; import { Text } from '@luke-ui/react/text'; import { test, expect } from 'vite-plus/test'; import { render, visualAppearances } from '../test-utils/render.js'; import { captureVisual, captureVisualAppearance, Stack } from '../test-utils/visual.js'; const LONG_CONTENT = 'one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen'; function getCodeElement(container: HTMLElement): HTMLElement { const target = container.querySelector('code'); if (!(target instanceof HTMLElement)) throw new Error('Expected a Code element.'); return target; } // Line clamp needs the text to wrap to produce more than one line, so the rendered box height is // the contract here: there is no DOM/ARIA assertion that can distinguish a wrapped, clamped block // from a single-line one. test('lineClamp of 2 wraps the content and clamps it to two lines', async () => { const { container } = render(
{LONG_CONTENT}
, ); const element = getCodeElement(container); const singleLineHeight = Number.parseFloat(getComputedStyle(element).lineHeight); const { height } = element.getBoundingClientRect(); expect(height).toBeGreaterThan(singleLineHeight * 1.5); // At this width the content wants about seven lines, so an unclamped box would be far taller. // The bound sits above two padded lines and below three, and `scrollHeight` confirms there is // still overflowing content for the clamp to cut. expect(height).toBeLessThan(singleLineHeight * 3); expect(element.scrollHeight).toBeGreaterThan(height); }); // `Text` emits `textWrap` after `lineClamp`, so `balance`/`pretty` would otherwise let a // single-line clamp wrap. Every single-line clamp value is paired with every wrapping value. for (const lineClamp of [true, 1] as const) { for (const textWrap of ['balance', 'pretty'] as const) { test(`lineClamp of ${String(lineClamp)} stays on one line with textWrap ${textWrap}`, async () => { const { container } = render(
{LONG_CONTENT}
, ); const element = getCodeElement(container); const singleLineHeight = Number.parseFloat(getComputedStyle(element).lineHeight); expect(element.getBoundingClientRect().height).toBeLessThanOrEqual(singleLineHeight * 1.5); }); } } test('textWrap still wraps when no single-line clamp is set', async () => { const { container } = render(
{LONG_CONTENT}
, ); const element = getCodeElement(container); const singleLineHeight = Number.parseFloat(getComputedStyle(element).lineHeight); expect(element.getBoundingClientRect().height).toBeGreaterThan(singleLineHeight * 1.5); }); test('default Code stays on one line with the same long content', async () => { const { container } = render(
{LONG_CONTENT}
, ); const element = getCodeElement(container); const singleLineHeight = Number.parseFloat(getComputedStyle(element).lineHeight); expect(element.getBoundingClientRect().height).toBeLessThanOrEqual(singleLineHeight * 1.5); }); test('kitchen sink', { tags: ['visual'] }, async () => { for (const appearance of visualAppearances) { const { locator } = render( Run npm install to install dependencies. The useTheme hook tracks the active theme. Set data-color-mode on the root element. , { appearance }, ); await captureVisualAppearance(locator, 'code/kitchen-sink', appearance); } }); test('long content states', { tags: ['visual'] }, async () => { const { locator } = render( {LONG_CONTENT} {LONG_CONTENT} , ); await captureVisual(locator, 'code/long-content'); });