eltro/test/cli.test.mjs

1088 lines
42 KiB
JavaScript

import fsPromise from 'fs/promises'
import path from 'path'
import t from '../lib/eltro.mjs'
import assert from '../lib/assert.mjs'
import Watcher, { EVENT_REMOVE, EVENT_UPDATE } from '../lib/watch/index.mjs'
import { stub } from '../lib/sinon.mjs'
import { CLI, MESSAGE_FILES_PAYLOAD, MESSAGE_FILES_REQUEST, MESSAGE_RUN_FINISHED, createMessage, fileMatches } from '../lib/cli.mjs'
const masterSlave = [
'master',
'slave'
]
function createSafeCli(e, overrides = { }) {
overrides.cluster = overrides.cluster || { isWorker: false }
return new CLI(e, overrides)
}
t.describe('CLI', function() {
let cli = createSafeCli()
t.describe('#constructor()', function() {
t.test('give default options', function() {
const eltro = { a: 1 }
const logger = { b: 2 }
const cluster = { c: 3 }
const process = { d: 4 }
const importer = { e: 5 }
let cliTest = createSafeCli(eltro, { logger, cluster, process, importer })
assert.strictEqual(cliTest.reporter, 'list')
assert.strictEqual(cliTest.ignoreOnly, false)
assert.strictEqual(cliTest.timeout, 2000)
assert.strictEqual(cliTest.watch, null)
assert.strictEqual(cliTest.run, 'test')
assert.strictEqual(cliTest.isSlave, false)
assert.deepEqual(cliTest.targets, ['test/**'])
assert.deepEqual(cliTest.files, [])
assert.notOk(cliTest.errored)
assert.strictEqual(cliTest.e, eltro)
assert.strictEqual(cliTest.logger, logger)
assert.strictEqual(cliTest.cluster, cluster)
assert.strictEqual(cliTest.process, process)
assert.strictEqual(cliTest.importer, importer)
})
t.test('should detect isSlave from cluster', function() {
const cluster = { isWorker: true }
let cliTest = createSafeCli(null, { cluster })
assert.strictEqual(cliTest.isSlave, true)
})
})
/*****************************************
* #parseOptions()
*****************************************/
t.describe('#parseOptions()', function() {
t.beforeEach(function() {
cli.loadDefaults()
})
t.test('should not do anything if no options', async function() {
await cli.parseOptions([])
assert.strictEqual(cli.reporter, 'list')
})
t.test('should support overriding reporter with shorthand option', async function() {
await cli.parseOptions(['-r', 'dot'])
assert.strictEqual(cli.reporter, 'dot')
})
t.test('should support overriding reporter with long option', async function() {
await cli.parseOptions(['--reporter', 'dot'])
assert.strictEqual(cli.reporter, 'dot')
})
t.test('should support enabling ignore-only long option', async function() {
await cli.parseOptions(['--ignore-only', '-r', 'dot'])
assert.strictEqual(cli.ignoreOnly, true)
})
t.test('should support reporter list', async function() {
await cli.parseOptions(['-r', 'list'])
assert.strictEqual(cli.reporter, 'list')
})
t.test('should mark errored if missing reporter', async function() {
let err = await assert.isRejected(cli.parseOptions(['--reporter']))
assert.match(err.message, /reporter/i)
})
t.test('should mark errored if invalid reporter', async function() {
let err = await assert.isRejected(cli.parseOptions(['--reporter', 'test']))
assert.match(err.message, /reporter/i)
})
t.test('should support overriding timeout with shorthand option', async function() {
await cli.parseOptions(['-t', '1000'])
assert.strictEqual(cli.timeout, 1000)
})
t.test('should support overriding timeout with long option', async function() {
await cli.parseOptions(['--timeout', '250'])
assert.strictEqual(cli.timeout, 250)
})
t.test('should mark errored if missing timeout', async function() {
let err = await assert.isRejected(cli.parseOptions(['--timeout']))
assert.match(err.message, /timeout/i)
})
t.test('should mark errored if invalid timeout', async function() {
let err = await assert.isRejected(cli.parseOptions(['--timeout', 'test']))
assert.match(err.message, /timeout/i)
})
t.test('should support overriding watch', async function() {
await cli.parseOptions(['-w', 'unittest_test1'])
assert.strictEqual(cli.watch, 'unittest_test1')
})
t.test('should support overriding watch with long option', async function() {
await cli.parseOptions(['--watch', 'unittest_test1'])
assert.strictEqual(cli.watch, 'unittest_test1')
})
t.test('should fail setting watch if value is missing', async function() {
let err = await assert.isRejected(cli.parseOptions(['--watch']))
assert.strictEqual(cli.watch, null)
assert.match(err.message, /watch/i)
})
t.test('should fail setting watch if value is parameter', async function() {
let err = await assert.isRejected(cli.parseOptions(['-w', '--reporter', 'list']))
assert.strictEqual(cli.watch, null)
assert.match(err.message, /watch/i)
})
t.test('should support overriding run', async function() {
await cli.parseOptions(['-n', 'unittest_run1'])
assert.strictEqual(cli.run, 'unittest_run1')
})
t.test('should support overriding run with long option', async function() {
await cli.parseOptions(['--npm', 'unittest_run1'])
assert.strictEqual(cli.run, 'unittest_run1')
})
t.test('should fail setting npm if value is missing', async function() {
let err = await assert.isRejected(cli.parseOptions(['--npm']))
assert.strictEqual(cli.run, 'test')
assert.match(err.message, /npm/i)
})
t.test('should fail setting npm if value is parameter', async function() {
let err = await assert.isRejected(cli.parseOptions(['-n', '--reporter', 'list']))
assert.strictEqual(cli.run, 'test')
assert.match(err.message, /npm/i)
})
t.test('when using run and no target, leave target empty', async function() {
await cli.parseOptions(['--npm', 'unittest_run1'])
assert.strictEqual(cli.targets.length, 0)
})
t.test('should add file to targets', async function() {
await cli.parseOptions(['test'])
assert.deepEqual(cli.targets, ['test'])
})
t.test('should add file to targets no matter where it is', async function() {
await cli.parseOptions(['test', '-r', 'list', 'test2'])
assert.deepEqual(cli.targets, ['test', 'test2'])
})
t.test('should default add test to target if no target', async function() {
await cli.parseOptions(['-r', 'list'])
assert.deepEqual(cli.targets, ['test/**'])
})
t.test('should mark errored if invalid shorthand option', async function() {
let err = await assert.isRejected(cli.parseOptions(['-A']))
assert.match(err.message, /unknown/i)
})
t.test('should mark errored if invalid longhand option', async function() {
let err = await assert.isRejected(cli.parseOptions(['--asdf']))
assert.match(err.message, /unknown/i)
})
})
/*****************************************
* #startWatcher()
*****************************************/
t.describe('#startWatcher()', function() {
let cli
let logger
t.afterEach(function() {
if (cli.watcher) {
return cli.watcher.close()
}
})
t.beforeEach(function() {
logger = {
log: stub(),
error: stub(),
}
cli = createSafeCli(null, { logger })
cli.watch = null
})
t.test('should do nothing if watch is empty or null', async function() {
assert.strictEqual(cli.watcher, null)
await cli.startWatcher()
assert.strictEqual(cli.watcher, null)
cli.watch = ''
await cli.startWatcher()
assert.strictEqual(cli.watcher, null)
})
t.test('should do nothing if isSlave', async function () {
cli.isSlave = true
cli.watch = 'test_quick'
await cli.startWatcher()
assert.strictEqual(cli.watcher, null)
})
t.test('should otherwise call watcher', async function () {
cli.isSlave = false
cli.watch = 'test_quick'
await cli.startWatcher()
assert.ok(cli.watcher)
assert.strictEqual(cli.watcher instanceof Watcher, true)
})
t.test('should fetch folders to watch from package.json', async function() {
cli.watch = 'test_quick'
await cli.startWatcher()
let packageJson = JSON.parse(await fsPromise.readFile('package.json'))
assert.ok(cli.watcher)
assert.deepStrictEqual(
cli.watcher.originalPaths.sort(),
packageJson.watch.test_quick.patterns.sort(),
)
})
t.test('should properly skip node_modules by default', async function() {
cli.watch = 'test_quick'
await cli.startWatcher()
assert.ok(cli.watcher)
assert.strictEqual(typeof cli.watcher.options.skip, 'function')
assert.notOk(cli.watcher.options.skip('filename.js'))
assert.notOk(cli.watcher.options.skip('folder/filename.js'))
assert.notOk(cli.watcher.options.skip('filename.mjs'))
assert.notOk(cli.watcher.options.skip('folder/filename.mjs'))
assert.notOk(cli.watcher.options.skip('filename'))
assert.notOk(cli.watcher.options.skip('folder/filename'))
assert.notOk(cli.watcher.options.skip('filename'))
assert.notOk(cli.watcher.options.skip('folder/filename'))
assert.ok(cli.watcher.options.skip('node_modules'))
})
t.test('should properly filter only javascript files by default', async function() {
cli.watch = 'test_quick'
await cli.startWatcher()
assert.ok(cli.watcher)
assert.strictEqual(typeof cli.watcher.options.filter.test, 'function')
assert.ok(cli.watcher.options.filter.test('filename.js'))
assert.ok(cli.watcher.options.filter.test('folder/filename.js'))
assert.ok(cli.watcher.options.filter.test('filename.mjs'))
assert.ok(cli.watcher.options.filter.test('folder/filename.mjs'))
assert.notOk(cli.watcher.options.filter.test('filename'))
assert.notOk(cli.watcher.options.filter.test('folder/filename'))
assert.notOk(cli.watcher.options.filter.test('filename.jsx'))
assert.notOk(cli.watcher.options.filter.test('folder/filename.jsx'))
assert.notOk(cli.watcher.options.filter.test('filename.xjs'))
assert.notOk(cli.watcher.options.filter.test('folder/filename.xjs'))
assert.notOk(cli.watcher.options.filter.test('filename.doc'))
assert.notOk(cli.watcher.options.filter.test('folder/filename.doc'))
})
t.test('should support custom extension list', async function() {
cli.watch = 'test_quick_js'
await cli.startWatcher()
assert.ok(cli.watcher)
assert.strictEqual(typeof cli.watcher.options.filter.test, 'function')
assert.ok(cli.watcher.options.filter.test('filename.js'))
assert.ok(cli.watcher.options.filter.test('folder/filename.js'))
assert.notOk(cli.watcher.options.filter.test('filename.bla'))
assert.notOk(cli.watcher.options.filter.test('folder/filename.bla'))
assert.notOk(cli.watcher.options.filter.test('filename.mjs'))
assert.notOk(cli.watcher.options.filter.test('folder/filename.mjs'))
assert.notOk(cli.watcher.options.filter.test('filename.doc'))
assert.notOk(cli.watcher.options.filter.test('folder/filename.doc'))
})
t.test('should throw if missing watch', async function() {
cli.watch = 'test_not_exist'
let err = await assert.isRejected(cli.startWatcher())
assert.match(err.message, /missing/i)
assert.match(err.message, /test_not_exist/i)
})
t.test('should throw if invalid extensions', async function() {
cli.watch = 'test_invalid_extensions'
let err = await assert.isRejected(cli.startWatcher())
assert.match(err.message, /extension/i)
assert.match(err.message, /test_invalid_extensions/i)
})
})
/*****************************************
* #fileMatchesTarget()
*****************************************/
t.describe('#fileMatchesTarget()', function() {
t.test('should match files correctly based on extension in folder', function() {
cli.targets = ['test/testtree/folder1/*.txt']
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.txt.mjs'))
})
t.test('should match files correctly only in that folder', function() {
cli.targets = ['test/*.txt']
assert.ok(cli.fileMatchesTarget('test/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/test/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/bla/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.txt.mjs'))
})
t.test('should match single file correctly', function() {
cli.targets = ['test/testtree/folder1/sampletest1.temp.mjs']
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs.mjs'))
})
t.test('should match every file in a folder', function() {
cli.targets = ['test/testtree/folder1/']
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
t.test('should work properly if there is a dot in front', function() {
cli.targets = ['./test/testtree/folder1/*.txt']
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.txt.mjs'))
cli.targets = ['./test/testtree/folder1/sampletest1.temp.mjs']
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs.mjs'))
cli.targets = ['./test/testtree/folder1/']
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
t.test('should support start as folder substitute', function() {
cli.targets = ['*/testtree/folder1/']
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.ok(cli.fileMatchesTarget('test1/testtree/folder1/sampletest1.temp.mjs'))
assert.ok(cli.fileMatchesTarget('bla/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
t.test('should support grabbing only files in folder', function() {
cli.targets = ['test/*']
assert.ok(cli.fileMatchesTarget('test/test.mjs'))
assert.ok(cli.fileMatchesTarget('test/test.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test1/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('bla/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
t.test('should support grabbing only pattern files in folder', function() {
cli.targets = ['test/*.mjs']
assert.ok(cli.fileMatchesTarget('test/test.mjs'))
assert.notOk(cli.fileMatchesTarget('test/test.txt'))
assert.ok(cli.fileMatchesTarget('test/test.herp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/test.mjs.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test1/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('bla/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
t.test('should support multiple star pattern', function() {
cli.targets = ['test/*/*.mjs']
assert.ok(cli.fileMatchesTarget('test/bla/test.mjs'))
assert.notOk(cli.fileMatchesTarget('test/bla/test.txt'))
assert.ok(cli.fileMatchesTarget('test/herp/test.herp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/test.mjs.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test1/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('bla/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
cli.targets = ['test/*/sample*.mjs']
assert.ok(cli.fileMatchesTarget('test/bla/sampletest.mjs'))
assert.ok(cli.fileMatchesTarget('test/herp/sample.test.herp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/bla/test.mjs'))
assert.notOk(cli.fileMatchesTarget('test/bla/test.txt'))
assert.notOk(cli.fileMatchesTarget('test/herp/test.herp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/test.mjs.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test1/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('bla/testtree/folder1/bla.txt'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
t.test('should support double star pattern', function() {
cli.targets = ['test/**/*.mjs']
assert.ok(cli.fileMatchesTarget('test/sampletest.mjs'))
assert.ok(cli.fileMatchesTarget('test/sample.test.herp.mjs'))
assert.ok(cli.fileMatchesTarget('test/test.mjs'))
assert.notOk(cli.fileMatchesTarget('test/test.mjs.txt'))
assert.ok(cli.fileMatchesTarget('test/bla/sampletest.mjs'))
assert.ok(cli.fileMatchesTarget('test/herp/sample.test.herp.mjs'))
assert.ok(cli.fileMatchesTarget('test/bla/test.mjs'))
assert.notOk(cli.fileMatchesTarget('test/bla/test.txt'))
assert.ok(cli.fileMatchesTarget('test/herp/test.herp.mjs'))
assert.notOk(cli.fileMatchesTarget('test/test.mjs.txt'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test1/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('bla/testtree/folder1/bla.txt'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
t.test('should support double star pattern at end', function() {
cli.targets = ['test/**']
assert.ok(cli.fileMatchesTarget('test/sampletest.mjs'))
assert.ok(cli.fileMatchesTarget('test/sample.test.herp.mjs'))
assert.ok(cli.fileMatchesTarget('test/test.mjs'))
assert.ok(cli.fileMatchesTarget('test/test.mjs.txt'))
assert.ok(cli.fileMatchesTarget('test/bla/sampletest.mjs'))
assert.ok(cli.fileMatchesTarget('test/herp/sample.test.herp.mjs'))
assert.ok(cli.fileMatchesTarget('test/bla/test.mjs'))
assert.ok(cli.fileMatchesTarget('test/bla/test.txt'))
assert.ok(cli.fileMatchesTarget('test/herp/test.herp.mjs'))
assert.ok(cli.fileMatchesTarget('test/test.mjs.txt'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('test1/testtree/folder1/sampletest1.temp.mjs'))
assert.notOk(cli.fileMatchesTarget('bla/testtree/folder1/bla.txt'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder2/sampletest1.temp.mjs'))
assert.ok(cli.fileMatchesTarget('test/testtree/folder1/bla/bla.mjs'))
})
})
/*****************************************
* #getFiles()
*****************************************/
t.describe('#getFiles()', function() {
t.describe('master', function() {
t.test('should mark errored if empty', async function() {
cli.targets = ['test/testtree/folder1/*.txt']
let files = await cli.getFiles()
assert.strictEqual(cli.files.length, 0)
assert.strictEqual(cli.files, files)
assert.ok(cli.errored)
})
t.test('should support direct file path if exists', async function() {
cli.targets = ['test/testtree/folder1/sampletest1.temp.mjs']
let files = await cli.getFiles()
assert.strictEqual(cli.files.length, 1)
assert.strictEqual(cli.files[0], 'test/testtree/folder1/sampletest1.temp.mjs')
assert.strictEqual(cli.files, files)
})
t.test('should return all files in a directory', async function() {
cli.targets = ['test/testtree/folder1/']
let files = await cli.getFiles()
assert.strictEqual(cli.files.length, 2)
cli.files.sort()
assert.strictEqual(cli.files[0], 'test/testtree/folder1/sampletest1.temp.mjs')
assert.strictEqual(cli.files[1], 'test/testtree/folder1/sampletest2.temp.mjs')
assert.strictEqual(cli.files, files)
})
t.test('should support start as folder substitute', async function() {
cli.targets = ['*/testtree/folder1/']
let files = await cli.getFiles()
assert.strictEqual(cli.files.length, 2)
cli.files.sort()
assert.strictEqual(cli.files[0], 'test/testtree/folder1/sampletest1.temp.mjs')
assert.strictEqual(cli.files[1], 'test/testtree/folder1/sampletest2.temp.mjs')
assert.strictEqual(cli.files, files)
})
t.test('should support grabbing only files in folder', async function() {
cli.targets = ['test/*']
let files = await cli.getFiles()
assert.ok(cli.files.length)
for (let i = 0; i < cli.files.length; i++) {
assert.notOk(cli.files[i].match(/\/folder1\//))
assert.notOk(cli.files[i].match(/\/folder2\//))
}
assert.strictEqual(cli.files, files)
})
t.test('should support grabbing only pattern files in folder', async function() {
cli.targets = ['test/*.test.mjs']
let files = await cli.getFiles()
assert.ok(cli.files.length)
for (let i = 0; i < cli.files.length; i++) {
assert.notOk(cli.files[i].match(/\/folder1\//))
assert.notOk(cli.files[i].match(/\/folder2\//))
}
assert.strictEqual(cli.files, files)
})
t.test('should support multiple star pattern', async function() {
cli.targets = ['test/testtree/*/*.mjs']
let files = await cli.getFiles()
assert.strictEqual(cli.files.length, 4)
cli.files.sort()
assert.deepEqual(cli.files, [
'test/testtree/folder1/sampletest1.temp.mjs',
'test/testtree/folder1/sampletest2.temp.mjs',
'test/testtree/folder2/sampletest3.temp.mjs',
'test/testtree/folder2/sampletest4.temp.mjs',
])
assert.strictEqual(cli.files, files)
cli.targets = ['test/testtree/*/sampletest*.mjs']
files = await cli.getFiles()
assert.strictEqual(cli.files.length, 4)
cli.files.sort()
assert.deepEqual(cli.files, [
'test/testtree/folder1/sampletest1.temp.mjs',
'test/testtree/folder1/sampletest2.temp.mjs',
'test/testtree/folder2/sampletest3.temp.mjs',
'test/testtree/folder2/sampletest4.temp.mjs',
])
assert.strictEqual(cli.files, files)
})
t.test('should support double star pattern', async function() {
cli.targets = ['test/**/*.mjs']
let files = await cli.getFiles()
assert.ok(cli.files.length)
let found = {
sampletest1: false,
sampletest2: false,
sampletest3: false,
sampletest4: false,
sampletest5: false,
cli: false
}
for (let i = 0; i < cli.files.length; i++) {
found.sampletest1 = found.sampletest1 || cli.files[i] === 'test/testtree/folder1/sampletest1.temp.mjs'
found.sampletest2 = found.sampletest2 || cli.files[i] === 'test/testtree/folder1/sampletest2.temp.mjs'
found.sampletest3 = found.sampletest3 || cli.files[i] === 'test/testtree/folder2/sampletest3.temp.mjs'
found.sampletest4 = found.sampletest4 || cli.files[i] === 'test/testtree/folder2/sampletest4.temp.mjs'
found.sampletest5 = found.sampletest5 || cli.files[i] === 'test/testtree/folder2/sampletest5.temp.txt'
found.cli = found.cli || cli.files[i] === 'test/cli.test.mjs'
}
assert.deepEqual(found, {
sampletest1: true,
sampletest2: true,
sampletest3: true,
sampletest4: true,
sampletest5: false,
cli: true
})
assert.strictEqual(cli.files, files)
})
t.test('should support double star pattern end', async function() {
cli.targets = ['test/**']
let files = await cli.getFiles()
assert.ok(cli.files.length)
let found = {
sampletest1: false,
sampletest2: false,
sampletest3: false,
sampletest4: false,
sampletest5: false,
cli: false
}
for (let i = 0; i < cli.files.length; i++) {
found.sampletest1 = found.sampletest1 || cli.files[i] === 'test/testtree/folder1/sampletest1.temp.mjs'
found.sampletest2 = found.sampletest2 || cli.files[i] === 'test/testtree/folder1/sampletest2.temp.mjs'
found.sampletest3 = found.sampletest3 || cli.files[i] === 'test/testtree/folder2/sampletest3.temp.mjs'
found.sampletest4 = found.sampletest4 || cli.files[i] === 'test/testtree/folder2/sampletest4.temp.mjs'
found.sampletest5 = found.sampletest5 || cli.files[i] === 'test/testtree/folder2/sampletest5.temp.txt'
found.cli = found.cli || cli.files[i] === 'test/cli.test.mjs'
}
assert.deepEqual(found, {
sampletest1: true,
sampletest2: true,
sampletest3: true,
sampletest4: true,
sampletest5: true,
cli: true
})
assert.strictEqual(cli.files, files)
})
})
t.describe('slave', function() {
let testCluster
let testProcess
let cli
t.beforeEach(function() {
testCluster = { isWorker: true }
testProcess = { send: stub(), on: stub(), off: stub() }
cli = createSafeCli(null, { cluster: testCluster, process: testProcess })
})
t.test('if cli is slave, ask master for list', function(done) {
const assertFiles = ['file1', 'file2', 'folder1/file3']
cli.getFiles().then(done.finish(function(files) {
assert.deepStrictEqual(files, assertFiles)
assert.ok(testProcess.off.called)
assert.strictEqual(testProcess.off.firstCall[0], 'message')
assert.strictEqual(typeof(testProcess.off.firstCall[1]), 'function')
assert.strictEqual(testProcess.off.firstCall[1], testProcess.on.firstCall[1])
assert.deepStrictEqual(cli.files, assertFiles)
}))
done.safeWrap(function() {
assert.notOk(testProcess.off.called)
assert.strictEqual(testProcess.on.callCount, 1)
assert.strictEqual(testProcess.send.callCount, 1)
assert.strictEqual(testProcess.on.firstCall[0], 'message')
assert.strictEqual(typeof(testProcess.on.firstCall[1]), 'function')
assert.strictEqual(testProcess.send.firstCall[0].messageType, MESSAGE_FILES_REQUEST)
process.nextTick(function() {
testProcess.on.firstCall[1](createMessage(MESSAGE_FILES_PAYLOAD, assertFiles))
})
})
})
})
})
/*****************************************
* # loadFiles()
*****************************************/
t.describe('#loadFiles()', function() {
let testProcess
let cli
let eltro
let importer
t.beforeEach(function() {
eltro = new t.Eltro()
importer = stub()
testProcess = { cwd: stub() }
testProcess.cwd.returns('root')
cli = createSafeCli(eltro, { process: testProcess, importer })
cli.files = ['file1.js']
})
masterSlave.forEach(child => {
t.describe(child, function () {
t.beforeEach(function () {
cli.isWorker = child === 'worker'
})
t.test('should call importer for every js or mjs file', async function() {
const testFiles = ['file1.txt', 'file2.js', path.join('folder', 'file3.mjs')]
cli.files = testFiles
let loaded = []
let filenames = []
importer.returnWith(function(path) {
filenames.push(eltro.activeGroup.name)
loaded.push(path)
return Promise.resolve()
})
assert.strictEqual(eltro.starting, null)
await cli.loadFiles()
assert.ok(eltro.starting)
assert.strictEqual(loaded.length, 2)
assert.match(loaded[0], path.join('root', testFiles[1]))
assert.match(loaded[1], path.join('root', testFiles[2]))
assert.match(filenames[0], testFiles[1])
assert.match(filenames[1], testFiles[2])
})
t.test('on error should throw and wrap in inner error', async function() {
const assertError = new Error('Ano hi no Omoide')
importer.returnWith(function(path) {
throw assertError
})
let err = await assert.isRejected(cli.loadFiles())
assert.match(err.message, /loading/)
assert.strictEqual(err.inner, assertError)
})
})
})
t.describe('master in watch mode', function() {
t.beforeEach(function () {
cli.watch = ['folder1']
})
t.test('should not import anything and resolve successfully', async function() {
importer.returnWith(function() {
throw new Error('should not be called')
})
assert.strictEqual(eltro.starting, null)
await cli.loadFiles()
assert.strictEqual(eltro.starting, null)
assert.notOk(importer.called)
})
})
})
/*****************************************
* # beginRun()
*****************************************/
t.describe('#beginRun()', function() {
let testProcess
let eltro
let cli
t.beforeEach(function() {
testProcess = { send: stub(), on: stub(), off: stub() }
eltro = new t.Eltro()
cli = createSafeCli(eltro, { process: testProcess })
eltro.run = stub()
})
masterSlave.forEach(child => {
t.describe(child, function () {
t.beforeEach(function () {
cli.isSlave = child === 'worker'
})
t.test('should pass options into eltro and run it', async function() {
const assertResult = { a: 1 }
const assertReporter = 'A girl of good family'
const assertIgnoreOnly = 'A girls talk'
const assertTimeout = 'Samurai figher'
cli.reporter = assertReporter
cli.ignoreOnly = assertIgnoreOnly
cli.timeout = assertTimeout
eltro.run.resolves(assertResult)
let result = await cli.beginRun()
assert.strictEqual(result, assertResult)
assert.strictEqual(eltro.reporter, assertReporter)
assert.strictEqual(eltro.ignoreOnly, assertIgnoreOnly)
assert.strictEqual(eltro.__timeout, assertTimeout)
if (child === 'worker') {
assert.ok(testProcess.send.called)
assert.strictEqual(testProcess.send.firstCall[0]?.messageType, MESSAGE_RUN_FINISHED)
assert.strictEqual(testProcess.send.firstCall[0]?.data?.stats, assertResult)
} else {
assert.notOk(testProcess.send.called)
}
})
})
})
t.describe('master in watch mode', function() {
t.beforeEach(function () {
cli.watch = ['folder1']
cli.runProgram = stub()
cli.watcher = { on: stub(), off: stub() }
})
t.test('should wait for stats on process and return that', function(done) {
const assertStats = { a: 1 }
let doneWasRun = false
cli.beginRun().then(done.finish(function(stats) {
assert.deepStrictEqual(stats, assertStats)
assert.strictEqual(cli.runProgram.callCount, 2)
assert.strictEqual(testProcess.off.firstCall[0], 'message')
assert.strictEqual(typeof(testProcess.off.firstCall[1]), 'function')
assert.strictEqual(testProcess.off.firstCall[1], testProcess.on.firstCall[1])
assert.strictEqual(cli.watcher.off.firstCall[0], 'change')
assert.strictEqual(typeof(cli.watcher.off.firstCall[1]), 'function')
assert.strictEqual(cli.watcher.off.firstCall[1], cli.watcher.on.firstCall[1])
assert.strictEqual(cli.watcher.off.secondCall[0], 'changed')
assert.strictEqual(typeof(cli.watcher.off.secondCall[1]), 'function')
assert.strictEqual(cli.watcher.off.secondCall[1], cli.watcher.on.secondCall[1])
doneWasRun = true
}))
done.safeWrap(function() {
assert.notOk(testProcess.off.called)
assert.strictEqual(testProcess.on.callCount, 1)
assert.strictEqual(testProcess.on.firstCall[0], 'message')
assert.strictEqual(typeof(testProcess.on.firstCall[1]), 'function')
assert.strictEqual(cli.watcher.on.callCount, 2)
assert.strictEqual(cli.watcher.on.firstCall[0], 'change')
assert.strictEqual(typeof(cli.watcher.on.firstCall[1]), 'function')
assert.strictEqual(cli.watcher.on.secondCall[0], 'changed')
assert.strictEqual(typeof(cli.watcher.on.secondCall[1]), 'function')
assert.strictEqual(cli.runProgram.callCount, 1)
testProcess.on.firstCall[1](createMessage(MESSAGE_RUN_FINISHED, { stats: assertStats }))
assert.notOk(doneWasRun)
assert.strictEqual(cli.runProgram.callCount, 1)
cli.watcher.on.secondCall[1]()
assert.strictEqual(cli.runProgram.callCount, 2)
cli.ac.abort()
})
})
t.test('should add and remove new files to files that are called in change', function() {
cli.files = ['test/file1.mjs']
cli.targets = ['test/*.mjs']
cli.beginRun()
assert.deepStrictEqual(cli.files, ['test/file1.mjs'])
assert.strictEqual(cli.watcher.on.firstCall[0], 'change')
cli.watcher.on.firstCall[1](EVENT_UPDATE, 'test/file1.mjs')
assert.deepStrictEqual(cli.files, ['test/file1.mjs'])
cli.watcher.on.firstCall[1](EVENT_UPDATE, 'test/bla/file1.mjs')
assert.deepStrictEqual(cli.files, ['test/file1.mjs'])
cli.watcher.on.firstCall[1](EVENT_UPDATE, 'test/file2.mjs')
assert.deepStrictEqual(cli.files, ['test/file1.mjs', 'test/file2.mjs'])
cli.watcher.on.firstCall[1](EVENT_REMOVE, 'test/file2.mjs')
assert.deepStrictEqual(cli.files, ['test/file1.mjs'])
cli.watcher.on.firstCall[1](EVENT_REMOVE, 'test/file1.mjs')
assert.deepStrictEqual(cli.files, [])
})
})
})
t.describe('#runProgram()', function() {
let testProcess
let testCluster
let testChildProcess
let testWorker
let cli
t.beforeEach(function() {
testProcess = { stdout: { write: stub() }, stderr: { write: stub() } }
testWorker = { on: stub(), once: stub(), kill: stub(), send: stub(), stderr: { on: stub() }, stdout: { on: stub() } }
testCluster = { fork: stub().returns(testWorker) }
testChildProcess = { spawn: stub().returns(testWorker) }
cli = createSafeCli(null, { cluster: testCluster, child_process: testChildProcess, process: testProcess })
})
t.describe('in test mode', function() {
t.beforeEach(function() {
cli.run = 'test'
})
t.test('should fork a worker', function() {
assert.notOk(cli.worker)
assert.notOk(testCluster.fork.called)
assert.notOk(testChildProcess.spawn.called)
cli.runProgram()
assert.ok(testCluster.fork.called)
assert.ok(cli.worker)
assert.notOk(testChildProcess.spawn.called)
assert.strictEqual(cli.worker, testWorker)
assert.strictEqual(testWorker.on.firstCall[0], 'message')
assert.strictEqual(testWorker.once.firstCall[0], 'exit')
assert.notOk(cli.worker.stderr.on.called)
assert.notOk(cli.worker.stdout.on.called)
})
t.test('should listen on message and send files on file request', function() {
const assertFiles = [{ a: 1 }]
cli.files = assertFiles
cli.runProgram()
assert.notOk(testWorker.send.called)
cli.worker.on.firstCall[1](createMessage(MESSAGE_FILES_REQUEST))
assert.ok(testWorker.send.called)
assert.strictEqual(testWorker.send.firstCall[0].messageType, MESSAGE_FILES_PAYLOAD)
assert.strictEqual(testWorker.send.firstCall[0].data, cli.files)
})
t.test('should close worker on exit', function() {
cli.runProgram()
assert.ok(cli.worker)
testWorker.once.firstCall[1]()
assert.notOk(cli.worker)
})
t.test('should not null worker on exit if different worker', function() {
const assertNewWorker = { }
cli.runProgram()
cli.worker = assertNewWorker
testWorker.once.firstCall[1]()
assert.strictEqual(cli.worker, assertNewWorker)
})
t.test('multiple calls should cancel', function() {
cli.runProgram()
assert.notOk(testWorker.kill.called)
assert.ok(testCluster.fork.called)
testCluster.fork.reset()
cli.runProgram()
assert.notOk(testCluster.fork.called)
assert.notOk(testWorker.kill.called)
})
})
t.describe('in npm mode', function() {
t.beforeEach(function() {
cli.run = 'somethingelse'
})
t.test('should spawn a worker', function() {
assert.notOk(cli.worker)
assert.notOk(testCluster.fork.called)
assert.notOk(testChildProcess.spawn.called)
cli.runProgram()
assert.notOk(testCluster.fork.called)
assert.ok(cli.worker)
assert.ok(testChildProcess.spawn.called)
assert.strictEqual(testChildProcess.spawn.firstCall[0], 'npm')
assert.deepStrictEqual(testChildProcess.spawn.firstCall[1], ['run', cli.run])
assert.strictEqual(cli.worker, testWorker)
assert.notOk(testWorker.on.called)
assert.strictEqual(testWorker.once.firstCall[0], 'exit')
assert.ok(cli.worker.stderr.on.called)
assert.ok(cli.worker.stdout.on.called)
assert.strictEqual(cli.worker.stderr.on.firstCall[0], 'data')
assert.strictEqual(cli.worker.stdout.on.firstCall[0], 'data')
})
t.test('should output stderr and stdout to process', function() {
const assertStdErrData = 'Kuroda Kenishi'
const assertStdOutData = 'Lugh no Ketsui'
cli.runProgram()
assert.notOk(testProcess.stderr.write.called)
assert.notOk(testProcess.stdout.write.called)
cli.worker.stderr.on.firstCall[1](assertStdErrData)
assert.notOk(testProcess.stdout.write.called)
assert.ok(testProcess.stderr.write.called)
assert.strictEqual(testProcess.stderr.write.firstCall[0], assertStdErrData)
testProcess.stderr.write.reset()
cli.worker.stdout.on.firstCall[1](assertStdOutData)
assert.ok(testProcess.stdout.write.called)
assert.notOk(testProcess.stderr.write.called)
assert.strictEqual(testProcess.stdout.write.firstCall[0], assertStdOutData)
})
t.test('should close worker on exit', function() {
cli.runProgram()
assert.ok(cli.worker)
testWorker.once.firstCall[1]()
assert.notOk(cli.worker)
})
t.test('should not null worker on exit if different worker', function() {
const assertNewWorker = { }
cli.runProgram()
cli.worker = assertNewWorker
testWorker.once.firstCall[1]()
assert.strictEqual(cli.worker, assertNewWorker)
})
t.test('multiple calls should kill', function() {
cli.runProgram()
assert.notOk(testWorker.kill.called)
assert.ok(testChildProcess.spawn.called)
testChildProcess.spawn.reset().returns(testWorker)
cli.runProgram()
assert.ok(testChildProcess.spawn.called)
assert.ok(testWorker.kill.called)
})
})
})
})
t.test('#fileMatches() should support filename matching with glob pattern', async function() {
assert.ok(fileMatches('bla.test.mjs', '*.mjs'))
assert.ok(fileMatches('bla.test.mjs', '*test.mjs'))
assert.ok(fileMatches('bla.test.mjs', 'bla*.mjs'))
assert.notOk(fileMatches('bla.test.mjs', 'bla*.js'))
assert.notOk(fileMatches('bla.test.mjs', '*.js'))
assert.notOk(fileMatches('bla.test.mjs', 'blas*.js'))
})