From 8c4a3b2c9db4ccd1ffb1f61d98de9c3dc2196cc9 Mon Sep 17 00:00:00 2001 From: Yunfei He Date: Mon, 25 May 2026 21:48:50 +0800 Subject: [PATCH] test: port Ink background and border-background tests (29 tests) Covers inheritance, override, hex/rgb/ansi256 colors, wide chars, emojis, fill area, fill with border/padding, border backgrounds. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/background-color.test.tsx | 518 +++++++++++++++++- 1 file changed, 514 insertions(+), 4 deletions(-) diff --git a/packages/runtime-tests/integration/components/background-color.test.tsx b/packages/runtime-tests/integration/components/background-color.test.tsx index 989f19e..413cff0 100644 --- a/packages/runtime-tests/integration/components/background-color.test.tsx +++ b/packages/runtime-tests/integration/components/background-color.test.tsx @@ -1,3 +1,4 @@ +import { defineComponent, shallowRef, nextTick } from "vue"; import { expect, test } from "vite-plus/test"; import { render } from "@vue-tui/testing"; import { Box, Text } from "@vue-tui/runtime"; @@ -5,10 +6,9 @@ import { Box, Text } from "@vue-tui/runtime"; const BG_BLUE = "\x1b[44m"; test("Box backgroundColor produces ANSI background codes", async () => { - const { frames } = await render( - () => , - { columns: 10 }, - ); + const { frames } = await render(() => , { + columns: 10, + }); expect(frames.at(-1)).toContain(BG_BLUE); }); @@ -51,3 +51,513 @@ test("wrapped text preserves backgroundColor on every line", async () => { expect(line).toContain(BG_BLUE); } }); + +// --- Ink background tests --- + +test("Text inherits parent Box background color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello World + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(`"Hello World"`); +}); + +test("Text explicit background color overrides inherited", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello World + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(`"Hello World"`); +}); + +test("Nested Box background inheritance", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + + Hello World + + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(`"Hello World"`); +}); + +test("Text without parent Box background has no inheritance", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello World + + )), + { columns: 100 }, + ); + expect(lastFrame()).toBe("Hello World"); +}); + +test("Multiple Text elements inherit same background", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + World + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "Hello + World" + `); +}); + +test("Mixed text with and without background inheritance", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Inherited + No BG + Red BG + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "Inherited + No BG  + Red BG " + `); +}); + +test("Complex nested structure with background inheritance", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + + Outer: + + Inner: + Explicit + + + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "Outer:  + Inner:  + Explicit" + `); +}); + +test("Box background with standard color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(`"Hello"`); +}); + +test("Box background with hex color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot( + `"Hello"`, + ); +}); + +test("Box background with rgb color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot( + `"Hello"`, + ); +}); + +test("Box background with ansi256 color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(`"Hello"`); +}); + +test("Box background with wide characters", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + こんにちは + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(`"こんにちは"`); +}); + +test("Box background with emojis", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + 🎉🎊 + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(`"🎉🎊"`); +}); + +test("Box background fills entire area with standard color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "Hello  +   +  " + `); +}); + +test("Box background fills with hex color", async () => { + const bgHexRed = "[48;2;255;0;0m"; + const bgReset = "[49m"; + + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + expect(output).toContain("Hello"); + expect(output).toContain(bgHexRed); + expect(output).toContain(bgReset); +}); + +test("Box background fills with rgb color", async () => { + const bgHexRed = "[48;2;255;0;0m"; + const bgReset = "[49m"; + + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + expect(output).toContain("Hello"); + expect(output).toContain(bgHexRed); + expect(output).toContain(bgReset); +}); + +test("Box background fills with ansi256 color", async () => { + const bgAnsi256Nine = "[48;5;9m"; + const bgReset = "[49m"; + + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + expect(output).toContain("Hello"); + expect(output).toContain(bgAnsi256Nine); + expect(output).toContain(bgReset); +}); + +test("Box background with border fills content area", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hi + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "╭────────╮ + │Hi │ + │ │ + │ │ + ╰────────╯" + `); +}); + +test("Box background with padding fills entire padded area", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hi + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "  +  Hi   +   +   +  " + `); +}); + +test("Box background with center alignment fills entire area", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hi + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "  + Hi  +  " + `); +}); + +test("Box background with column layout fills entire area", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Line 1 + Line 2 + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "Line 1  + Line 2  +   +   +  " + `); +}); + +test("Box background updates on rerender", async () => { + const bgColor = shallowRef(undefined); + + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello + + )), + { columns: 100 }, + ); + + expect(lastFrame()).toBe("Hello"); + + bgColor.value = "green"; + await nextTick(); + expect(lastFrame()).toMatchInlineSnapshot(`"Hello"`); + + bgColor.value = undefined; + await nextTick(); + expect(lastFrame()).toBe("Hello"); +}); + +test("Box backgroundColor fills full width on every line when text wraps", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello World!! + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "Hello  + World!! " + `); +}); + +test("Text-only backgroundColor colors text content but does not fill Box width", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hello World!! + + )), + { columns: 100 }, + ); + expect(lastFrame()).toMatchInlineSnapshot(` + "Hello + World!!" + `); +}); + +// --- Ink border-backgrounds tests --- + +test("border with background color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + + Test + + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + expect(output).toContain("┌"); + expect(output).toContain("┐"); + expect(output).toContain("└"); + expect(output).toContain("┘"); + expect(output).toContain("Test"); + // Named blue background => ESC[44m + expect(output).toContain("[44m"); +}); + +test("border with different background colors per side", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + + Test + + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + expect(output).toContain("┌"); + expect(output).toContain("┐"); + expect(output).toContain("└"); + expect(output).toContain("┘"); + expect(output).toContain("Test"); + // red => 41, green => 42, yellow => 43, blue => 44 + expect(output).toContain("[41m"); + expect(output).toContain("[42m"); + expect(output).toContain("[43m"); + expect(output).toContain("[44m"); +}); + +test("border background color fallback to general borderBackgroundColor", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + + Test + + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + expect(output).toContain("┌"); + expect(output).toContain("┐"); + expect(output).toContain("└"); + expect(output).toContain("┘"); + expect(output).toContain("Test"); + // cyan => 46, magenta => 45 + expect(output).toContain("[46m"); + expect(output).toContain("[45m"); +}); + +test("vertical border background does not bleed into content rows", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Text longer than the Box width, so will definitely wrap. + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + const bgCyanPattern = "\\[46m"; + const bgResetPattern = "\\[49m"; + const tableBorderChar = "|"; + const tableBorderPattern = bgCyanPattern + tableBorderChar + bgResetPattern; + const contentRowPattern = new RegExp(`^${tableBorderPattern}.*${tableBorderPattern}$`); + + const tableRows = output.split("\n"); + const contentRows = tableRows.slice(1, -1); + for (const contentRow of contentRows) { + expect(contentRow).toMatch(contentRowPattern); + } +}); + +test("foreground, background and dim combine correctly", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Hi + + )), + { columns: 100 }, + ); + const output = lastFrame()!; + // red FG (31), cyan BG (46), dim (2) + expect(output).toContain("[31m"); + expect(output).toContain("[46m"); + expect(output).toContain("[2m"); +});