diff --git a/package.json b/package.json index 28c3c58..758cc31 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "devDependencies": { "@commitlint/config-conventional": "^19", "@oclif/prettier-config": "^0.2.1", + "@oclif/test": "^4.0.9", "@types/chai": "^4.3.16", "@types/mocha": "^10.0.8", "@types/node": "^18", diff --git a/src/table.tsx b/src/table.tsx index d408296..366ae4b 100644 --- a/src/table.tsx +++ b/src/table.tsx @@ -391,8 +391,9 @@ export function Skeleton(props: React.PropsWithChildren & {readonly height?: num * because it uses ansiEscapes.clearTerminal, which doesn't seem to have * the desired effect in powershell. */ -class Stdout extends WriteStream { +class Stream extends WriteStream { private frames: string[] = [] + public lastFrame(): string | undefined { return this.frames.filter((f) => stripAnsi(f) !== '').at(-1) } @@ -403,15 +404,31 @@ class Stdout extends WriteStream { } } +class Output { + public stream: Stream | WriteStream + + public constructor(fd = 1) { + this.stream = process.env.NODE_ENV === 'test' ? process.stdout : new WriteStream(fd) + } + + public maybePrintLastFrame() { + if (this.stream instanceof Stream) { + process.stdout.write(`${this.stream.lastFrame()}\n`) + } else { + process.stdout.write('\n') + } + } +} + /** * Renders a table with the given data. * @param options see {@link TableOptions} */ export function printTable>(options: TableOptions): void { - const stdout = new Stdout(1) - const instance = render(, {stdout}) + const output = new Output() + const instance = render(
, {stdout: output.stream}) instance.unmount() - process.stdout.write(`${stdout.lastFrame()}\n`) + output.maybePrintLastFrame() } function Container(props: ContainerProps) { @@ -426,7 +443,7 @@ export function printTables[]>( tables: {[P in keyof T]: TableOptions}, options?: Omit, ): void { - const stdout = new Stdout(1) + const output = new Output() const leftMargin = options?.marginLeft ?? options?.margin ?? 0 const rightMargin = options?.marginRight ?? options?.margin ?? 0 const columns = process.stdout.columns - (leftMargin + rightMargin) @@ -443,8 +460,8 @@ export function printTables[]>(
))} , - {stdout}, + {stdout: output.stream}, ) instance.unmount() - process.stdout.write(`${stdout.lastFrame()}\n`) + output.maybePrintLastFrame() } diff --git a/test/table.test.tsx b/test/table.test.tsx index ce9860e..d5aeec8 100644 --- a/test/table.test.tsx +++ b/test/table.test.tsx @@ -1,11 +1,12 @@ /* eslint-disable perfectionist/sort-objects */ +import {captureOutput} from '@oclif/test' import ansis from 'ansis' import {config, expect} from 'chai' import {Box} from 'ink' import {render} from 'ink-testing-library' import React from 'react' -import {Cell, Header, Skeleton, Table, formatTextWithMargins} from '../src/table.js' +import {Cell, Header, Skeleton, Table, formatTextWithMargins, printTable} from '../src/table.js' config.truncateThreshold = 0 @@ -689,3 +690,30 @@ scing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, }) }) }) + +describe('printTable compatibility with @oclif/test', () => { + it('should print a simple table', async () => { + const data = [ + {name: 'Foo', age: 12}, + {name: 'Bar', age: 15}, + ] + + const expected = `┌──────┬─────┐ +│ name │ age │ +├──────┼─────┤ +│ Foo │ 12 │ +├──────┼─────┤ +│ Bar │ 15 │ +└──────┴─────┘ + +` + + const {stdout} = await captureOutput(async () => + printTable({ + data, + columns: ['name', 'age'], + }), + ) + expect(stdout).to.equal(expected) + }) +}) diff --git a/yarn.lock b/yarn.lock index 2b50b31..2dc0058 100644 --- a/yarn.lock +++ b/yarn.lock @@ -318,6 +318,14 @@ resolved "https://registry.yarnpkg.com/@oclif/prettier-config/-/prettier-config-0.2.1.tgz#1def9f38134f9bfb229257f48a35f7d0d183dc78" integrity sha512-XB8kwQj8zynXjIIWRm+6gO/r8Qft2xKtwBMSmq1JRqtA6TpwpqECqiu8LosBCyg2JBXuUy2lU23/L98KIR7FrQ== +"@oclif/test@^4.0.9": + version "4.0.9" + resolved "https://registry.yarnpkg.com/@oclif/test/-/test-4.0.9.tgz#c4b4b4878911489a79f296a15448e76d860b39d2" + integrity sha512-xDGBFBNE6ckoBT9EhMi6ZvwAaEeJRGvRmn2qZWujJl9EJ56a72KHZsvTJVgl2p/AQ2vZ1UH06YZ440GOnjExzQ== + dependencies: + ansis "^3.3.2" + debug "^4.3.6" + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -1218,6 +1226,13 @@ debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@~4.3.6: dependencies: ms "2.1.2" +debug@^4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + decamelize@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"