@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
224 lines (190 loc) • 7.11 kB
text/typescript
import { diskUtil } from '@sprucelabs/spruce-skill-utils'
import { test, assert, errorAssert } from '@sprucelabs/test-utils'
import { FeatureActionResponse } from '../../../../features/features.types'
import CreatePluginAction from '../../../../features/view/actions/CreatePluginAction'
import AbstractSkillTest from '../../../../tests/AbstractSkillTest'
export default class CreatingAViewPluginTest extends AbstractSkillTest {
protected static skillCacheKey = 'views'
private static action: CreatePluginAction
protected static async beforeEach(): Promise<void> {
await super.beforeEach()
this.action = this.Action('view', 'createPlugin')
}
protected static async hasAction() {
assert.isFunction(this.action.execute)
}
protected static async createsExpectedFile(
readable: string,
expected: string,
combinedViewAction: string
) {
const results = await this.execute({ nameReadable: readable })
this.assertExpectedFileCreated(results, expected, combinedViewAction)
assert.isFalsy(
results.errors,
'Errors were returned and none were expected!'
)
}
protected static async usesCamelNameIfProvided() {
const results = await this.execute({
nameReadable: 'test',
nameCamel: 'testCamel',
})
this.assertExpectedFileCreated(results, 'testCamel', 'updated')
}
protected static async actuallyCreatesFile() {
this.assertViewPluginWritten('test')
this.assertViewPluginWritten('another')
this.assertViewPluginWritten('aThird')
}
protected static async throwsIfPluginAlreadyExists() {
await this.assertThrowsAlreadyExists('test')
await this.assertThrowsAlreadyExists('another')
}
protected static async contentsAreEqualToExpected() {
this.assertPluginContentsEqualExpected('test', 'Test')
this.assertPluginContentsEqualExpected('another', 'Another')
this.assertPluginContentsEqualExpected('aThird', 'AThird')
}
protected static async combineViewsFileIsValid() {
const combined = this.getPathToCombinedViewsFile()
await this.Service('typeChecker').check(combined)
}
protected static async updatesViewCombinedFileWithTypesAsExpected() {
const expected = ` interface ViewControllerPlugins {
aThird: AThirdViewPlugin
another: AnotherViewPlugin
test: TestViewPlugin
testCamel: TestCamelViewPlugin
}`
this.assertCombinedFileIncludes(expected)
}
protected static async updatesViewCombinedWithPluginsAsExpected() {
const expected = `export const pluginsByName = {
aThird: AThirdViewPlugin,
another: AnotherViewPlugin,
test: TestViewPlugin,
testCamel: TestCamelViewPlugin,
}
`
this.assertCombinedFileIncludes(expected)
this.assertCombinedFileIncludes('heartwood({ vcs, pluginsByName })')
}
protected static async viewPluginCanImportAnotherViewPlugin() {
this.writeFile('export class ExternalViewPlugin {}', 'external.ts')
this.writeFile(
`export { ExternalViewPlugin as default } from './external'`,
'actual.view.plugin.ts'
)
await this.syncViews()
const expected = `export const pluginsByName = {
actual: ExternalViewPlugin,
aThird: AThirdViewPlugin,
another: AnotherViewPlugin,
test: TestViewPlugin,
testCamel: TestCamelViewPlugin,
}
`
this.assertCombinedFileIncludes(expected)
}
protected static async canImportPluginFromExternalLibrary() {
this.writeFile(
"export { CardViewController as default } from '@sprucelabs/heartwood-view-controllers'",
'card.view.plugin.ts'
)
await this.syncViews()
const expected = `export const pluginsByName = {
actual: ExternalViewPlugin,
card: CardViewController,
aThird: AThirdViewPlugin,
another: AnotherViewPlugin,
test: TestViewPlugin,
testCamel: TestCamelViewPlugin,
}
`
this.assertCombinedFileIncludes(expected)
}
private static async syncViews() {
await this.Action('view', 'sync').execute({})
}
private static writeFile(content: string, fileName: string) {
const actualPlugiContent = content
const actualDestination = this.resolvePath('src', fileName)
diskUtil.writeFile(actualDestination, actualPlugiContent)
}
private static assertCombinedFileIncludes(expected: string) {
const combined = this.getPathToCombinedViewsFile()
const contents = diskUtil.readFile(combined)
assert.doesInclude(contents, expected)
}
private static assertPluginContentsEqualExpected(
nameCamel: string,
namePascal: string
) {
const contents = diskUtil.readFile(
this.buildPathToViewPlugin(nameCamel)
)
const expected = `import { ViewControllerPlugin } from '@sprucelabs/heartwood-view-controllers'\n\nexport default class ${namePascal}ViewPlugin implements ViewControllerPlugin {}`
assert.isEqual(contents.trim(), expected.trim())
}
private static async assertThrowsAlreadyExists(name: string) {
const results = await this.execute({ nameReadable: name })
assert.isTruthy(results.errors)
errorAssert.assertError(
results.errors[0],
'VIEW_PLUGIN_ALREADY_EXISTS',
{
name,
}
)
}
private static assertViewPluginWritten(name: string) {
const path = this.buildPathToViewPlugin(name)
assert.isTrue(
diskUtil.doesFileExist(path),
`File ${path} was not written!`
)
}
private static buildPathToViewPlugin(name: string) {
return this.resolvePath('src', 'viewPlugins', `${name}.view.plugin.ts`)
}
private static async execute(options: {
nameReadable: string
nameCamel?: string
}) {
return await this.action.execute(options)
}
private static assertExpectedFileCreated(
results: FeatureActionResponse,
expected: string,
combinedViewAction: string
) {
const expectedName = `${expected}.view.plugin.ts`
assert.doesInclude(results.files?.[0], {
action: 'generated',
name: expectedName,
path: this.resolvePath('src', 'viewPlugins', expectedName),
})
assert.doesInclude(results.files?.[1], {
action: combinedViewAction,
name: 'views.ts',
path: this.getPathToCombinedViewsFile(),
})
}
private static getPathToCombinedViewsFile() {
return this.resolveHashSprucePath('views', 'views.ts')
}
}