Commit 20960b7
Changed files (13)
src/core.ts
@@ -205,12 +205,15 @@ export class ProcessPromise extends Promise<ProcessOutput> {
)
child.on('close', (code, signal) => {
- let message = `${stderr || '\n'} at ${__from}`
- message += `\n exit code: ${code}${
- exitCodeInfo(code) ? ' (' + exitCodeInfo(code) + ')' : ''
- }`
- if (signal !== null) {
- message += `\n signal: ${signal}`
+ let message = `exit code: ${code}`
+ if (code != 0 || signal != null) {
+ message = `${stderr || '\n'} at ${__from}`
+ message += `\n exit code: ${code}${
+ exitCodeInfo(code) ? ' (' + exitCodeInfo(code) + ')' : ''
+ }`
+ if (signal != null) {
+ message += `\n signal: ${signal}`
+ }
}
let output = new ProcessOutput({
code,
test/fixtures/cd-parallel-contexts.mjs
@@ -0,0 +1,34 @@
+import { strict as assert } from 'assert'
+import { ProcessPromise } from '../../build/index.js'
+import { runInCtx, getCtx } from '../../build/experimental.js'
+
+let cwd = process.cwd()
+let resolve, reject
+let promise = new ProcessPromise((...args) => ([resolve, reject] = args))
+
+try {
+ fs.mkdirpSync('/tmp/zx-cd-parallel')
+ runInCtx({ ...getCtx() }, async () => {
+ assert.equal($.cwd, cwd)
+ await sleep(10)
+ cd('/tmp/zx-cd-parallel')
+ assert.ok(getCtx().cwd.endsWith('/zx-cd-parallel'))
+ assert.ok($.cwd.endsWith('/zx-cd-parallel'))
+ })
+
+ runInCtx({ ...getCtx() }, async () => {
+ assert.equal($.cwd, cwd)
+ assert.equal(getCtx().cwd, cwd)
+ await sleep(20)
+ assert.equal(getCtx().cwd, cwd)
+ assert.ok($.cwd.endsWith('/zx-cd-parallel'))
+ resolve()
+ })
+
+ await promise
+} catch (e) {
+ assert(!e, e)
+} finally {
+ fs.rmSync('/tmp/zx-cd-parallel', { recursive: true })
+ cd(cwd)
+}
test/fixtures/cd-relative-paths.mjs
@@ -0,0 +1,33 @@
+import { strict as assert } from 'assert'
+
+let cwd = process.cwd()
+assert.equal($.cwd, cwd)
+try {
+ fs.mkdirpSync('/tmp/zx-cd-test/one/two')
+ cd('/tmp/zx-cd-test/one/two')
+ let p1 = $`pwd`
+ assert.ok($.cwd.endsWith('/two'))
+ assert.ok(process.cwd().endsWith('/two'))
+
+ cd('..')
+ let p2 = $`pwd`
+ assert.ok($.cwd.endsWith('/one'))
+ assert.ok(process.cwd().endsWith('/one'))
+
+ cd('..')
+ let p3 = $`pwd`
+ assert.ok(process.cwd().endsWith('/zx-cd-test'))
+ assert.ok($.cwd.endsWith('/tmp/zx-cd-test'))
+
+ let results = (await Promise.all([p1, p2, p3])).map((p) =>
+ path.basename(p.stdout.trim())
+ )
+
+ assert.deepEqual(results, ['two', 'one', 'zx-cd-test'])
+} catch (e) {
+ assert(!e, e)
+} finally {
+ fs.rmSync('/tmp/zx-cd-test', { recursive: true })
+ cd(cwd)
+ assert.equal($.cwd, cwd)
+}
test/fixtures/filename-dirname.mjs
@@ -0,0 +1,4 @@
+import { strict } from 'assert'
+
+strict.equal(path.basename(__filename), 'filename-dirname.mjs')
+strict.equal(path.basename(__dirname), 'fixtures')
test/fixtures/kill-signal.mjs
@@ -0,0 +1,13 @@
+import { strict } from 'assert'
+
+let p = $`while true; do :; done`
+setTimeout(() => p.kill('SIGKILL'), 100)
+let signal
+
+try {
+ await p
+} catch (p) {
+ signal = p.signal
+}
+
+strict.equal(signal, 'SIGKILL')
test/fixtures/kill.mjs
@@ -0,0 +1,5 @@
+let p = nothrow($`sleep 9999`)
+setTimeout(() => {
+ p.kill()
+}, 100)
+await p
test/fixtures/require.mjs
@@ -0,0 +1,4 @@
+import { strict as assert } from 'assert'
+let data = require('../../package.json')
+assert.equal(data.name, 'zx')
+assert.equal(data, require('zx/package.json'))
test/cli.test.js
@@ -12,52 +12,55 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { assert, testFactory } from './test-utils.js'
+import test from 'ava'
+import '../build/globals.js'
-const test = testFactory('cli', import.meta)
+$.verbose = false
-test('supports `-v` flag / prints version', async () => {
- let v = (await $`node build/cli.js -v`).toString().trim()
- assert.equal(v, require('../package.json').version)
+test('supports `-v` flag / prints version', async (t) => {
+ t.regex((await $`node build/cli.js -v`).toString(), /\d+.\d+.\d+/)
})
-test('prints help', async () => {
+test('prints help', async (t) => {
let help
try {
await $`node build/cli.js`
} catch (err) {
help = err.toString().trim()
}
- assert(help.includes('print current zx version'))
+ t.true(help.includes('print current zx version'))
})
-test('supports `--experimental` flag', async () => {
+test('supports `--experimental` flag', async (t) => {
await $`echo 'echo("test")' | node build/cli.js --experimental`
+ t.pass()
})
-test('supports `--quiet` flag / Quiet mode is working', async () => {
+test('supports `--quiet` flag / Quiet mode is working', async (t) => {
let p = await $`node build/cli.js --quiet docs/markdown.md`
- assert(!p.stdout.includes('whoami'))
+ t.true(!p.stdout.includes('whoami'))
})
-test('supports `--shell` flag ', async () => {
+test('supports `--shell` flag ', async (t) => {
let shell = $.shell
- let p = await $`node build/cli.js --shell=${shell} <<< '$\`echo \${$.shell}\`'`
- assert(p.stdout.includes(shell))
+ let p =
+ await $`node build/cli.js --shell=${shell} <<< '$\`echo \${$.shell}\`'`
+ t.true(p.stdout.includes(shell))
})
-test('supports `--prefix` flag ', async () => {
+test('supports `--prefix` flag ', async (t) => {
let prefix = 'set -e;'
- let p = await $`node build/cli.js --prefix=${prefix} <<< '$\`echo \${$.prefix}\`'`
- assert(p.stdout.includes(prefix))
+ let p =
+ await $`node build/cli.js --prefix=${prefix} <<< '$\`echo \${$.prefix}\`'`
+ t.true(p.stdout.includes(prefix))
})
-test('scripts from https', async () => {
+test('scripts from https', async (t) => {
let script = path.resolve('test/fixtures/echo.http')
let server = quiet($`while true; do cat ${script} | nc -l 8080; done`)
let p = await quiet($`node build/cli.js http://127.0.0.1:8080/echo.mjs`)
- assert(p.stdout.includes('test'))
+ t.true(p.stdout.includes('test'))
server.kill()
let err
@@ -66,21 +69,34 @@ test('scripts from https', async () => {
} catch (e) {
err = e
}
- assert(err.stderr.includes('ECONNREFUSED'))
+ t.true(err.stderr.includes('ECONNREFUSED'))
})
-test('scripts with no extension', async () => {
+test('scripts with no extension', async (t) => {
await $`node build/cli.js test/fixtures/no-extension`
- assert.match(
- (await fs.readFile('test/fixtures/no-extension.mjs')).toString(),
- /Test file to verify no-extension didn't overwrite similarly name .mjs file./
+ t.true(
+ /Test file to verify no-extension didn't overwrite similarly name .mjs file./.test(
+ (await fs.readFile('test/fixtures/no-extension.mjs')).toString()
+ )
)
})
-test('The require() is working from stdin', async () => {
+test('require() is working from stdin', async (t) => {
await $`node build/cli.js <<< 'require("./package.json").name'`
+ t.pass()
})
-test('Markdown scripts are working', async () => {
+test('require() is working in ESM', async (t) => {
+ await $`node build/cli.js test/fixtures/require.mjs`
+ t.pass()
+})
+
+test('__filename & __dirname are defined', async (t) => {
+ await $`node build/cli.js test/fixtures/filename-dirname.mjs`
+ t.pass()
+})
+
+test('markdown scripts are working', async (t) => {
await $`node build/cli.js docs/markdown.md`
+ t.pass()
})
test/experimental.test.js
@@ -12,18 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import test from 'ava'
+import '../build/globals.js'
+
+$.verbose = false
+
import {
echo,
retry,
startSpinner,
withTimeout,
} from '../build/experimental.js'
-import { assert, testFactory } from './test-utils.js'
-import chalk from 'chalk'
-const test = testFactory('experimental', import.meta)
-
-test('Retry works', async () => {
+test('Retry works', async (t) => {
let exitCode = 0
let now = Date.now()
try {
@@ -31,11 +32,11 @@ test('Retry works', async () => {
} catch (p) {
exitCode = p.exitCode
}
- assert.equal(exitCode, 123)
- assert(Date.now() >= now + 50 * (5 - 1))
+ t.is(exitCode, 123)
+ t.true(Date.now() >= now + 50 * (5 - 1))
})
-test('withTimeout works', async () => {
+test('withTimeout works', async (t) => {
let exitCode = 0
let signal
try {
@@ -44,26 +45,27 @@ test('withTimeout works', async () => {
exitCode = p.exitCode
signal = p.signal
}
- assert.equal(exitCode, null)
- assert.equal(signal, 'SIGKILL')
+ t.is(exitCode, null)
+ t.is(signal, 'SIGKILL')
let p = await withTimeout(0)`echo 'test'`
- assert.equal(p.stdout.trim(), 'test')
+ t.is(p.stdout.trim(), 'test')
})
-test('echo works', async () => {
- echo(chalk.red('foo'), chalk.green('bar'), chalk.bold('baz'))
- echo`${chalk.red('foo')} ${chalk.green('bar')} ${chalk.bold('baz')}`
+test('echo works', async (t) => {
+ echo(chalk.cyan('foo'), chalk.green('bar'), chalk.bold('baz'))
+ echo`${chalk.cyan('foo')} ${chalk.green('bar')} ${chalk.bold('baz')}`
echo(
- await $`echo ${chalk.red('foo')}`,
+ await $`echo ${chalk.cyan('foo')}`,
await $`echo ${chalk.green('bar')}`,
await $`echo ${chalk.bold('baz')}`
)
+ t.pass()
})
-test('spinner works', async () => {
+test('spinner works', async (t) => {
let s = startSpinner('waiting')
-
await sleep(1000)
s()
+ t.pass()
})
test/full.test.js
@@ -1,17 +0,0 @@
-// Copyright 2022 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import './cli.test.js'
-import './index.test.js'
-import './experimental.test.js'
test/index.test.js
@@ -12,54 +12,56 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import test from 'ava'
import { inspect } from 'node:util'
import chalk from 'chalk'
import { Writable } from 'node:stream'
import { Socket } from 'node:net'
-
-import { assert, testFactory } from './test-utils.js'
+import '../build/globals.js'
import { ProcessPromise } from '../build/index.js'
-import { getCtx, runInCtx } from '../build/context.js'
-const test = testFactory('index', import.meta)
+$.verbose = false
-test('Only stdout is used during command substitution', async () => {
+test('Only stdout is used during command substitution', async (t) => {
let hello = await $`echo Error >&2; echo Hello`
let len = +(await $`echo ${hello} | wc -c`)
- assert(len === 6)
+ t.is(len, 6)
})
-test('Env vars works', async () => {
- process.env.FOO = 'foo'
- let foo = await $`echo $FOO`
- assert(foo.stdout === 'foo\n')
+test('Env vars works', async (t) => {
+ process.env.ZX_TEST_FOO = 'foo'
+ let foo = await $`echo $ZX_TEST_FOO`
+ t.is(foo.stdout, 'foo\n')
})
-test('Env vars is safe to pass', async () => {
- process.env.FOO = 'hi; exit 1'
- await $`echo $FOO`
+test('Env vars is safe to pass', async (t) => {
+ process.env.ZX_TEST_BAR = 'hi; exit 1'
+ await $`echo $ZX_TEST_BAR`
+ t.pass()
})
-test('Arguments are quoted', async () => {
+test('Arguments are quoted', async (t) => {
let bar = 'bar"";baz!$#^$\'&*~*%)({}||\\/'
- assert((await $`echo ${bar}`).stdout.trim() === bar)
+ t.is((await $`echo ${bar}`).stdout.trim(), bar)
})
-test('Undefined and empty string correctly quoted', async () => {
- $`echo ${undefined}`
- $`echo ${''}`
+test('Undefined and empty string correctly quoted', async (t) => {
+ t.verbose = true
+ t.is((await $`echo -n ${undefined}`).toString(), 'undefined')
+ t.is((await $`echo -n ${''}`).toString(), '')
})
-test('Can create a dir with a space in the name', async () => {
+test('Can create a dir with a space in the name', async (t) => {
let name = 'foo bar'
try {
await $`mkdir /tmp/${name}`
} finally {
await fs.rmdir('/tmp/' + name)
}
+ t.pass()
})
-test('Pipefail is on', async () => {
+test('Pipefail is on', async (t) => {
let p
try {
p = await $`cat /dev/not_found | sort`
@@ -67,29 +69,21 @@ test('Pipefail is on', async () => {
console.log('Caught an exception -> ok')
p = e
}
- assert(p.exitCode !== 0)
-})
-
-test('The __filename & __dirname are defined', async () => {
- console.log(__filename, __dirname)
+ t.not(p.exitCode, 0)
})
-test('The toString() is called on arguments', async () => {
+test('The toString() is called on arguments', async (t) => {
let foo = 0
let p = await $`echo ${foo}`
- assert(p.stdout === '0\n')
+ t.is(p.stdout, '0\n')
})
-test('Can use array as an argument', async () => {
- try {
- let files = ['./cli.ts', './test/index.test.js']
- await $`tar czf archive ${files}`
- } finally {
- await $`rm archive`
- }
+test('Can use array as an argument', async (t) => {
+ let args = ['-n', 'foo']
+ t.is((await $`echo ${args}`).toString(), 'foo')
})
-test('Quiet mode is working', async () => {
+test.serial('Quiet mode is working', async (t) => {
let stdout = ''
let log = console.log
console.log = (...args) => {
@@ -97,28 +91,28 @@ test('Quiet mode is working', async () => {
}
await quiet($`echo 'test'`)
console.log = log
- assert(!stdout.includes('echo'))
+ t.is(stdout, '')
})
-test('Pipes are working', async () => {
+test('Pipes are working', async (t) => {
let { stdout } = await $`echo "hello"`
.pipe($`awk '{print $1" world"}'`)
.pipe($`tr '[a-z]' '[A-Z]'`)
- assert(stdout === 'HELLO WORLD\n')
+ t.is(stdout, 'HELLO WORLD\n')
try {
await $`echo foo`.pipe(fs.createWriteStream('/tmp/output.txt'))
- assert((await fs.readFile('/tmp/output.txt')).toString() === 'foo\n')
+ t.is((await fs.readFile('/tmp/output.txt')).toString(), 'foo\n')
let r = $`cat`
fs.createReadStream('/tmp/output.txt').pipe(r.stdin)
- assert((await r).stdout === 'foo\n')
+ t.is((await r).stdout, 'foo\n')
} finally {
await fs.rm('/tmp/output.txt')
}
})
-test('question', async () => {
+test('question', async (t) => {
let p = question('foo or bar? ', { choices: ['foo', 'bar'] })
setImmediate(() => {
@@ -127,10 +121,10 @@ test('question', async () => {
process.stdin.emit('data', '\n')
})
- assert.equal(await p, 'foo')
+ t.is(await p, 'foo')
})
-test('ProcessPromise', async () => {
+test('ProcessPromise', async (t) => {
let contents = ''
let stream = new Writable({
write: function (chunk, encoding, next) {
@@ -140,9 +134,9 @@ test('ProcessPromise', async () => {
})
let p = $`echo 'test'`.pipe(stream)
await p
- assert(p._piped)
- assert.equal(contents, 'test\n')
- assert(p.stderr instanceof Socket)
+ t.true(p._piped)
+ t.is(contents, 'test\n')
+ t.true(p.stderr instanceof Socket)
let err
try {
@@ -150,96 +144,86 @@ test('ProcessPromise', async () => {
} catch (p) {
err = p
}
- assert.equal(
- err.message,
- 'The pipe() method does not take strings. Forgot $?'
- )
+ t.is(err.message, 'The pipe() method does not take strings. Forgot $?')
})
-test('ProcessPromise: inherits native Promise', async () => {
+test('ProcessPromise: inherits native Promise', async (t) => {
const p1 = $`echo 1`
const p2 = p1.then((v) => v)
const p3 = p2.then((v) => v)
const p4 = p3.catch((v) => v)
const p5 = p1.finally((v) => v)
- assert.ok(p1 instanceof Promise)
- assert.ok(p1 instanceof ProcessPromise)
- assert.ok(p2 instanceof ProcessPromise)
- assert.ok(p3 instanceof ProcessPromise)
- assert.ok(p4 instanceof ProcessPromise)
- assert.ok(p5 instanceof ProcessPromise)
- assert.ok(p1 !== p2)
- assert.ok(p2 !== p3)
- assert.ok(p3 !== p4)
- assert.ok(p5 !== p1)
+ t.true(p1 instanceof Promise)
+ t.true(p1 instanceof ProcessPromise)
+ t.true(p2 instanceof ProcessPromise)
+ t.true(p3 instanceof ProcessPromise)
+ t.true(p4 instanceof ProcessPromise)
+ t.true(p5 instanceof ProcessPromise)
+ t.true(p1 !== p2)
+ t.true(p2 !== p3)
+ t.true(p3 !== p4)
+ t.true(p5 !== p1)
})
-test('ProcessOutput thrown as error', async () => {
+test('ProcessOutput thrown as error', async (t) => {
let err
try {
await $`wtf`
} catch (p) {
err = p
}
- assert(err.exitCode > 0)
- assert(err.stderr.includes('/bin/bash: wtf: command not found\n'))
- assert(err[inspect.custom]().includes('Command not found'))
+ t.true(err.exitCode > 0)
+ t.true(err.stderr.includes('/bin/bash: wtf: command not found\n'))
+ t.true(err[inspect.custom]().includes('Command not found'))
})
-test('The pipe() throws if already resolved', async () => {
+test('The pipe() throws if already resolved', async (t) => {
let out,
p = $`echo "Hello"`
await p
try {
out = await p.pipe($`less`)
} catch (err) {
- assert.equal(
+ t.is(
err.message,
`The pipe() method shouldn't be called after promise is already resolved!`
)
}
if (out) {
- assert.fail('Expected failure!')
+ t.fail('Expected failure!')
}
})
-test('ProcessOutput::exitCode do not throw', async () => {
- assert((await $`grep qwerty README.md`.exitCode) !== 0)
- assert((await $`[[ -f ${__filename} ]]`.exitCode) === 0)
+test('await $`cmd`.exitCode does not throw', async (t) => {
+ t.not(await $`grep qwerty README.md`.exitCode, 0)
+ t.is(await $`[[ -f README.md ]]`.exitCode, 0)
})
-test('The nothrow() do not throw', async () => {
+test('The nothrow() do not throw', async (t) => {
let { exitCode } = await nothrow($`exit 42`)
- assert(exitCode === 42)
+ t.is(exitCode, 42)
})
-test('globby available', async () => {
- assert(globby === glob)
- assert(typeof globby === 'function')
- assert(typeof globby.globbySync === 'function')
- assert(typeof globby.globbyStream === 'function')
- assert(typeof globby.generateGlobTasks === 'function')
- assert(typeof globby.isDynamicPattern === 'function')
- assert(typeof globby.isGitIgnored === 'function')
- assert(typeof globby.isGitIgnoredSync === 'function')
+test('globby available', async (t) => {
+ t.is(globby, glob)
+ t.is(typeof globby, 'function')
+ t.is(typeof globby.globbySync, 'function')
+ t.is(typeof globby.globbyStream, 'function')
+ t.is(typeof globby.generateGlobTasks, 'function')
+ t.is(typeof globby.isDynamicPattern, 'function')
+ t.is(typeof globby.isGitIgnored, 'function')
+ t.is(typeof globby.isGitIgnoredSync, 'function')
console.log(chalk.greenBright('globby available'))
- assert(await globby('test/fixtures/*'), [
- 'test/fixtures/interactive.mjs',
- 'test/fixtures/no-extension',
- 'test/fixtures/no-extension.mjs',
- ])
+ t.deepEqual(await globby('*.md'), ['README.md'])
})
-test('fetch', async () => {
- assert(
- await fetch('https://example.com'),
- await fetch('https://example.com', { method: 'GET' })
- )
+test('fetch', async t => {
+ t.regex(await fetch('https://medv.io').then(res => res.text()), /Anton Medvedev/)
})
-test('Executes a script from $PATH', async () => {
+test('Executes a script from $PATH', async (t) => {
const isWindows = process.platform === 'win32'
const oldPath = process.env.PATH
@@ -262,106 +246,33 @@ test('Executes a script from $PATH', async () => {
process.env.PATH = oldPath
fs.rmSync('/tmp/script-from-path')
}
+ t.pass()
})
-test('The cd() works with relative paths', async () => {
- let cwd = process.cwd()
- assert.equal($.cwd, cwd)
- try {
- fs.mkdirpSync('/tmp/zx-cd-test/one/two')
- cd('/tmp/zx-cd-test/one/two')
- let p1 = $`pwd`
- assert.ok($.cwd.endsWith('/two'))
- assert.ok(process.cwd().endsWith('/two'))
-
- cd('..')
- let p2 = $`pwd`
- assert.ok($.cwd.endsWith('/one'))
- assert.ok(process.cwd().endsWith('/one'))
-
- cd('..')
- let p3 = $`pwd`
- assert.ok(process.cwd().endsWith('/zx-cd-test'))
- assert.ok($.cwd.endsWith('/tmp/zx-cd-test'))
-
- let results = (await Promise.all([p1, p2, p3])).map((p) =>
- path.basename(p.stdout.trim())
- )
-
- assert.deepEqual(results, ['two', 'one', 'zx-cd-test'])
- } catch (e) {
- assert(!e, e)
- } finally {
- fs.rmSync('/tmp/zx-cd-test', { recursive: true })
- cd(cwd)
- assert.equal($.cwd, cwd)
- }
+test('The cd() works with relative paths', async (t) => {
+ await $`node build/cli.js test/fixtures/cd-relative-paths.mjs`
+ t.pass()
})
-test('cd() does not affect parallel contexts', async () => {
- let cwd = process.cwd()
- let resolve, reject
- let promise = new ProcessPromise((...args) => ([resolve, reject] = args))
-
- try {
- fs.mkdirpSync('/tmp/zx-cd-parallel')
- runInCtx({ ...getCtx() }, async () => {
- assert.equal($.cwd, cwd)
- await sleep(10)
- cd('/tmp/zx-cd-parallel')
- assert.ok(getCtx().cwd.endsWith('/zx-cd-parallel'))
- assert.ok($.cwd.endsWith('/zx-cd-parallel'))
- })
-
- runInCtx({ ...getCtx() }, async () => {
- assert.equal($.cwd, cwd)
- assert.equal(getCtx().cwd, cwd)
- await sleep(20)
- assert.equal(getCtx().cwd, cwd)
- assert.ok($.cwd.endsWith('/zx-cd-parallel'))
- resolve()
- })
-
- await promise
- } catch (e) {
- assert(!e, e)
- } finally {
- fs.rmSync('/tmp/zx-cd-parallel', { recursive: true })
- cd(cwd)
- }
+test('cd() does not affect parallel contexts', async (t) => {
+ await $`node build/cli.js test/fixtures/cd-parallel-contexts.mjs`
+ t.pass()
})
-test('The kill() method works', async () => {
- let p = nothrow($`sleep 9999`)
- setTimeout(() => {
- p.kill()
- }, 100)
- await p
-})
-
-test('The signal is passed with kill() method', async () => {
- let p = $`while true; do :; done`
- setTimeout(() => p.kill('SIGKILL'), 100)
- let signal
- try {
- await p
- } catch (p) {
- signal = p.signal
- }
- assert.equal(signal, 'SIGKILL')
+test('The kill() method works', async (t) => {
+ await $`node build/cli.js test/fixtures/kill.mjs`
+ t.pass()
})
-test('YAML works', async () => {
- assert.deepEqual(YAML.parse(YAML.stringify({ foo: 'bar' })), { foo: 'bar' })
- console.log(chalk.greenBright('YAML works'))
+test('The signal is passed with kill() method', async (t) => {
+ await $`node build/cli.js test/fixtures/kill-signal.mjs`
+ t.pass()
})
-test('which available', async () => {
- assert.equal(which.sync('npm'), await which('npm'))
+test('YAML works', async (t) => {
+ t.deepEqual(YAML.parse(YAML.stringify({ foo: 'bar' })), { foo: 'bar' })
})
-test('require() is working in ESM', async () => {
- let data = require('../package.json')
- assert.equal(data.name, 'zx')
- assert.equal(data, require('zx/package.json'))
+test('which available', async (t) => {
+ t.is(which.sync('npm'), await which('npm'))
})
test/test-utils.js
@@ -1,113 +0,0 @@
-// Copyright 2022 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import chalk from 'chalk'
-import { fileURLToPath } from 'node:url'
-import { relative } from 'node:path'
-import { setTimeout as sleep } from 'node:timers/promises'
-
-export { strict as assert } from 'assert'
-
-let queued = 0
-let passed = 0
-let failed = 0
-let total = 0
-let skipped = 0
-let focused = 0
-
-const singleThread = (fn) => {
- let p = Promise.resolve()
- return async function (...args) {
- return (p = p.catch((_) => _).then(() => fn.call(this, ...args)))
- }
-}
-
-const run = singleThread((cb) => cb())
-
-const warmup = sleep(100)
-
-const log = (name, group, err, file = '') => {
- if (err) {
- console.log(err)
- console.log(file)
- }
- console.log(
- '\n' +
- chalk[err ? 'bgRedBright' : 'bgGreenBright'].black(
- `${chalk.inverse(' ' + group + ' ')} ${name} `
- )
- )
-}
-
-export const test = async function (name, cb, ms, focus, skip) {
- const filter = RegExp(process.argv[3] || '.')
- const { group, meta } = this
- const file = meta ? relative(process.cwd(), fileURLToPath(meta.url)) : ''
-
- if (filter.test(name) || filter.test(group) || filter.test(file)) {
- focused += +!!focus
- queued++
-
- await warmup
- try {
- if (!focused === !focus && !skip) {
- await run(cb)
- passed++
- log(name, group)
- } else {
- skipped++
- }
- } catch (e) {
- log(name, group, e, file)
- failed++
- } finally {
- total++
-
- if (total === queued) {
- printTestDigest()
- }
- }
- }
-}
-
-export const only = async function (name, cb, ms) {
- return test.call(this, name, cb, ms, true, false)
-}
-
-export const skip = async function (name, cb, ms) {
- return test.call(this, name, cb, ms, false, true)
-}
-
-export const testFactory = (group, meta) =>
- Object.assign(test.bind({ group, meta }), {
- test,
- skip,
- only,
- group,
- meta,
- })
-
-export const printTestDigest = () => {
- console.log(
- '\n' +
- chalk.black.bgYellowBright(
- ` zx version is ${require('../package.json').version} `
- ) +
- '\n' +
- chalk.greenBright(` ๐บ tests passed: ${passed} `) +
- (skipped ? chalk.yellowBright(`\n ๐ง skipped: ${skipped} `) : '') +
- (failed ? chalk.redBright(`\n โ failed: ${failed} `) : '')
- )
- failed && process.exit(1)
-}
package.json
@@ -22,8 +22,8 @@
"scripts": {
"fmt": "prettier --write .",
"build": "tsc",
- "test": "tsc && node build/cli.js test/full.test.js",
- "coverage": "c8 --reporter=html npm run test:unit"
+ "test": "tsc && ava",
+ "coverage": "c8 --reporter=html npm test"
},
"dependencies": {
"@types/fs-extra": "^9.0.13",
@@ -31,6 +31,7 @@
"@types/node": "^17.0",
"@types/ps-tree": "^1.1.2",
"@types/which": "^2.0.1",
+ "ava": "^4.2.0",
"chalk": "^5.0.1",
"fs-extra": "^10.1.0",
"globby": "^13.1.1",