UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

299 lines (244 loc) • 9.68 kB
import { eventDiskUtil, eventNameUtil } from '@sprucelabs/spruce-event-utils' import { diskUtil, namesUtil, versionUtil, } from '@sprucelabs/spruce-skill-utils' import { test, assert } from '@sprucelabs/test-utils' import { errorAssert } from '@sprucelabs/test-utils' import { FeatureActionResponse } from '../../../features/features.types' import AbstractEventTest from '../../../tests/AbstractEventTest' import { DEMO_NUMBER_CREATING_AN_EVENT } from '../../../tests/constants' import testUtil from '../../../tests/utilities/test.utility' import uiAssert from '../../../tests/utilities/uiAssert.utility' import { CliInterface, RegisteredSkill } from '../../../types/cli.types' import actionUtil from '../../../utilities/action.utility' const EVENT_NAME_READABLE = 'my fantastically amazing event' const EVENT_NAME = 'my-fantastically-amazing-event' const EVENT_CAMEL = 'myFantasticallyAmazingEvent' export default class CreatingAnEventTest extends AbstractEventTest { private static readonly expectedVersion = versionUtil.generateVersion().constValue @test() protected static async hasCreateAction() { assert.isFunction(this.Action('event', 'create').execute) } @test() protected static async cantCreateEventWithoutBeingRegistered() { await this.FeatureFixture().installCachedFeatures('events') const results = await this.Action('event', 'create').execute({ nameReadable: EVENT_NAME_READABLE, nameKebab: EVENT_NAME, nameCamel: EVENT_CAMEL, version: this.expectedVersion, }) assert.isArray(results.errors) errorAssert.assertError(results.errors[0], 'SKILL_NOT_REGISTERED') } @test() protected static async createsPayloadBuildersAndSchemas() { const { results, skill } = await this.createEvent() const filesThatShouldExist = [ new RegExp( `${namesUtil.toCamel(skill.slug)}.*?${ this.expectedVersion }.*?myFantasticallyAmazingEventResponsePayload`, 'gis' ), new RegExp( `${namesUtil.toCamel(skill.slug)}.*?${ this.expectedVersion }.*?myFantasticallyAmazingEventEmitTargetAndPayload`, 'gis' ), new RegExp( `${namesUtil.toCamel(skill.slug)}.*?${ this.expectedVersion }.*?myFantasticallyAmazingEventEmitPayload`, 'gis' ), 'emitPayload.builder.ts', 'emitTarget.builder.ts', ] const checker = this.Service('typeChecker') for (const name of filesThatShouldExist) { const match = testUtil.assertFileByPathInGeneratedFiles( name, results.files ) await checker.check(match) } } @test() protected static async createsEventWithPayloadsPermissionsAndOptions() { const { results, cli, skill } = await this.createEvent() assert.isFalsy(results.errors) await this.copyEventBuildersAndPermissions(EVENT_NAME) const syncResults = await this.Action('event', 'sync').execute({}) assert.isFalsy(syncResults.errors) const mixedResults = actionUtil.mergeActionResults(results, syncResults) await this.assertExpectedTargetAndPayload(mixedResults, skill) await this.assertExpectedPayloadSchemas(mixedResults) await this.assertReturnsEventFromHealthCheck(cli, skill) await this.assertCreatesOptionsFile(mixedResults) } @test() protected static async createdEventsAreTypedCorrectly() { const { results } = await this.createEvent() assert.isFalsy(results.errors) const { fqen } = results.meta ?? {} const testFileContents = diskUtil .readFile(this.resolveTestPath('client-test.ts.hbs')) .replace('{{fqen}}', fqen) const testFile = this.resolvePath('src', 'test-client.ts') diskUtil.writeFile(testFile, testFileContents) await this.Service('typeChecker').check(testFile) } @test() protected static async canReferenceSchemaFromOtherModule() { const { results } = await this.createEvent() await this.Service('pkg').install( '@sprucelabs/heartwood-view-controllers' ) const emitPayloadFile = testUtil.assertFileByNameInGeneratedFiles( 'emitPayload.builder.ts', results.files ) const newContents = `import { formBuilderImportExportObjectSchema } from '@sprucelabs/heartwood-view-controllers' import { buildSchema } from '@sprucelabs/schema' const createFormEmitPayloadBuilder = buildSchema({ id: 'myFantasticallyAmazingEventEmitPayload', fields: { ...formBuilderImportExportObjectSchema.fields, }, }) export default createFormEmitPayloadBuilder ` diskUtil.writeFile(emitPayloadFile, newContents) const syncResults = await this.Action('event', 'sync').execute({}) assert.isFalsy(syncResults.errors) } @test() protected static async asksForVersionIfPreviousVersionExistsOnDifferentDay() { await this.createEvent({ version: versionUtil.generateVersion('2020_01_10').constValue, }) void this.Action('event', 'create').execute({ nameReadable: EVENT_NAME_READABLE, nameKebab: EVENT_NAME, nameCamel: EVENT_CAMEL, }) await uiAssert.assertRendersSelect(this.ui) this.ui.reset() } private static async createEvent(options?: { version?: string }) { const cli = await this.FeatureFixture().installCachedFeatures('events') const skill = await this.registerCurrentSkill() const results = await this.Action('event', 'create').execute({ nameReadable: EVENT_NAME_READABLE, nameKebab: EVENT_NAME, nameCamel: EVENT_CAMEL, version: this.expectedVersion, ...options, }) return { results, cli, skill } } private static async registerCurrentSkill() { return await this.getSkillFixture().registerCurrentSkill( { name: 'my new skill', }, { phone: DEMO_NUMBER_CREATING_AN_EVENT, } ) } private static async assertCreatesOptionsFile( results: FeatureActionResponse ) { const optionsFile = testUtil.assertFileByNameInGeneratedFiles( 'event.options.ts', results.files ) const imported = await this.Service('import').importDefault(optionsFile) assert.isEqualDeep(imported, { isGlobal: false }) } private static async assertExpectedTargetAndPayload( results: FeatureActionResponse, skill: RegisteredSkill ) { const match = testUtil.assertFileByPathInGeneratedFiles( new RegExp( `${namesUtil.toCamel(skill.slug)}.*?${ this.expectedVersion }.*?myFantasticallyAmazingEventEmitTargetAndPayload`, 'gis' ), results.files ) const schema = await this.Service('schema').importSchema(match) assert.isEqual( schema.id, 'myFantasticallyAmazingEventEmitTargetAndPayload' ) assert.isTruthy(schema.fields?.payload) assert.isTruthy(schema.fields?.target) } private static async assertReturnsEventFromHealthCheck( cli: CliInterface, skill: RegisteredSkill ) { const health = await cli.checkHealth() assert.isTruthy(health.event) assert.isLength(health.event.events, 1) const eventName = EVENT_NAME const eventNamespace = namesUtil.toKebab(skill.slug) assert.doesInclude(health.event.events, { eventName, eventNamespace, version: this.expectedVersion, }) assert.doesInclude(health.event.contracts, { fullyQualifiedEventName: eventNameUtil.join({ eventName, eventNamespace, version: this.expectedVersion, }), }) } private static async assertExpectedPayloadSchemas( results: FeatureActionResponse ) { const payloadSchemas = [ { fileName: 'emitPayload.builder.ts', expectedId: 'myFantasticallyAmazingEventEmitPayload', }, { fileName: 'emitTarget.builder.ts', expectedId: 'myFantasticallyAmazingEventEmitTarget', }, { fileName: 'responsePayload.builder.ts', expectedId: 'myFantasticallyAmazingEventResponsePayload', }, ] const schemas = this.Service('schema') for (const payload of payloadSchemas) { const match = testUtil.assertFileByNameInGeneratedFiles( payload.fileName, results.files ) assert.isEqual( match, eventDiskUtil.resolveEventPath(this.cwd + '/src/events', { fileName: payload.fileName as any, eventName: EVENT_NAME, version: this.expectedVersion, }) ) const imported = await schemas.importSchema(match) assert.isEqual(imported.id, payload.expectedId) } } }