yeoman-test
Version:
Test utilities for Yeoman generators
323 lines (322 loc) • 12.4 kB
TypeScript
/// <reference types="node" resolution-mode="require"/>
import { EventEmitter } from 'node:events';
import { type Store } from 'mem-fs';
import type { BaseEnvironmentOptions, BaseGenerator, GetGeneratorConstructor, GetGeneratorOptions, PromptAnswers, LookupOptions } from '@yeoman/types';
import { type MemFsEditorFile, type MemFsEditor } from 'mem-fs-editor';
import type { DefaultGeneratorApi, DefaultEnvironmentApi } from '../types/type-helpers.js';
import RunResult, { type RunResultOptions } from './run-result.js';
import { type CreateEnv, type Dependency, type YeomanTest } from './helpers.js';
import { type AskedQuestions, type DummyPromptOptions, type TestAdapterOptions } from './adapter.js';
/**
* Provides settings for creating a `RunContext`.
*/
export type RunContextSettings = {
/**
* Automatically run this generator in a tmp dir
* @default true
*/
tmpdir?: boolean;
cwd?: string;
oldCwd?: string;
forwardCwd?: boolean;
autoCleanup?: boolean;
memFs?: Store<MemFsEditorFile>;
/**
* File path to the generator (only used if Generator is a constructor)
*/
resolved?: string;
/**
* Namespace (only used if Generator is a constructor)
* @default 'gen:test'
*/
namespace?: string;
};
type PromiseRunResult<GeneratorType extends BaseGenerator> = Promise<RunResult<GeneratorType>>;
type MockedGeneratorFactory<GenParameter extends BaseGenerator = DefaultGeneratorApi> = (GeneratorClass?: GetGeneratorConstructor<GenParameter>) => GetGeneratorConstructor<GenParameter>;
type EnvOptions = BaseEnvironmentOptions & {
createEnv?: CreateEnv;
};
export declare class RunContextBase<GeneratorType extends BaseGenerator = DefaultGeneratorApi> extends EventEmitter {
readonly mockedGenerators: Record<string, BaseGenerator>;
env: DefaultEnvironmentApi;
generator: GeneratorType;
readonly settings: RunContextSettings;
readonly envOptions: EnvOptions;
completed: boolean;
targetDirectory?: string;
editor: MemFsEditor;
memFs: Store<MemFsEditorFile>;
spawnStub?: any;
mockedGeneratorFactory: MockedGeneratorFactory;
readonly askedQuestions: AskedQuestions;
protected environmentPromise?: PromiseRunResult<GeneratorType>;
private args;
private options;
private answers?;
private readonly adapterOptions?;
private keepFsState?;
private readonly onGeneratorCallbacks;
private readonly onTargetDirectoryCallbacks;
private readonly onEnvironmentCallbacks;
private readonly inDirCallbacks;
private readonly Generator?;
private readonly helpers;
private readonly temporaryDir;
private oldCwd?;
private eventListenersSet;
private envCB;
private built;
private ran;
private errored;
private readonly beforePrepareCallbacks;
/**
* This class provide a run context object to façade the complexity involved in setting
* up a generator for testing
* @constructor
* @param Generator - Namespace or generator constructor. If the later
* is provided, then namespace is assumed to be
* 'gen:test' in all cases
* @param settings
* @return {this}
*/
constructor(generatorType?: string | GetGeneratorConstructor<GeneratorType>, settings?: RunContextSettings, envOptions?: EnvOptions, helpers?: YeomanTest);
/**
* Run the generator on the environment and promises a RunResult instance.
* @return {PromiseRunResult} Promise a RunResult instance.
*/
run(): PromiseRunResult<GeneratorType>;
on(eventName: string | symbol, listener: (...args: any[]) => void): this;
/**
* @deprecated
* Clean the provided directory, then change directory into it
* @param dirPath - Directory path (relative to CWD). Prefer passing an absolute
* file path for predictable results
* @param [cb] - callback who'll receive the folder path as argument
* @return run context instance
*/
inDir(dirPath: string, cb?: (folderPath: string) => void): this;
/**
* Register an callback to prepare the destination folder.
* @param [cb] - callback who'll receive the folder path as argument
* @return this - run context instance
*/
doInDir(cb: (folderPath: string) => void): this;
/**
* @deprecated
* Change directory without deleting directory content.
* @param dirPath - Directory path (relative to CWD). Prefer passing an absolute
* file path for predictable results
* @return run context instance
*/
cd(dirPath: string): this;
/**
* Cleanup a temporary directory and change the CWD into it
*
* This method is called automatically when creating a RunContext. Only use it if you need
* to use the callback.
*
* @param [cb] - callback who'll receive the folder path as argument
* @return this - run context instance
*/
inTmpDir(cb?: (folderPath: string) => void): this;
/**
* Restore cwd to initial cwd.
* @return {this} run context instance
*/
restore(): this;
/**
* Clean the directory used for tests inside inDir/inTmpDir
* @param {Boolean} force - force directory cleanup for not tmpdir
*/
cleanup(): void;
/**
* Clean the directory used for tests inside inDir/inTmpDir
* @param {Boolean} force - force directory cleanup for not tmpdir
*/
cleanupTemporaryDir(): void;
/**
* Clean the directory used for tests inside inDir/inTmpDir
* @param force - force directory cleanup for not tmpdir
*/
cleanTestDirectory(force?: boolean): void;
/**
* TestAdapter options.
*/
withAdapterOptions(options: Omit<TestAdapterOptions, 'mockedAnswers'>): this;
/**
* Create an environment
*
* This method is called automatically when creating a RunContext. Only use it if you need
* to use the callback.
*
* @param {Function} [cb] - callback who'll receive the folder path as argument
* @return {this} run context instance
*/
withEnvironment(cb: any): this;
/**
* Run lookup on the environment.
*
* @param lookups - lookup to run.
*/
withLookups(lookups: LookupOptions | LookupOptions[]): this;
/**
* Provide arguments to the run context
* @param args - command line arguments as Array or space separated string
*/
withArguments(args: string | string[]): this;
/**
* Provide options to the run context
* @param {Object} options - command line options (e.g. `--opt-one=foo`)
* @return {this}
*/
withOptions(options: Partial<Omit<GetGeneratorOptions<GeneratorType>, 'env' | 'namespace' | 'resolved'>>): this;
/**
* @deprecated
* Mock the prompt with dummy answers
* @param answers - Answers to the prompt questions
* @param options - Options or callback.
* @param {Function} [options.callback] - Callback.
* @param {Boolean} [options.throwOnMissingAnswer] - Throw if a answer is missing.
* @return {this}
*/
withPrompts(answers: PromptAnswers, options?: Omit<DummyPromptOptions, 'mockedAnswers'>): this;
/**
* Mock answers for prompts
* @param answers - Answers to the prompt questions
* @param options - Options or callback.
* @return {this}
*/
withAnswers(answers: PromptAnswers, options?: Omit<DummyPromptOptions, 'mockedAnswers'>): this;
/**
* Provide dependent generators
* @param {Array} dependencies - paths to the generators dependencies
* @return {this}
* @example
* var angular = new RunContext('../../app');
* angular.withGenerators([
* '../../common',
* '../../controller',
* '../../main',
* [helpers.createDummyGenerator(), 'testacular:app']
* ]);
* angular.on('end', function () {
* // assert something
* });
*/
withGenerators(dependencies: Dependency[]): this;
withSpawnMock(options?: ((...args: any[]) => any) | {
stub?: (...args: any[]) => any;
registerSinonDefaults?: boolean;
callback?: (stub: any) => void | Promise<void>;
}): this;
withMockedGeneratorFactory(mockedGeneratorFactory: MockedGeneratorFactory): this;
/**
* Create mocked generators
* @param namespaces - namespaces of mocked generators
* @return this
* @example
* var angular = helpers
* .create('../../app')
* .withMockedGenerators([
* 'foo:app',
* 'foo:bar',
* ])
* .run()
* .then(runResult => assert(runResult
* .mockedGenerators['foo:app']
.calledOnce));
*/
withMockedGenerators(namespaces: string[]): this;
/**
* Mock the local configuration with the provided config
* @param localConfig - should look just like if called config.getAll()
*/
withLocalConfig(localConfig: any): this;
/**
* Don't reset mem-fs state cleared to aggregate snapshots from multiple runs.
*/
withKeepFsState(): this;
/**
* Add files to mem-fs.
* Files will be resolved relative to targetDir.
*
* Files with Object content will be merged to existing content.
* To avoid merging, `JSON.stringify` the content.
*/
withFiles(files: Record<string, string | Record<string, unknown>>): this;
withFiles(relativePath: string, files: Record<string, string | Record<string, unknown>>): this;
/**
* Add .yo-rc.json to mem-fs.
*
* @param content
* @returns
*/
withYoRc(content: string | Record<string, unknown>): this;
/**
* Add a generator config to .yo-rc.json
*/
withYoRcConfig(key: string, content: Record<string, unknown>): this;
/**
* Commit mem-fs files.
*/
commitFiles(): this;
/**
* Execute callback after targetDirectory is set
* @param callback
* @returns
*/
onTargetDirectory(callback: (this: this, targetDirectory: string) => any): this;
/**
* Execute callback after generator is ready
* @param callback
* @returns
*/
onGenerator(callback: (this: this, generator: GeneratorType) => any): this;
/**
* Execute callback prefore parepare
* @param callback
* @returns
*/
onBeforePrepare(callback: (this: this) => void | Promise<void>): this;
/**
* Execute callback after environment is ready
* @param callback
* @returns
*/
onEnvironment(callback: (this: this, env: DefaultEnvironmentApi) => any): this;
prepare(): Promise<void>;
protected assertNotBuild(): void;
/**
* Build the generator and the environment.
* @return {RunContext|false} this
*/
build(): Promise<void>;
/**
* Return a promise representing the generator run process
* @return Promise resolved on end or rejected on error
*/
protected toPromise(): PromiseRunResult<GeneratorType>;
protected _createRunResultOptions(): RunResultOptions<GeneratorType>;
/**
* Keeps compatibility with events
*/
private setupEventListeners;
/**
* Set the target directory.
* @private
* @param {String} dirPath - Directory path (relative to CWD). Prefer passing an absolute
* file path for predictable results
* @return {this} run context instance
*/
private setDir;
}
export default class RunContext<GeneratorType extends BaseGenerator = BaseGenerator> extends RunContextBase<GeneratorType> implements Promise<RunResult<GeneratorType>> {
then<TResult1 = RunResult<GeneratorType>, TResult2 = never>(onfulfilled?: ((value: RunResult<GeneratorType>) => TResult1 | PromiseLike<TResult1>) | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined): Promise<TResult1 | TResult2>;
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined): Promise<RunResult<GeneratorType> | TResult>;
finally(onfinally?: (() => void) | undefined): Promise<RunResult<GeneratorType>>;
get [Symbol.toStringTag](): string;
}
export declare class BasicRunContext<GeneratorType extends BaseGenerator = BaseGenerator> extends RunContext<GeneratorType> {
run(): PromiseRunResult<any>;
}
export {};