@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
316 lines (267 loc) • 9.2 kB
text/typescript
import AbstractSpruceTest, {
test,
assert,
errorAssert,
suite,
generateId,
} from '@sprucelabs/test-utils'
import {
CommandService,
ExecuteCommandOptions,
} from '../../../../services/CommandService'
import LintService from '../../../../services/LintService'
import StaticTestFinderImpl, {
StaticTestFinder,
} from '../../../../tests/staticToInstanceMigration/StaticTestFinder'
import StaticToInstanceMigratorImpl, {
StaticToInstanceMigrator,
} from '../../../../tests/staticToInstanceMigration/StaticToInstanceMigrator'
import StaticToInstanceTestFileMigratorImpl, {
StaticToInstanceTestFileMigrator,
} from '../../../../tests/staticToInstanceMigration/StaticToInstanceTestFileMigrator'
export default class StaticToInstanceMigratorTest extends AbstractSpruceTest {
private testFinder: FakeStaticTestFinder
private testFileMigrator: FakeFileMigrator
private migrator: StaticToInstanceMigrator
private readFiles: string[] = []
private fakedFileContents: Record<string, string> = {}
private lastWrittenFile?: { destination: string; contents: string }
private spyCommandService: SpyCommandService
public constructor() {
super()
StaticTestFinderImpl.Class = FakeStaticTestFinder
StaticToInstanceTestFileMigratorImpl.Class = FakeFileMigrator
StaticToInstanceMigratorImpl.diskUtil.readFile = (source) => {
this.readFiles.push(source)
return this.fakedFileContents[source] ?? generateId()
}
StaticToInstanceMigratorImpl.diskUtil.writeFile = (
destination: string,
contents: string
) => {
this.lastWrittenFile = {
destination,
contents,
}
}
this.testFinder = StaticTestFinderImpl.Finder() as FakeStaticTestFinder
this.testFileMigrator =
StaticToInstanceTestFileMigratorImpl.Migrator() as FakeFileMigrator
this.spyCommandService = new SpyCommandService()
const lintService = new LintService(
this.cwd,
() => this.spyCommandService
)
this.migrator = StaticToInstanceMigratorImpl.Migrator({
testFinder: this.testFinder,
testFileMigrator: this.testFileMigrator,
lintService,
})
}
protected throwsWithMissing() {
const err = assert.doesThrow(() =>
//@ts-ignore
StaticToInstanceMigratorImpl.Migrator()
)
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
parameters: ['testFinder', 'testFileMigrator', 'lintService'],
})
}
protected async runThrowsWithMissing() {
//@ts-ignore
const err = await assert.doesThrowAsync(() => this.migrator.run())
errorAssert.assertError(err, 'MISSING_PARAMETERS', {
parameters: ['lookupDir'],
})
}
protected async passesLookupDirToTestFinder() {
const path = generateId()
await this.run(path)
assert.isEqual(this.testFinder.lastLookupDir, path)
}
protected async returnsStatsBasedOnTestsFound(results: string[]) {
this.setFakedFinderResults(results)
const stats = await this.run()
assert.isEqualDeep(stats, {
totalTestsUpdated: this.testFinder.fakedResults.length,
totalTestsSkipped: 0,
})
}
protected async passesOneFilesContentsToMigrator(filename: string) {
this.setFakedFinderResults([filename])
await this.run()
assert.isEqualDeep(this.readFiles, [filename])
}
protected async passesResultsOfFileToMigrator() {
this.setFakedFinderResults(['a'])
this.setFakedFileContents({
a: generateId(),
})
await this.run()
this.assertContentsPassedToFileMigratorEquals([
this.fakedFileContents['a'],
])
}
protected async passesResultsOfMultipleFilesToMigrator() {
const contents1 = generateId()
const contents2 = generateId()
this.setFakedFinderResults(['what', 'the'])
this.setFakedFileContents({
what: contents1,
the: contents2,
})
await this.run()
this.assertContentsPassedToFileMigratorEquals([contents1, contents2])
}
protected async writesResponseOfMigrate() {
const filename = generateId()
this.setFakedFinderResults([filename])
this.setFakedFileContents({
[filename]: generateId(),
})
await this.run()
assert.isEqualDeep(this.lastWrittenFile, {
destination: filename,
contents: this.testFileMigrator.fakedMigrateResponse,
})
}
protected async returnsSkippedIfMigratedIsTheSame() {
this.setFakedFinderResults(['a'])
const contents = generateId()
this.setFakedFileContents({
a: contents,
})
this.setMigrateFileResponse(contents)
const stats = await this.run()
assert.isEqualDeep(stats, {
totalTestsUpdated: 0,
totalTestsSkipped: 1,
})
}
protected async countsSkippedAndMatched() {
const contents1 = generateId()
const contents2 = generateId()
this.setFakedFinderResults(['what', 'the', 'heck'])
this.setFakedFileContents({
what: contents1,
the: contents2,
heck: generateId(),
})
this.testFileMigrator.fakedMigrateResponsesByContents = {
[contents1]: contents1,
[contents2]: contents2,
}
const stats = await this.run()
assert.isEqualDeep(stats, {
totalTestsUpdated: 1,
totalTestsSkipped: 2,
})
}
protected async doesNotWriteFileThatDidNotChange() {
this.setFakedFinderResults(['a'])
const contents = generateId()
this.setFakedFileContents({
a: contents,
})
this.setMigrateFileResponse(contents)
await this.run()
assert.isUndefined(this.lastWrittenFile)
}
protected async lintsMigratedFiles() {
await this.run()
assert.isTrue(this.spyCommandService.didExecute)
assert.doesInclude(
this.spyCommandService.lastCommand,
`await cli.lintFiles(['**/*.ts'])`
)
}
protected async shouldLintAfterMigrating() {
this.setFakedFinderResults(['match'])
this.setFakedFileContents({
match: generateId(),
})
StaticToInstanceMigratorImpl.diskUtil.writeFile = () => {
assert.isFalse(
this.spyCommandService.didExecute,
'Should not lint yet'
)
}
await this.run()
}
private setMigrateFileResponse(contents: string) {
this.testFileMigrator.fakedMigrateResponse = contents
}
private assertContentsPassedToFileMigratorEquals(expected: string[]) {
assert.isEqualDeep(
this.testFileMigrator.contentsPassedToMigrate,
expected
)
}
private setFakedFileContents(contents: Record<string, string>) {
this.fakedFileContents = contents
}
private setFakedFinderResults(results: string[]) {
this.testFinder.fakedResults = results
}
private async run(path?: string) {
return await this.migrator.run(path ?? generateId())
}
}
class FakeStaticTestFinder implements StaticTestFinder {
public lastLookupDir?: string
public fakedResults: string[] = []
public async find(lookupDir: string): Promise<string[]> {
this.lastLookupDir = lookupDir
return this.fakedResults
}
}
class FakeFileMigrator implements StaticToInstanceTestFileMigrator {
public contentsPassedToMigrate: string[] = []
public fakedMigrateResponse = generateId()
public fakedMigrateResponsesByContents: Record<string, string> = {}
public migrate(contents: string): string {
this.contentsPassedToMigrate.push(contents)
return (
this.fakedMigrateResponsesByContents[contents] ??
this.fakedMigrateResponse
)
}
}
class SpyCommandService implements CommandService {
public didExecute = false
public lastCommand?: string
public async execute(
cmd: string,
options?: ExecuteCommandOptions
): Promise<{ stdout: string }> {
this.lastCommand = options?.args?.[1] ?? cmd
this.didExecute = true
return {
stdout: generateId(),
}
}
public getCwd(): string {
return ''
}
public setCwd(_cwd: string): void {}
public kill(): void {}
public pid(): number | undefined {
return 0
}
}