Skip to content

Commit

Permalink
test: measure codecov, add missing tests (#359)
Browse files Browse the repository at this point in the history
* test: measure codecov, add missing tests

* test: relax some asserts

* test: tweak up test utils

* test: fixes

* test: separate tests for experimental api

* test: check withTimeout w/ 0

* test: suppress concurrency

* test: use local server for http test

* test: fix http hang

* test: add test for econnrefused

* test: replace localhost with 127.0.0.1 due to nodejs 17 requirement

* test: check --prefix and --shell flags
  • Loading branch information
antongolub committed Mar 19, 2022
1 parent d7ed8c7 commit a203460
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 80 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/node_modules/
package-lock.json
yarn.lock
coverage
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
"node": ">= 16.0.0"
},
"scripts": {
"test": "node zx.mjs test.mjs"
"test:cov": "c8 --reporter=html npm run test",
"test": "node zx.mjs test/full.test.mjs",
"test:zx": "npm run test zx",
"test:index": "npm run test index"
},
"dependencies": {
"@types/fs-extra": "^9.0.13",
Expand Down
10 changes: 6 additions & 4 deletions src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,14 @@ export async function question(query, options) {
const rl = createInterface({
input: process.stdin,
output: process.stdout,
terminal: true,
completer,
})
const question = (q) => new Promise((resolve) => rl.question(q ?? '', resolve))
let answer = await question(query)
rl.close()
return answer

return new Promise((resolve) => rl.question(query ?? '', (answer) => {
rl.close()
resolve(answer)
}))
}

export async function fetch(url, init) {
Expand Down
60 changes: 60 additions & 0 deletions test/experimental.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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 {echo, retry, startSpinner, withTimeout} from '../src/experimental.mjs'
import {assert, test as t} from './test-utils.mjs'
import chalk from 'chalk'

const test = t.bind(null, 'experimental')

if (test('Retry works')) {
let exitCode = 0
let now = Date.now()
try {
await retry(5, 50)`exit 123`
} catch (p) {
exitCode = p.exitCode
}
assert.equal(exitCode, 123)
assert(Date.now() >= now + 50 * (5 - 1))
}

if (test('withTimeout works')) {
let exitCode = 0
let signal
try {
await withTimeout(100, 'SIGKILL')`sleep 9999`
} catch (p) {
exitCode = p.exitCode
signal = p.signal
}
assert.equal(exitCode, null)
assert.equal(signal, 'SIGKILL')

let p = await withTimeout(0)`echo 'test'`
assert.equal(p.stdout.trim(), 'test')
}

if (test('echo works')) {
echo(chalk.red('foo'), chalk.green('bar'), chalk.bold('baz'))
echo`${chalk.red('foo')} ${chalk.green('bar')} ${chalk.bold('baz')}`
echo(await $`echo ${chalk.red('foo')}`, await $`echo ${chalk.green('bar')}`, await $`echo ${chalk.bold('baz')}`)
}

if (test('spinner works')) {
let s = startSpinner('waiting')

await sleep(1000)
s()
}
6 changes: 6 additions & 0 deletions test/fixtures/echo.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
HTTP/1.1 200 OK
Content-Type: text/javascript; charset=UTF-8
Content-Length: 15
Server: netcat!

$`echo 'test'`
File renamed without changes.
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions test/full.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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 {printTestDigest} from './test-utils.mjs'
await import('./zx.test.mjs')
await import('./index.test.mjs')
await import('./experimental.test.mjs')

printTestDigest()
141 changes: 66 additions & 75 deletions test.mjs → test/index.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {strict as assert} from 'assert'
import {retry, echo, startSpinner, withTimeout } from './src/experimental.mjs'
import {inspect} from 'util'
import chalk from 'chalk'
import {Writable} from 'stream'
import {Socket} from 'net'

let всегоТестов = 0
import {assert, test as t} from './test-utils.mjs'

function test(name) {
let фильтр = process.argv[3] || '.'
if (RegExp(фильтр).test(name)) {
console.log('\n' + chalk.bgGreenBright.black(` ${name} `))
всегоТестов++
return true
}
return false
}
const test = t.bind(null, 'index')

if (test('Only stdout is used during command substitution')) {
let hello = await $`echo Error >&2; echo Hello`
Expand Down Expand Up @@ -86,29 +80,20 @@ if (test('The toString() is called on arguments')) {

if (test('Can use array as an argument')) {
try {
let files = ['./zx.mjs', './test.mjs']
let files = ['./zx.mjs', './test/index.test.mjs']
await $`tar czf archive ${files}`
} finally {
await $`rm archive`
}
}

if (test('Scripts with no extension')) {
await $`node zx.mjs tests/no-extension`
assert.match((await fs.readFile('tests/no-extension.mjs')).toString(), /Test file to verify no-extension didn't overwrite similarly name .mjs file./)
}

if (test('The require() is working from stdin')) {
await $`node zx.mjs <<< 'require("./package.json").name'`
}

if (test('Markdown scripts are working')) {
await $`node zx.mjs docs/markdown.md`
}

if (test('Quiet mode is working')) {
let {stdout} = await $`node zx.mjs --quiet docs/markdown.md`
assert(!stdout.includes('whoami'))
let stdout = ''
let log = console.log
console.log = (...args) => {stdout += args.join(' ')}
await quiet($`echo 'test'`)
console.log = log
assert(!stdout.includes('echo'))
}

if (test('Pipes are working')) {
Expand All @@ -131,6 +116,41 @@ if (test('Pipes are working')) {
}
}

if (test('question')) {
let p = question('foo or bar? ', {choices: ['foo', 'bar']})

setImmediate(() => {
process.stdin.emit('data', 'fo')
process.stdin.emit('data', '\t')
process.stdin.emit('data', '\n')
})

assert.equal(await p, 'foo')
}

if (test('ProcessPromise')) {
let contents = ''
let stream = new Writable({
write: function(chunk, encoding, next) {
contents += chunk.toString()
next()
}
})
let p = $`echo 'test'`.pipe(stream)
await p
assert(p._piped)
assert.equal(contents, 'test\n')
assert(p.stderr instanceof Socket)

let err
try {
$`echo 'test'`.pipe('str')
} catch (p) {
err = p
}
assert.equal(err.message, 'The pipe() method does not take strings. Forgot $?')
}

if (test('ProcessOutput thrown as error')) {
let err
try {
Expand All @@ -139,6 +159,8 @@ if (test('ProcessOutput thrown as error')) {
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'))
}

if (test('The pipe() throws if already resolved')) {
Expand Down Expand Up @@ -174,6 +196,19 @@ if (test('globby available')) {
assert(typeof globby.isGitIgnored === 'function')
assert(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'
])
}

if (test('fetch')) {
assert(
await fetch('https://example.com'),
await fetch('https://example.com', {method: 'GET'})
)
}

if (test('Executes a script from $PATH')) {
Expand Down Expand Up @@ -201,6 +236,7 @@ if (test('Executes a script from $PATH')) {
}

if (test('The cd() works with relative paths')) {
let cwd = process.cwd()
try {
fs.mkdirpSync('/tmp/zx-cd-test/one/two')
cd('/tmp/zx-cd-test/one/two')
Expand All @@ -216,7 +252,7 @@ if (test('The cd() works with relative paths')) {
assert.deepEqual(results, ['two', 'one', 'zx-cd-test'])
} finally {
fs.rmSync('/tmp/zx-cd-test', {recursive: true})
cd(__dirname)
cd(cwd)
}
}

Expand Down Expand Up @@ -249,53 +285,8 @@ if (test('which available')) {
assert.equal(which.sync('npm'), await which('npm'))
}

if (test('Retry works (experimental)')) {
let exitCode = 0
let now = Date.now()
try {
await retry(5, 50)`exit 123`
} catch (p) {
exitCode = p.exitCode
}
assert.equal(exitCode, 123)
assert(Date.now() >= now + 50 * (5 - 1))
}

if (test('withTimeout works (experimental)')) {
let exitCode = 0
let signal
try {
await withTimeout(100, 'SIGKILL')`sleep 9999`
} catch (p) {
exitCode = p.exitCode
signal = p.signal
}
assert.equal(exitCode, null)
assert.equal(signal, 'SIGKILL')
}

if (test('echo works (experimental)')) {
echo(chalk.red('foo'), chalk.green('bar'), chalk.bold('baz'))
echo`${chalk.red('foo')} ${chalk.green('bar')} ${chalk.bold('baz')}`
echo(await $`echo ${chalk.red('foo')}`, await $`echo ${chalk.green('bar')}`, await $`echo ${chalk.bold('baz')}`)
}

if (test('spinner works (experimental)')) {
let s = startSpinner('waiting')

await sleep(1000)
s()
}

let version
if (test('require() is working in ESM')) {
let data = require('./package.json')
version = data.version
let data = require('../package.json')
assert.equal(data.name, 'zx')
assert.equal(data, require('zx/package.json'))
}

console.log('\n' +
chalk.black.bgYellowBright(` zx version is ${version} `) + '\n' +
chalk.greenBright(` 🍺 ${всегоТестов} tests passed `)
)
36 changes: 36 additions & 0 deletions test/test-utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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'

export {strict as assert} from 'assert'

let всегоТестов = 0

export function test(group, name) {
let фильтр = process.argv[3] || '.'
if (RegExp(фильтр).test(name) || RegExp(фильтр).test(group)) {
console.log('\n' + chalk.bgGreenBright.black(`${chalk.inverse(' ' + group + ' ')} ${name} `))
всегоТестов++
return true
}
return false
}

export const printTestDigest = () => {
console.log('\n' +
chalk.black.bgYellowBright(` zx version is ${require('../package.json').version} `) + '\n' +
chalk.greenBright(` 🍺 ${всегоТестов} tests passed `)
)
}

0 comments on commit a203460

Please sign in to comment.