diff --git a/packages/core/src/prompts/prompt.ts b/packages/core/src/prompts/prompt.ts index 66a6348..7cfda84 100644 --- a/packages/core/src/prompts/prompt.ts +++ b/packages/core/src/prompts/prompt.ts @@ -210,6 +210,10 @@ export default class Prompt { } private async onKeypress(char: string | undefined, key: Key) { + if (this.state === 'validating') { + return; + } + if (this._track && key.name !== 'return') { if (key.name && this._isActionKey(char, key)) { this.rl?.write(null, { ctrl: true, name: 'h' }); diff --git a/packages/core/test/prompts/prompt.test.ts b/packages/core/test/prompts/prompt.test.ts index 5a29d93..12bd95f 100644 --- a/packages/core/test/prompts/prompt.test.ts +++ b/packages/core/test/prompts/prompt.test.ts @@ -391,4 +391,37 @@ describe('Prompt', () => { expect(instance.state).to.equal('submit'); expect(instance.error).to.equal(''); }); + + test('ignores keypresses while async validation is pending', async () => { + const eventSpy = vi.fn(); + let resolveValidation: (problem: string | undefined) => void; + const validation = new Promise((resolve) => { + resolveValidation = resolve; + }); + const instance = new Prompt({ + input, + output, + render: () => 'foo', + validate: () => validation, + }); + const resultPromise = instance.prompt(); + + instance.value = 'valid'; + input.emit('keypress', '', { name: 'return' }); + + expect(instance.state).to.equal('validating'); + + instance.on('key', eventSpy); + input.emit('keypress', 'z', { name: 'z' }); + input.emit('keypress', '\x03', { name: 'c' }); + + expect(eventSpy).not.toHaveBeenCalled(); + expect(instance.state).to.equal('validating'); + + resolveValidation(undefined); + await resultPromise; + + expect(instance.state).to.equal('submit'); + expect(instance.error).to.equal(''); + }); });