@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
482 lines (359 loc) • 13.5 kB
text/typescript
import { diskUtil } from '@sprucelabs/spruce-skill-utils'
import { test, assert } from '@sprucelabs/test-utils'
import { errorAssert } from '@sprucelabs/test-utils'
import CommandServiceImpl from '../../services/CommandService'
import LintService from '../../services/LintService'
import AbstractCliTest from '../../tests/AbstractCliTest'
import testUtil from '../../tests/utilities/test.utility'
export default class DeployingASkillTest extends AbstractCliTest {
private static readonly fastHerokuOptions = {
teamName: process.env.HEROKU_TEAM_NAME ?? '',
shouldBuildAndLint: false,
shouldRunTests: false,
}
protected static async beforeEach() {
await super.beforeEach()
CommandServiceImpl.fakeCommand('which heroku', {
code: 0,
})
CommandServiceImpl.fakeCommand('grep api.heroku.com ~/.netrc', {
code: 0,
})
CommandServiceImpl.fakeCommand('git status', {
code: 0,
})
CommandServiceImpl.fakeCommand('git init', {
code: 0,
stdout: 'Initialized empty Git repository in',
})
CommandServiceImpl.fakeCommand('git ls-remote heroku', {
code: 0,
})
CommandServiceImpl.fakeCommand('which git', {
code: 0,
})
CommandServiceImpl.fakeCommand('heroku create good-heroku-name', {
code: 0,
})
CommandServiceImpl.fakeCommand('heroku create bad-heroku-name', {
code: 1,
})
CommandServiceImpl.fakeCommand('heroku buildpacks:set heroku/nodejs', {
code: 0,
})
CommandServiceImpl.fakeCommand(
'git push --set-upstream heroku master',
{
code: 0,
}
)
diskUtil.writeFile(this.resolvePath('Procfile'), 'web: npm run boot')
}
protected static async hasDeployAction() {
assert.isFunction(this.Action('deploy', 'heroku').execute)
}
protected static async deployHaltedBecauseNotRegistered() {
await this.FeatureFixture().installCachedFeatures('deploy')
diskUtil.writeFile(this.resolvePath('src/index.ts'), 'aoeustahoesuntao')
const results = await this.Action('deploy', 'heroku').execute({
teamName: process.env.HEROKU_TEAM_NAME ?? '',
})
assert.isTruthy(results.errors)
assert.isArray(results.errors)
errorAssert.assertError(results.errors[0], 'DEPLOY_FAILED', {
stage: 'skill',
})
}
protected static async deployHaltedWithBadBuild() {
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'haulted wth bad build',
})
diskUtil.writeFile(this.resolvePath('src/index.ts'), 'aoeustahoesuntao')
const results = await this.Action('deploy', 'heroku').execute({
teamName: process.env.HEROKU_TEAM_NAME ?? '',
})
assert.isTruthy(results.errors)
assert.isArray(results.errors)
errorAssert.assertError(results.errors[0], 'DEPLOY_FAILED', {
stage: 'building',
})
}
protected static async healthCheckReportsNotDeployed() {
const cli = await this.FeatureFixture().installCachedFeatures('deploy')
const health = (await cli.checkHealth()) as any
assert.isFalsy(health.errors)
assert.isTruthy(health.deploy)
assert.isEqual(health.deploy.status, 'passed')
assert.isLength(health.deploy.deploys, 0)
}
protected static async deployHaltedWithBadTest() {
await this.FeatureFixture().installCachedFeatures('deployWithTests')
LintService.enableLinting()
await this.getSkillFixture().registerCurrentSkill({
name: 'haulted wth bad test',
})
const promise = this.Action('test', 'create').execute({
nameReadable: 'Test failed',
nameCamel: 'testFailed',
type: 'behavioral',
})
await this.waitForInput()
await this.ui.sendInput('')
await promise
const results = await this.Action('deploy', 'heroku').execute({
teamName: process.env.HEROKU_TEAM_NAME ?? '',
})
assert.isTruthy(results.errors)
assert.isArray(results.errors)
errorAssert.assertError(results.errors[0], 'TEST_FAILED')
}
protected static async errorsIfHerokuClientNotInstalled() {
CommandServiceImpl.fakeCommand('which heroku', {
code: 1,
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'heroku not installed',
})
const results = await this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
assert.isTruthy(results.errors)
errorAssert.assertError(results.errors[0], 'MISSING_DEPENDENCIES', {
'dependencies[0].name': 'heroku',
})
}
protected static async errorsIfGitNotInstalled() {
CommandServiceImpl.fakeCommand('which git', {
code: 1,
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'git not installed',
})
const results = await this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
assert.isTruthy(results.errors)
errorAssert.assertError(results.errors[0], 'MISSING_DEPENDENCIES', {
'dependencies[0].name': 'git',
})
}
protected static async errorsIfNotInGitRepo() {
CommandServiceImpl.fakeCommand('git status', {
code: 128,
stderr: 'fatal: not a git repository (or any of the parent directories): .git',
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'not in git repo',
})
const promise = this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
await this.waitForInput()
await this.ui.sendInput('n')
const results = await promise
assert.isTruthy(results.errors)
errorAssert.assertError(results.errors[0], 'DEPLOY_FAILED', {
stage: 'git',
})
}
protected static async canCreateGitRepoIfNeeded() {
CommandServiceImpl.fakeCommand('git status', {
code: 128,
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'creates git repo',
})
const promise = this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
await this.waitForInput()
CommandServiceImpl.fakeCommand('git status', {
code: 0,
})
await this.ui.sendInput('y')
const results = await promise
assert.isFalsy(results.errors)
}
protected static async errorsWhenNotLoggedIntoHerkou() {
CommandServiceImpl.fakeCommand('grep api.heroku.com ~/.netrc', {
code: 1,
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'not logged into heroku',
})
const results = await this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
assert.isTruthy(results.errors)
errorAssert.assertError(results.errors[0], 'DEPLOY_FAILED', {
stage: 'heroku',
})
}
protected static async failsWhenDeclineToCreateProcFile() {
diskUtil.deleteFile(this.resolvePath('Procfile'))
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'decline proc file',
})
const promise = this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
await this.waitForInput()
assert.doesInclude(this.ui.invocations, {
command: 'confirm',
})
await this.ui.sendInput('n')
const results = await promise
assert.isTruthy(results.errors)
errorAssert.assertError(results.errors[0], 'DEPLOY_FAILED', {
stage: 'procfile',
})
}
protected static async createsValidProcFile() {
diskUtil.deleteFile(this.resolvePath('Procfile'))
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'valid proc file',
})
const promise = this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
await this.waitForInput()
await this.ui.sendInput('y')
const results = await promise
assert.isFalsy(results.errors)
const match = testUtil.assertFileByNameInGeneratedFiles(
'Procfile',
results.files
)
const contents = diskUtil.readFile(match)
assert.isEqual(contents, 'worker: npm run boot')
}
protected static async failsWhenDeclineToCreateRemoteBranch() {
CommandServiceImpl.fakeCommand('git ls-remote heroku', {
code: 128,
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'decline to create remote branch',
})
const promise = this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
await this.waitForInput()
assert.doesInclude(this.ui.invocations, {
command: 'confirm',
})
await this.ui.sendInput('n')
const results = await promise
assert.isTruthy(results.errors)
errorAssert.assertError(results.errors[0], 'DEPLOY_FAILED', {
stage: 'remote',
})
}
protected static async asksForHerokuAppName() {
CommandServiceImpl.fakeCommand('git ls-remote heroku', {
code: 128,
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'ask for app name',
})
const promise = this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
await this.waitForInput()
await this.ui.sendInput('y')
await this.waitForInput()
assert.doesInclude(this.ui.invocations, {
command: 'prompt',
options: {
type: 'text',
},
})
await this.ui.sendInput(`good-heroku-name`)
const results = await promise
assert.isFalsy(results.errors)
}
protected static async keepsAskingForAppNameUntilAGoodOneIsSelected() {
CommandServiceImpl.fakeCommand('git ls-remote heroku', {
code: 128,
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'haulted wth bad build',
})
const promise = this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
await this.waitForInput()
assert.doesInclude(this.ui.invocations, {
command: 'confirm',
})
await this.ui.sendInput('y')
await this.waitForInput()
assert.doesInclude(this.ui.invocations, {
command: 'prompt',
options: {
type: 'text',
},
})
await this.ui.sendInput(`bad-heroku-name`)
await this.waitForInput()
await this.ui.sendInput('bad-heroku-name')
await this.waitForInput()
await this.ui.sendInput('good-heroku-name')
const results = await promise
assert.isFalsy(results.errors)
}
protected static async failsWithPendingChangesToCommit() {
CommandServiceImpl.fakeCommand('git status', {
code: 0,
stdout: 'Changes not staged for commit',
})
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'pending changes to commit',
})
const results = await this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
assert.isTruthy(results.errors)
errorAssert.assertError(results.errors[0], 'DEPLOY_FAILED', {
stage: 'git',
})
}
protected static async canDeploySkill() {
await this.FeatureFixture().installCachedFeatures('deploy')
await this.getSkillFixture().registerCurrentSkill({
name: 'can deploy',
})
const results = await this.Action('deploy', 'heroku').execute(
this.fastHerokuOptions
)
assert.isFalsy(results.errors)
}
}