UNPKG

yeoman-test

Version:

Test utilities for Yeoman generators

323 lines (322 loc) 12.4 kB
/// <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 {};