Commit d09edf8

Anton Golub <antongolub@antongolub.com>
2024-05-20 15:39:57
test: refactor core tests, add scopes (#814)
1 parent 69e7368
Changed files (1)
test/core.test.js
@@ -22,599 +22,633 @@ import { ProcessPromise, ProcessOutput } from '../build/index.js'
 import '../build/globals.js'
 
 describe('core', () => {
-  test('only stdout is used during command substitution', async () => {
-    let hello = await $`echo Error >&2; echo Hello`
-    let len = +(await $`echo ${hello} | wc -c`)
-    assert.equal(len, 6)
-  })
+  describe('$', () => {
+    test('is a regular function', async () => {
+      const _$ = $.bind(null)
+      let foo = await _$`echo foo`
+      assert.equal(foo.stdout, 'foo\n')
+      assert.ok(typeof $.call === 'function')
+      assert.ok(typeof $.apply === 'function')
+    })
 
-  test('env vars works', async () => {
-    process.env.ZX_TEST_FOO = 'foo'
-    let foo = await $`echo $ZX_TEST_FOO`
-    assert.equal(foo.stdout, 'foo\n')
-  })
+    test('only stdout is used during command substitution', async () => {
+      let hello = await $`echo Error >&2; echo Hello`
+      let len = +(await $`echo ${hello} | wc -c`)
+      assert.equal(len, 6)
+    })
 
-  test('env vars is safe to pass', async () => {
-    process.env.ZX_TEST_BAR = 'hi; exit 1'
-    await $`echo $ZX_TEST_BAR`
-  })
+    test('env vars works', async () => {
+      process.env.ZX_TEST_FOO = 'foo'
+      let foo = await $`echo $ZX_TEST_FOO`
+      assert.equal(foo.stdout, 'foo\n')
+    })
 
-  test('arguments are quoted', async () => {
-    let bar = 'bar"";baz!$#^$\'&*~*%)({}||\\/'
-    assert.equal((await $`echo ${bar}`).stdout.trim(), bar)
-  })
+    test('env vars is safe to pass', async () => {
+      process.env.ZX_TEST_BAR = 'hi; exit 1'
+      await $`echo $ZX_TEST_BAR`
+    })
 
-  test('undefined and empty string correctly quoted', async () => {
-    assert.equal((await $`echo -n ${undefined}`).toString(), 'undefined')
-    assert.equal((await $`echo -n ${''}`).toString(), '')
-  })
+    test('arguments are quoted', async () => {
+      let bar = 'bar"";baz!$#^$\'&*~*%)({}||\\/'
+      assert.equal((await $`echo ${bar}`).stdout.trim(), bar)
+    })
+
+    test('undefined and empty string correctly quoted', async () => {
+      assert.equal((await $`echo -n ${undefined}`).toString(), 'undefined')
+      assert.equal((await $`echo -n ${''}`).toString(), '')
+    })
 
-  test.skip('handles multiline literals', async () => {
-    assert.equal(
-      (
-        await $`echo foo
+    test.skip('handles multiline literals', async () => {
+      assert.equal(
+        (
+          await $`echo foo
      bar
      "baz
       qux"
 `
-      ).toString(),
-      'foo bar baz\n      qux\n'
-    )
-    assert.equal(
-      (
-        await $`echo foo \
+        ).toString(),
+        'foo bar baz\n      qux\n'
+      )
+      assert.equal(
+        (
+          await $`echo foo \
                      bar \
                      baz \
 `
-      ).toString(),
-      'foo bar baz\n'
-    )
-  })
-
-  test('can create a dir with a space in the name', async () => {
-    let name = 'foo bar'
-    try {
-      await $`mkdir /tmp/${name}`
-    } catch {
-      assert.unreachable()
-    } finally {
-      await fs.rmdir('/tmp/' + name)
-    }
-  })
-
-  test('pipefail is on', async () => {
-    let p
-    try {
-      p = await $`cat /dev/not_found | sort`
-    } catch (e) {
-      p = e
-    }
-    assert.notEqual(p.exitCode, 0)
-  })
-
-  test('toString() is called on arguments', async () => {
-    let foo = 0
-    let p = await $`echo ${foo}`
-    assert.equal(p.stdout, '0\n')
-  })
-
-  test('can use array as an argument', async () => {
-    let args = ['-n', 'foo']
-    assert.equal((await $`echo ${args}`).toString(), 'foo')
-  })
+        ).toString(),
+        'foo bar baz\n'
+      )
+    })
 
-  test('quiet() mode is working', async () => {
-    let stdout = ''
-    let log = console.log
-    console.log = (...args) => {
-      stdout += args.join(' ')
-    }
-    await $`echo 'test'`.quiet()
-    console.log = log
-    assert.equal(stdout, '')
-    {
-      // Deprecated.
-      let stdout = ''
-      let log = console.log
-      console.log = (...args) => {
-        stdout += args.join(' ')
+    test('can create a dir with a space in the name', async () => {
+      let name = 'foo bar'
+      try {
+        await $`mkdir /tmp/${name}`
+      } catch {
+        assert.unreachable()
+      } finally {
+        await fs.rmdir('/tmp/' + name)
       }
-      await quiet($`echo 'test'`)
-      console.log = log
-      assert.equal(stdout, '')
-    }
-  })
+    })
 
-  test('handles `input` option', async () => {
-    const p1 = $({ input: 'foo' })`cat`
-    const p2 = $({ input: Readable.from('bar') })`cat`
-    const p3 = $({ input: Buffer.from('baz') })`cat`
-    const p4 = $({ input: p3 })`cat`
-    const p5 = $({ input: await p3 })`cat`
-
-    assert.equal((await p1).stdout, 'foo')
-    assert.equal((await p2).stdout, 'bar')
-    assert.equal((await p3).stdout, 'baz')
-    assert.equal((await p4).stdout, 'baz')
-    assert.equal((await p5).stdout, 'baz')
-  })
+    test('pipefail is on', async () => {
+      let p
+      try {
+        p = await $`cat /dev/not_found | sort`
+      } catch (e) {
+        p = e
+      }
+      assert.notEqual(p.exitCode, 0)
+    })
 
-  test('requires $.shell to be specified', async () => {
-    await within(() => {
-      $.shell = undefined
-      assert.throws(() => $`echo foo`, /shell/)
+    test('toString() is called on arguments', async () => {
+      let foo = 0
+      let p = await $`echo ${foo}`
+      assert.equal(p.stdout, '0\n')
     })
-  })
 
-  test('`$.sync()` provides synchronous API', () => {
-    const o1 = $.sync`echo foo`
-    const o2 = $({ sync: true })`echo foo`
-    assert.equal(o1.stdout, 'foo\n')
-    assert.equal(o2.stdout, 'foo\n')
-  })
+    test('can use array as an argument', async () => {
+      let args = ['-n', 'foo']
+      assert.equal((await $`echo ${args}`).toString(), 'foo')
+    })
 
-  test('pipes are working', async () => {
-    let { stdout } = await $`echo "hello"`
-      .pipe($`awk '{print $1" world"}'`)
-      .pipe($`tr '[a-z]' '[A-Z]'`)
-    assert.equal(stdout, 'HELLO WORLD\n')
-
-    try {
-      await $`echo foo`.pipe(fs.createWriteStream('/tmp/output.txt'))
-      assert.equal((await fs.readFile('/tmp/output.txt')).toString(), 'foo\n')
-
-      let r = $`cat`
-      fs.createReadStream('/tmp/output.txt').pipe(r.stdin)
-      assert.equal((await r).stdout, 'foo\n')
-    } finally {
-      await fs.rm('/tmp/output.txt')
-    }
-  })
+    test('requires $.shell to be specified', async () => {
+      await within(() => {
+        $.shell = undefined
+        assert.throws(() => $`echo foo`, /shell/)
+      })
+    })
 
-  test('provides presets', async () => {
-    const $$ = $({ nothrow: true })
-    assert.equal((await $$`exit 1`).exitCode, 1)
-  })
+    test('malformed cmd error', async () => {
+      assert.throws(() => $`\033`, /malformed/i)
+    })
 
-  test('ProcessPromise', async () => {
-    let contents = ''
-    let stream = new Writable({
-      write: function (chunk, encoding, next) {
-        contents += chunk.toString()
-        next()
-      },
-    })
-    let p = $`echo 'test'`.pipe(stream)
-    await p
-    assert.ok(p._piped)
-    assert.equal(contents, 'test\n')
-    assert.ok(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 $?'
-    )
-  })
+    test('snapshots works', async () => {
+      await within(async () => {
+        $.prefix += 'echo success;'
+        let p = $`:`
+        $.prefix += 'echo fail;'
+        let out = await p
+        assert.equal(out.stdout, 'success\n')
+        assert.doesNotMatch(out.stdout, /fail/)
+      })
+    })
 
-  test('ProcessPromise: inherits native Promise', async () => {
-    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(p1 instanceof Promise)
-    assert(p1 instanceof ProcessPromise)
-    assert(p2 instanceof ProcessPromise)
-    assert(p3 instanceof ProcessPromise)
-    assert(p4 instanceof ProcessPromise)
-    assert(p5 instanceof ProcessPromise)
-    assert.ok(p1 !== p2)
-    assert.ok(p2 !== p3)
-    assert.ok(p3 !== p4)
-    assert.ok(p5 !== p1)
-  })
+    test('$ thrown as error', async () => {
+      let err
+      try {
+        await $`wtf`
+      } catch (p) {
+        err = p
+      }
+      assert.ok(err.exitCode > 0)
+      assert.ok(err.stderr.includes('wtf: command not found'))
+      assert.ok(err[inspect.custom]().includes('Command not found'))
+    })
 
-  test('ProcessPromise: implements toString()', async () => {
-    const p = $`echo foo`
-    assert.equal((await p).toString(), 'foo\n')
-  })
+    test('error event is handled', async () => {
+      await within(async () => {
+        $.cwd = 'wtf'
+        try {
+          await $`pwd`
+          assert.unreachable('should have thrown')
+        } catch (err) {
+          assert.ok(err instanceof ProcessOutput)
+          assert.match(err.message, /No such file or directory/)
+        }
+      })
+    })
 
-  test('ProcessPromise: implements json()', async () => {
-    const p = $`echo '{"key":"value"}'`
-    assert.deepEqual((await p).json(), { key: 'value' })
-  })
+    test('await $`cmd`.exitCode does not throw', async () => {
+      assert.notEqual(await $`grep qwerty README.md`.exitCode, 0)
+      assert.equal(await $`[[ -f README.md ]]`.exitCode, 0)
+    })
 
-  test('ProcessPromise: implements text()', async () => {
-    const p = $`echo foo`
-    assert.equal((await p).toString(), 'foo\n')
-  })
+    test('`$.sync()` provides synchronous API', () => {
+      const o1 = $.sync`echo foo`
+      const o2 = $({ sync: true })`echo foo`
+      assert.equal(o1.stdout, 'foo\n')
+      assert.equal(o2.stdout, 'foo\n')
+    })
 
-  test('ProcessPromise: implements buffer()', async () => {
-    const p = $`echo foo`
-    assert.equal((await p).buffer().compare(Buffer.from('foo\n', 'utf-8')), 0)
-  })
+    describe('$({opts}) API', () => {
+      test('provides presets', async () => {
+        const $$ = $({ nothrow: true })
+        assert.equal((await $$`exit 1`).exitCode, 1)
+      })
 
-  test('ProcessPromise: implements valueOf()', async () => {
-    const p = $`echo foo`
-    assert.equal((await p).valueOf(), 'foo')
-    assert.ok((await p) == 'foo')
-  })
+      test('handles `input` option', async () => {
+        const p1 = $({ input: 'foo' })`cat`
+        const p2 = $({ input: Readable.from('bar') })`cat`
+        const p3 = $({ input: Buffer.from('baz') })`cat`
+        const p4 = $({ input: p3 })`cat`
+        const p5 = $({ input: await p3 })`cat`
+
+        assert.equal((await p1).stdout, 'foo')
+        assert.equal((await p2).stdout, 'bar')
+        assert.equal((await p3).stdout, 'baz')
+        assert.equal((await p4).stdout, 'baz')
+        assert.equal((await p5).stdout, 'baz')
+      })
 
-  test('cd() works with relative paths', async () => {
-    let cwd = process.cwd()
-    try {
-      fs.mkdirpSync('/tmp/zx-cd-test/one/two')
-      cd('/tmp/zx-cd-test/one/two')
-      let p1 = $`pwd`
-      assert.equal($.cwd, undefined)
-      assert.ok(process.cwd().endsWith('/two'))
-
-      cd('..')
-      let p2 = $`pwd`
-      assert.equal($.cwd, undefined)
-      assert.ok(process.cwd().endsWith('/one'))
-
-      cd('..')
-      let p3 = $`pwd`
-      assert.equal($.cwd, undefined)
-      assert.ok(process.cwd().endsWith('/tmp/zx-cd-test'))
-
-      const 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.ok(!e, e)
-    } finally {
-      fs.rmSync('/tmp/zx-cd-test', { recursive: true })
-      cd(cwd)
-    }
-  })
+      test('handles `timeout` and `timeoutSignal`', async () => {
+        let exitCode, signal
+        try {
+          await $({
+            timeout: 10,
+            timeoutSignal: 'SIGKILL',
+          })`sleep 999`
+        } catch (p) {
+          exitCode = p.exitCode
+          signal = p.signal
+        }
+        assert.equal(exitCode, null)
+        assert.equal(signal, 'SIGKILL')
+      })
+    })
 
-  test('cd() does not affect parallel contexts ($.cwdSyncHook enabled)', async () => {
-    syncProcessCwd()
-    const cwd = process.cwd()
-    try {
-      fs.mkdirpSync('/tmp/zx-cd-parallel/one/two')
-      await Promise.all([
-        within(async () => {
-          assert.equal(process.cwd(), cwd)
-          cd('/tmp/zx-cd-parallel/one')
-          await sleep(Math.random() * 15)
-          assert.ok(process.cwd().endsWith('/tmp/zx-cd-parallel/one'))
-        }),
-        within(async () => {
-          assert.equal(process.cwd(), cwd)
-          await sleep(Math.random() * 15)
-          assert.equal(process.cwd(), cwd)
-        }),
-        within(async () => {
-          assert.equal(process.cwd(), cwd)
-          await sleep(Math.random() * 15)
-          $.cwd = '/tmp/zx-cd-parallel/one/two'
-          assert.equal(process.cwd(), cwd)
-          assert.ok(
-            (await $`pwd`).stdout
-              .toString()
-              .trim()
-              .endsWith('/tmp/zx-cd-parallel/one/two')
-          )
-        }),
-      ])
-    } catch (e) {
-      assert.ok(!e, e)
-    } finally {
-      fs.rmSync('/tmp/zx-cd-parallel', { recursive: true })
-      cd(cwd)
-      syncProcessCwd(false)
-    }
-  })
+    test('accepts `stdio`', async () => {
+      let p = $({ stdio: 'ignore' })`echo foo`
 
-  test('cd() fails on entering not existing dir', async () => {
-    assert.throws(() => cd('/tmp/abra-kadabra'))
+      assert.equal((await p).stdout, '')
+    })
   })
 
-  test('cd() accepts ProcessOutput in addition to string', async () => {
-    await within(async () => {
-      const tmpDir = await $`mktemp -d`
-      cd(tmpDir)
-      assert.equal(
-        basename(process.cwd()),
-        basename(tmpDir.toString().trimEnd())
-      )
+  describe('ProcessPromise', () => {
+    test('inherits native Promise', async () => {
+      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(p1 instanceof Promise)
+      assert(p1 instanceof ProcessPromise)
+      assert(p2 instanceof ProcessPromise)
+      assert(p3 instanceof ProcessPromise)
+      assert(p4 instanceof ProcessPromise)
+      assert(p5 instanceof ProcessPromise)
+      assert.ok(p1 !== p2)
+      assert.ok(p2 !== p3)
+      assert.ok(p3 !== p4)
+      assert.ok(p5 !== p1)
     })
-  })
 
-  test('abort() method works', async () => {
-    const p = $({ detached: true })`sleep 999`
-    setTimeout(() => p.abort(), 100)
+    test('resolves with ProcessOutput', async () => {
+      const o = await $`echo foo`
+      assert.ok(o instanceof ProcessOutput)
+    })
 
-    try {
+    test('stdio() works', async () => {
+      let p = $`printf foo`
       await p
-      assert.unreachable('should have thrown')
-    } catch ({ message }) {
-      assert.match(message, /The operation was aborted/)
-    }
-  })
+      assert.throws(() => p.stdin)
+      assert.equal((await p).stdout, 'foo')
 
-  test('accepts optional AbortController', async () => {
-    const ac = new AbortController()
-    const p = $({ ac, detached: true })`sleep 999`
-    setTimeout(() => ac.abort(), 100)
-
-    try {
-      await p
-      assert.unreachable('should have thrown')
-    } catch ({ message }) {
-      assert.match(message, /The operation was aborted/)
-    }
-  })
+      let b = $`read; printf $REPLY`
+      b.stdin.write('bar\n')
+      assert.equal((await b).stdout, 'bar')
+    })
 
-  test('accepts AbortController `signal` separately', async () => {
-    const ac = new AbortController()
-    const signal = ac.signal
-    const p = $({ signal, detached: true })`sleep 999`
-    setTimeout(() => ac.abort(), 100)
+    describe('pipe() API', () => {
+      test('is chainable', async () => {
+        let { stdout } = await $`echo "hello"`
+          .pipe($`awk '{print $1" world"}'`)
+          .pipe($`tr '[a-z]' '[A-Z]'`)
+        assert.equal(stdout, 'HELLO WORLD\n')
+      })
 
-    try {
-      await p
-      assert.unreachable('should have thrown')
-    } catch ({ message }) {
-      assert.match(message, /The operation was aborted/)
-    }
-  })
+      test('accepts Writable', async () => {
+        let contents = ''
+        let stream = new Writable({
+          write: function (chunk, encoding, next) {
+            contents += chunk.toString()
+            next()
+          },
+        })
+        let p = $`echo 'test'`.pipe(stream)
+        await p
+        assert.ok(p._piped)
+        assert.equal(contents, 'test\n')
+        assert.ok(p.stderr instanceof Socket)
+      })
 
-  test('kill() method works', async () => {
-    let p = $`sleep 999`.nothrow()
-    setTimeout(() => {
-      p.kill()
-    }, 100)
-    await p
-  })
+      test('accepts WriteStream', async () => {
+        try {
+          await $`echo foo`.pipe(fs.createWriteStream('/tmp/output.txt'))
+          assert.equal(
+            (await fs.readFile('/tmp/output.txt')).toString(),
+            'foo\n'
+          )
 
-  test('a 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')
-  })
+          let r = $`cat`
+          fs.createReadStream('/tmp/output.txt').pipe(r.stdin)
+          assert.equal((await r).stdout, 'foo\n')
+        } finally {
+          await fs.rm('/tmp/output.txt')
+        }
+      })
 
-  test('within() works', async () => {
-    let resolve, reject
-    let promise = new Promise((...args) => ([resolve, reject] = args))
+      test('checks argument type', async () => {
+        let err
+        try {
+          $`echo 'test'`.pipe('str')
+        } catch (p) {
+          err = p
+        }
+        assert.equal(
+          err.message,
+          'The pipe() method does not take strings. Forgot $?'
+        )
+      })
 
-    function yes() {
-      assert.equal($.verbose, true)
-      resolve()
-    }
+      test('throws if already resolved', async (t) => {
+        let ok = true
+        let p = $`echo "Hello"`
+        await p
+        try {
+          await p.pipe($`less`)
+          ok = false
+        } catch (err) {
+          assert.equal(
+            err.message,
+            `The pipe() method shouldn't be called after promise is already resolved!`
+          )
+        }
+        assert.ok(ok, 'Expected failure!')
+      })
+    })
 
-    assert.equal($.verbose, false)
+    describe('abort()', () => {
+      test('just works', async () => {
+        const p = $({ detached: true })`sleep 999`
+        setTimeout(() => p.abort(), 100)
+
+        try {
+          await p
+          assert.unreachable('should have thrown')
+        } catch ({ message }) {
+          assert.match(message, /The operation was aborted/)
+        }
+      })
 
-    within(() => {
-      $.verbose = true
-    })
-    assert.equal($.verbose, false)
+      test('accepts optional AbortController', async () => {
+        const ac = new AbortController()
+        const p = $({ ac, detached: true })`sleep 999`
+        setTimeout(() => ac.abort(), 100)
+
+        try {
+          await p
+          assert.unreachable('should have thrown')
+        } catch ({ message }) {
+          assert.match(message, /The operation was aborted/)
+        }
+      })
 
-    within(async () => {
-      $.verbose = true
-      setTimeout(yes, 10)
+      test('accepts AbortController `signal` separately', async () => {
+        const ac = new AbortController()
+        const signal = ac.signal
+        const p = $({ signal, detached: true })`sleep 999`
+        setTimeout(() => ac.abort(), 100)
+
+        try {
+          await p
+          assert.unreachable('should have thrown')
+        } catch ({ message }) {
+          assert.match(message, /The operation was aborted/)
+        }
+      })
     })
-    assert.equal($.verbose, false)
 
-    await promise
-  })
+    describe('kill()', () => {
+      test('just works', async () => {
+        let p = $`sleep 999`.nothrow()
+        setTimeout(() => {
+          p.kill()
+        }, 100)
+        await p
+      })
 
-  test('within() restores previous cwd', async () => {
-    let resolve, reject
-    let promise = new Promise((...args) => ([resolve, reject] = args))
+      test('a 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')
+      })
+    })
 
-    let pwd = await $`pwd`
+    test('quiet() mode is working', async () => {
+      let stdout = ''
+      let log = console.log
+      console.log = (...args) => {
+        stdout += args.join(' ')
+      }
+      await $`echo 'test'`.quiet()
+      console.log = log
+      assert.equal(stdout, '')
+      {
+        // Deprecated.
+        let stdout = ''
+        let log = console.log
+        console.log = (...args) => {
+          stdout += args.join(' ')
+        }
+        await quiet($`echo 'test'`)
+        console.log = log
+        assert.equal(stdout, '')
+      }
+    })
 
-    within(async () => {
-      cd('/tmp')
-      setTimeout(async () => {
-        assert.ok((await $`pwd`).stdout.trim().endsWith('/tmp'))
-        resolve()
-      }, 1000)
+    test('nothrow() do not throw', async () => {
+      let { exitCode } = await $`exit 42`.nothrow()
+      assert.equal(exitCode, 42)
+      {
+        // Deprecated.
+        let { exitCode } = await nothrow($`exit 42`)
+        assert.equal(exitCode, 42)
+      }
     })
 
-    assert.equal((await $`pwd`).stdout, pwd.stdout)
-    await promise
-  })
+    describe('halt()', () => {
+      test('just works', async () => {
+        let filepath = `/tmp/${Math.random().toString()}`
+        let p = $`touch ${filepath}`.halt()
+        await sleep(1)
+        assert.ok(
+          !fs.existsSync(filepath),
+          'The cmd called, but it should not have been called'
+        )
+        await p.run()
+        assert.ok(fs.existsSync(filepath), 'The cmd should have been called')
+      })
 
-  test(`within() isolates nested context and returns cb result`, async () => {
-    within(async () => {
-      const res = await within(async () => {
-        $.verbose = true
+      test('await on halted throws', async () => {
+        let p = $`sleep 1`.halt()
+        let ok = true
+        try {
+          await p
+          ok = false
+        } catch (err) {
+          assert.equal(err.message, 'The process is halted!')
+        }
+        assert.ok(ok, 'Expected failure!')
+      })
+    })
 
-        return within(async () => {
-          assert.equal($.verbose, true)
-          $.verbose = false
+    describe('timeout()', () => {
+      test('expiration works', async () => {
+        let exitCode, signal
+        try {
+          await $`sleep 1`.timeout(999)
+        } catch (p) {
+          exitCode = p.exitCode
+          signal = p.signal
+        }
+        assert.equal(exitCode, undefined)
+        assert.equal(signal, undefined)
+      })
 
-          return within(async () => {
-            assert.equal($.verbose, false)
-            $.verbose = true
-            return 'foo'
-          })
-        })
+      test('accepts a signal opt', async () => {
+        let exitCode, signal
+        try {
+          await $`sleep 999`.timeout(10, 'SIGKILL')
+        } catch (p) {
+          exitCode = p.exitCode
+          signal = p.signal
+        }
+        assert.equal(exitCode, null)
+        assert.equal(signal, 'SIGKILL')
       })
-      assert.equal($.verbose, false)
-      assert.equal(res, 'foo')
     })
   })
 
-  test('stdio() works', async () => {
-    let p = $`printf foo`
-    await p
-    assert.throws(() => p.stdin)
-    assert.equal((await p).stdout, 'foo')
+  describe('ProcessOutput', () => {
+    test('implements toString()', async () => {
+      const p = $`echo foo`
+      assert.equal((await p).toString(), 'foo\n')
+    })
 
-    let b = $`read; printf $REPLY`
-    b.stdin.write('bar\n')
-    assert.equal((await b).stdout, 'bar')
-  })
+    test('implements valueOf()', async () => {
+      const p = $`echo foo`
+      assert.equal((await p).valueOf(), 'foo')
+      assert.ok((await p) == 'foo')
+    })
 
-  test('stdio as option', async () => {
-    let p = $({ stdio: 'ignore' })`echo foo`
+    test('implements json()', async () => {
+      const p = $`echo '{"key":"value"}'`
+      assert.deepEqual((await p).json(), { key: 'value' })
+    })
 
-    assert.equal((await p).stdout, '')
-  })
+    test('implements text()', async () => {
+      const p = $`echo foo`
+      assert.equal((await p).toString(), 'foo\n')
+    })
 
-  test('snapshots works', async () => {
-    await within(async () => {
-      $.prefix += 'echo success;'
-      let p = $`:`
-      $.prefix += 'echo fail;'
-      let out = await p
-      assert.equal(out.stdout, 'success\n')
-      assert.doesNotMatch(out.stdout, /fail/)
+    test('implements buffer()', async () => {
+      const p = $`echo foo`
+      assert.equal((await p).buffer().compare(Buffer.from('foo\n', 'utf-8')), 0)
     })
   })
 
-  test('timeout() works', async () => {
-    let exitCode, signal
-    try {
-      await $`sleep 999`.timeout(10, 'SIGKILL')
-    } catch (p) {
-      exitCode = p.exitCode
-      signal = p.signal
-    }
-    assert.equal(exitCode, null)
-    assert.equal(signal, 'SIGKILL')
-  })
+  describe('cd()', () => {
+    test('works with relative paths', async () => {
+      let cwd = process.cwd()
+      try {
+        fs.mkdirpSync('/tmp/zx-cd-test/one/two')
+        cd('/tmp/zx-cd-test/one/two')
+        let p1 = $`pwd`
+        assert.equal($.cwd, undefined)
+        assert.ok(process.cwd().endsWith('/two'))
+
+        cd('..')
+        let p2 = $`pwd`
+        assert.equal($.cwd, undefined)
+        assert.ok(process.cwd().endsWith('/one'))
+
+        cd('..')
+        let p3 = $`pwd`
+        assert.equal($.cwd, undefined)
+        assert.ok(process.cwd().endsWith('/tmp/zx-cd-test'))
+
+        const 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.ok(!e, e)
+      } finally {
+        fs.rmSync('/tmp/zx-cd-test', { recursive: true })
+        cd(cwd)
+      }
+    })
 
-  test('timeout is configurable via opts', async () => {
-    let exitCode, signal
-    try {
-      await $({
-        timeout: 10,
-        timeoutSignal: 'SIGKILL',
-      })`sleep 999`
-    } catch (p) {
-      exitCode = p.exitCode
-      signal = p.signal
-    }
-    assert.equal(exitCode, null)
-    assert.equal(signal, 'SIGKILL')
-  })
+    test('does not affect parallel contexts ($.cwdSyncHook enabled)', async () => {
+      syncProcessCwd()
+      const cwd = process.cwd()
+      try {
+        fs.mkdirpSync('/tmp/zx-cd-parallel/one/two')
+        await Promise.all([
+          within(async () => {
+            assert.equal(process.cwd(), cwd)
+            cd('/tmp/zx-cd-parallel/one')
+            await sleep(Math.random() * 15)
+            assert.ok(process.cwd().endsWith('/tmp/zx-cd-parallel/one'))
+          }),
+          within(async () => {
+            assert.equal(process.cwd(), cwd)
+            await sleep(Math.random() * 15)
+            assert.equal(process.cwd(), cwd)
+          }),
+          within(async () => {
+            assert.equal(process.cwd(), cwd)
+            await sleep(Math.random() * 15)
+            $.cwd = '/tmp/zx-cd-parallel/one/two'
+            assert.equal(process.cwd(), cwd)
+            assert.ok(
+              (await $`pwd`).stdout
+                .toString()
+                .trim()
+                .endsWith('/tmp/zx-cd-parallel/one/two')
+            )
+          }),
+        ])
+      } catch (e) {
+        assert.ok(!e, e)
+      } finally {
+        fs.rmSync('/tmp/zx-cd-parallel', { recursive: true })
+        cd(cwd)
+        syncProcessCwd(false)
+      }
+    })
 
-  test('timeout() expiration works', async () => {
-    let exitCode, signal
-    try {
-      await $`sleep 1`.timeout(999)
-    } catch (p) {
-      exitCode = p.exitCode
-      signal = p.signal
-    }
-    assert.equal(exitCode, undefined)
-    assert.equal(signal, undefined)
-  })
+    test('fails on entering not existing dir', async () => {
+      assert.throws(() => cd('/tmp/abra-kadabra'))
+    })
 
-  test('$ thrown as error', async () => {
-    let err
-    try {
-      await $`wtf`
-    } catch (p) {
-      err = p
-    }
-    assert.ok(err.exitCode > 0)
-    assert.ok(err.stderr.includes('wtf: command not found'))
-    assert.ok(err[inspect.custom]().includes('Command not found'))
+    test('accepts ProcessOutput in addition to string', async () => {
+      await within(async () => {
+        const tmpDir = await $`mktemp -d`
+        cd(tmpDir)
+        assert.equal(
+          basename(process.cwd()),
+          basename(tmpDir.toString().trimEnd())
+        )
+      })
+    })
   })
 
-  test('error event is handled', async () => {
-    await within(async () => {
-      $.cwd = 'wtf'
-      try {
-        await $`pwd`
-        assert.unreachable('should have thrown')
-      } catch (err) {
-        assert.ok(err instanceof ProcessOutput)
-        assert.match(err.message, /No such file or directory/)
+  describe('within()', () => {
+    test('just works', async () => {
+      let resolve, reject
+      let promise = new Promise((...args) => ([resolve, reject] = args))
+
+      function yes() {
+        assert.equal($.verbose, true)
+        resolve()
       }
-    })
-  })
 
-  test('pipe() throws if already resolved', async (t) => {
-    let ok = true
-    let p = $`echo "Hello"`
-    await p
-    try {
-      await p.pipe($`less`)
-      ok = false
-    } catch (err) {
-      assert.equal(
-        err.message,
-        `The pipe() method shouldn't be called after promise is already resolved!`
-      )
-    }
-    assert.ok(ok, 'Expected failure!')
-  })
+      assert.equal($.verbose, false)
 
-  test('await $`cmd`.exitCode does not throw', async () => {
-    assert.notEqual(await $`grep qwerty README.md`.exitCode, 0)
-    assert.equal(await $`[[ -f README.md ]]`.exitCode, 0)
-  })
+      within(() => {
+        $.verbose = true
+      })
+      assert.equal($.verbose, false)
 
-  test('nothrow() do not throw', async () => {
-    let { exitCode } = await $`exit 42`.nothrow()
-    assert.equal(exitCode, 42)
-    {
-      // Deprecated.
-      let { exitCode } = await nothrow($`exit 42`)
-      assert.equal(exitCode, 42)
-    }
-  })
+      within(async () => {
+        $.verbose = true
+        setTimeout(yes, 10)
+      })
+      assert.equal($.verbose, false)
 
-  test('malformed cmd error', async () => {
-    assert.throws(() => $`\033`, /malformed/i)
-  })
+      await promise
+    })
 
-  test('$ is a regular function', async () => {
-    const _$ = $.bind(null)
-    let foo = await _$`echo foo`
-    assert.equal(foo.stdout, 'foo\n')
-    assert.ok(typeof $.call === 'function')
-    assert.ok(typeof $.apply === 'function')
-  })
+    test('restores previous cwd', async () => {
+      let resolve, reject
+      let promise = new Promise((...args) => ([resolve, reject] = args))
 
-  test('halt() works', async () => {
-    let filepath = `/tmp/${Math.random().toString()}`
-    let p = $`touch ${filepath}`.halt()
-    await sleep(1)
-    assert.ok(
-      !fs.existsSync(filepath),
-      'The cmd called, but it should not have been called'
-    )
-    await p.run()
-    assert.ok(fs.existsSync(filepath), 'The cmd should have been called')
-  })
+      let pwd = await $`pwd`
 
-  test('await on halted throws', async () => {
-    let p = $`sleep 1`.halt()
-    let ok = true
-    try {
-      await p
-      ok = false
-    } catch (err) {
-      assert.equal(err.message, 'The process is halted!')
-    }
-    assert.ok(ok, 'Expected failure!')
+      within(async () => {
+        cd('/tmp')
+        setTimeout(async () => {
+          assert.ok((await $`pwd`).stdout.trim().endsWith('/tmp'))
+          resolve()
+        }, 1000)
+      })
+
+      assert.equal((await $`pwd`).stdout, pwd.stdout)
+      await promise
+    })
+
+    test(`isolates nested context and returns cb result`, async () => {
+      within(async () => {
+        const res = await within(async () => {
+          $.verbose = true
+
+          return within(async () => {
+            assert.equal($.verbose, true)
+            $.verbose = false
+
+            return within(async () => {
+              assert.equal($.verbose, false)
+              $.verbose = true
+              return 'foo'
+            })
+          })
+        })
+        assert.equal($.verbose, false)
+        assert.equal(res, 'foo')
+      })
+    })
   })
 
-  describe('presets', () => {
+  describe('shell presets', () => {
     const originalWhichSync = which.sync
     before(() => {
       which.sync = (bin) => bin