@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
249 lines (200 loc) • 7.34 kB
text/typescript
import { diskUtil } from '@sprucelabs/spruce-skill-utils'
import { test, assert } from '@sprucelabs/test-utils'
import WatchFeature from '../../../features/watch/WatchFeature'
import AbstractCliTest from '../../../tests/AbstractCliTest'
import { GeneratedFileOrDir } from '../../../types/cli.types'
export default class WatchingForChangesTest extends AbstractCliTest {
protected static async beforeEach(): Promise<void> {
await super.beforeEach()
diskUtil.createDir(this.resolvePath('dist'))
diskUtil.createDir(this.resolvePath('build'))
}
()
protected static async installsWatchers() {
await this.installWatch()
await this.assertIsFeatureInstalled('watch')
}
()
protected static async notWatchingAtTheStart() {
const cli = await this.installWatch()
const isWatching = await cli.getFeature('watch').isWatching()
assert.isFalse(isWatching)
}
()
protected static async canStartAndStopWatch() {
const cli = await this.installWatch()
const feature = cli.getFeature('watch')
void feature.startWatching()
let isWatching = await feature.isWatching()
assert.isTrue(isWatching)
await feature.stopWatching()
isWatching = await feature.isWatching()
assert.isFalse(isWatching)
}
('does not watch src', 'src', false)
('does watch build', 'build', true)
('does watch dist', 'dist', true)
protected static async watchesInCorrectDir(
path: string,
shouldFire: boolean
) {
const cli = await this.installWatch()
const feature = cli.getFeature('watch')
let fireCount = 0
void cli.on('watcher.did-detect-change', () => {
fireCount++
})
await this.startWatching(feature)
diskUtil.writeFile(
this.resolvePath(path, 'test.ts'),
'console.log("hello world")'
)
await this.stopWatching(feature)
assert.isEqual(fireCount, shouldFire ? 1 : 0)
}
('fires once with one change', 1)
('fires once with two changes', 2)
('fires once with three changes', 3)
protected static async watcherFiresEventWhenASrcFileChanges(
changeCount: number
) {
let fireCount = 0
const cli = await this.installWatch()
const feature = cli.getFeature('watch')
let payloadChanges: any = {}
void cli.on('watcher.did-detect-change', (payload) => {
fireCount++
payloadChanges = payload.changes
})
diskUtil.createDir(this.cwd)
await this.startWatching(feature)
const expectedChanges: any[] = []
for (let idx = 0; idx < changeCount; idx++) {
const filename = `index-${idx}.js`
diskUtil.writeFile(
this.resolvePath('build', filename),
'console.log("hello world")'
)
expectedChanges.push({
id: 'generatedFile',
values: {
action: 'generated',
path: this.resolvePath('build', filename),
name: filename,
},
})
}
await this.stopWatching(feature)
assert.isEqual(fireCount, 1)
assert.isTrue(payloadChanges.length >= changeCount)
for (const expected of expectedChanges) {
assert.doesInclude(payloadChanges, expected)
}
}
()
protected static async canTrackAddingDir() {
await this.watchRunStop(async () => {
const newDirDest = this.resolvePath('build', 'new_dir')
diskUtil.createDir(newDirDest)
const expected: GeneratedFileOrDir[] = [
{
id: 'generatedDir',
values: {
action: 'generated',
name: 'new_dir',
path: this.resolvePath('build', 'new_dir'),
},
},
]
return expected
})
}
()
protected static async canTrackDeletingDir() {
const newDirDest = this.resolvePath('build', 'new_dir')
diskUtil.createDir(newDirDest)
await this.watchRunStop(async () => {
diskUtil.deleteDir(newDirDest)
const expected: GeneratedFileOrDir[] = [
{
id: 'generatedDir',
values: {
action: 'deleted',
name: 'new_dir',
path: this.resolvePath('build', 'new_dir'),
},
},
]
return expected
})
}
()
protected static async canTrackDeletingFile() {
const newFile = this.resolvePath('build', 'test.js')
diskUtil.writeFile(newFile, 'test')
await this.watchRunStop(async () => {
diskUtil.deleteFile(newFile)
const expected: GeneratedFileOrDir[] = [
{
id: 'generatedFile',
values: {
action: 'deleted',
name: 'test.js',
path: this.resolvePath('build', 'test.js'),
},
},
]
return expected
})
}
()
protected static async canTrackDeletingFileInDirectory() {
const newDirDest = this.resolvePath('build', 'new_dir')
diskUtil.createDir(newDirDest)
const newFile = this.resolvePath('build', 'new_dir', 'test.js')
diskUtil.writeFile(newFile, 'test')
await this.watchRunStop(async () => {
diskUtil.deleteFile(newFile)
const expected: GeneratedFileOrDir[] = [
{
id: 'generatedFile',
values: {
action: 'deleted',
name: 'test.js',
path: this.resolvePath('build', 'new_dir', 'test.js'),
},
},
]
return expected
})
}
private static async stopWatching(feature: WatchFeature) {
await this.wait(3000)
await feature.stopWatching()
}
private static async startWatching(feature: WatchFeature) {
void feature.startWatching({ delay: 0 })
await this.wait(1000)
}
protected static async watchRunStop(
runner: () => Promise<GeneratedFileOrDir[]>
) {
const cli = await this.installWatch()
const feature = cli.getFeature('watch')
let payloadChanges: any = {}
void cli.on('watcher.did-detect-change', (payload) => {
payloadChanges = payload.changes
})
await this.startWatching(feature)
const expected: GeneratedFileOrDir[] = await runner()
await this.stopWatching(feature)
for (const e of expected) {
assert.doesInclude(payloadChanges, e)
}
}
private static async installWatch() {
const fixture = this.FeatureFixture()
const cli = await fixture.installFeatures([{ code: 'watch' }])
return cli
}
}