UNPKG

@yeoman/adapter

Version:

Input Output adapter for yeoman's generator/environment stack

120 lines 4.97 kB
import events from 'node:events'; import { Duplex } from 'node:stream'; import { createPrompt } from '@inquirer/core'; import { createLogger } from '../log.js'; import { createAdapterPromptModule } from '../inquirer.js'; const defaultConfig = {}; const isValueSet = (type, answer) => { if (type === 'list' || type === 'select') { // List prompt accepts any answer value including null return answer !== undefined; } if (type === 'confirm') { // Ensure that we don't replace `false` with default `true` return answer || answer === false; } // Other prompts treat all falsy values to default return Boolean(answer); }; const createDummyPrompt = ({ calls }, options = {}) => { const { mockedAnswers = {}, callback = answer => answer, throwOnMissingAnswer = false } = options; return createPrompt((config, done) => { let answer = mockedAnswers[config.name]; if (!isValueSet(config.type, answer)) { if (answer === undefined && config.default === undefined) { const missingAnswerMessage = `yeoman-test: question ${config.name ?? ''} was asked but answer was not provided`; console.warn(missingAnswerMessage); if (throwOnMissingAnswer) { throw new Error(missingAnswerMessage); } } answer = config.default; if (answer === undefined && config.type === 'confirm') { // Confirm prompt defaults to true answer = true; } } calls.push({ question: config, answer }); done(callback(answer, { question: config, answers: { [config.name]: answer } })); return config.message; }); }; export const defineConfig = (config) => Object.assign(defaultConfig, config); export const getConfig = () => ({ ...defaultConfig }); /** * @experimental */ export class TestAdapter { promptModule; diff; log; registerDummyPrompt; mockedAnswers; calls = []; abortController = new AbortController(); signal = this.abortController.signal; spyFactory; constructor(options = {}) { const { spyFactory = defaultConfig.spyFactory ?? (spyOptions => () => spyOptions.returns), log = defaultConfig.log ?? createLogger(), mockedAnswers, callback, throwOnMissingAnswer, } = options; this.spyFactory = spyFactory; this.promptModule = createAdapterPromptModule({ input: Duplex.from('should not read from input'), output: Duplex.from(async () => { }), skipTTYChecks: true, signal: this.abortController.signal, }); this.mockedAnswers = {}; this.addAnswers(mockedAnswers ?? {}); const actualRegisterPrompt = this.promptModule.registerPrompt.bind(this.promptModule); this.registerDummyPrompt = (promptModuleName, customPromptOptions) => actualRegisterPrompt(promptModuleName, createDummyPrompt({ calls: this.calls }, { callback, mockedAnswers: this.mockedAnswers, throwOnMissingAnswer, ...customPromptOptions })); this.promptModule.registerPrompt = (name) => this.registerDummyPrompt(name); for (const promptName of Object.keys(this.promptModule.prompts)) { this.promptModule.registerPrompt(promptName, undefined); } this.diff = this.spyFactory({}); this.log = this.spyFactory({}); Object.assign(this.log, events.EventEmitter.prototype); const descriptors = Object.getOwnPropertyDescriptors(log); // Make sure all log methods are defined const logMethods = Object.entries(descriptors) .filter(([method, desc]) => typeof desc.value === 'function' && !Object.getOwnPropertyDescriptor(this.log, method)) .map(([method]) => method); for (const methodName of logMethods) { this.log[methodName] = this.spyFactory({ returns: this.log }); } } async queue(function_) { return function_(this); } async progress(function_, _options) { return function_({ step() { } }); } close() { this.abort(); } abort(reason) { this.abortController.abort(reason); } async prompt(questions, initialAnswers) { try { return (await this.promptModule(questions, initialAnswers)); } catch (error) { this.abortController.abort(error); throw error; } } /** * Add answers to the mocked answers. */ addAnswers(answers) { // Copy properties using Object.getOwnPropertyDescriptor to preserve getters and setters for (const key in answers) { const descriptors = Object.getOwnPropertyDescriptor(answers, key); if (descriptors) { Object.defineProperty(this.mockedAnswers, key, descriptors); } } } } //# sourceMappingURL=test-adapter.js.map