From 55ae385baab05e0912af30db26e7c82c27db23fc Mon Sep 17 00:00:00 2001 From: Simon Boudrias Date: Mon, 8 Jul 2024 18:04:17 -0400 Subject: [PATCH] Chore(testing): Typecheck test files --- packages/checkbox/checkbox.test.mts | 10 +++++----- packages/confirm/confirm.test.mts | 2 +- packages/core/core.test.mts | 6 +++--- packages/core/src/lib/pagination/lines.test.mts | 2 +- packages/editor/editor.test.mts | 2 +- packages/input/input.test.mts | 17 +++++++++-------- packages/number/number.test.mts | 14 +++++++------- packages/password/password.test.mts | 2 +- packages/prompts/prompts.test.mts | 14 ++++++++------ packages/select/select.test.mts | 2 +- packages/testing/src/index.mts | 12 ++++++------ tsconfig.test.json | 13 +++++++++++++ 12 files changed, 56 insertions(+), 40 deletions(-) create mode 100644 tsconfig.test.json diff --git a/packages/checkbox/checkbox.test.mts b/packages/checkbox/checkbox.test.mts index 17b169ec9..cf5b67279 100644 --- a/packages/checkbox/checkbox.test.mts +++ b/packages/checkbox/checkbox.test.mts @@ -644,7 +644,7 @@ describe('checkbox prompt', () => { const { answer, events, getScreen } = await render(checkbox, { message: 'Select a number', choices: numberedChoices, - validate(items: ReadonlyArray) { + validate: (items: ReadonlyArray) => { if (items.length !== 1) { return 'Please select only one choice'; } @@ -732,9 +732,9 @@ describe('checkbox prompt', () => { choices: numberedChoices, theme: { style: { - renderSelectedChoices(selected: { value: number }[]) { + renderSelectedChoices: (selected: { value: number }[]) => { if (selected.length > 1) { - return `You have selected ${selected[0].value} and ${selected.length - 1} more.`; + return `You have selected ${(selected[0] as { value: number }).value} and ${selected.length - 1} more.`; } return `You have selected ${selected .slice(0, 1) @@ -764,10 +764,10 @@ describe('checkbox prompt', () => { choices: numberedChoices, theme: { style: { - renderSelectedChoices( + renderSelectedChoices: ( selected: { value: number }[], all: ({ value: number } | Separator)[], - ) { + ) => { return `You have selected ${selected.length} out of ${all.length} options.`; }, }, diff --git a/packages/confirm/confirm.test.mts b/packages/confirm/confirm.test.mts index e364888a4..ff36c1d48 100644 --- a/packages/confirm/confirm.test.mts +++ b/packages/confirm/confirm.test.mts @@ -113,7 +113,7 @@ describe('confirm prompt', () => { it('supports transformer option', async () => { const { answer, events, getScreen } = await render(confirm, { message: 'Do you want to proceed?', - transformer: (value) => (value ? 'Oui!' : 'Oh non!'), + transformer: (value: boolean) => (value ? 'Oui!' : 'Oh non!'), }); expect(getScreen()).toMatchInlineSnapshot('"? Do you want to proceed? (Y/n)"'); diff --git a/packages/core/core.test.mts b/packages/core/core.test.mts index ebc4c832c..12c97d474 100644 --- a/packages/core/core.test.mts +++ b/packages/core/core.test.mts @@ -54,7 +54,7 @@ describe('createPrompt()', () => { }); it('useEffect: works with setting state at once with objects', async () => { - const Prompt = (config: { message: string }, done: (value: string) => void) => { + const Prompt = (_config: { message: string }, done: (value: string) => void) => { const [value, setValue] = useState([1, 2]); useEffect(() => { @@ -518,7 +518,7 @@ describe('Error handling', () => { }); it('surface errors in useEffect cleanup functions', async () => { - const Prompt = (config: object, done: (value: string) => void) => { + const Prompt = (_config: object, done: (value: string) => void) => { useEffect(() => { done('done'); @@ -537,7 +537,7 @@ describe('Error handling', () => { }); it('prevent returning promises from useEffect hook', async () => { - const Prompt = (config: object, done: (value: string) => void) => { + const Prompt = (_config: object, done: (value: string) => void) => { // @ts-expect-error: Testing an invalid behavior. useEffect(async () => { done('done'); diff --git a/packages/core/src/lib/pagination/lines.test.mts b/packages/core/src/lib/pagination/lines.test.mts index 23843f3ac..1c811f10f 100644 --- a/packages/core/src/lib/pagination/lines.test.mts +++ b/packages/core/src/lib/pagination/lines.test.mts @@ -1,7 +1,7 @@ import { describe, it, expect } from 'vitest'; import { lines } from './lines.mjs'; -function renderResult(result) { +function renderResult(result: string[]) { return `\n${result.join('\n')}\n`; } diff --git a/packages/editor/editor.test.mts b/packages/editor/editor.test.mts index c39c0ebb5..defb74327 100644 --- a/packages/editor/editor.test.mts +++ b/packages/editor/editor.test.mts @@ -73,7 +73,7 @@ describe('editor prompt', () => { it('handles validation', async () => { const { answer, events, getScreen } = await render(editor, { message: 'Add a description', - validate(value) { + validate: (value: string) => { switch (value) { case '1': { return true; diff --git a/packages/input/input.test.mts b/packages/input/input.test.mts index 2fd8ceed1..236d5ddec 100644 --- a/packages/input/input.test.mts +++ b/packages/input/input.test.mts @@ -23,7 +23,8 @@ describe('input prompt', () => { it('handle transformer', async () => { const { answer, events, getScreen } = await render(input, { message: 'What is your name', - transformer: (value, { isFinal }) => (isFinal ? 'Transformed' : `t+${value}`), + transformer: (value: string, { isFinal }: { isFinal: boolean }) => + isFinal ? 'Transformed' : `t+${value}`, }); expect(getScreen()).toMatchInlineSnapshot(`"? What is your name t+"`); @@ -39,7 +40,7 @@ describe('input prompt', () => { it('handle synchronous validation', async () => { const { answer, events, getScreen } = await render(input, { message: 'Answer 2 ===', - validate: (value) => value === '2', + validate: (value: string) => value === '2', }); expect(getScreen()).toMatchInlineSnapshot(`"? Answer 2 ==="`); @@ -65,8 +66,8 @@ describe('input prompt', () => { it('handle asynchronous validation', async () => { const { answer, events, getScreen } = await render(input, { message: 'Answer 2 ===', - validate(value) { - return new Promise((resolve) => { + validate: (value: string) => { + return new Promise((resolve) => { if (value === '2') { resolve(true); } else { @@ -198,13 +199,13 @@ describe('input prompt', () => { it('is theme-able', async () => { const { answer, events, getScreen } = await render(input, { message: 'Answer must be: 2', - validate: (value) => value === '2', + validate: (value?: string) => value === '2', theme: { prefix: 'Q:', style: { - message: (text) => `${text} ===`, - error: (text) => `!! ${text} !!`, - answer: (text) => `_${text}_`, + message: (text: string) => `${text} ===`, + error: (text: string) => `!! ${text} !!`, + answer: (text: string) => `_${text}_`, }, }, }); diff --git a/packages/number/number.test.mts b/packages/number/number.test.mts index fa47aa2fe..d7fd4e1fa 100644 --- a/packages/number/number.test.mts +++ b/packages/number/number.test.mts @@ -156,7 +156,7 @@ describe('number prompt', () => { it('handle synchronous validation', async () => { const { answer, events, getScreen } = await render(number, { message: 'Answer 2 ===', - validate: (value) => value === 2, + validate: (value?: number) => value === 2, }); expect(getScreen()).toMatchInlineSnapshot(`"? Answer 2 ==="`); @@ -182,8 +182,8 @@ describe('number prompt', () => { it('handle asynchronous validation', async () => { const { answer, events, getScreen } = await render(number, { message: 'Answer 2 ===', - validate(value) { - return new Promise((resolve) => { + validate: (value?: number) => { + return new Promise((resolve) => { if (value === 2) { resolve(true); } else { @@ -320,13 +320,13 @@ describe('number prompt', () => { it('is theme-able', async () => { const { answer, events, getScreen } = await render(number, { message: 'Answer must be: 2', - validate: (value) => value === 2, + validate: (value?: number) => value === 2, theme: { prefix: 'Q:', style: { - message: (text) => `${text} ===`, - error: (text) => `!! ${text} !!`, - answer: (text) => `_${text}_`, + message: (text: string) => `${text} ===`, + error: (text: string) => `!! ${text} !!`, + answer: (text: string) => `_${text}_`, }, }, }); diff --git a/packages/password/password.test.mts b/packages/password/password.test.mts index 832844cb5..7a1093ec6 100644 --- a/packages/password/password.test.mts +++ b/packages/password/password.test.mts @@ -64,7 +64,7 @@ describe('password prompt', () => { const { answer, events, getScreen } = await render(password, { message: 'Enter your password', mask: true, - validate: (value) => value.length >= 8, + validate: (value: string) => value.length >= 8, }); expect(getScreen()).toMatchInlineSnapshot(`"? Enter your password"`); diff --git a/packages/prompts/prompts.test.mts b/packages/prompts/prompts.test.mts index 6367989be..3c0c723ff 100644 --- a/packages/prompts/prompts.test.mts +++ b/packages/prompts/prompts.test.mts @@ -29,9 +29,11 @@ describe('@inquirer/prompts', () => { /** * Type assertions to validate the interfaces. */ -Expect< - Equal< - Parameters[0]['theme']['helpMode'], - Parameters[0]['theme']['helpMode'] - > ->; +export interface Test { + 1: Expect< + Equal< + NonNullable[0]['theme']>['helpMode'], + NonNullable[0]['theme']>['helpMode'] + > + >; +} diff --git a/packages/select/select.test.mts b/packages/select/select.test.mts index b3f09b26e..87da489c5 100644 --- a/packages/select/select.test.mts +++ b/packages/select/select.test.mts @@ -16,7 +16,7 @@ const numberedChoices = [ { value: 10 }, { value: 11 }, { value: 12 }, -]; +] as const; afterEach(() => { vi.useRealTimers(); diff --git a/packages/testing/src/index.mts b/packages/testing/src/index.mts index 888d792ab..dd47202e9 100644 --- a/packages/testing/src/index.mts +++ b/packages/testing/src/index.mts @@ -2,7 +2,7 @@ import { Stream } from 'node:stream'; import MuteStream from 'mute-stream'; import stripAnsi from 'strip-ansi'; import ansiEscapes from 'ansi-escapes'; -import type { Prompt } from '@inquirer/type'; +import type { Prompt, Context } from '@inquirer/type'; const ignoredAnsi = new Set([ansiEscapes.cursorHide, ansiEscapes.cursorShow]); @@ -42,11 +42,11 @@ class BufferedStream extends Stream.Writable { } } -export async function render>( - prompt: TestedPrompt, - props: Parameters[0], - options?: Parameters[1], -) { +export async function render< + const Props, + const Value, + const TestedPrompt extends Prompt, +>(prompt: TestedPrompt, props: Props, options?: Context) { const input = new MuteStream(); input.unmute(); diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 000000000..a7f118e25 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*.test.mts"], + "exclude": ["packages/inquirer/test/**"], + "compilerOptions": { + "lib": ["es2023"], + "target": "es2022", + "module": "NodeNext", + "moduleResolution": "nodenext", + "skipLibCheck": true, + "noEmit": true + } +}