UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

191 lines (158 loc) • 5.99 kB
import { diskUtil, namesUtil } from '@sprucelabs/spruce-skill-utils' import { test, assert, errorAssert, generateId } from '@sprucelabs/test-utils' import CreateAppAction from '../../../features/view/actions/CreateAppAction' import AbstractSkillTest from '../../../tests/AbstractSkillTest' import testUtil from '../../../tests/utilities/test.utility' export default class CreatingAnAppControllerTest extends AbstractSkillTest { protected static skillCacheKey = 'views' private static acPath: string private static skillNamespace = generateId().replace(/\d/g, '') private static action: CreateAppAction private static lastExecution: { actionCode: string featureCode: string }[] = [] protected static async beforeAll(): Promise<void> { await super.beforeAll() this.acPath = this.resolvePath('src/App.ac.ts') const pgk = this.Service('pkg') pgk.set({ path: 'skill.namespace', value: this.skillNamespace }) } protected static async beforeEach(): Promise<void> { await super.beforeEach() this.action = this.Action('view', 'createApp') await this.cli.on('feature.will-execute', (payload) => { this.lastExecution.push(payload) }) } @test() protected static async generatesExpectedFile() { const results = await this.execute() assert.isFalsy(results.errors) testUtil.assertFileByPathInGeneratedFiles(this.acPath, results.files) assert.doesInclude(results.files, { action: 'generated', name: 'App.ac.ts', path: this.acPath, }) assert.doesInclude(results.files, { action: 'generated', name: 'views.ts', path: this.combinedViewsPath, }) } @test() protected static async syncsViewsOnCreation() { assert.doesInclude(this.lastExecution, { actionCode: 'sync', featureCode: 'view', }) assert.isEqual(this.lastExecution[1].actionCode, 'sync') assert.isTrue( diskUtil.doesFileExist(this.combinedViewsPath), 'views.ts does not exist' ) } @test() protected static async throwsIfAppAlreadyExists() { await this.executeAndAssertThrowsAvcExists() } @test() protected static async acIncludesExpectedContents() { const contents = diskUtil.readFile(this.acPath) assert.doesInclude( contents, `export default class ${this.className} extends AbstractAppController` ) assert.doesInclude( contents, 'public async load(_options: AppControllerLoadOptions)' ) } @test() protected static async generatedFilesAreValid() { await this.Service('typeChecker').check(this.acPath) await this.assertCombinedViewsFileIsValid() } @test() protected static async doesNotDropAppIntoSkillViewTypes() { const expected = `interface ViewControllerMap {}` this.assertCombinedViewsContains(expected) } @test() protected static async callsHeartwoodImportFunctionAsExpected() { this.assertCombinedViewsContains( `heartwood({ vcs, pluginsByName, App: ${this.className} })` ) } @test() protected static async combineViewsTypesAsExpected() { const expected = `interface AppControllerMap { '${this.skillNamespace}' : ${this.className} }` this.assertCombinedViewsContains(expected) } @test() protected static async throwsEvenIfAppMoves() { const destination = this.resolvePath(`src/${generateId()}/App.ac.ts`) diskUtil.moveFile(this.acPath, destination) await this.executeAndAssertThrowsAvcExists() this.acPath = destination } @test() protected static async canRenameAppAndItUpdatesCombinedViews() { const contents = diskUtil.readFile(this.acPath) const updatedContents = contents.replace( this.className, 'NewAppControllerImpl' ) diskUtil.writeFile(this.acPath, updatedContents) await this.Action('view', 'sync').execute({}) this.assertCombinedViewsContains( 'heartwood({ vcs, pluginsByName, App: NewAppControllerImpl })' ) await this.assertCombinedViewsFileIsValid() } @test() protected static async importsAppFromCombinedViews() { const testScript = `import { App } from '#` + `spruce/views/views' const app = new App({} as any) console.log(app) if (App.id !== '${this.skillNamespace}') { throw new Error('App.id is not correct') }` const testScriptPath = this.resolvePath('src/test.ts') diskUtil.writeFile(testScriptPath, testScript) await this.Service('typeChecker').check(testScriptPath) } private static async assertCombinedViewsFileIsValid() { await this.Service('typeChecker').check(this.combinedViewsPath) } private static assertCombinedViewsContains(expected: string) { const contents = diskUtil.readFile(this.combinedViewsPath) assert.doesInclude( contents.replace(/\s/g, ''), expected.replace(/\s/g, ''), `The combined views file does not include the expected contents.` ) } private static get combinedViewsPath() { return this.resolveHashSprucePath('views', 'views.ts') } private static get className() { return `${namesUtil.toPascal(this.skillNamespace)}AppController` } private static async executeAndAssertThrowsAvcExists() { const results = await this.execute() assert.isTruthy(results.errors) errorAssert.assertError( results.errors[0], 'APP_CONTROLLER_ALREADY_EXISTS' ) } private static async execute() { return await this.action.execute() } }