CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-prompts

Lightweight, beautiful and user-friendly interactive CLI prompts library with promise-based API

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

testing.mddocs/

Testing Utilities

Functions for programmatic testing, response injection, and pre-answering questions during automated testing scenarios. These utilities enable deterministic testing of prompt-based applications without user interaction.

const prompts = require('prompts');
// Or for specific imports:
const { inject, override } = require('prompts');

Capabilities

Inject Function

Programmatically inject responses to simulate user input during testing. Injected values are consumed in order and removed from the internal queue as they are used.

/**
 * Programmatically inject responses for testing
 * @param answers - Array of values to inject as responses
 */
function inject(answers: any[]): void;

The inject function accepts an array of values that will be used as responses to prompts in the order they are provided. Each value can be:

  • Simple value: Used as a direct response to the next prompt
  • Array of values: Used for prompts that might be asked multiple times
  • Error instance: Simulates user cancellation/abort

Usage Examples:

const prompts = require('prompts');

// Basic injection for testing
prompts.inject(['alice', 25, true]);

const response = await prompts([
  { type: 'text', name: 'name', message: 'Your name?' },
  { type: 'number', name: 'age', message: 'Your age?' },
  { type: 'confirm', name: 'subscribe', message: 'Subscribe?' }
]);

// Result: { name: 'alice', age: 25, subscribe: true }

// Inject array values for repeated prompts
prompts.inject([
  'user1',
  ['red', 'blue'], // For multiselect prompt
  'completed'
]);

// Inject error to simulate cancellation
prompts.inject([
  'alice',
  new Error('User cancelled'),
  'fallback'
]);

// Test complex scenarios
prompts.inject([
  'setup-wizard',
  true,  // confirm to continue
  ['database', 'auth'], // multiselect features
  'production' // environment
]);

const config = await prompts([
  { type: 'text', name: 'projectName', message: 'Project name?' },
  { type: 'confirm', name: 'useDefaults', message: 'Use defaults?' },
  { type: 'multiselect', name: 'features', message: 'Select features:', choices: [...] },
  { type: 'select', name: 'env', message: 'Environment:', choices: [...] }
]);

Override Function

Pre-answer questions by providing an object with answers mapped to question names. This allows selective answering of specific prompts while letting others proceed normally.

/**
 * Pre-answer questions by question name
 * @param answers - Object mapping question names to their answers
 */
function override(answers: Record<string, any>): void;

The override function takes an object where keys are question names and values are the answers to provide for those questions. Questions with overridden answers will be skipped during prompting.

Usage Examples:

const prompts = require('prompts');

// Override specific questions
prompts.override({
  username: 'alice',
  environment: 'production'
});

const response = await prompts([
  { type: 'text', name: 'username', message: 'Username?' }, // Skipped, uses 'alice'
  { type: 'number', name: 'port', message: 'Port?' },       // User prompted
  { type: 'select', name: 'environment', message: 'Env?', choices: [...] } // Skipped, uses 'production'
]);

// Combine with command-line arguments
const prompts = require('prompts');
const yargs = require('yargs');

// Use command-line args as overrides
prompts.override(yargs.argv);

// Now CLI args like --username=alice --port=3000 will pre-answer those questions

// Override from environment variables
prompts.override({
  apiKey: process.env.API_KEY,
  database: process.env.DATABASE_URL,
  environment: process.env.NODE_ENV
});

// Override for testing specific scenarios
prompts.override({
  confirmDeletion: true,
  backupFirst: false,
  targetEnvironment: 'staging'
});

Testing Patterns

Unit Testing with Injection

const prompts = require('prompts');

describe('User Setup', () => {
  it('should create user with valid inputs', async () => {
    // Arrange
    prompts.inject(['John Doe', 'john@example.com', 30, true]);
    
    // Act
    const user = await createUserInteractively();
    
    // Assert
    expect(user.name).toBe('John Doe');
    expect(user.email).toBe('john@example.com');
    expect(user.age).toBe(30);
    expect(user.newsletter).toBe(true);
  });

  it('should handle user cancellation', async () => {
    // Arrange
    prompts.inject(['John', new Error('Cancelled by user')]);
    
    // Act & Assert
    await expect(createUserInteractively()).rejects.toThrow('User cancelled setup');
  });
});

Integration Testing with Override

const prompts = require('prompts');

describe('CLI Application', () => {
  beforeEach(() => {
    // Reset any previous overrides
    prompts.override({});
  });

  it('should use production config when specified', async () => {
    // Arrange
    prompts.override({
      environment: 'production',
      confirm: true
    });
    
    // Act
    const config = await loadConfiguration();
    
    // Assert
    expect(config.environment).toBe('production');
    expect(config.debug).toBe(false);
  });
});

Testing Multiselect and Complex Inputs

// Test multiselect inputs
prompts.inject([
  ['option1', 'option3'], // Array for multiselect
  true,                   // Confirmation
  'custom-value'          // Text input
]);

// Test autocomplete inputs
prompts.inject([
  'java', // Will match 'JavaScript' in autocomplete
  2       // Select index 2 from filtered results
]);

// Test conditional prompts
prompts.inject([
  'pizza',        // Triggers additional topping question
  'pepperoni',    // Topping selection
  true            // Final confirmation
]);

Testing Best Practices

Clean State Management

beforeEach(() => {
  // Clear any previous injections and overrides
  prompts.inject([]);
  prompts.override({});
});

Error Simulation

// Simulate different types of cancellation
prompts.inject([
  'valid-input',
  new Error('User pressed Ctrl+C'),
  'recovery-value'
]);

// Test partial completion scenarios
prompts.inject([
  'first-answer',
  'second-answer',
  new Error('Connection lost') // Simulate interruption
]);

Environment-Specific Testing

// Test different environments
const testCases = [
  { env: 'development', debug: true },
  { env: 'staging', debug: false },
  { env: 'production', debug: false }
];

testCases.forEach(({ env, debug }) => {
  it(`should configure correctly for ${env}`, async () => {
    prompts.override({ environment: env });
    const config = await setupEnvironment();
    expect(config.debug).toBe(debug);
  });
});

Injection Behavior

Value Consumption

  • Injected values are consumed in FIFO (first-in, first-out) order
  • Each prompt consumes exactly one injected value
  • If no injected value is available, the prompt displays normally to the user
  • Used values are removed from the injection queue

Array Values

  • Array values are used for prompts that return arrays (multiselect, list)
  • For single-value prompts, the entire array is used as the value
  • For multiselect prompts, array items are treated as selected values

Error Handling

  • Error instances in the injection queue simulate user cancellation
  • The error is thrown when that position in the queue is reached
  • Subsequent prompts will use remaining injected values after error handling

Override Behavior

Name Matching

  • Override keys must exactly match the name property of questions
  • Case-sensitive matching
  • Questions without matching override names prompt normally

Value Types

  • Override values can be any type appropriate for the question
  • No type checking is performed; ensure values match expected types
  • Invalid values may cause prompt errors

Persistence

  • Override values persist until explicitly cleared with prompts.override({})
  • New override calls merge with existing overrides
  • Set a key to undefined to remove a specific override

Install with Tessl CLI

npx tessl i tessl/npm-prompts

docs

choice-prompts.md

confirmation-prompts.md

core-prompting.md

index.md

number-date-prompts.md

testing.md

text-prompts.md

tile.json