CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-yeoman-test

Test utilities for Yeoman generators providing a fluent API for setting up test environments and asserting generated content

Overview
Eval results
Files

test-environment.mddocs/

Test Environment Setup

The test environment functionality provides utilities for creating and configuring Yeoman environments specifically optimized for testing. This includes custom test adapters, shared file systems, and environment-specific configuration options that ensure isolated and predictable test execution.

Capabilities

Environment Creation

Create Yeoman environments configured for testing scenarios.

/**
 * Create a standard Yeoman environment
 * @param options - Base environment options
 * @returns Promise resolving to environment instance
 */
async createEnv(options: BaseEnvironmentOptions): Promise<DefaultEnvironmentApi>;

/**
 * Creates a test environment with TestAdapter and testing-specific configuration
 * @param environmentConstructor - Optional custom environment constructor
 * @param options - Environment options (defaults include localConfigOnly: true)
 * @returns Promise resolving to configured test environment
 */
async createTestEnv(
  environmentConstructor?: CreateEnv,
  options?: BaseEnvironmentOptions
): Promise<DefaultEnvironmentApi>;

type CreateEnv = (options: BaseEnvironmentOptions) => Promise<BaseEnvironment>;

Usage Examples:

import helpers from "yeoman-test";

// Basic environment
const env = await helpers.createEnv({
  cwd: process.cwd(),
  force: true
});

// Test environment with defaults
const testEnv = await helpers.createTestEnv();

// Custom test environment
const customTestEnv = await helpers.createTestEnv(
  // Custom environment constructor
  (options) => new CustomEnvironment(options),
  // Custom options
  {
    localConfigOnly: false,
    skipCache: false,
    cwd: "/custom/path"
  }
);

Test Adapter Creation

Create and configure TestAdapter instances for prompt mocking and interaction simulation.

/**
 * Creates a TestAdapter using default options
 * @param options - Optional adapter configuration
 * @returns TestAdapter instance configured for testing
 */
createTestAdapter(options?: TestAdapterOptions): TestAdapter;

class TestAdapter extends BaseTestAdapter {
  constructor(options?: TestAdapterOptions);
}

Usage Examples:

import helpers from "yeoman-test";

// Basic test adapter
const adapter = helpers.createTestAdapter();

// Configured test adapter
const adapter = helpers.createTestAdapter({
  mockedAnswers: {
    projectName: "test-app",
    features: ["typescript", "testing"]
  },
  throwOnMissingAnswer: true,
  callback: (answer, options) => {
    console.log(`Answered ${options.question.name}: ${answer}`);
    return answer;
  }
});

// Use with custom environment
const env = await helpers.createEnv({
  adapter,
  force: true
});

Environment Configuration Options

BaseEnvironmentOptions

Standard Yeoman environment options that can be used with test environments.

interface BaseEnvironmentOptions {
  /** Current working directory for the environment */
  cwd?: string;
  
  /** Force overwrite existing files */
  force?: boolean;
  
  /** Skip generator lookup caching */
  skipCache?: boolean;
  
  /** Skip automatic npm/yarn install */
  skipInstall?: boolean;
  
  /** Use local configuration only */
  localConfigOnly?: boolean;
  
  /** Custom adapter instance */
  adapter?: any;
  
  /** Shared file system instance */
  sharedFs?: any;
  
  /** Additional shared options for generators */
  sharedOptions?: Record<string, any>;
  
  /** Enable new error handler */
  newErrorHandler?: boolean;
}

TestAdapterOptions

Configuration options specific to the TestAdapter for prompt mocking.

interface TestAdapterOptions {
  /** Pre-configured answers for prompts */
  mockedAnswers?: PromptAnswers;
  
  /** Throw error if no answer provided for a prompt */
  throwOnMissingAnswer?: boolean;
  
  /** Callback function called for each prompt answer */
  callback?: DummyPromptCallback;
  
  /** Custom spy factory for creating mocks */
  spyFactory?: (options: { returns?: any }) => any;
}

type DummyPromptCallback = (
  this: any,
  answer: any,
  options: { question: any }
) => any;

type PromptAnswers = Record<string, any>;

