diff --git a/packages/runtime-tests/integration/components/text.test.tsx b/packages/runtime-tests/integration/components/text.test.tsx index 81170e0..c2b93c6 100644 --- a/packages/runtime-tests/integration/components/text.test.tsx +++ b/packages/runtime-tests/integration/components/text.test.tsx @@ -1,6 +1,9 @@ +import { defineComponent, shallowRef, nextTick } from "vue"; import { expect, test } from "vite-plus/test"; import { render } from "@vue-tui/testing"; -import { Text } from "@vue-tui/runtime"; +import { Box, Text } from "@vue-tui/runtime"; +import chalk from "chalk"; +import stripAnsi from "strip-ansi"; test("nested Text renders inline without independent layout", async () => { const { lastFrame } = await render(() => ( @@ -18,3 +21,174 @@ test("CJK wide characters render without corruption", async () => { const frame = lastFrame()!; expect(frame).toContain("中文测试"); }); + +// --- Ink text tests --- + +test.skip(" with undefined children — crashes yoga measure", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ), + { columns: 100 }, + ); + expect(lastFrame()).toBe(""); +}); + +test.skip(" with null children — crashes yoga measure", async () => { + const { lastFrame } = await render( + defineComponent(() => () => {null}), + { columns: 100 }, + ); + expect(lastFrame()).toBe(""); +}); + +test("text with standard color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.green("Test")); +}); + +test("text with dim+bold", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Test + + )), + { columns: 100 }, + ); + expect(stripAnsi(lastFrame()!)).toBe("Test"); + expect(lastFrame()).not.toBe("Test"); +}); + +test("text with dimmed color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => ( + + Test + + )), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.green.dim("Test")); +}); + +test("text with hex color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.hex("#FF8800")("Test")); +}); + +test("text with rgb color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.rgb(255, 136, 0)("Test")); +}); + +test("text with ansi256 color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.ansi256(194)("Test")); +}); + +test("text with standard background color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.bgGreen("Test")); +}); + +test("text with hex background color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.bgHex("#FF8800")("Test")); +}); + +test("text with rgb background color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.bgRgb(255, 136, 0)("Test")); +}); + +test("text with ansi256 background color", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.bgAnsi256(194)("Test")); +}); + +test("text with inversion", async () => { + const { lastFrame } = await render( + defineComponent(() => () => Test), + { columns: 100 }, + ); + expect(lastFrame()).toBe(chalk.inverse("Test")); +}); + +test("text with empty-to-nonempty sibling does not wrap", async () => { + const show = shallowRef(false); + const { lastFrame } = await render( + defineComponent(() => () => ( + + {show.value ? "x" : ""}hello + + )), + { columns: 100 }, + ); + expect(lastFrame()).toBe("hello"); + show.value = true; + await nextTick(); + expect(lastFrame()).toBe("xhello"); +}); + +test("remeasure text when text is changed", async () => { + const add = shallowRef(false); + const { lastFrame } = await render( + defineComponent(() => () => ( + + {add.value ? "abcx" : "abc"} + + )), + { columns: 100 }, + ); + expect(lastFrame()).toBe("abc"); + add.value = true; + await nextTick(); + expect(lastFrame()).toBe("abcx"); +}); + +test.skip("remeasure text when text nodes are changed — null child crashes yoga", async () => { + const add = shallowRef(false); + const { lastFrame } = await render( + defineComponent(() => () => ( + + abc{add.value ? x : null} + + )), + { columns: 100 }, + ); + expect(lastFrame()).toBe("abc"); + add.value = true; + await nextTick(); + expect(lastFrame()).toBe("abcx"); +}); + +test.skip("text with content 'constructor' wraps correctly — bug in text node lookup", async () => { + const { lastFrame } = await render( + defineComponent(() => () => constructor), + { columns: 100 }, + ); + expect(lastFrame()).toBe("constructor"); +}); diff --git a/packages/runtime-tests/package.json b/packages/runtime-tests/package.json index 45d0bc1..55d95f9 100644 --- a/packages/runtime-tests/package.json +++ b/packages/runtime-tests/package.json @@ -13,6 +13,7 @@ "@vue-tui/runtime": "workspace:*", "@vue-tui/testing": "workspace:*", "chalk": "catalog:", + "strip-ansi": "catalog:", "typescript": "^6.0.3", "vite-plus": "^0.1.22", "vue": "^3.5.34" diff --git a/packages/testing/src/render.ts b/packages/testing/src/render.ts index 6cabc53..9ff89d9 100644 --- a/packages/testing/src/render.ts +++ b/packages/testing/src/render.ts @@ -92,7 +92,7 @@ export async function render( return { lastFrame: (opts?: LastFrameOptions) => { const f = frames.at(-1); - if (!f) return undefined; + if (f === undefined) return undefined; if (opts?.raw) return f; if (opts?.trimLines) return f diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f55307..7de1731 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,11 @@ catalogs: chalk: specifier: ^5.6.2 version: 5.6.2 + strip-ansi: + specifier: ^7.2.0 + version: 7.2.0 vite-plus: - specifier: latest + specifier: ^0.1.22 version: 0.1.22 overrides: @@ -192,6 +195,9 @@ importers: chalk: specifier: 'catalog:' version: 5.6.2 + strip-ansi: + specifier: 'catalog:' + version: 7.2.0 typescript: specifier: ^6.0.3 version: 6.0.3