UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

281 lines (217 loc) • 8.21 kB
import { diskUtil, versionUtil } from '@sprucelabs/spruce-skill-utils' import { test, assert } from '@sprucelabs/test-utils' import featuresUtil from '../../features/feature.utilities' import { FeatureActionResponse, FeatureInstallResponse, } from '../../features/features.types' import CommandServiceImpl from '../../services/CommandService' import AbstractSchemaTest from '../../tests/AbstractSchemaTest' import testUtil from '../../tests/utilities/test.utility' export default class FeatureCommandExecuterContTest extends AbstractSchemaTest { @test() protected static async canSkipOptionalDependencies() { const { promise: actionPromise } = await this.startBuildingNewErrorUntilOptionalDependencies('skip') const results = await this.finishBuildingUpToNamingNewError(actionPromise) assert.isTruthy(results.files) assert.isFalsy(results.errors) const pluginsDir = this.resolveHashSprucePath('features') assert.isFalse(diskUtil.doesDirExist(pluginsDir)) testUtil.assertFileByNameInGeneratedFiles( 'myNewError.schema.ts', results.files ) } @test() protected static async shouldEmitExecutionEvents() { this.fakeInstallCommands() const executer = this.Action('skill', 'create', { shouldAutoHandleDependencies: true, }) let emittedWillEvent = false let willEventCommand = '' let emittedDidEvent = false let didEventCommand = '' let willExecuteHitCount = 0 let didExecuteHitCount = 0 const emitter = this.emitter void emitter.on('feature.will-execute', (payload) => { emittedWillEvent = true willExecuteHitCount++ willEventCommand = featuresUtil.generateCommand( payload.featureCode, payload.actionCode ) return {} }) void emitter.on('feature.did-execute', (payload) => { emittedDidEvent = true didExecuteHitCount++ didEventCommand = featuresUtil.generateCommand( payload.featureCode, payload.actionCode ) return { meta: { taco: 'bell', }, } }) assert.isFalse(emittedWillEvent) assert.isFalse(emittedDidEvent) assert.isEqual(willExecuteHitCount, 0) assert.isEqual(didExecuteHitCount, 0) const promise = executer.execute({}) await this.waitForInput() await this.ui.sendInput('My new skill') await this.ui.sendInput('So great!') const results = await promise assert.isEqual(results.meta?.taco, 'bell') assert.isEqual(willEventCommand, 'create.skill') assert.isEqual(didEventCommand, 'create.skill') assert.isEqual(willExecuteHitCount, 1) assert.isEqual(didExecuteHitCount, 1) } @test() protected static async canPermanentlySkipOptionalDependencies() { const { promise: actionPromise } = await this.startBuildingNewErrorUntilOptionalDependencies( 'alwaysSkip' ) await this.finishBuildingUpToNamingNewError(actionPromise) const executer = this.Action('error', 'create', { shouldAutoHandleDependencies: true, }) const promise = executer.execute({}) await this.waitForInput() assert.doesNotInclude(this.ui.getLastInvocation(), { command: 'prompt', options: { type: 'select', }, }) await this.ui.sendInput('My second error') await this.ui.sendInput('') const secondTimeResults = await promise assert.isTruthy(secondTimeResults.files) testUtil.assertFileByNameInGeneratedFiles( 'myNewError.schema.ts', secondTimeResults.files ) } @test() protected static async shouldReturnProperSummary() { this.fakeInstallCommands() const executer = this.Action('skill', 'create', { shouldAutoHandleDependencies: true, }) const results = await executer.execute({ name: 'install summary test skill', description: 'go team!', }) assert.isTruthy(results.files) assert.isTruthy(results.packagesInstalled) assert.isAbove(results.files.length, 0) assert.isAbove(results.packagesInstalled.length, 0) } @test() protected static async shouldAskInstallDependentFeatures() { this.fakeInstallCommands() const executer = this.Action('schema', 'create', { shouldAutoHandleDependencies: true, }) void executer.execute({}) await this.waitForInput() this.ui.reset() const lastQuestion = this.ui.getLastInvocation() assert.isEqual(lastQuestion.command, 'prompt') assert.doesInclude( lastQuestion.options.label, /install the skill feature/gi ) } @test() protected static async shouldAddListenerWithoutBreakingOnSkill() { this.fakeInstallCommands() await this.FeatureFixture().installCachedFeatures('schemas') const executer = this.Action('event', 'listen', { shouldAutoHandleDependencies: true, }) const promise = executer.execute({}) await this.waitForInput() await this.ui.sendInput('Y') await this.waitForInput() await this.ui.sendInput('\n') await this.waitForInput() await this.ui.sendInput('skill') await this.ui.sendInput('will-boot') const results = await promise const version = versionUtil.generateVersion().dirValue testUtil.assertFileByNameInGeneratedFiles( `will-boot.${version}.listener.ts`, results.files ) } private static async finishBuildingUpToNamingNewError( actionPromise: Promise<FeatureInstallResponse & FeatureActionResponse> ) { await this.ui.sendInput('') await this.waitForInput() await this.ui.sendInput('') await this.waitForInput() await this.ui.sendInput('My new error') await this.ui.sendInput('') const results = await actionPromise return results } private static async startBuildingNewErrorUntilOptionalDependencies( skillFeatureAnswer: 'skip' | 'yes' | 'alwaysSkip' ) { const executer = this.Action('error', 'create', { shouldAutoHandleDependencies: true, }) const promise = executer.execute({}) await this.waitForInput() const message = this.ui.invocations[this.ui.invocations.length - 2].options.message assert.isTruthy(message) assert.doesInclude(message, /2 required/gi) assert.doesInclude(message, /1 optional/gi) assert.doesInclude(this.ui.getLastInvocation(), { command: 'prompt', options: { type: 'select', options: { choices: [ { value: 'yes', label: 'Yes', }, { value: 'skip', label: 'Skip', }, { value: 'alwaysSkip', label: 'Always skip', }, ], }, }, }) await this.ui.sendInput(skillFeatureAnswer) await this.ui.sendInput('y') await this.waitForInput() await this.ui.sendInput('My new module') await this.ui.sendInput('it is for testing') await this.waitForInput() return { promise } } private static fakeInstallCommands() { CommandServiceImpl.fakeCommand(new RegExp(/yarn|npm/gis), { code: 0, }) } }