Advanced Environment Patterns

Custom Environment Integration

import helpers from "yeoman-test";
import CustomEnvironment from "./custom-environment";

// Use custom environment class
const env = await helpers.createTestEnv(
  (options) => new CustomEnvironment(options),
  {
    cwd: process.cwd(),
    customFeature: true
  }
);

// Register generators
env.register("./path/to/generator", { namespace: "my:gen" });

// Create generator instance
const generator = await env.create("my:gen", {
  generatorArgs: ["init"],
  generatorOptions: { force: true }
});

Shared File System Configuration

import { create as createMemFs } from "mem-fs";
import helpers from "yeoman-test";

// Create shared file system
const sharedFs = createMemFs();

// Use with multiple environments
const env1 = await helpers.createTestEnv(undefined, { 
  sharedFs,
  cwd: "/test/dir1" 
});

const env2 = await helpers.createTestEnv(undefined, { 
  sharedFs,
  cwd: "/test/dir2"
});

// Both environments share the same file system

Environment Event Handling

const env = await helpers.createTestEnv();

// Listen for environment events
env.on("compose", (namespace, generator) => {
  console.log(`Composing with ${namespace}`);
});

env.on("error", (error) => {
  console.error("Environment error:", error);
});

// Register and run generator
env.register("./my-generator", { namespace: "my:app" });
const generator = await env.create("my:app");
await env.runGenerator(generator);

Prompt Mock Configuration

import helpers from "yeoman-test";

// Advanced prompt mocking
const adapter = helpers.createTestAdapter({
  mockedAnswers: {
    projectName: "my-project",
    features: ["typescript", "testing"],
    author: "Test Author"
  },
  
  throwOnMissingAnswer: true,
  
  callback: (answer, { question }) => {
    // Log all prompt interactions
    console.log(`Question: ${question.message}`);
    console.log(`Answer: ${answer}`);
    
    // Modify answers based on question
    if (question.name === "projectName") {
      return answer.toLowerCase().replace(/\s+/g, "-");
    }
    
    return answer;
  }
});

const env = await helpers.createTestEnv(undefined, { adapter });

Integration with RunContext

The test environment functionality integrates seamlessly with RunContext:

import helpers from "yeoman-test";

// Environment configuration flows through to RunContext
await helpers.run("my-generator", {
  // RunContext settings
  tmpdir: true,
  namespace: "my:app"  
}, {
  // Environment options
  localConfigOnly: false,
  skipInstall: false,
  force: true
});

// Custom environment constructor
const customEnvFactory = (options) => new CustomEnvironment(options);

await helpers.run("my-generator", {}, {
  createEnv: customEnvFactory,
  cwd: "/custom/path"
});

Testing Environment Behavior

describe("environment behavior", () => {
  let env: DefaultEnvironmentApi;
  
  beforeEach(async () => {
    env = await helpers.createTestEnv({
      localConfigOnly: true,
      force: true
    });
  });
  
  it("registers generators correctly", () => {
    env.register("./path/to/generator", { namespace: "my:gen" });
    
    const registered = env.getRegisteredPackages();
    expect(registered).toHaveProperty("my:gen");
  });
  
  it("creates generators with options", async () => {
    env.register("./my-generator", { namespace: "my:app" });
    
    const generator = await env.create("my:app", {
      generatorArgs: ["init", "--force"],
      generatorOptions: { skipInstall: true }
    });
    
    expect(generator.options.skipInstall).toBe(true);
  });
});

Default Environment Behavior

Test environments created with createTestEnv include these defaults:

  • TestAdapter: Automatically configured for prompt mocking
  • localConfigOnly: true: Prevents global configuration interference
  • newErrorHandler: true: Enhanced error handling for better test debugging
  • Isolated file system: Uses mem-fs for safe file operations
  • Skip behaviors: Cache and install skipping enabled by default

These defaults ensure consistent, isolated test execution while maintaining the flexibility to override any behavior when needed.

Install with Tessl CLI

npx tessl i tessl/npm-yeoman-test

docs

generator-helpers.md

index.md

run-context.md

run-result.md

test-adapter.md

test-environment.md

tile.json