Repository: pinojs/pino
Pull request #438 (2018-06-15 15:58:02)

Modernize test syntax [WIP – Do not merge]
To match the code refactor, this updates the tests syntax.

The goal is to make tests very clean and clear. 

This introduces async/await syntax to tests - support for async/await tests on Node 6 is made possible with [`qodaa`](http://github.com/davidmarkclements/qodaa) 

There's still a lot to do, this is just to get early feedback - also I'm seeing if CI works


Patch:
diff --git a/bin.js b/bin.js
old mode 100644
new mode 100755
diff --git a/lib/events.js b/lib/events.js
index 65a5c1a..250864c 100644
--- a/lib/events.js
+++ b/lib/events.js
@@ -5,7 +5,7 @@ const { onTerminatedSym, streamSym } = require('./symbols')
 function events (instance) {
   const stream = instance[streamSym]
 
-  if (stream instanceof SonicBoom === true) {
+  if (stream instanceof SonicBoom) {
     if (stream.fd === -1) {
       stream.on('ready', register)
     } else {
@@ -35,6 +35,8 @@ function events (instance) {
     }
 
     function theWorldIsBurning (err) {
+      if (theWorldIsBurning.called === true) return
+      theWorldIsBurning.called = true
       runInternalHandler()
       handlers.handledOnTerminate = true
       if (isExtreme()) instance[onTerminatedSym](this.name, err)
diff --git a/lib/tools.js b/lib/tools.js
index b78f963..e485c67 100644
--- a/lib/tools.js
+++ b/lib/tools.js
@@ -137,6 +137,7 @@ function getPrettyStream (opts, prettifier, dest) {
   }
   try {
     var prettyFactory = require('pino-pretty')
+    prettyFactory.asMetaWrapper = asMetaWrapper
     return asMetaWrapper(prettyFactory(opts), dest)
   } catch (e) {
     throw Error('Missing `pino-pretty` module: `pino-pretty` must be installed separately')
diff --git a/package.json b/package.json
index d6cf5fa..2cb2851 100644
--- a/package.json
+++ b/package.json
@@ -17,8 +17,8 @@
   ],
   "scripts": {
     "browser-test": "airtap --local 8080 test/browser*test.js",
-    "test": "standard | snazzy && NODE_OPTIONS='--no-warnings' tap -j 4 --no-cov test/*test.js",
-    "ci": "standard | snazzy && NODE_OPTIONS='--no-warnings' tap -j 4 --cov test/*test.js",
+    "test": "standard | snazzy && NODE_OPTIONS='--no-warnings -r qodaa' tap -j 4 --no-cov test/*test.js",
+    "ci": "standard | snazzy && TAP_TIMEOUT=480000 NODE_OPTIONS='--no-warnings -r qodaa' tap -j 4 --cov test/*test.js",
     "bench": "node benchmarks/utils/runbench all",
     "bench-basic": "node benchmarks/utils/runbench basic",
     "bench-object": "node benchmarks/utils/runbench object",
@@ -68,6 +68,7 @@
     "pino-pretty": "^1.0.1",
     "pre-commit": "^1.2.2",
     "proxyquire": "^2.0.1",
+    "qodaa": "^1.0.1",
     "snazzy": "^7.1.1",
     "split2": "^2.2.0",
     "standard": "^11.0.1",


Test patch:
diff --git a/test/add-level.test.js b/test/add-level.test.js
index 4cf1b7d..dc0e789 100644
--- a/test/add-level.test.js
+++ b/test/add-level.test.js
@@ -1,154 +1,126 @@
 'use strict'
 
-var test = require('tap').test
-var sink = require('./helper').sink
-var pino = require('../')
-
-test('can add a custom level via constructor', function (t) {
-  t.plan(2)
-
-  var log = pino({level: 'foo', levelVal: 35}, sink(function (chunk, enc, cb) {
-    t.is(chunk.msg, 'bar')
-    cb()
-  }))
-
-  t.is(typeof log.foo, 'function')
-  log.foo('bar')
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const pino = require('../')
+
+test('can add a custom level via constructor', async ({is}) => {
+  const stream = sink()
+  const instance = pino({level: 'foo', levelVal: 35}, stream)
+  is(typeof instance.foo, 'function')
+  instance.foo('bar')
+  const { msg } = await once(stream, 'data')
+  is(msg, 'bar')
 })
 
-test('can add a custom level to a prior instance', function (t) {
-  t.plan(2)
-
-  var log = pino(sink(function (chunk, enc, cb) {
-    t.is(chunk.msg, 'bar')
-  }))
-
-  log.addLevel('foo2', 35)
-  t.is(typeof log.foo2, 'function')
-  log.foo2('bar')
+test('can add a custom level to a prior instance', async ({is}) => {
+  const stream = sink()
+  const instance = pino(stream)
+  instance.addLevel('foo2', 35)
+  is(typeof instance.foo2, 'function')
+  instance.foo2('bar')
+  const { msg } = await once(stream, 'data')
+  is(msg, 'bar')
 })
 
-test('custom level via constructor does not affect other instances', function (t) {
-  t.plan(2)
-
-  var log = pino({level: 'foo3', levelVal: 36})
-  var other = pino()
-  t.is(typeof log.foo3, 'function')
-  t.is(typeof other.foo3, 'undefined')
+test('custom level via constructor does not affect other instances', async ({is}) => {
+  const instance = pino({level: 'foo3', levelVal: 36})
+  const other = pino()
+  is(typeof instance.foo3, 'function')
+  is(typeof other.foo3, 'undefined')
 })
 
-test('custom level on one instance does not affect other instances', function (t) {
-  t.plan(2)
-
-  var log = pino()
-  log.addLevel('foo4', 37)
-  var other = pino()
-  log.addLevel('foo5', 38)
-  t.is(typeof other.foo4, 'undefined')
-  t.is(typeof other.foo5, 'undefined')
+test('custom level on one instance does not affect other instances', async ({is}) => {
+  const instance = pino()
+  instance.addLevel('foo4', 37)
+  const other = pino()
+  instance.addLevel('foo5', 38)
+  is(typeof other.foo4, 'undefined')
+  is(typeof other.foo5, 'undefined')
 })
 
-test('custom levels encompass higher levels', function (t) {
-  t.plan(1)
-
-  var log = pino({level: 'foo', levelVal: 35}, sink(function (chunk, enc, cb) {
-    t.is(chunk.msg, 'bar')
-    cb()
-  }))
-
-  log.warn('bar')
+test('custom levels encompass higher levels', async ({is}) => {
+  const stream = sink()
+  const instance = pino({level: 'foo', levelVal: 35}, stream)
+  instance.warn('bar')
+  const { msg } = await once(stream, 'data')
+  is(msg, 'bar')
 })
 
-test('after the fact add level does not include lower levels', function (t) {
-  t.plan(1)
-
-  var log = pino(sink(function (chunk, enc, cb) {
-    t.is(chunk.msg, 'bar')
-    cb()
-  }))
-
-  log.addLevel('foo', 35)
-  log.level = 'foo'
-  log.info('nope')
-  log.foo('bar')
+test('after the fact add level does not include lower levels', async ({is}) => {
+  const stream = sink()
+  const instance = pino(stream)
+  instance.addLevel('foo', 35)
+  instance.level = 'foo'
+  instance.info('nope')
+  instance.foo('bar')
+  const { msg } = await once(stream, 'data')
+  is(msg, 'bar')
 })
 
-test('after the fact add of a lower level does not include it', function (t) {
-  t.plan(1)
-
-  var log = pino(sink(function (chunk, enc, cb) {
-    t.is(chunk.msg, 'bar')
-    cb()
-  }))
-
-  log.level = 'info'
-  log.addLevel('foo', 15)
-  log.info('bar')
-  log.foo('nope')
+test('after the fact add of a lower level does not include it', async ({is}) => {
+  const stream = sink()
+  const instance = pino(stream)
+  instance.level = 'info'
+  instance.addLevel('foo', 15)
+  instance.info('bar')
+  instance.foo('nope')
+  const { msg } = await once(stream, 'data')
+  is(msg, 'bar')
 })
 
-test('children can be set to custom level', function (t) {
-  t.plan(2)
-
-  var parent = pino({level: 'foo', levelVal: 35}, sink(function (chunk, enc, cb) {
-    t.is(chunk.msg, 'bar')
-    t.is(chunk.child, 'yes')
-    cb()
-  }))
-  var child = parent.child({child: 'yes'})
+test('children can be set to custom level', async ({is}) => {
+  const stream = sink()
+  const parent = pino({level: 'foo', levelVal: 35}, stream)
+  const child = parent.child({childMsg: 'yes'})
   child.foo('bar')
+  const { msg, childMsg } = await once(stream, 'data')
+  is(msg, 'bar')
+  is(childMsg, 'yes')
 })
 
-test('custom levels exists on children', function (t) {
-  t.plan(2)
-
-  var parent = pino({}, sink(function (chunk, enc, cb) {
-    t.is(chunk.msg, 'bar')
-    t.is(chunk.child, 'yes')
-    cb()
-  }))
+test('custom levels exists on children', async ({is}) => {
+  const stream = sink()
+  const parent = pino({}, stream)
   parent.addLevel('foo', 35)
-  var child = parent.child({child: 'yes'})
+  const child = parent.child({childMsg: 'yes'})
   child.foo('bar')
+  const { msg, childMsg } = await once(stream, 'data')
+  is(msg, 'bar')
+  is(childMsg, 'yes')
 })
 
-test('rejects already known labels', function (t) {
-  t.plan(1)
-  var log = pino({level: 'info', levelVal: 900})
-  t.is(log.levelVal, 30)
+test('rejects already known labels', async ({is}) => {
+  const instance = pino({level: 'info', levelVal: 900})
+  is(instance.levelVal, 30)
 })
 
-test('reject already known values', function (t) {
-  t.plan(1)
+test('reject already known values', async ({is}) => {
   try {
     pino({level: 'foo', levelVal: 30})
   } catch (e) {
-    t.is(e.message.indexOf('level value') > -1, true)
+    is(e.message.indexOf('level value') > -1, true)
   }
 })
 
-test('reject values of Infinity', function (t) {
-  t.plan(1)
-  t.throws(function () {
+test('reject values of Infinity', async ({throws}) => {
+  throws(() => {
     pino({level: 'foo', levelVal: Infinity})
   }, /.*level value is already used.*/)
 })
 
-test('level numbers are logged correctly after level change', function (t) {
-  t.plan(1)
-  var log = pino({level: 'foo', levelVal: 25}, sink(function (chunk, enc, cb) {
-    t.is(chunk.level, 25)
-  }))
-  log.level = 'debug'
-  log.foo('bar')
+test('level numbers are logged correctly after level change', async ({is}) => {
+  const stream = sink()
+  const instance = pino({level: 'foo', levelVal: 25}, stream)
+  instance.level = 'debug'
+  instance.foo('bar')
+  const { level } = await once(stream, 'data')
+  is(level, 25)
 })
 
-test('levels state is not shared between instances', function (t) {
-  t.plan(2)
-
-  var instance1 = pino({level: 'foo', levelVal: 35})
-  t.is(typeof instance1.foo, 'function')
-
-  var instance2 = pino()
-  t.is(instance2.hasOwnProperty('foo'), false)
+test('levels state is not shared between instances', async ({is}) => {
+  const instance1 = pino({level: 'foo', levelVal: 35})
+  is(typeof instance1.foo, 'function')
+  const instance2 = pino()
+  is(instance2.hasOwnProperty('foo'), false)
 })
diff --git a/test/basic.test.js b/test/basic.test.js
index a570ec4..eb324de 100644
--- a/test/basic.test.js
+++ b/test/basic.test.js
@@ -1,134 +1,117 @@
 'use strict'
-
-var test = require('tap').test
-var os = require('os')
-var proxyquire = require('proxyquire')
-var pino = require('../')
-var sink = require('./helper').sink
-var check = require('./helper').check
-
-var pid = process.pid
-var hostname = os.hostname()
-
-test('pino version is exposed', function (t) {
-  t.plan(2)
-  var instance = pino()
-  t.ok(instance.pino)
-  t.is(instance.pino, require('../package.json').version)
+const os = require('os')
+const { test } = require('tap')
+const { sink, check, once } = require('./helper')
+const proxyquire = require('proxyquire')
+const pino = require('../')
+const { version } = require('../package.json')
+const { pid } = process
+const hostname = os.hostname()
+
+test('pino version is exposed', async ({is}) => {
+  const instance = pino()
+  is(instance.pino, version)
 })
 
-test('child exposes pino version', function (t) {
-  t.plan(1)
-  var child = pino().child({foo: 'bar'})
-  t.ok(child.pino)
+test('child exposes pino version', async ({is}) => {
+  const child = pino().child({foo: 'bar'})
+  is(child.pino, version)
 })
 
 function levelTest (name, level) {
-  test(name + ' logs as ' + level, function (t) {
-    t.plan(2)
-    var instance = pino(sink(function (chunk, enc, cb) {
-      check(t, chunk, level, 'hello world')
-    }))
-
+  test(`${name} logs as ${level}`, async ({is}) => {
+    const stream = sink()
+    const instance = pino(stream)
     instance.level = name
     instance[name]('hello world')
+    check(is, await once(stream, 'data'), level, 'hello world')
   })
 
-  test('passing objects at level ' + name, function (t) {
-    t.plan(2)
-    var instance = pino(sink(function (chunk, enc, cb) {
-      t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-      delete chunk.time
-      t.deepEqual(chunk, {
-        pid: pid,
-        hostname: hostname,
-        level: level,
-        hello: 'world',
-        v: 1
-      })
-    }))
-
+  test(`passing objects at level ${name}`, async ({is}) => {
+    const stream = sink()
+    const instance = pino(stream)
     instance.level = name
     instance[name]({ hello: 'world' })
-  })
 
-  test('passing an object and a string at level ' + name, function (t) {
-    t.plan(2)
-    var instance = pino(sink(function (chunk, enc, cb) {
-      t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-      delete chunk.time
-      t.deepEqual(chunk, {
-        pid: pid,
-        hostname: hostname,
-        level: level,
-        msg: 'a string',
-        hello: 'world',
-        v: 1
-      })
-    }))
+    const result = await once(stream, 'data')
+    is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+    is(result.pid, pid)
+    is(result.hostname, hostname)
+    is(result.level, level)
+    is(result.hello, 'world')
+    is(result.v, 1)
+  })
 
+  test(`passing an object and a string at level ${name}`, async ({is, same}) => {
+    const stream = sink()
+    const instance = pino(stream)
     instance.level = name
     instance[name]({ hello: 'world' }, 'a string')
+    const result = await once(stream, 'data')
+    is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+    delete result.time
+    same(result, {
+      pid: pid,
+      hostname: hostname,
+      level: level,
+      msg: 'a string',
+      hello: 'world',
+      v: 1
+    })
   })
 
-  test('formatting logs as ' + name, function (t) {
-    t.plan(2)
-    var instance = pino(sink(function (chunk, enc, cb) {
-      check(t, chunk, level, 'hello 42')
-    }))
-
+  test(`formatting logs as ${name}`, async ({is}) => {
+    const stream = sink()
+    const instance = pino(stream)
     instance.level = name
     instance[name]('hello %d', 42)
+    const result = await once(stream, 'data')
+    check(is, result, level, 'hello 42')
   })
 
-  test('passing error with a serializer at level ' + name, function (t) {
-    t.plan(2)
-    var err = new Error('myerror')
-    var instance = pino({
+  test(`passing error with a serializer at level ${name}`, async ({is, same}) => {
+    const stream = sink()
+    const err = new Error('myerror')
+    const instance = pino({
       serializers: {
         err: pino.stdSerializers.err
       }
-    }, sink(function (chunk, enc, cb) {
-      t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-      delete chunk.time
-      t.deepEqual(chunk, {
-        pid: pid,
-        hostname: hostname,
-        level: level,
-        err: {
-          type: 'Error',
-          message: err.message,
-          stack: err.stack
-        },
-        v: 1
-      })
-      cb()
-    }))
-
+    }, stream)
     instance.level = name
-    instance[name]({ err: err })
+    instance[name]({ err })
+    const result = await once(stream, 'data')
+    is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+    delete result.time
+    same(result, {
+      pid: pid,
+      hostname: hostname,
+      level: level,
+      err: {
+        type: 'Error',
+        message: err.message,
+        stack: err.stack
+      },
+      v: 1
+    })
   })
 
-  test('child logger for level ' + name, function (t) {
-    t.plan(2)
-    var instance = pino(sink(function (chunk, enc, cb) {
-      t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-      delete chunk.time
-      t.deepEqual(chunk, {
-        pid: pid,
-        hostname: hostname,
-        level: level,
-        msg: 'hello world',
-        hello: 'world',
-        v: 1
-      })
-    }))
-
+  test(`child logger for level ${name}`, async ({is, same}) => {
+    const stream = sink()
+    const instance = pino(stream)
     instance.level = name
-    var child = instance.child({
-      hello: 'world'
-    })
+    const child = instance.child({ hello: 'world' })
     child[name]('hello world')
+    const result = await once(stream, 'data')
+    is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+    delete result.time
+    same(result, {
+      pid: pid,
+      hostname: hostname,
+      level: level,
+      msg: 'hello world',
+      hello: 'world',
+      v: 1
+    })
   })
 }
 
@@ -139,295 +122,234 @@ levelTest('info', 30)
 levelTest('debug', 20)
 levelTest('trace', 10)
 
-test('serializers can return undefined to strip field', function (t) {
-  t.plan(1)
-  var instance = pino({
+test('serializers can return undefined to strip field', async ({is}) => {
+  const stream = sink()
+  const instance = pino({
     serializers: {
-      test: function (o) { return undefined }
+      test () { return undefined }
     }
-  }, sink(function (obj, enc, cb) {
-    t.notOk('test' in obj)
-    cb()
-  }))
+  }, stream)
 
   instance.info({ test: 'sensitive info' })
+  const result = await once(stream, 'data')
+  is('test' in result, false)
 })
 
-test('does not explode with a circular ref', function (t) {
-  var instance = pino(sink(function (chunk, enc, cb) {
-    // nothing to check
-    cb()
-  }))
-  var b = {}
-  var a = {
+test('does not explode with a circular ref', async ({doesNotThrow}) => {
+  const stream = sink()
+  const instance = pino(stream)
+  const b = {}
+  const a = {
     hello: b
   }
   b.a = a // circular ref
-  instance.info(a)
-  t.end()
+  doesNotThrow(() => instance.info(a))
 })
 
-test('explode with a circular ref with safe = false', function (t) {
-  var instance = pino({ safe: false }, sink(function (chunk, enc, cb) {
-    // nothing to check
-    cb()
-  }))
-  var b = {}
-  var a = {
+test('explode with a circular ref when safe is false', async ({throws}) => {
+  const stream = sink()
+  const instance = pino({ safe: false }, stream)
+  const b = {}
+  const a = {
     hello: b
   }
   b.a = a // circular ref
-  t.throws(function () {
-    instance.info(a)
-  })
-  t.end()
+  throws(() => instance.info(a))
 })
 
-test('set the name', function (t) {
-  t.plan(2)
-
-  var instance = pino({
+test('set the name', async ({is, same}) => {
+  const stream = sink()
+  const instance = pino({
     name: 'hello'
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 60,
-      name: 'hello',
-      msg: 'this is fatal',
-      v: 1
-    })
-    cb()
-  }))
-
+  }, stream)
   instance.fatal('this is fatal')
+  const result = await once(stream, 'data')
+  is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 60,
+    name: 'hello',
+    msg: 'this is fatal',
+    v: 1
+  })
 })
 
-test('set the messageKey', function (t) {
-  t.plan(2)
-
-  var message = 'hello world'
-  var messageKey = 'fooMessage'
-  var instance = pino({
-    messageKey: messageKey
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      fooMessage: message,
-      v: 1
-    })
-    cb()
-  }))
-
+test('set the messageKey', async ({is, same}) => {
+  const stream = sink()
+  const message = 'hello world'
+  const messageKey = 'fooMessage'
+  const instance = pino({
+    messageKey
+  }, stream)
   instance.info(message)
+  const result = await once(stream, 'data')
+  is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 30,
+    fooMessage: message,
+    v: 1
+  })
 })
 
-test('set undefined properties', function (t) {
-  t.plan(2)
-
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      hello: 'world',
-      v: 1
-    })
-    cb()
-  }))
-
+test('set undefined properties', async ({is, same}) => {
+  const stream = sink()
+  const instance = pino(stream)
   instance.info({ hello: 'world', property: undefined })
+  const result = await once(stream, 'data')
+  is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 30,
+    hello: 'world',
+    v: 1
+  })
 })
 
-test('set properties defined in the prototype chain', function (t) {
-  t.plan(2)
-
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      hello: 'world',
-      v: 1
-    })
-    cb()
-  }))
-
-  function MyObject () {
-    this.hello = 'world'
-  }
-
-  MyObject.prototype.some = function () {}
-
-  instance.info(new MyObject())
+test('prototype properties are not logged', async ({is}) => {
+  const stream = sink()
+  const instance = pino(stream)
+  instance.info(Object.create({hello: 'world'}))
+  const { hello } = await once(stream, 'data')
+  is(hello, undefined)
 })
 
-test('set the base', function (t) {
-  t.plan(2)
-
-  var instance = pino({
+test('set the base', async ({is, same}) => {
+  const stream = sink()
+  const instance = pino({
     base: {
       a: 'b'
     }
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      a: 'b',
-      level: 60,
-      msg: 'this is fatal',
-      v: 1
-    })
-    cb()
-  }))
+  }, stream)
 
   instance.fatal('this is fatal')
+  const result = await once(stream, 'data')
+  is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    a: 'b',
+    level: 60,
+    msg: 'this is fatal',
+    v: 1
+  })
 })
 
-test('set the base to null', function (t) {
-  t.plan(2)
-
-  var instance = pino({
+test('set the base to null', async ({is, same}) => {
+  const stream = sink()
+  const instance = pino({
     base: null
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      level: 60,
-      msg: 'this is fatal',
-      v: 1
-    })
-    cb()
-  }))
-
+  }, stream)
   instance.fatal('this is fatal')
-})
-
-test('throw if creating child without bindings', function (t) {
-  t.plan(1)
-
-  var instance = pino(
-    sink(function (chunk, enc, cb) {
-      t.ok(Date.parse(chunk.time) <= new Date(), 'time is greater than Date.now()')
-      t.end()
-    }))
-
-  t.throws(function () {
-    instance.child()
+  const result = await once(stream, 'data')
+  is(new Date(result.time) <= new Date(), true, 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    level: 60,
+    msg: 'this is fatal',
+    v: 1
   })
 })
 
-test('correctly escape msg strings / 1', function (t) {
-  t.plan(1)
+test('throw if creating child without bindings', async ({throws}) => {
+  const stream = sink()
+  const instance = pino(stream)
+  throws(() => instance.child())
+})
 
-  var instance = pino({
+test('correctly escapes msg strings with stray double quote at end', async ({same}) => {
+  const stream = sink()
+  const instance = pino({
     name: 'hello'
-  }, sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 60,
-      name: 'hello',
-      msg: 'this contains "',
-      v: 1
-    })
-    cb()
-  }))
+  }, stream)
 
   instance.fatal('this contains "')
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 60,
+    name: 'hello',
+    msg: 'this contains "',
+    v: 1
+  })
 })
 
-test('correctly escape msg strings / 2', function (t) {
-  t.plan(1)
-
-  var instance = pino({
+test('correctly escape msg strings with unclosed double quote', async ({same}) => {
+  const stream = sink()
+  const instance = pino({
     name: 'hello'
-  }, sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 60,
-      name: 'hello',
-      msg: '" this contains',
-      v: 1
-    })
-    cb()
-  }))
-
+  }, stream)
   instance.fatal('" this contains')
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 60,
+    name: 'hello',
+    msg: '" this contains',
+    v: 1
+  })
 })
 
 // https://github.com/pinojs/pino/issues/139
-test('object and format string', function (t) {
-  var instance = pino(sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      msg: 'foo bar',
-      v: 1
-    })
-    t.end()
-    cb()
-  }))
-
+test('object and format string', async ({same}) => {
+  const stream = sink()
+  const instance = pino(stream)
   instance.info({}, 'foo %s', 'bar')
-})
 
-test('object and format string property', function (t) {
-  var instance = pino(sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      msg: 'foo bar',
-      answer: 42,
-      v: 1
-    })
-    t.end()
-    cb()
-  }))
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 30,
+    msg: 'foo bar',
+    v: 1
+  })
+})
 
+test('object and format string property', async ({same}) => {
+  const stream = sink()
+  const instance = pino(stream)
   instance.info({ answer: 42 }, 'foo %s', 'bar')
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 30,
+    msg: 'foo bar',
+    answer: 42,
+    v: 1
+  })
 })
 
-test('correctly strip undefined when returned from toJSON', function (t) {
-  t.plan(1)
-
-  var instance = pino({
+test('correctly strip undefined when returned from toJSON', async ({is}) => {
+  const stream = sink()
+  const instance = pino({
     test: 'this'
-  }, sink(function (obj, enc, cb) {
-    t.notOk('test' in obj)
-    cb()
-  }))
-
-  instance.fatal({test: {toJSON: function () { return undefined }}})
+  }, stream)
+  instance.fatal({test: {toJSON () { return undefined }}})
+  const result = await once(stream, 'data')
+  is('test' in result, false)
 })
 
-test('correctly support node v4+ stderr', function (t) {
-  t.plan(1)
-
+test('correctly supports stderr', async ({same}) => {
   // stderr inherits from Stream, rather than Writable
-  var dest = {
+  const dest = {
     writable: true,
-    write: function (chunk) {
-      chunk = JSON.parse(chunk)
-      delete chunk.time
-      t.deepEqual(chunk, {
+    write (result) {
+      result = JSON.parse(result)
+      delete result.time
+      same(result, {
         pid: pid,
         hostname: hostname,
         level: 60,
@@ -436,94 +358,77 @@ test('correctly support node v4+ stderr', function (t) {
       })
     }
   }
-
-  var instance = pino(dest)
-
+  const instance = pino(dest)
   instance.fatal('a message')
 })
 
-test('normalize number to string', function (t) {
-  var instance = pino(sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      msg: '1',
-      v: 1
-    })
-    t.end()
-    cb()
-  }))
-
+test('normalize number to string', async ({same}) => {
+  const stream = sink()
+  const instance = pino(stream)
   instance.info(1)
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 30,
+    msg: '1',
+    v: 1
+  })
 })
 
-test('normalize number to string with an object', function (t) {
-  var instance = pino(sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      msg: '1',
-      answer: 42,
-      v: 1
-    })
-    t.end()
-    cb()
-  }))
-
+test('normalize number to string with an object', async ({same}) => {
+  const stream = sink()
+  const instance = pino(stream)
   instance.info({ answer: 42 }, 1)
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 30,
+    msg: '1',
+    answer: 42,
+    v: 1
+  })
 })
 
-test('handles objects with null prototype', function (t) {
-  var instance = pino(sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      test: 'test',
-      v: 1
-    })
-    t.end()
-    cb()
-  }))
-  var o = Object.create(null)
+test('handles objects with null prototype', async ({same}) => {
+  const stream = sink()
+  const instance = pino(stream)
+  const o = Object.create(null)
   o.test = 'test'
   instance.info(o)
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 30,
+    test: 'test',
+    v: 1
+  })
 })
 
 // https://github.com/pinojs/pino/issues/222
-test('children with same names render in correct order', function (t) {
-  t.plan(1)
-  var root = pino(sink(function (chunk, enc, cb) {
-    t.is(chunk.a, 3, 'last logged object takes precedence')
-    cb()
-  }))
-
+test('children with same names render in correct order', async ({is}) => {
+  const stream = sink()
+  const root = pino(stream)
   root.child({a: 1}).child({a: 2}).info({a: 3})
+  const { a } = await once(stream, 'data')
+  is(a, 3, 'last logged object takes precedence')
 })
 
 // https://github.com/pinojs/pino/pull/251 - use this.stringify
-test('when safe is true it should ONLY use `fast-safe-stringify`', function (t) {
-  t.plan(2)
-  var safeStates = [true, false]
-  var isFastSafeStringifyCalled = null
-  var mockedPino = proxyquire('../', {
-    'fast-safe-stringify': function () {
+test('when safe is true it should ONLY use `fast-safe-stringify`', async ({is}) => {
+  var isFastSafeStringifyCalled = false
+  const mockedPino = proxyquire('../', {
+    'fast-safe-stringify' () {
       isFastSafeStringifyCalled = true
       return '{ "hello": "world" }'
     }
   })
-  safeStates.forEach(function (safeState) {
-    isFastSafeStringifyCalled = false
-    var instance = mockedPino({ safe: safeState }, sink(function (chunk, enc, cb) {
-      cb()
-    }))
-    instance.info({ hello: 'world' })
-    t.equal(isFastSafeStringifyCalled, safeState)
-  })
-  t.end()
+  const instance = mockedPino({ safe: true }, sink())
+  instance.info({ hello: 'world' })
+  is(isFastSafeStringifyCalled, true)
 })
diff --git a/test/browser-levels.test.js b/test/browser-levels.test.js
index d63575d..00029a7 100644
--- a/test/browser-levels.test.js
+++ b/test/browser-levels.test.js
@@ -1,10 +1,9 @@
 'use strict'
-var test = require('tape')
-var pino = require('../browser')
+const test = require('tape')
+const pino = require('../browser')
 
-test('set the level by string', function (t) {
-  t.plan(4)
-  var expected = [
+test('set the level by string', ({end, same, is}) => {
+  const expected = [
     {
       level: 50,
       msg: 'this is an error'
@@ -14,10 +13,10 @@ test('set the level by string', function (t) {
       msg: 'this is fatal'
     }
   ]
-  var instance = pino({
+  const instance = pino({
     browser: {
-      write: function (actual) {
-        checkLogObjects(t, actual, expected.shift())
+      write (actual) {
+        checkLogObjects(is, same, actual, expected.shift())
       }
     }
   })
@@ -26,12 +25,12 @@ test('set the level by string', function (t) {
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
-  t.end()
+
+  end()
 })
 
-test('set the level by string. init with silent', function (t) {
-  t.plan(4)
-  var expected = [
+test('set the level by string. init with silent', ({end, same, is}) => {
+  const expected = [
     {
       level: 50,
       msg: 'this is an error'
@@ -41,11 +40,11 @@ test('set the level by string. init with silent', function (t) {
       msg: 'this is fatal'
     }
   ]
-  var instance = pino({
+  const instance = pino({
     level: 'silent',
     browser: {
-      write: function (actual) {
-        checkLogObjects(t, actual, expected.shift())
+      write (actual) {
+        checkLogObjects(is, same, actual, expected.shift())
       }
     }
   })
@@ -54,12 +53,12 @@ test('set the level by string. init with silent', function (t) {
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
-  t.end()
+
+  end()
 })
 
-test('set the level by string. init with silent and transmit', function (t) {
-  t.plan(4)
-  var expected = [
+test('set the level by string. init with silent and transmit', ({end, same, is}) => {
+  const expected = [
     {
       level: 50,
       msg: 'this is an error'
@@ -69,16 +68,15 @@ test('set the level by string. init with silent and transmit', function (t) {
       msg: 'this is fatal'
     }
   ]
-  var instance = pino({
+  const instance = pino({
     level: 'silent',
     browser: {
-      write: function (actual) {
-        checkLogObjects(t, actual, expected.shift())
+      write (actual) {
+        checkLogObjects(is, same, actual, expected.shift())
       }
     },
     transmit: {
-      send: function () {
-      }
+      send () {}
     }
   })
 
@@ -86,12 +84,12 @@ test('set the level by string. init with silent and transmit', function (t) {
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
-  t.end()
+
+  end()
 })
 
-test('set the level via constructor', function (t) {
-  t.plan(4)
-  var expected = [
+test('set the level via constructor', ({end, same, is}) => {
+  const expected = [
     {
       level: 50,
       msg: 'this is an error'
@@ -101,11 +99,11 @@ test('set the level via constructor', function (t) {
       msg: 'this is fatal'
     }
   ]
-  var instance = pino({
+  const instance = pino({
     level: 'error',
     browser: {
-      write: function (actual) {
-        checkLogObjects(t, actual, expected.shift())
+      write (actual) {
+        checkLogObjects(is, same, actual, expected.shift())
       }
     }
   })
@@ -113,77 +111,79 @@ test('set the level via constructor', function (t) {
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
-  t.end()
+
+  end()
 })
 
-test('the wrong level throws', function (t) {
-  t.plan(1)
-  var instance = pino()
-  t.throws(function () {
+test('the wrong level throws', ({end, throws}) => {
+  const instance = pino()
+  throws(() => {
     instance.level = 'kaboom'
   })
+  end()
 })
 
-test('the wrong level by number throws', function (t) {
-  t.plan(1)
-  var instance = pino()
-  t.throws(function () {
+test('the wrong level by number throws', ({end, throws}) => {
+  const instance = pino()
+  throws(() => {
     instance.levelVal = 55
   })
+  end()
 })
 
-test('exposes level string mappings', function (t) {
-  t.plan(1)
-  t.equal(pino.levels.values.error, 50)
+test('exposes level string mappings', ({end, is}) => {
+  is(pino.levels.values.error, 50)
+  end()
 })
 
-test('exposes level number mappings', function (t) {
-  t.plan(1)
-  t.equal(pino.levels.labels[50], 'error')
+test('exposes level number mappings', ({end, is}) => {
+  is(pino.levels.labels[50], 'error')
+  end()
 })
 
-test('returns level integer', function (t) {
-  t.plan(1)
-  var instance = pino({level: 'error'})
-  t.equal(instance.levelVal, 50)
+test('returns level integer', ({end, is}) => {
+  const instance = pino({level: 'error'})
+  is(instance.levelVal, 50)
+  end()
 })
 
-test('silent level via constructor', function (t) {
-  var instance = pino({
+test('silent level via constructor', ({end, fail}) => {
+  const instance = pino({
     level: 'silent',
     browser: {
-      write: function (actual) {
-        t.fail('no data should be logged')
+      write () {
+        fail('no data should be logged')
       }
     }
   })
 
-  Object.keys(pino.levels.values).forEach(function (level) {
+  Object.keys(pino.levels.values).forEach((level) => {
     instance[level]('hello world')
   })
-  t.end()
+
+  end()
 })
 
-test('silent level by string', function (t) {
-  var instance = pino({
+test('silent level by string', ({end, fail}) => {
+  const instance = pino({
     browser: {
-      write: function (actual) {
-        t.fail('no data should be logged')
+      write () {
+        fail('no data should be logged')
       }
     }
   })
 
   instance.level = 'silent'
 
-  Object.keys(pino.levels.values).forEach(function (level) {
+  Object.keys(pino.levels.values).forEach((level) => {
     instance[level]('hello world')
   })
-  t.end()
+
+  end()
 })
 
-test('exposed levels', function (t) {
-  t.plan(1)
-  t.deepEqual(Object.keys(pino.levels.values), [
+test('exposed levels', ({end, same}) => {
+  same(Object.keys(pino.levels.values), [
     'fatal',
     'error',
     'warn',
@@ -191,11 +191,11 @@ test('exposed levels', function (t) {
     'debug',
     'trace'
   ])
+  end()
 })
 
-test('exposed labels', function (t) {
-  t.plan(1)
-  t.deepEqual(Object.keys(pino.levels.labels), [
+test('exposed labels', ({end, same}) => {
+  same(Object.keys(pino.levels.labels), [
     '10',
     '20',
     '30',
@@ -203,15 +203,16 @@ test('exposed labels', function (t) {
     '50',
     '60'
   ])
+  end()
 })
 
-function checkLogObjects (t, actual, expected) {
-  t.ok(actual.time <= Date.now(), 'time is greater than Date.now()')
+function checkLogObjects (is, same, actual, expected) {
+  is(actual.time <= Date.now(), true, 'time is greater than Date.now()')
 
-  var actualCopy = Object.assign({}, actual)
-  var expectedCopy = Object.assign({}, expected)
+  const actualCopy = Object.assign({}, actual)
+  const expectedCopy = Object.assign({}, expected)
   delete actualCopy.time
   delete expectedCopy.time
 
-  t.deepEqual(actualCopy, expectedCopy)
+  same(actualCopy, expectedCopy)
 }
diff --git a/test/browser-serializers.test.js b/test/browser-serializers.test.js
index ddba55f..93714cc 100644
--- a/test/browser-serializers.test.js
+++ b/test/browser-serializers.test.js
@@ -2,118 +2,121 @@
 // eslint-disable-next-line
 if (typeof $1 !== 'undefined') $1 = arguments.callee.caller.arguments[0]
 
-var test = require('tape')
-var fresh = require('fresh-require')
-var pino = require('../browser')
+const test = require('tape')
+const fresh = require('fresh-require')
+const pino = require('../browser')
 
-var parentSerializers = {
-  test: function () { return 'parent' }
+const parentSerializers = {
+  test: () => 'parent'
 }
 
-var childSerializers = {
-  test: function () { return 'child' }
+const childSerializers = {
+  test: () => 'child'
 }
 
-test('serializers override values', function (t) {
-  t.plan(1)
-
-  var parent = pino({ serializers: parentSerializers,
-    browser: { serialize: true,
-      write: function (o) {
-        t.is(o.test, 'parent')
-      }}})
+test('serializers override values', ({end, is}) => {
+  const parent = pino({
+    serializers: parentSerializers,
+    browser: {
+      serialize: true,
+      write (o) {
+        is(o.test, 'parent')
+        end()
+      }
+    }
+  })
 
   parent.fatal({test: 'test'})
 })
 
-test('without the serialize option, serializers do not override values', function (t) {
-  t.plan(1)
-
-  var parent = pino({ serializers: parentSerializers,
+test('without the serialize option, serializers do not override values', ({end, is}) => {
+  const parent = pino({ serializers: parentSerializers,
     browser: {
-      write: function (o) {
-        t.is(o.test, 'test')
-      }}})
+      write (o) {
+        is(o.test, 'test')
+        end()
+      }
+    }
+  })
 
   parent.fatal({test: 'test'})
 })
 
 if (process.title !== 'browser') {
-  test('if serialize option is true, standard error serializer is auto enabled', function (t) {
-    t.plan(1)
-    var err = Error('test')
+  test('if serialize option is true, standard error serializer is auto enabled', ({end, same}) => {
+    const err = Error('test')
     err.code = 'test'
     err.type = 'Error' // get that cov
-    var expect = pino.stdSerializers.err(err)
+    const expect = pino.stdSerializers.err(err)
 
-    var consoleError = console.error
+    const consoleError = console.error
     console.error = function (err) {
-      t.deepEqual(err, expect)
+      same(err, expect)
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       browser: { serialize: true }
     })
 
     console.error = consoleError
 
     logger.fatal(err)
+    end()
   })
 
-  test('if serialize option is array, standard error serializer is auto enabled', function (t) {
-    t.plan(1)
-    var err = Error('test')
+  test('if serialize option is array, standard error serializer is auto enabled', ({end, same}) => {
+    const err = Error('test')
     err.code = 'test'
-    var expect = pino.stdSerializers.err(err)
+    const expect = pino.stdSerializers.err(err)
 
-    var consoleError = console.error
+    const consoleError = console.error
     console.error = function (err) {
-      t.deepEqual(err, expect)
+      same(err, expect)
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       browser: { serialize: [] }
     })
 
     console.error = consoleError
 
     logger.fatal(err)
+    end()
   })
 
-  test('if serialize option is array containing !stdSerializers.err, standard error serializer is disabled', function (t) {
-    t.plan(1)
-    var err = Error('test')
+  test('if serialize option is array containing !stdSerializers.err, standard error serializer is disabled', ({end, is}) => {
+    const err = Error('test')
     err.code = 'test'
-    var expect = err
+    const expect = err
 
-    var consoleError = console.error
+    const consoleError = console.error
     console.error = function (err) {
-      t.is(err, expect)
+      is(err, expect)
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       browser: { serialize: ['!stdSerializers.err'] }
     })
 
     console.error = consoleError
 
     logger.fatal(err)
+    end()
   })
 
-  test('in browser, serializers apply to all objects', function (t) {
-    t.plan(3)
-    var consoleError = console.error
+  test('in browser, serializers apply to all objects', ({end, is}) => {
+    const consoleError = console.error
     console.error = function (test, test2, test3, test4, test5) {
-      t.is(test.key, 'serialized')
-      t.is(test2.key2, 'serialized2')
-      t.is(test5.key3, 'serialized3')
+      is(test.key, 'serialized')
+      is(test2.key2, 'serialized2')
+      is(test5.key3, 'serialized3')
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       serializers: {
-        key: function () { return 'serialized' },
-        key2: function () { return 'serialized2' },
-        key3: function () { return 'serialized3' }
+        key: () => 'serialized',
+        key2: () => 'serialized2',
+        key3: () => 'serialized3'
       },
       browser: { serialize: true }
     })
@@ -121,22 +124,22 @@ if (process.title !== 'browser') {
     console.error = consoleError
 
     logger.fatal({key: 'test'}, {key2: 'test'}, 'str should skip', [{foo: 'array should skip'}], {key3: 'test'})
+    end()
   })
 
-  test('serialize can be an array of selected serializers', function (t) {
-    t.plan(3)
-    var consoleError = console.error
+  test('serialize can be an array of selected serializers', ({end, is}) => {
+    const consoleError = console.error
     console.error = function (test, test2, test3, test4, test5) {
-      t.is(test.key, 'test')
-      t.is(test2.key2, 'serialized2')
-      t.is(test5.key3, 'test')
+      is(test.key, 'test')
+      is(test2.key2, 'serialized2')
+      is(test5.key3, 'test')
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       serializers: {
-        key: function () { return 'serialized' },
-        key2: function () { return 'serialized2' },
-        key3: function () { return 'serialized3' }
+        key: () => 'serialized',
+        key2: () => 'serialized2',
+        key3: () => 'serialized3'
       },
       browser: { serialize: ['key2'] }
     })
@@ -144,18 +147,18 @@ if (process.title !== 'browser') {
     console.error = consoleError
 
     logger.fatal({key: 'test'}, {key2: 'test'}, 'str should skip', [{foo: 'array should skip'}], {key3: 'test'})
+    end()
   })
 
-  test('serialize filter applies to child loggers', function (t) {
-    t.plan(3)
-    var consoleError = console.error
+  test('serialize filter applies to child loggers', ({end, is}) => {
+    const consoleError = console.error
     console.error = function (binding, test, test2, test3, test4, test5) {
-      t.is(test.key, 'test')
-      t.is(test2.key2, 'serialized2')
-      t.is(test5.key3, 'test')
+      is(test.key, 'test')
+      is(test2.key2, 'serialized2')
+      is(test5.key3, 'test')
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       browser: { serialize: ['key2'] }
     })
 
@@ -163,22 +166,22 @@ if (process.title !== 'browser') {
 
     logger.child({aBinding: 'test',
       serializers: {
-        key: function () { return 'serialized' },
-        key2: function () { return 'serialized2' },
-        key3: function () { return 'serialized3' }
+        key: () => 'serialized',
+        key2: () => 'serialized2',
+        key3: () => 'serialized3'
       }}).fatal({key: 'test'}, {key2: 'test'}, 'str should skip', [{foo: 'array should skip'}], {key3: 'test'})
+    end()
   })
 
-  test('parent serializers apply to child bindings', function (t) {
-    t.plan(1)
-    var consoleError = console.error
+  test('parent serializers apply to child bindings', ({end, is}) => {
+    const consoleError = console.error
     console.error = function (binding) {
-      t.is(binding.key, 'serialized')
+      is(binding.key, 'serialized')
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       serializers: {
-        key: function () { return 'serialized' }
+        key: () => 'serialized'
       },
       browser: { serialize: true }
     })
@@ -186,16 +189,16 @@ if (process.title !== 'browser') {
     console.error = consoleError
 
     logger.child({key: 'test'}).fatal({test: 'test'})
+    end()
   })
 
-  test('child serializers apply to child bindings', function (t) {
-    t.plan(1)
-    var consoleError = console.error
+  test('child serializers apply to child bindings', ({end, is}) => {
+    const consoleError = console.error
     console.error = function (binding) {
-      t.is(binding.key, 'serialized')
+      is(binding.key, 'serialized')
     }
 
-    var logger = fresh('../browser', require)({
+    const logger = fresh('../browser', require)({
       browser: { serialize: true }
     })
 
@@ -203,100 +206,113 @@ if (process.title !== 'browser') {
 
     logger.child({key: 'test',
       serializers: {
-        key: function () { return 'serialized' }
+        key: () => 'serialized'
       }}).fatal({test: 'test'})
+    end()
   })
 }
 
-test('child does not overwrite parent serializers', function (t) {
-  t.plan(2)
-
+test('child does not overwrite parent serializers', ({end, is}) => {
   var c = 0
-  var parent = pino({ serializers: parentSerializers,
-    browser: { serialize: true,
-      write: function (o) {
+  const parent = pino({ serializers: parentSerializers,
+    browser: {
+      serialize: true,
+      write (o) {
         c++
-        if (c === 1) t.is(o.test, 'parent')
-        if (c === 2) t.is(o.test, 'child')
+        if (c === 1) is(o.test, 'parent')
+        if (c === 2) {
+          is(o.test, 'child')
+          end()
+        }
       }}})
-  var child = parent.child({ serializers: childSerializers })
+  const child = parent.child({ serializers: childSerializers })
 
   parent.fatal({test: 'test'})
   child.fatal({test: 'test'})
 })
 
-test('children inherit parent serializers', function (t) {
-  t.plan(1)
-
-  var parent = pino({ serializers: parentSerializers,
-    browser: { serialize: true,
-      write: function (o) {
-        t.is(o.test, 'parent')
-      }}})
+test('children inherit parent serializers', ({end, is}) => {
+  const parent = pino({ serializers: parentSerializers,
+    browser: {
+      serialize: true,
+      write (o) {
+        is(o.test, 'parent')
+      }
+    }
+  })
 
-  var child = parent.child({a: 'property'})
+  const child = parent.child({a: 'property'})
   child.fatal({test: 'test'})
+  end()
 })
 
-test('children serializers get called', function (t) {
-  t.plan(1)
-
-  var parent = pino({
+test('children serializers get called', ({end, is}) => {
+  const parent = pino({
     test: 'this',
-    browser: { serialize: true,
-      write: function (o) {
-        t.is(o.test, 'child')
-      }}})
+    browser: {
+      serialize: true,
+      write (o) {
+        is(o.test, 'child')
+      }
+    }
+  })
 
-  var child = parent.child({ 'a': 'property', serializers: childSerializers })
+  const child = parent.child({ 'a': 'property', serializers: childSerializers })
 
   child.fatal({test: 'test'})
+  end()
 })
 
-test('children serializers get called when inherited from parent', function (t) {
-  t.plan(1)
-
-  var parent = pino({
+test('children serializers get called when inherited from parent', ({end, is}) => {
+  const parent = pino({
     test: 'this',
     serializers: parentSerializers,
-    browser: { serialize: true,
-      write: function (o) {
-        t.is(o.test, 'pass')
-      }}})
+    browser: {
+      serialize: true,
+      write: (o) => {
+        is(o.test, 'pass')
+      }
+    }
+  })
 
-  var child = parent.child({serializers: {test: function () { return 'pass' }}})
+  const child = parent.child({serializers: { test: () => 'pass' }})
 
   child.fatal({test: 'fail'})
+  end()
 })
 
-test('non overriden serializers are available in the children', function (t) {
-  t.plan(4)
-  var pSerializers = {
-    onlyParent: function () { return 'parent' },
-    shared: function () { return 'parent' }
+test('non overriden serializers are available in the children', ({end, is}) => {
+  const pSerializers = {
+    onlyParent: () => 'parent',
+    shared: () => 'parent'
   }
 
-  var cSerializers = {
-    shared: function () { return 'child' },
-    onlyChild: function () { return 'child' }
+  const cSerializers = {
+    shared: () => 'child',
+    onlyChild: () => 'child'
   }
 
   var c = 0
 
-  var parent = pino({ serializers: pSerializers,
-    browser: { serialize: true,
-      write: function (o) {
+  const parent = pino({
+    serializers: pSerializers,
+    browser: {
+      serialize: true,
+      write (o) {
         c++
-        if (c === 1) t.is(o.shared, 'child')
-        if (c === 2) t.is(o.onlyParent, 'parent')
-        if (c === 3) t.is(o.onlyChild, 'child')
-        if (c === 4) t.is(o.onlyChild, 'test')
-      }}})
+        if (c === 1) is(o.shared, 'child')
+        if (c === 2) is(o.onlyParent, 'parent')
+        if (c === 3) is(o.onlyChild, 'child')
+        if (c === 4) is(o.onlyChild, 'test')
+      }
+    }
+  })
 
-  var child = parent.child({ serializers: cSerializers })
+  const child = parent.child({ serializers: cSerializers })
 
   child.fatal({shared: 'test'})
   child.fatal({onlyParent: 'test'})
   child.fatal({onlyChild: 'test'})
   parent.fatal({onlyChild: 'test'})
+  end()
 })
diff --git a/test/browser-transmit.test.js b/test/browser-transmit.test.js
index cb22448..5f427a5 100644
--- a/test/browser-transmit.test.js
+++ b/test/browser-transmit.test.js
@@ -1,108 +1,103 @@
 'use strict'
-var test = require('tape')
-var pino = require('../browser')
+const test = require('tape')
+const pino = require('../browser')
 
 function noop () {}
 
-test('throws if transmit object does not have send function', function (t) {
-  t.throws(function () {
+test('throws if transmit object does not have send function', ({end, throws}) => {
+  throws(() => {
     pino({browser: {transmit: {}}})
   })
 
-  t.throws(function () {
+  throws(() => {
     pino({browser: {transmit: {send: 'not a func'}}})
   })
 
-  t.end()
+  end()
 })
 
-test('calls send function after write', function (t) {
-  t.plan(1)
+test('calls send function after write', ({end, is}) => {
   var c = 0
-  var logger = pino({
+  const logger = pino({
     browser: {
-      write: function (o) {
+      write: () => {
         c++
       },
       transmit: {
-        send: function () {
-          t.is(c, 1)
-        }
+        send () { is(c, 1) }
       }
     }
   })
 
   logger.fatal({test: 'test'})
+  end()
 })
 
-test('passes send function the logged level', function (t) {
-  t.plan(1)
-  var logger = pino({
+test('passes send function the logged level', ({end, is}) => {
+  const logger = pino({
     browser: {
-      write: function (o) {
-      },
+      write () {},
       transmit: {
-        send: function (level) {
-          t.is(level, 'fatal')
+        send (level) {
+          is(level, 'fatal')
         }
       }
     }
   })
 
   logger.fatal({test: 'test'})
+  end()
 })
 
-test('passes send function messages in logEvent object', function (t) {
-  t.plan(2)
-  var logger = pino({
+test('passes send function messages in logEvent object', ({end, same, is}) => {
+  const logger = pino({
     browser: {
       write: noop,
       transmit: {
-        send: function (level, logEvent) {
-          var messages = logEvent.messages
-          t.same(messages[0], {test: 'test'})
-          t.is(messages[1], 'another test')
+        send (level, {messages}) {
+          same(messages[0], {test: 'test'})
+          is(messages[1], 'another test')
         }
       }
     }
   })
 
   logger.fatal({test: 'test'}, 'another test')
+  end()
 })
 
-test('supplies a timestamp (ts) in logEvent object which is exactly the same as the `time` property in asObject mode', function (t) {
-  t.plan(1)
+test('supplies a timestamp (ts) in logEvent object which is exactly the same as the `time` property in asObject mode', ({end, is}) => {
   var expected
-  var logger = pino({
+  const logger = pino({
     browser: {
       asObject: true, // implict because `write`, but just to be explicit
-      write: function (o) {
+      write (o) {
         expected = o.time
       },
       transmit: {
-        send: function (level, logEvent) {
-          t.is(logEvent.ts, expected)
+        send (level, logEvent) {
+          is(logEvent.ts, expected)
         }
       }
     }
   })
 
   logger.fatal('test')
+  end()
 })
 
-test('passes send function child bindings via logEvent object', function (t) {
-  t.plan(4)
-  var logger = pino({
+test('passes send function child bindings via logEvent object', ({end, same, is}) => {
+  const logger = pino({
     browser: {
       write: noop,
       transmit: {
-        send: function (level, logEvent) {
-          var messages = logEvent.messages
-          var bindings = logEvent.bindings
-          t.same(bindings[0], {first: 'binding'})
-          t.same(bindings[1], {second: 'binding2'})
-          t.same(messages[0], {test: 'test'})
-          t.is(messages[1], 'another test')
+        send (level, logEvent) {
+          const messages = logEvent.messages
+          const bindings = logEvent.bindings
+          same(bindings[0], {first: 'binding'})
+          same(bindings[1], {second: 'binding2'})
+          same(messages[0], {test: 'test'})
+          is(messages[1], 'another test')
         }
       }
     }
@@ -112,40 +107,40 @@ test('passes send function child bindings via logEvent object', function (t) {
     .child({first: 'binding'})
     .child({second: 'binding2'})
     .fatal({test: 'test'}, 'another test')
+  end()
 })
 
-test('passes send function level:{label, value} via logEvent object', function (t) {
-  t.plan(2)
-  var logger = pino({
+test('passes send function level:{label, value} via logEvent object', ({end, is}) => {
+  const logger = pino({
     browser: {
       write: noop,
       transmit: {
-        send: function (level, logEvent) {
-          var label = logEvent.level.label
-          var value = logEvent.level.value
+        send (level, logEvent) {
+          const label = logEvent.level.label
+          const value = logEvent.level.value
 
-          t.is(label, 'fatal')
-          t.is(value, 60)
+          is(label, 'fatal')
+          is(value, 60)
         }
       }
     }
   })
 
   logger.fatal({test: 'test'}, 'another test')
+  end()
 })
 
-test('calls send function according to transmit.level', function (t) {
-  t.plan(2)
+test('calls send function according to transmit.level', ({end, is}) => {
   var c = 0
-  var logger = pino({
+  const logger = pino({
     browser: {
       write: noop,
       transmit: {
         level: 'error',
-        send: function (level) {
+        send (level) {
           c++
-          if (c === 1) t.is(level, 'error')
-          if (c === 2) t.is(level, 'fatal')
+          if (c === 1) is(level, 'error')
+          if (c === 2) is(level, 'fatal')
         }
       }
     }
@@ -153,20 +148,20 @@ test('calls send function according to transmit.level', function (t) {
   logger.warn('ignored')
   logger.error('test')
   logger.fatal('test')
+  end()
 })
 
-test('transmit.level defaults to logger level', function (t) {
-  t.plan(2)
+test('transmit.level defaults to logger level', ({end, is}) => {
   var c = 0
-  var logger = pino({
+  const logger = pino({
     level: 'error',
     browser: {
       write: noop,
       transmit: {
-        send: function (level) {
+        send (level) {
           c++
-          if (c === 1) t.is(level, 'error')
-          if (c === 2) t.is(level, 'fatal')
+          if (c === 1) is(level, 'error')
+          if (c === 2) is(level, 'fatal')
         }
       }
     }
@@ -174,22 +169,22 @@ test('transmit.level defaults to logger level', function (t) {
   logger.warn('ignored')
   logger.error('test')
   logger.fatal('test')
+  end()
 })
 
-test('transmit.level is effective even if lower than logger level', function (t) {
-  t.plan(3)
+test('transmit.level is effective even if lower than logger level', ({end, is}) => {
   var c = 0
-  var logger = pino({
+  const logger = pino({
     level: 'error',
     browser: {
       write: noop,
       transmit: {
         level: 'info',
-        send: function (level) {
+        send (level) {
           c++
-          if (c === 1) t.is(level, 'warn')
-          if (c === 2) t.is(level, 'error')
-          if (c === 3) t.is(level, 'fatal')
+          if (c === 1) is(level, 'warn')
+          if (c === 2) is(level, 'error')
+          if (c === 3) is(level, 'fatal')
         }
       }
     }
@@ -197,26 +192,26 @@ test('transmit.level is effective even if lower than logger level', function (t)
   logger.warn('ignored')
   logger.error('test')
   logger.fatal('test')
+  end()
 })
 
-test('applies all serializers to messages and bindings (serialize:false - default)', function (t) {
-  t.plan(4)
-  var logger = pino({
+test('applies all serializers to messages and bindings (serialize:false - default)', ({end, same, is}) => {
+  const logger = pino({
     serializers: {
-      first: function () { return 'first' },
-      second: function () { return 'second' },
-      test: function () { return 'serialize it' }
+      first: () => 'first',
+      second: () => 'second',
+      test: () => 'serialize it'
     },
     browser: {
       write: noop,
       transmit: {
-        send: function (level, logEvent) {
-          var messages = logEvent.messages
-          var bindings = logEvent.bindings
-          t.same(bindings[0], {first: 'first'})
-          t.same(bindings[1], {second: 'second'})
-          t.same(messages[0], {test: 'serialize it'})
-          t.is(messages[1].type, 'Error')
+        send (level, logEvent) {
+          const messages = logEvent.messages
+          const bindings = logEvent.bindings
+          same(bindings[0], {first: 'first'})
+          same(bindings[1], {second: 'second'})
+          same(messages[0], {test: 'serialize it'})
+          is(messages[1].type, 'Error')
         }
       }
     }
@@ -226,27 +221,27 @@ test('applies all serializers to messages and bindings (serialize:false - defaul
     .child({first: 'binding'})
     .child({second: 'binding2'})
     .fatal({test: 'test'}, Error())
+  end()
 })
 
-test('applies all serializers to messages and bindings (serialize:true)', function (t) {
-  t.plan(4)
-  var logger = pino({
+test('applies all serializers to messages and bindings (serialize:true)', ({end, same, is}) => {
+  const logger = pino({
     serializers: {
-      first: function () { return 'first' },
-      second: function () { return 'second' },
-      test: function () { return 'serialize it' }
+      first: () => 'first',
+      second: () => 'second',
+      test: () => 'serialize it'
     },
     browser: {
       serialize: true,
       write: noop,
       transmit: {
-        send: function (level, logEvent) {
-          var messages = logEvent.messages
-          var bindings = logEvent.bindings
-          t.same(bindings[0], {first: 'first'})
-          t.same(bindings[1], {second: 'second'})
-          t.same(messages[0], {test: 'serialize it'})
-          t.is(messages[1].type, 'Error')
+        send (level, logEvent) {
+          const messages = logEvent.messages
+          const bindings = logEvent.bindings
+          same(bindings[0], {first: 'first'})
+          same(bindings[1], {second: 'second'})
+          same(messages[0], {test: 'serialize it'})
+          is(messages[1].type, 'Error')
         }
       }
     }
@@ -256,4 +251,5 @@ test('applies all serializers to messages and bindings (serialize:true)', functi
     .child({first: 'binding'})
     .child({second: 'binding2'})
     .fatal({test: 'test'}, Error())
+  end()
 })
diff --git a/test/browser.test.js b/test/browser.test.js
index 81ac2e6..a737dc1 100644
--- a/test/browser.test.js
+++ b/test/browser.test.js
@@ -1,7 +1,7 @@
 'use strict'
-var test = require('tape')
-var fresh = require('fresh-require')
-var pino = require('../browser')
+const test = require('tape')
+const fresh = require('fresh-require')
+const pino = require('../browser')
 
 levelTest('fatal')
 levelTest('error')
@@ -10,76 +10,68 @@ levelTest('info')
 levelTest('debug')
 levelTest('trace')
 
-test('silent level', function (t) {
-  var instance = pino({
+test('silent level', ({end, fail, pass}) => {
+  const instance = pino({
     level: 'silent',
-    browser: {write: function (o) {
-      t.fail()
-    }}
+    browser: {write: fail}
   })
   instance.info('test')
-  var child = instance.child({test: 'test'})
+  const child = instance.child({test: 'test'})
   child.info('msg-test')
   // use setTimeout because setImmediate isn't supported in most browsers
-  setTimeout(function () {
-    t.pass()
-    t.end()
+  setTimeout(() => {
+    pass()
+    end()
   }, 0)
 })
 
-test('enabled false', function (t) {
-  var instance = pino({
+test('enabled false', ({end, fail, pass}) => {
+  const instance = pino({
     enabled: false,
-    browser: {write: function (o) {
-      t.fail()
-    }}
+    browser: {write: fail}
   })
   instance.info('test')
-  var child = instance.child({test: 'test'})
+  const child = instance.child({test: 'test'})
   child.info('msg-test')
   // use setTimeout because setImmediate isn't supported in most browsers
-  setTimeout(function () {
-    t.pass()
-    t.end()
+  setTimeout(() => {
+    pass()
+    end()
   }, 0)
 })
 
-test('throw if creating child without bindings', function (t) {
-  t.plan(1)
-
-  var instance = pino()
-
-  t.throws(function () {
-    instance.child()
-  })
+test('throw if creating child without bindings', ({end, throws}) => {
+  const instance = pino()
+  throws(() => instance.child())
+  end()
 })
 
-test('stubs write, flush and ee methods on instance', function (t) {
-  var instance = pino()
-
-  t.ok(isFunc(instance.setMaxListeners))
-  t.ok(isFunc(instance.getMaxListeners))
-  t.ok(isFunc(instance.emit))
-  t.ok(isFunc(instance.addListener))
-  t.ok(isFunc(instance.on))
-  t.ok(isFunc(instance.prependListener))
-  t.ok(isFunc(instance.once))
-  t.ok(isFunc(instance.prependOnceListener))
-  t.ok(isFunc(instance.removeListener))
-  t.ok(isFunc(instance.removeAllListeners))
-  t.ok(isFunc(instance.listeners))
-  t.ok(isFunc(instance.listenerCount))
-  t.ok(isFunc(instance.eventNames))
-  t.ok(isFunc(instance.write))
-  t.ok(isFunc(instance.flush))
-
-  t.is(instance.on(), undefined)
-
-  t.end()
+test('stubs write, flush and ee methods on instance', ({end, ok, is}) => {
+  const instance = pino()
+
+  ok(isFunc(instance.setMaxListeners))
+  ok(isFunc(instance.getMaxListeners))
+  ok(isFunc(instance.emit))
+  ok(isFunc(instance.addListener))
+  ok(isFunc(instance.on))
+  ok(isFunc(instance.prependListener))
+  ok(isFunc(instance.once))
+  ok(isFunc(instance.prependOnceListener))
+  ok(isFunc(instance.removeListener))
+  ok(isFunc(instance.removeAllListeners))
+  ok(isFunc(instance.listeners))
+  ok(isFunc(instance.listenerCount))
+  ok(isFunc(instance.eventNames))
+  ok(isFunc(instance.write))
+  ok(isFunc(instance.flush))
+
+  is(instance.on(), undefined)
+
+  end()
 })
 
-test('exposes levels object', function (t) {
-  t.deepEqual(pino.levels, {
+test('exposes levels object', ({end, same}) => {
+  same(pino.levels, {
     values: {
       fatal: 60,
       error: 50,
@@ -97,31 +89,35 @@ test('exposes levels object', function (t) {
       '60': 'fatal'
     }
   })
-  t.end()
+
+  end()
 })
 
-test('exposes LOG_VERSION', function (t) {
-  t.is(pino.LOG_VERSION, 1)
-  t.end()
+test('exposes LOG_VERSION', ({end, is}) => {
+  is(pino.LOG_VERSION, 1)
+
+  end()
 })
 
-test('exposes faux stdSerializers', function (t) {
-  t.ok(pino.stdSerializers)
-  t.ok(pino.stdSerializers.req)
-  t.ok(pino.stdSerializers.res)
-  t.ok(pino.stdSerializers.err)
-  t.deepEqual(pino.stdSerializers.req(), {})
-  t.deepEqual(pino.stdSerializers.res(), {})
-  t.end()
+test('exposes faux stdSerializers', ({end, ok, same}) => {
+  ok(pino.stdSerializers)
+  ok(pino.stdSerializers.req)
+  ok(pino.stdSerializers.res)
+  ok(pino.stdSerializers.err)
+  same(pino.stdSerializers.req(), {})
+  same(pino.stdSerializers.res(), {})
+
+  end()
 })
 
-test('exposes err stdSerializer', function (t) {
-  t.ok(pino.stdSerializers)
-  t.ok(pino.stdSerializers.req)
-  t.ok(pino.stdSerializers.res)
-  t.ok(pino.stdSerializers.err)
-  t.ok(pino.stdSerializers.err(Error()))
-  t.end()
+test('exposes err stdSerializer', ({end, ok}) => {
+  ok(pino.stdSerializers)
+  ok(pino.stdSerializers.req)
+  ok(pino.stdSerializers.res)
+  ok(pino.stdSerializers.err)
+  ok(pino.stdSerializers.err(Error()))
+
+  end()
 })
 
 consoleMethodTest('error')
@@ -138,284 +134,294 @@ absentConsoleMethodTest('trace', 'log')
 
 // do not run this with airtap
 if (process.title !== 'browser') {
-  test('in absence of console, log methods become noops', function (t) {
+  test('in absence of console, log methods become noops', ({end, ok}) => {
     var console = global.console
     delete global.console
-    var instance = fresh('../browser', require)()
+    const instance = fresh('../browser', require)()
     global.console = console
-    t.ok(fnName(instance.log).match(/noop/))
-    t.ok(fnName(instance.fatal).match(/noop/))
-    t.ok(fnName(instance.error).match(/noop/))
-    t.ok(fnName(instance.warn).match(/noop/))
-    t.ok(fnName(instance.info).match(/noop/))
-    t.ok(fnName(instance.debug).match(/noop/))
-    t.ok(fnName(instance.trace).match(/noop/))
-    t.end()
+    ok(fnName(instance.log).match(/noop/))
+    ok(fnName(instance.fatal).match(/noop/))
+    ok(fnName(instance.error).match(/noop/))
+    ok(fnName(instance.warn).match(/noop/))
+    ok(fnName(instance.info).match(/noop/))
+    ok(fnName(instance.debug).match(/noop/))
+    ok(fnName(instance.trace).match(/noop/))
+    end()
   })
 }
 
-test('opts.browser.asObject logs pino-like object to console', function (t) {
-  t.plan(3)
+test('opts.browser.asObject logs pino-like object to console', ({end, ok, is}) => {
   var info = console.info
   console.info = function (o) {
-    t.is(o.level, 30)
-    t.is(o.msg, 'test')
-    t.ok(o.time)
+    is(o.level, 30)
+    is(o.msg, 'test')
+    ok(o.time)
     console.info = info
   }
-  var instance = require('../browser')({
+  const instance = require('../browser')({
     browser: {
       asObject: true
     }
   })
 
   instance.info('test')
+  end()
 })
 
-test('opts.browser.write func log single string', function (t) {
-  t.plan(3)
-  var instance = pino({
+test('opts.browser.write func log single string', ({end, ok, is}) => {
+  const instance = pino({
     browser: {
       write: function (o) {
-        t.is(o.level, 30)
-        t.is(o.msg, 'test')
-        t.ok(o.time)
+        is(o.level, 30)
+        is(o.msg, 'test')
+        ok(o.time)
       }
     }
   })
   instance.info('test')
-  t.end()
+
+  end()
 })
 
-test('opts.browser.write func string joining', function (t) {
-  t.plan(3)
-  var instance = pino({
+test('opts.browser.write func string joining', ({end, ok, is}) => {
+  const instance = pino({
     browser: {
       write: function (o) {
-        t.is(o.level, 30)
-        t.is(o.msg, 'test test2 test3')
-        t.ok(o.time)
+        is(o.level, 30)
+        is(o.msg, 'test test2 test3')
+        ok(o.time)
       }
     }
   })
   instance.info('test', 'test2', 'test3')
-  t.end()
+
+  end()
 })
 
-test('opts.browser.write func string object joining', function (t) {
-  t.plan(3)
-  var instance = pino({
+test('opts.browser.write func string object joining', ({end, ok, is}) => {
+  const instance = pino({
     browser: {
       write: function (o) {
-        t.is(o.level, 30)
-        t.is(o.msg, 'test {"test":"test2"} {"test":"test3"}')
-        t.ok(o.time)
+        is(o.level, 30)
+        is(o.msg, 'test {"test":"test2"} {"test":"test3"}')
+        ok(o.time)
       }
     }
   })
   instance.info('test', {test: 'test2'}, {test: 'test3'})
-  t.end()
+
+  end()
 })
 
-test('opts.browser.write func string interpolation', function (t) {
-  t.plan(3)
-  var instance = pino({
+test('opts.browser.write func string interpolation', ({end, ok, is}) => {
+  const instance = pino({
     browser: {
       write: function (o) {
-        t.is(o.level, 30)
-        t.is(o.msg, 'test2 test ({"test":"test3"})')
-        t.ok(o.time)
+        is(o.level, 30)
+        is(o.msg, 'test2 test ({"test":"test3"})')
+        ok(o.time)
       }
     }
   })
   instance.info('%s test (%j)', 'test2', {test: 'test3'})
-  t.end()
+
+  end()
 })
 
-test('opts.browser.write func number', function (t) {
-  t.plan(3)
-  var instance = pino({
+test('opts.browser.write func number', ({end, ok, is}) => {
+  const instance = pino({
     browser: {
       write: function (o) {
-        t.is(o.level, 30)
-        t.is(o.msg, 1)
-        t.ok(o.time)
+        is(o.level, 30)
+        is(o.msg, 1)
+        ok(o.time)
       }
     }
   })
   instance.info(1)
-  t.end()
+
+  end()
 })
 
-test('opts.browser.write func log single object', function (t) {
-  t.plan(3)
-  var instance = pino({
+test('opts.browser.write func log single object', ({end, ok, is}) => {
+  const instance = pino({
     browser: {
       write: function (o) {
-        t.is(o.level, 30)
-        t.is(o.test, 'test')
-        t.ok(o.time)
+        is(o.level, 30)
+        is(o.test, 'test')
+        ok(o.time)
       }
     }
   })
   instance.info({test: 'test'})
-  t.end()
+
+  end()
 })
 
-test('opts.browser.write obj writes to methods corresponding to level', function (t) {
-  t.plan(3)
-  var instance = pino({
+test('opts.browser.write obj writes to methods corresponding to level', ({end, ok, is}) => {
+  const instance = pino({
     browser: {
       write: {
         error: function (o) {
-          t.is(o.level, 50)
-          t.is(o.test, 'test')
-          t.ok(o.time)
+          is(o.level, 50)
+          is(o.test, 'test')
+          ok(o.time)
         }
       }
     }
   })
   instance.error({test: 'test'})
-  t.end()
+
+  end()
 })
 
-test('opts.browser.asObject/write supports child loggers', function (t) {
-  var instance = pino({
-    browser: {write: function (o) {
-      t.is(o.level, 30)
-      t.is(o.test, 'test')
-      t.is(o.msg, 'msg-test')
-      t.ok(o.time)
-    }}
+test('opts.browser.asObject/write supports child loggers', ({end, ok, is}) => {
+  const instance = pino({
+    browser: {
+      write (o) {
+        is(o.level, 30)
+        is(o.test, 'test')
+        is(o.msg, 'msg-test')
+        ok(o.time)
+      }
+    }
   })
-  var child = instance.child({test: 'test'})
+  const child = instance.child({test: 'test'})
   child.info('msg-test')
-  t.end()
+
+  end()
 })
 
-test('opts.browser.asObject/write supports child child loggers', function (t) {
-  var instance = pino({
-    browser: {write: function (o) {
-      t.is(o.level, 30)
-      t.is(o.test, 'test')
-      t.is(o.foo, 'bar')
-      t.is(o.msg, 'msg-test')
-      t.ok(o.time)
-    }}
+test('opts.browser.asObject/write supports child child loggers', ({end, ok, is}) => {
+  const instance = pino({
+    browser: {
+      write (o) {
+        is(o.level, 30)
+        is(o.test, 'test')
+        is(o.foo, 'bar')
+        is(o.msg, 'msg-test')
+        ok(o.time)
+      }
+    }
   })
-  var child = instance.child({test: 'test'}).child({foo: 'bar'})
+  const child = instance.child({test: 'test'}).child({foo: 'bar'})
   child.info('msg-test')
-  t.end()
+
+  end()
 })
 
-test('opts.browser.asObject/write supports child child child loggers', function (t) {
-  var instance = pino({
-    browser: {write: function (o) {
-      t.is(o.level, 30)
-      t.is(o.test, 'test')
-      t.is(o.foo, 'bar')
-      t.is(o.baz, 'bop')
-      t.is(o.msg, 'msg-test')
-      t.ok(o.time)
-    }}
+test('opts.browser.asObject/write supports child child child loggers', ({end, ok, is}) => {
+  const instance = pino({
+    browser: {
+      write (o) {
+        is(o.level, 30)
+        is(o.test, 'test')
+        is(o.foo, 'bar')
+        is(o.baz, 'bop')
+        is(o.msg, 'msg-test')
+        ok(o.time)
+      }
+    }
   })
-  var child = instance.child({test: 'test'}).child({foo: 'bar'}).child({baz: 'bop'})
+  const child = instance.child({test: 'test'}).child({foo: 'bar'}).child({baz: 'bop'})
   child.info('msg-test')
-  t.end()
+
+  end()
 })
 
-test('opts.browser.asObject defensively mitigates naughty numbers', function (t) {
-  var instance = pino({
-    browser: {asObject: true, write: function () {}}
+test('opts.browser.asObject defensively mitigates naughty numbers', ({end, pass}) => {
+  const instance = pino({
+    browser: {asObject: true, write: () => {}}
   })
-  var child = instance.child({test: 'test'})
+  const child = instance.child({test: 'test'})
   child._childLevel = -10
   child.info('test')
-  t.pass() // if we reached here, there was no infinite loop, so, .. pass.
-  t.end()
+  pass() // if we reached here, there was no infinite loop, so, .. pass.
+
+  end()
 })
 
-test('opts.browser.write obj falls back to console where a method is not supplied', function (t) {
-  t.plan(6)
+test('opts.browser.write obj falls back to console where a method is not supplied', ({end, ok, is}) => {
   var info = console.info
-  console.info = function (o) {
-    t.is(o.level, 30)
-    t.is(o.msg, 'test')
-    t.ok(o.time)
+  console.info = (o) => {
+    is(o.level, 30)
+    is(o.msg, 'test')
+    ok(o.time)
     console.info = info
   }
-  var instance = require('../browser')({
+  const instance = require('../browser')({
     browser: {
       write: {
-        error: function (o) {
-          t.is(o.level, 50)
-          t.is(o.test, 'test')
-          t.ok(o.time)
+        error (o) {
+          is(o.level, 50)
+          is(o.test, 'test')
+          ok(o.time)
         }
       }
     }
   })
   instance.error({test: 'test'})
   instance.info('test')
-  t.end()
+
+  end()
 })
 
 function levelTest (name) {
-  test(name + ' logs', function (t) {
+  test(name + ' logs', ({end, is}) => {
     var msg = 'hello world'
-    sink(name, function (args) {
-      t.is(args[0], msg)
-      t.end()
+    sink(name, (args) => {
+      is(args[0], msg)
+      end()
     })
     pino({level: name})[name](msg)
   })
 
-  test('passing objects at level ' + name, function (t) {
+  test('passing objects at level ' + name, ({end, is}) => {
     var msg = { hello: 'world' }
-    sink(name, function (args) {
-      t.is(args[0], msg)
-      t.end()
+    sink(name, (args) => {
+      is(args[0], msg)
+      end()
     })
     pino({level: name})[name](msg)
   })
 
-  test('passing an object and a string at level ' + name, function (t) {
+  test('passing an object and a string at level ' + name, ({end, is}) => {
     var a = { hello: 'world' }
     var b = 'a string'
-    sink(name, function (args) {
-      t.is(args[0], a)
-      t.is(args[1], b)
-      t.end()
+    sink(name, (args) => {
+      is(args[0], a)
+      is(args[1], b)
+      end()
     })
     pino({level: name})[name](a, b)
   })
 
-  test('formatting logs as ' + name, function (t) {
-    sink(name, function (args) {
-      t.is(args[0], 'hello %d')
-      t.is(args[1], 42)
-      t.end()
+  test('formatting logs as ' + name, ({end, is}) => {
+    sink(name, (args) => {
+      is(args[0], 'hello %d')
+      is(args[1], 42)
+      end()
     })
     pino({level: name})[name]('hello %d', 42)
   })
 
-  test('passing error at level ' + name, function (t) {
+  test('passing error at level ' + name, ({end, is}) => {
     var err = new Error('myerror')
-    sink(name, function (args) {
-      t.is(args[0], err)
-      t.end()
+    sink(name, (args) => {
+      is(args[0], err)
+      end()
     })
     pino({level: name})[name](err)
   })
 
-  test('passing error with a serializer at level ' + name, function (t) {
+  test('passing error with a serializer at level ' + name, ({end, is}) => {
     // in browser - should have no effect (should not crash)
     var err = new Error('myerror')
-    sink(name, function (args) {
-      t.is(args[0].err, err)
-      t.end()
+    sink(name, (args) => {
+      is(args[0].err, err)
+      end()
     })
-    var instance = pino({
+    const instance = pino({
       level: name,
       serializers: {
         err: pino.stdSerializers.err
@@ -424,57 +430,57 @@ function levelTest (name) {
     instance[name]({err: err})
   })
 
-  test('child logger for level ' + name, function (t) {
+  test('child logger for level ' + name, ({end, is}) => {
     var msg = 'hello world'
     var parent = { hello: 'world' }
-    sink(name, function (args) {
-      t.is(args[0], parent)
-      t.is(args[1], msg)
-      t.end()
+    sink(name, (args) => {
+      is(args[0], parent)
+      is(args[1], msg)
+      end()
     })
-    var instance = pino({level: name})
-    var child = instance.child(parent)
+    const instance = pino({level: name})
+    const child = instance.child(parent)
     child[name](msg)
   })
 
-  test('child-child logger for level ' + name, function (t) {
+  test('child-child logger for level ' + name, ({end, is}) => {
     var msg = 'hello world'
     var grandParent = { hello: 'world' }
     var parent = { hello: 'you' }
-    sink(name, function (args) {
-      t.is(args[0], grandParent)
-      t.is(args[1], parent)
-      t.is(args[2], msg)
-      t.end()
+    sink(name, (args) => {
+      is(args[0], grandParent)
+      is(args[1], parent)
+      is(args[2], msg)
+      end()
     })
-    var instance = pino({level: name})
-    var child = instance.child(grandParent).child(parent)
+    const instance = pino({level: name})
+    const child = instance.child(grandParent).child(parent)
     child[name](msg)
   })
 }
 
 function consoleMethodTest (level, method) {
   if (!method) method = level
-  test('pino().' + level + ' uses console.' + method, function (t) {
-    sink(method, function (args) {
-      t.is(args[0], 'test')
-      t.end()
+  test('pino().' + level + ' uses console.' + method, ({end, is}) => {
+    sink(method, (args) => {
+      is(args[0], 'test')
+      end()
     })
-    var instance = require('../browser')({level: level})
+    const instance = require('../browser')({level: level})
     instance[level]('test')
   })
 }
 
 function absentConsoleMethodTest (method, fallback) {
-  test('in absence of console.' + method + ', console.' + fallback + ' is used', function (t) {
+  test('in absence of console.' + method + ', console.' + fallback + ' is used', ({end, is}) => {
     var fn = console[method]
     console[method] = undefined
     sink(fallback, function (args) {
-      t.is(args[0], 'test')
-      t.end()
+      is(args[0], 'test')
+      end()
       console[method] = fn
     })
-    var instance = require('../browser')({level: method})
+    const instance = require('../browser')({level: method})
     instance[method]('test')
   })
 }
diff --git a/test/crlf.test.js b/test/crlf.test.js
index 735edd0..be80ba9 100644
--- a/test/crlf.test.js
+++ b/test/crlf.test.js
@@ -1,36 +1,32 @@
 'use strict'
 
-var test = require('tap').test
-var pino = require('../')
-var writer = require('flush-write-stream')
+const { test } = require('tap')
+const writer = require('flush-write-stream')
+const pino = require('../')
 
 function capture () {
-  var ws = writer(function (chunk, enc, cb) {
-    this.data += chunk.toString()
+  const ws = writer((chunk, enc, cb) => {
+    ws.data += chunk.toString()
     cb()
   })
   ws.data = ''
   return ws
 }
 
-test('pino uses LF by default', function (t) {
-  t.plan(1)
-  var stream = capture()
-  var logger = pino(stream)
+test('pino uses LF by default', async ({ok}) => {
+  const stream = capture()
+  const logger = pino(stream)
   logger.info('foo')
   logger.error('bar')
-  t.ok(/foo[^\r\n]+\n[^\r\n]+bar[^\r\n]+\n/.test(stream.data))
-  t.end()
+  ok(/foo[^\r\n]+\n[^\r\n]+bar[^\r\n]+\n/.test(stream.data))
 })
 
-test('pino can log CRLF', function (t) {
-  t.plan(1)
-  var stream = capture()
-  var logger = pino({
+test('pino can log CRLF', async ({ok}) => {
+  const stream = capture()
+  const logger = pino({
     crlf: true
   }, stream)
   logger.info('foo')
   logger.error('bar')
-  t.ok(/foo[^\n]+\r\n[^\n]+bar[^\n]+\r\n/.test(stream.data))
-  t.end()
+  ok(/foo[^\n]+\r\n[^\n]+bar[^\n]+\r\n/.test(stream.data))
 })
diff --git a/test/error.test.js b/test/error.test.js
index 005017c..749b6e6 100644
--- a/test/error.test.js
+++ b/test/error.test.js
@@ -1,130 +1,124 @@
 'use strict'
-var test = require('tap').test
-var pino = require('../')
-var sink = require('./helper').sink
+const os = require('os')
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const pino = require('../')
 
-var os = require('os')
-var pid = process.pid
-var hostname = os.hostname()
-var level = 50
-var name = 'error'
-
-test('err is serialized with additional properties set on the Error object', function (t) {
-  t.plan(2)
-  var err = Object.assign(new Error('myerror'), {foo: 'bar'})
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: level,
-      type: 'Error',
-      msg: err.message,
-      stack: err.stack,
-      foo: err.foo,
-      v: 1
-    })
-    cb()
-  }))
+const { pid } = process
+const hostname = os.hostname()
+const level = 50
+const name = 'error'
 
+test('err is serialized with additional properties set on the Error object', async ({ok, same}) => {
+  const stream = sink()
+  const err = Object.assign(new Error('myerror'), {foo: 'bar'})
+  const instance = pino(stream)
   instance.level = name
   instance[name](err)
+  const result = await once(stream, 'data')
+  ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: level,
+    type: 'Error',
+    msg: err.message,
+    stack: err.stack,
+    foo: err.foo,
+    v: 1
+  })
 })
 
-test('type should be retained, even if type is a property', function (t) {
-  t.plan(2)
-  var err = Object.assign(new Error('myerror'), {type: 'bar'})
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: level,
-      type: 'bar',
-      msg: err.message,
-      stack: err.stack,
-      v: 1
-    })
-    cb()
-  }))
-
+test('type should be retained, even if type is a property', async ({ok, same}) => {
+  const stream = sink()
+  const err = Object.assign(new Error('myerror'), {type: 'bar'})
+  const instance = pino(stream)
   instance.level = name
   instance[name](err)
+  const result = await once(stream, 'data')
+  ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: level,
+    type: 'bar',
+    msg: err.message,
+    stack: err.stack,
+    v: 1
+  })
 })
 
-test('type, message and stack should be first level properties', function (t) {
-  t.plan(2)
-  var err = Object.assign(new Error('foo'), { foo: 'bar' })
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: level,
-      type: 'Error',
-      msg: err.message,
-      stack: err.stack,
-      foo: err.foo,
-      v: 1
-    })
-    cb()
-  }))
-
+test('type, message and stack should be first level properties', async ({ok, same}) => {
+  const stream = sink()
+  const err = Object.assign(new Error('foo'), { foo: 'bar' })
+  const instance = pino(stream)
   instance.level = name
   instance[name](err)
+
+  const result = await once(stream, 'data')
+  ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: level,
+    type: 'Error',
+    msg: err.message,
+    stack: err.stack,
+    foo: err.foo,
+    v: 1
+  })
 })
 
-test('err serializer', function (t) {
-  t.plan(2)
-  var err = Object.assign(new Error('myerror'), {foo: 'bar'})
-  var instance = pino({
+test('err serializer', async ({ok, same}) => {
+  const stream = sink()
+  const err = Object.assign(new Error('myerror'), {foo: 'bar'})
+  const instance = pino({
     serializers: {
       err: pino.stdSerializers.err
     }
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: level,
-      err: {
-        type: 'Error',
-        message: err.message,
-        stack: err.stack,
-        foo: err.foo
-      },
-      v: 1
-    })
-    cb()
-  }))
+  }, stream)
 
   instance.level = name
   instance[name]({ err })
-})
-
-test('an error with statusCode property is not confused for a http response', function (t) {
-  t.plan(2)
-  var err = Object.assign(new Error('StatusCodeErr'), { statusCode: 500 })
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: level,
+  const result = await once(stream, 'data')
+  ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: level,
+    err: {
       type: 'Error',
-      msg: err.message,
+      message: err.message,
       stack: err.stack,
-      statusCode: err.statusCode,
-      v: 1
-    })
-    cb()
-  }))
+      foo: err.foo
+    },
+    v: 1
+  })
+})
+
+test('an error with statusCode property is not confused for a http response', async ({ok, same}) => {
+  const stream = sink()
+  const err = Object.assign(new Error('StatusCodeErr'), { statusCode: 500 })
+  const instance = pino(stream)
 
   instance.level = name
   instance[name](err)
+  const result = await once(stream, 'data')
+
+  ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: level,
+    type: 'Error',
+    msg: err.message,
+    stack: err.stack,
+    statusCode: err.statusCode,
+    v: 1
+  })
 })
diff --git a/test/escaping.test.js b/test/escaping.test.js
index 8a67822..50f723c 100644
--- a/test/escaping.test.js
+++ b/test/escaping.test.js
@@ -1,33 +1,30 @@
 'use strict'
 
-var test = require('tap').test
-var pino = require('../')
-var sink = require('./helper').sink
-var os = require('os')
+const os = require('os')
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const pino = require('../')
 
-var pid = process.pid
-var hostname = os.hostname()
+const { pid } = process
+const hostname = os.hostname()
 
 function testEscape (ch, key) {
-  test('correctly escape ' + ch, function (t) {
-    t.plan(1)
-
-    var instance = pino({
+  test('correctly escape ' + ch, async ({same}) => {
+    const stream = sink()
+    const instance = pino({
       name: 'hello'
-    }, sink(function (chunk, enc, cb) {
-      delete chunk.time
-      t.deepEqual(chunk, {
-        pid: pid,
-        hostname: hostname,
-        level: 60,
-        name: 'hello',
-        msg: 'this contains ' + key,
-        v: 1
-      })
-      cb()
-    }))
-
+    }, stream)
     instance.fatal('this contains ' + key)
+    const result = await once(stream, 'data')
+    delete result.time
+    same(result, {
+      pid: pid,
+      hostname: hostname,
+      level: 60,
+      name: 'hello',
+      msg: 'this contains ' + key,
+      v: 1
+    })
   })
 }
 
@@ -38,7 +35,7 @@ testEscape('\\r', '\r')
 testEscape('\\t', '\t')
 testEscape('\\b', '\b')
 
-var toEscape = [
+const toEscape = [
   '\u0000', // NUL  Null character
   '\u0001', // SOH  Start of Heading
   '\u0002', // STX  Start of Text
@@ -73,26 +70,24 @@ var toEscape = [
   '\u001F' // US   Unit Separator
 ]
 
-toEscape.forEach(function (key) {
+toEscape.forEach((key) => {
   testEscape(JSON.stringify(key), key)
 })
 
-test('correctly escape `hello \\u001F world \\n \\u0022`', function (t) {
-  t.plan(1)
-  var instance = pino({
+test('correctly escape `hello \\u001F world \\n \\u0022`', async ({same}) => {
+  const stream = sink()
+  const instance = pino({
     name: 'hello'
-  }, sink(function (chunk, enc, cb) {
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 60,
-      name: 'hello',
-      msg: 'hello \u001F world \n \u0022',
-      v: 1
-    })
-    cb()
-  }))
-
+  }, stream)
   instance.fatal('hello \u001F world \n \u0022')
+  const result = await once(stream, 'data')
+  delete result.time
+  same(result, {
+    pid: pid,
+    hostname: hostname,
+    level: 60,
+    name: 'hello',
+    msg: 'hello \u001F world \n \u0022',
+    v: 1
+  })
 })
diff --git a/test/events.test.js b/test/events.test.js
index cfbe487..bf89f8b 100644
--- a/test/events.test.js
+++ b/test/events.test.js
@@ -1,131 +1,59 @@
 'use strict'
 
-var test = require('tap').test
-var path = require('path')
-var writeStream = require('flush-write-stream')
-var fork = require('child_process').fork
-var spawn = require('child_process').spawn
-var fixturesPath = path.join(__dirname, 'fixtures', 'events')
-
-test('no event loop logs successfully', function (t) {
-  t.plan(1)
-  var output = ''
-  var child = fork(path.join(fixturesPath, 'no-event-loop.js'), {silent: true})
-
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
-    output += s
-    cb()
-  }))
-
-  child.on('close', function () {
-    t.match(output, /"msg":"h"/)
-  })
+const { test } = require('tap')
+const { join } = require('path')
+const { fork, spawn, spawnSync } = require('child_process')
+const { once } = require('./helper')
+
+const fixtures = join(__dirname, 'fixtures', 'events')
+
+test('logs successfully in a single tick process', async ({is}) => {
+  const child = fork(join(fixtures, 'single-tick.js'), {silent: true})
+  const output = await once(child.stdout, 'data')
+  await once(child, 'close')
+  is(/"msg":"h"/.test(await output), true)
 })
 
-test('terminates when uncaughtException is fired with onTerminate registered', function (t) {
-  t.plan(3)
-  var output = ''
-  var errorOutput = ''
-  var child = spawn(process.argv[0], [path.join(fixturesPath, 'uncaught-exception.js')], {silent: true})
-
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
-    output += s
-    cb()
-  }))
-
-  child.stderr.pipe(writeStream(function (s, enc, cb) {
-    errorOutput += s
-    cb()
-  }))
-
-  child.on('close', function () {
-    t.match(output, /"msg":"h"/)
-    t.match(output, /terminated/g)
-    t.match(errorOutput, /this is not caught/g)
-  })
+test('terminates when uncaughtException is fired with onTerminated registered', async ({is}) => {
+  const { stdout, stderr, status } = spawnSync(process.argv[0], [join(fixtures, 'uncaught-exception.js')], {timeout: 30000})
+  is(status, 0)
+  is(/"msg":"h"/.test(stdout), true)
+  is(/terminated/g.test(stdout), true)
+  is(/this is not caught/g.test(stderr), true)
 })
 
-test('terminates when uncaughtException is fired without onTerminate registered', function (t) {
-  t.plan(2)
-  var output = ''
-  var child = spawn(process.argv[0], [path.join(fixturesPath, 'uncaught-exception-no-terminate.js')], {silent: true})
-
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
-    output += s
-    cb()
-  }))
-
-  child.on('exit', function (code) {
-    t.is(code, 1)
-  })
-
-  child.on('close', function () {
-    t.match(output, /"msg":"h"/)
-  })
+test('terminates when uncaughtException is fired without onTerminated registered', async ({is}) => {
+  const { stdout, status } = spawnSync(process.argv[0], [join(fixtures, 'uncaught-exception-no-terminate.js')], {timeout: 30000})
+  is(status, 1)
+  is(/"msg":"h"/.test(stdout), true)
 })
 
-test('terminates on SIGHUP when no other handlers registered', function (t) {
-  t.plan(2)
-  var output = ''
-  var child = spawn(process.argv[0], [path.join(fixturesPath, 'sighup-no-handler.js')], {silent: true})
-
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
-    output += s
-    cb()
-  }))
-
-  child.stderr.pipe(process.stdout)
-
-  child.on('exit', function (code) {
-    t.is(code, 0)
-  })
-
-  child.on('close', function () {
-    t.match(output, /"msg":"h"/)
-  })
-
-  setTimeout(function () { child.kill('SIGHUP') }, 2000)
+test('terminates on SIGHUP when no other handlers registered', async ({is}) => {
+  const child = spawn(process.argv[0], [join(fixtures, 'sighup-no-handler.js')])
+  await once(child.stdout, 'data')
+  const output = once(child.stdout, 'data')
+  child.kill('SIGHUP')
+  const code = await once(child, 'exit')
+  is(code, 0)
+  is(/"msg":"h"/.test(await output), true)
 })
 
-test('lets app terminate when SIGHUP received with multiple handlers', function (t) {
-  t.plan(3)
-  var output = ''
-  var child = spawn(process.argv[0], [path.join(fixturesPath, 'sighup-with-handler.js')], {silent: true})
-
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
-    output += s
-    cb()
-  }))
-
-  child.on('exit', function (code) {
-    t.is(code, 0)
-  })
-
-  child.on('close', function () {
-    t.match(output, /"msg":"h"/)
-    t.match(output, /app sighup/)
-  })
-
-  setTimeout(function () { child.kill('SIGHUP') }, 2000)
+test('lets app terminate when SIGHUP received with multiple handlers', async ({is}) => {
+  const child = spawn(process.argv[0], [join(fixtures, 'sighup-with-handler.js')])
+  await once(child.stdout, 'data')
+  const output = once(child.stdout, 'data')
+  const output2 = output.then(() => once(child.stdout, 'data'))
+  child.kill('SIGHUP')
+  const code = await once(child, 'exit')
+  is(code, 0)
+  is(/"msg":"h"/.test(await output + ''), true)
+  is(/app sighup/.test(await output2 + ''), true)
 })
 
-test('destination', function (t) {
-  t.plan(2)
-  var output = ''
-  var child = spawn(process.argv[0], [path.join(fixturesPath, 'destination.js')], {silent: true})
-
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
-    output += s
-    cb()
-  }))
-
-  child.stderr.pipe(process.stdout)
-
-  child.on('exit', function (code) {
-    t.is(code, 0)
-  })
-
-  child.on('close', function () {
-    t.notEqual(null, output.match(/"msg":"h"/))
-  })
+test('destination', async ({is}) => {
+  const child = spawn(process.argv[0], [join(fixtures, 'destination.js')], {silent: true})
+  const output = once(child.stdout, 'data')
+  const code = await once(child, 'exit')
+  is(code, 0)
+  is(/"msg":"h"/.test(await output), true)
 })
diff --git a/test/extreme.test.js b/test/extreme.test.js
index 56f9ccb..4dcee0a 100644
--- a/test/extreme.test.js
+++ b/test/extreme.test.js
@@ -1,38 +1,37 @@
 'use strict'
 
-var test = require('tap').test
-var fs = require('fs')
-var os = require('os')
-var path = require('path')
-var writeStream = require('flush-write-stream')
-var fork = require('child_process').fork
-
-test('extreme mode', function (t) {
-  var now = Date.now
-  var hostname = os.hostname
-  var proc = process
+const os = require('os')
+const { createWriteStream } = require('fs')
+const { join } = require('path')
+const { test } = require('tap')
+const { fork } = require('child_process')
+const writer = require('flush-write-stream')
+const { once } = require('./helper')
+
+test('extreme mode', async ({is, teardown}) => {
+  const now = Date.now
+  const hostname = os.hostname
+  const proc = process
   global.process = {
     __proto__: process,
     pid: 123456
   }
-  Date.now = function () {
-    return 1459875739796
-  }
-  os.hostname = function () {
-    return 'abcdefghijklmnopqr'
-  }
+  Date.now = () => 1459875739796
+  os.hostname = () => 'abcdefghijklmnopqr'
   delete require.cache[require.resolve('../')]
-  var pino = require('../')
+  const pino = require('../')
   var expected = ''
   var actual = ''
-  var normal = pino(writeStream(function (s, enc, cb) {
+  const normal = pino(writer((s, enc, cb) => {
     expected += s
     cb()
   }))
 
-  var dest = fs.createWriteStream('/dev/null')
-  dest.write = function (s) { actual += s }
-  var extreme = pino(dest)
+  const dest = createWriteStream('/dev/null')
+  dest.write = (s) => {
+    actual += s
+  }
+  const extreme = pino(dest)
 
   var i = 44
   while (i--) {
@@ -43,30 +42,26 @@ test('extreme mode', function (t) {
   var expected2 = expected.split('\n')[0]
   var actual2 = ''
 
-  var child = fork(path.join(__dirname, '/fixtures/extreme.js'), {silent: true})
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
+  const child = fork(join(__dirname, '/fixtures/extreme.js'), {silent: true})
+  child.stdout.pipe(writer((s, enc, cb) => {
     actual2 += s
     cb()
   }))
-
-  child.on('close', function () {
-    t.is(actual, expected)
-    t.is(actual2.trim(), expected2)
-
-    t.teardown(function () {
-      os.hostname = hostname
-      Date.now = now
-      global.process = proc
-    })
-
-    t.end()
+  await once(child, 'close')
+  is(actual, expected)
+  is(actual2.trim(), expected2)
+
+  teardown(() => {
+    os.hostname = hostname
+    Date.now = now
+    global.process = proc
   })
 })
 
-test('extreme mode with child', function (t) {
-  var now = Date.now
-  var hostname = os.hostname
-  var proc = process
+test('extreme mode with child', async ({is, teardown}) => {
+  const now = Date.now
+  const hostname = os.hostname
+  const proc = process
   global.process = {
     __proto__: process,
     pid: 123456
@@ -78,17 +73,17 @@ test('extreme mode with child', function (t) {
     return 'abcdefghijklmnopqr'
   }
   delete require.cache[require.resolve('../')]
-  var pino = require('../')
+  const pino = require('../')
   var expected = ''
   var actual = ''
-  var normal = pino(writeStream(function (s, enc, cb) {
+  const normal = pino(writer((s, enc, cb) => {
     expected += s
     cb()
   })).child({ hello: 'world' })
 
-  var dest = fs.createWriteStream('/dev/null')
+  const dest = createWriteStream('/dev/null')
   dest.write = function (s) { actual += s }
-  var extreme = pino(dest).child({ hello: 'world' })
+  const extreme = pino(dest).child({ hello: 'world' })
 
   var i = 500
   while (i--) {
@@ -101,36 +96,30 @@ test('extreme mode with child', function (t) {
   var expected2 = expected.split('\n')[0]
   var actual2 = ''
 
-  var child = fork(path.join(__dirname, '/fixtures/extreme-child.js'), {silent: true})
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
+  const child = fork(join(__dirname, '/fixtures/extreme-child.js'), {silent: true})
+  child.stdout.pipe(writer((s, enc, cb) => {
     actual2 += s
     cb()
   }))
-
-  child.on('close', function () {
-    t.is(actual, expected)
-    t.is(actual2.trim(), expected2)
-
-    t.teardown(function () {
-      os.hostname = hostname
-      Date.now = now
-      global.process = proc
-    })
-
-    t.end()
+  await once(child, 'close')
+  is(actual, expected)
+  is(actual2.trim(), expected2)
+
+  teardown(() => {
+    os.hostname = hostname
+    Date.now = now
+    global.process = proc
   })
 })
 
-test('throw an error if extreme is passed', function (t) {
-  var pino = require('..')
-  t.throws(() => {
+test('throw an error if extreme is passed', async ({throws}) => {
+  const pino = require('..')
+  throws(() => {
     pino({extreme: true})
   })
-  t.end()
 })
 
-test('flush does nothing without extreme mode', function (t) {
+test('flush does nothing without extreme mode', async () => {
   var instance = require('..')()
   instance.flush()
-  t.end()
 })
diff --git a/test/fixtures/events/sighup-no-handler.js b/test/fixtures/events/sighup-no-handler.js
index af2c21b..e596abc 100644
--- a/test/fixtures/events/sighup-no-handler.js
+++ b/test/fixtures/events/sighup-no-handler.js
@@ -19,4 +19,5 @@ log.info('h')
 function foo () {
   setTimeout(foo, 500)
 }
+console.log('ready')
 foo()
diff --git a/test/fixtures/events/sighup-with-handler.js b/test/fixtures/events/sighup-with-handler.js
index f02c2c2..c564b5b 100644
--- a/test/fixtures/events/sighup-with-handler.js
+++ b/test/fixtures/events/sighup-with-handler.js
@@ -13,4 +13,5 @@ process.on('SIGHUP', function () {
 function foo () {
   setTimeout(foo, 500)
 }
+console.log('ready')
 foo()
diff --git a/test/fixtures/events/no-event-loop.js b/test/fixtures/events/single-tick.js
similarity index 100%
rename from test/fixtures/events/no-event-loop.js
rename to test/fixtures/events/single-tick.js
diff --git a/test/helper.js b/test/helper.js
index d4a8811..b6b322e 100644
--- a/test/helper.js
+++ b/test/helper.js
@@ -1,28 +1,36 @@
 'use strict'
 
-var writeStream = require('flush-write-stream')
-var split = require('split2')
-var os = require('os')
-var pid = process.pid
-var hostname = os.hostname()
+const os = require('os')
+const writer = require('flush-write-stream')
+const split = require('split2')
+const pid = process.pid
+const hostname = os.hostname()
+const v = 1
+
+function once (emitter, name) {
+  return new Promise((resolve, reject) => {
+    if (name !== 'error') emitter.once('error', reject)
+    emitter.once(name, (...args) => {
+      emitter.removeListener('error', reject)
+      resolve(...args)
+    })
+  })
+}
 
 function sink (func) {
-  var result = split(JSON.parse)
-  result.pipe(writeStream.obj(func))
+  const result = split(JSON.parse)
+  if (func) result.pipe(writer.obj(func))
   return result
 }
 
-function check (t, chunk, level, msg) {
-  t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+function check (is, chunk, level, msg) {
+  is(new Date(chunk.time) <= new Date(), true, 'time is greater than Date.now()')
   delete chunk.time
-  t.deepEqual(chunk, {
-    pid: pid,
-    hostname: hostname,
-    level: level,
-    msg: msg,
-    v: 1
-  })
+  is(chunk.pid, pid)
+  is(chunk.hostname, hostname)
+  is(chunk.level, level)
+  is(chunk.msg, msg)
+  is(chunk.v, v)
 }
 
-module.exports.sink = sink
-module.exports.check = check
+module.exports = { sink, check, once }
diff --git a/test/http.test.js b/test/http.test.js
index 365fa63..afd3570 100644
--- a/test/http.test.js
+++ b/test/http.test.js
@@ -1,22 +1,20 @@
 'use strict'
 
-var test = require('tap').test
-var os = require('os')
-var pino = require('../')
-var sink = require('./helper').sink
-var http = require('http')
+const http = require('http')
+const os = require('os')
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const pino = require('../')
 
-var pid = process.pid
-var hostname = os.hostname()
-
-test('http request support', function (t) {
-  t.plan(3)
+const { pid } = process
+const hostname = os.hostname()
 
+test('http request support', async ({ok, same, error, teardown}) => {
   var originalReq
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+  const instance = pino(sink((chunk, enc) => {
+    ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
     delete chunk.time
-    t.deepEqual(chunk, {
+    same(chunk, {
       pid: pid,
       hostname: hostname,
       level: 30,
@@ -30,35 +28,32 @@ test('http request support', function (t) {
         remotePort: originalReq.connection.remotePort
       }
     })
-    cb()
   }))
 
-  var server = http.createServer(function (req, res) {
+  const server = http.createServer((req, res) => {
     originalReq = req
     instance.info(req, 'my request')
     res.end('hello')
-  }).listen(function (err) {
-    t.error(err)
-    t.teardown(server.close.bind(server))
-
-    http.get('http://localhost:' + server.address().port, function (res) {
-      res.resume()
-    })
   })
+  server.unref()
+  server.listen()
+  const err = await once(server, 'listening')
+  error(err)
+  const res = await once(http.get('http://localhost:' + server.address().port), 'response')
+  res.resume()
+  server.close()
 })
 
-test('http request support via serializer', function (t) {
-  t.plan(3)
-
+test('http request support via serializer', async ({ok, same, error, teardown}) => {
   var originalReq
-  var instance = pino({
+  const instance = pino({
     serializers: {
       req: pino.stdSerializers.req
     }
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+  }, sink((chunk, enc) => {
+    ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
     delete chunk.time
-    t.deepEqual(chunk, {
+    same(chunk, {
       pid: pid,
       hostname: hostname,
       level: 30,
@@ -72,35 +67,33 @@ test('http request support via serializer', function (t) {
         remotePort: originalReq.connection.remotePort
       }
     })
-    cb()
   }))
 
-  var server = http.createServer(function (req, res) {
+  const server = http.createServer(function (req, res) {
     originalReq = req
     instance.info({ req: req }, 'my request')
     res.end('hello')
-  }).listen(function (err) {
-    t.error(err)
-    t.teardown(server.close.bind(server))
-
-    http.get('http://localhost:' + server.address().port, function (res) {
-      res.resume()
-    })
   })
+  server.unref()
+  server.listen()
+  const err = await once(server, 'listening')
+  error(err)
+
+  const res = await once(http.get('http://localhost:' + server.address().port), 'response')
+  res.resume()
+  server.close()
 })
 
-test('http request support via serializer without request connection', function (t) {
-  t.plan(3)
-
+test('http request support via serializer without request connection', async ({ok, same, error, teardown}) => {
   var originalReq
-  var instance = pino({
+  const instance = pino({
     serializers: {
       req: pino.stdSerializers.req
     }
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+  }, sink((chunk, enc) => {
+    ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
     delete chunk.time
-    t.deepEqual(chunk, {
+    same(chunk, {
       pid: pid,
       hostname: hostname,
       level: 30,
@@ -112,32 +105,30 @@ test('http request support via serializer without request connection', function
         headers: originalReq.headers
       }
     })
-    cb()
   }))
 
-  var server = http.createServer(function (req, res) {
+  const server = http.createServer(function (req, res) {
     originalReq = req
     delete req.connection
     instance.info({ req: req }, 'my request')
     res.end('hello')
-  }).listen(function (err) {
-    t.error(err)
-    t.teardown(server.close.bind(server))
-
-    http.get('http://localhost:' + server.address().port, function (res) {
-      res.resume()
-    })
   })
+  server.unref()
+  server.listen()
+  const err = await once(server, 'listening')
+  error(err)
+
+  const res = await once(http.get('http://localhost:' + server.address().port), 'response')
+  res.resume()
+  server.close()
 })
 
-test('http response support', function (t) {
-  t.plan(3)
-
+test('http response support', async ({ok, same, error, teardown}) => {
   var originalRes
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+  const instance = pino(sink((chunk, enc) => {
+    ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
     delete chunk.time
-    t.deepEqual(chunk, {
+    same(chunk, {
       pid: pid,
       hostname: hostname,
       level: 30,
@@ -148,35 +139,34 @@ test('http response support', function (t) {
         header: originalRes._header
       }
     })
-    cb()
   }))
 
-  var server = http.createServer(function (req, res) {
+  const server = http.createServer(function (req, res) {
     originalRes = res
     res.end('hello')
     instance.info(res, 'my response')
-  }).listen(function (err) {
-    t.error(err)
-    t.teardown(server.close.bind(server))
-
-    http.get('http://localhost:' + server.address().port, function (res) {
-      res.resume()
-    })
   })
-})
+  server.unref()
+  server.listen()
+  const err = await once(server, 'listening')
+
+  error(err)
 
-test('http response support via a serializer', function (t) {
-  t.plan(3)
+  const res = await once(http.get('http://localhost:' + server.address().port), 'response')
+  res.resume()
+  server.close()
+})
 
+test('http response support via a serializer', async ({ok, same, error, teardown}) => {
   var originalRes
-  var instance = pino({
+  const instance = pino({
     serializers: {
       res: pino.stdSerializers.res
     }
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+  }, sink((chunk, enc) => {
+    ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
     delete chunk.time
-    t.deepEqual(chunk, {
+    same(chunk, {
       pid: pid,
       hostname: hostname,
       level: 30,
@@ -187,35 +177,34 @@ test('http response support via a serializer', function (t) {
         header: originalRes._header
       }
     })
-    cb()
   }))
 
-  var server = http.createServer(function (req, res) {
+  const server = http.createServer(function (req, res) {
     originalRes = res
     res.end('hello')
     instance.info({ res: res }, 'my response')
-  }).listen(function (err) {
-    t.error(err)
-    t.teardown(server.close.bind(server))
-
-    http.get('http://localhost:' + server.address().port, function (res) {
-      res.resume()
-    })
   })
-})
 
-test('http request support via serializer in a child', function (t) {
-  t.plan(3)
+  server.unref()
+  server.listen()
+  const err = await once(server, 'listening')
+  error(err)
 
+  const res = await once(http.get('http://localhost:' + server.address().port), 'response')
+  res.resume()
+  server.close()
+})
+
+test('http request support via serializer in a child', async ({ok, same, error, teardown}) => {
   var originalReq
-  var instance = pino({
+  const instance = pino({
     serializers: {
       req: pino.stdSerializers.req
     }
-  }, sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
+  }, sink((chunk, enc) => {
+    ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
     delete chunk.time
-    t.deepEqual(chunk, {
+    same(chunk, {
       pid: pid,
       hostname: hostname,
       level: 30,
@@ -229,20 +218,21 @@ test('http request support via serializer in a child', function (t) {
         remotePort: originalReq.connection.remotePort
       }
     })
-    cb()
   }))
 
-  var server = http.createServer(function (req, res) {
+  const server = http.createServer(function (req, res) {
     originalReq = req
-    var child = instance.child({ req: req })
+    const child = instance.child({ req: req })
     child.info('my request')
     res.end('hello')
-  }).listen(function (err) {
-    t.error(err)
-    t.teardown(server.close.bind(server))
-
-    http.get('http://localhost:' + server.address().port, function (res) {
-      res.resume()
-    })
   })
+
+  server.unref()
+  server.listen()
+  const err = await once(server, 'listening')
+  error(err)
+
+  const res = await once(http.get('http://localhost:' + server.address().port), 'response')
+  res.resume()
+  server.close()
 })
diff --git a/test/is-level-enabled.test.js b/test/is-level-enabled.test.js
index 34992f3..32ca8ce 100644
--- a/test/is-level-enabled.test.js
+++ b/test/is-level-enabled.test.js
@@ -1,53 +1,41 @@
 'use strict'
 
-var test = require('tap').test
-var pino = require('../')
+const { test } = require('tap')
+const pino = require('../')
 
-test('can check if current level enabled', function (t) {
-  t.plan(1)
-
-  var log = pino({level: 'debug'})
-  t.is(true, log.isLevelEnabled('debug'))
+test('can check if current level enabled', async ({is}) => {
+  const log = pino({level: 'debug'})
+  is(true, log.isLevelEnabled('debug'))
 })
 
-test('can check if level enabled after level set', function (t) {
-  t.plan(2)
-
-  var log = pino()
-  t.is(false, log.isLevelEnabled('debug'))
+test('can check if level enabled after level set', async ({is}) => {
+  const log = pino()
+  is(false, log.isLevelEnabled('debug'))
   log.level = 'debug'
-  t.is(true, log.isLevelEnabled('debug'))
+  is(true, log.isLevelEnabled('debug'))
 })
 
-test('can check if higher level enabled', function (t) {
-  t.plan(1)
-
-  var log = pino({level: 'debug'})
-  t.is(true, log.isLevelEnabled('error'))
+test('can check if higher level enabled', async ({is}) => {
+  const log = pino({level: 'debug'})
+  is(true, log.isLevelEnabled('error'))
 })
 
-test('can check if lower level is disabled', function (t) {
-  t.plan(1)
-
-  var log = pino({level: 'error'})
-  t.is(false, log.isLevelEnabled('trace'))
+test('can check if lower level is disabled', async ({is}) => {
+  const log = pino({level: 'error'})
+  is(false, log.isLevelEnabled('trace'))
 })
 
-test('can check if child has current level enabled', function (t) {
-  t.plan(3)
-
-  var log = pino().child({level: 'debug'})
-  t.is(true, log.isLevelEnabled('debug'))
-  t.is(true, log.isLevelEnabled('error'))
-  t.is(false, log.isLevelEnabled('trace'))
+test('can check if child has current level enabled', async ({is}) => {
+  const log = pino().child({level: 'debug'})
+  is(true, log.isLevelEnabled('debug'))
+  is(true, log.isLevelEnabled('error'))
+  is(false, log.isLevelEnabled('trace'))
 })
 
-test('can check if custom level is enabled', function (t) {
-  t.plan(3)
-
-  var log = pino({level: 'debug'})
+test('can check if custom level is enabled', async ({is}) => {
+  const log = pino({level: 'debug'})
   log.addLevel('foo', 35)
-  t.is(true, log.isLevelEnabled('foo'))
-  t.is(true, log.isLevelEnabled('error'))
-  t.is(false, log.isLevelEnabled('trace'))
+  is(true, log.isLevelEnabled('foo'))
+  is(true, log.isLevelEnabled('error'))
+  is(false, log.isLevelEnabled('trace'))
 })
diff --git a/test/levels.test.js b/test/levels.test.js
index 6f57b2f..4c2b1c9 100644
--- a/test/levels.test.js
+++ b/test/levels.test.js
@@ -1,131 +1,122 @@
 'use strict'
 
-var test = require('tap').test
-var pino = require('../')
-var sink = require('./helper').sink
-var check = require('./helper').check
-
-test('set the level by string', function (t) {
-  t.plan(4)
-  var expected = [{
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const { check } = require('./helper')
+const pino = require('../')
+
+test('set the level by string', async ({is}) => {
+  const expected = [{
     level: 50,
     msg: 'this is an error'
   }, {
     level: 60,
     msg: 'this is fatal'
   }]
-  var instance = pino(sink(function (chunk, enc, cb) {
-    var current = expected.shift()
-    check(t, chunk, current.level, current.msg)
-    cb()
-  }))
-
+  const stream = sink()
+  const instance = pino(stream)
   instance.level = 'error'
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
+  const result = await once(stream, 'data')
+  const current = expected.shift()
+  check(is, result, current.level, current.msg)
 })
 
-test('the wrong level throws', function (t) {
-  t.plan(1)
-  var instance = pino()
-  t.throws(function () {
+test('the wrong level throws', async ({throws}) => {
+  const instance = pino()
+  throws(() => {
     instance.level = 'kaboom'
   })
 })
 
-test('set the level by number', function (t) {
-  t.plan(4)
-  var expected = [{
+test('set the level by number', async ({is}) => {
+  const expected = [{
     level: 50,
     msg: 'this is an error'
   }, {
     level: 60,
     msg: 'this is fatal'
   }]
-  var instance = pino(sink(function (chunk, enc, cb) {
-    var current = expected.shift()
-    check(t, chunk, current.level, current.msg)
-    cb()
-  }))
+  const stream = sink()
+  const instance = pino(stream)
 
   instance.levelVal = 50
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
+  const result = await once(stream, 'data')
+  const current = expected.shift()
+  check(is, result, current.level, current.msg)
 })
 
-test('set the level by number via string method', function (t) {
-  t.plan(4)
-  var expected = [{
+test('set the level by number via string method', async ({is}) => {
+  const expected = [{
     level: 50,
     msg: 'this is an error'
   }, {
     level: 60,
     msg: 'this is fatal'
   }]
-  var instance = pino(sink(function (chunk, enc, cb) {
-    var current = expected.shift()
-    check(t, chunk, current.level, current.msg)
-    cb()
-  }))
+  const stream = sink()
+  const instance = pino(stream)
 
   instance.level = 50
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
+
+  const result = await once(stream, 'data')
+  const current = expected.shift()
+  check(is, result, current.level, current.msg)
 })
 
-test('exposes level string mappings', function (t) {
-  t.plan(1)
-  t.equal(pino.levels.values.error, 50)
+test('exposes level string mappings', async ({is}) => {
+  is(pino.levels.values.error, 50)
 })
 
-test('exposes level number mappings', function (t) {
-  t.plan(1)
-  t.equal(pino.levels.labels[50], 'error')
+test('exposes level number mappings', async ({is}) => {
+  is(pino.levels.labels[50], 'error')
 })
 
-test('returns level integer', function (t) {
-  t.plan(1)
-  var instance = pino({ level: 'error' })
-  t.equal(instance.levelVal, 50)
+test('returns level integer', async ({is}) => {
+  const instance = pino({ level: 'error' })
+  is(instance.levelVal, 50)
 })
 
-test('child returns level integer', function (t) {
-  t.plan(1)
-  var parent = pino({ level: 'error' })
-  var child = parent.child({ foo: 'bar' })
-  t.equal(child.levelVal, 50)
+test('child returns level integer', async ({is}) => {
+  const parent = pino({ level: 'error' })
+  const child = parent.child({ foo: 'bar' })
+  is(child.levelVal, 50)
 })
 
-test('set the level via constructor', function (t) {
-  t.plan(4)
-  var expected = [{
+test('set the level via constructor', async ({is}) => {
+  const expected = [{
     level: 50,
     msg: 'this is an error'
   }, {
     level: 60,
     msg: 'this is fatal'
   }]
-  var instance = pino({ level: 'error' }, sink(function (chunk, enc, cb) {
-    var current = expected.shift()
-    check(t, chunk, current.level, current.msg)
-    cb()
-  }))
+  const stream = sink()
+  const instance = pino({ level: 'error' }, stream)
 
   instance.info('hello world')
   instance.error('this is an error')
   instance.fatal('this is fatal')
-})
-
-test('level-change event', function (t) {
-  var instance = pino()
-  var handle = function (lvl, val, prevLvl, prevVal) {
-    t.is(lvl, 'trace')
-    t.is(val, 10)
-    t.is(prevLvl, 'info')
-    t.is(prevVal, 30)
+  const result = await once(stream, 'data')
+  const current = expected.shift()
+  check(is, result, current.level, current.msg)
+})
+
+test('level-change event', async ({is}) => {
+  const instance = pino()
+  function handle (lvl, val, prevLvl, prevVal) {
+    is(lvl, 'trace')
+    is(val, 10)
+    is(prevLvl, 'info')
+    is(prevVal, 30)
   }
   instance.on('level-change', handle)
   instance.level = 'trace'
@@ -134,9 +125,9 @@ test('level-change event', function (t) {
 
   var count = 0
 
-  var l1 = function () { count += 1 }
-  var l2 = function () { count += 1 }
-  var l3 = function () { count += 1 }
+  const l1 = () => count++
+  const l2 = () => count++
+  const l3 = () => count++
   instance.on('level-change', l1)
   instance.on('level-change', l2)
   instance.on('level-change', l3)
@@ -149,69 +140,62 @@ test('level-change event', function (t) {
   instance.removeListener('level-change', l2)
   instance.level = 'info'
 
-  t.is(count, 6)
-  t.end()
+  is(count, 6)
 })
 
-test('enable', function (t) {
-  var instance = pino({
+test('enable', async ({fail}) => {
+  const instance = pino({
     level: 'trace',
     enabled: false
-  }, sink(function (chunk, enc, cb) {
-    t.fail('no data should be logged')
+  }, sink((result, enc) => {
+    fail('no data should be logged')
   }))
 
-  Object.keys(pino.levels.values).forEach(function (level) {
+  Object.keys(pino.levels.values).forEach((level) => {
     instance[level]('hello world')
   })
-  t.end()
 })
 
-test('silent level', function (t) {
-  var instance = pino({
+test('silent level', async ({fail}) => {
+  const instance = pino({
     level: 'silent'
-  }, sink(function (chunk, enc, cb) {
-    t.fail('no data should be logged')
+  }, sink((result, enc) => {
+    fail('no data should be logged')
   }))
 
-  Object.keys(pino.levels.values).forEach(function (level) {
+  Object.keys(pino.levels.values).forEach((level) => {
     instance[level]('hello world')
   })
-  t.end()
 })
 
-test('silent is a noop', function (t) {
-  var instance = pino({
+test('silent is a noop', async ({fail}) => {
+  const instance = pino({
     level: 'silent'
-  }, sink(function (chunk, enc, cb) {
-    t.fail('no data should be logged')
+  }, sink((result, enc) => {
+    fail('no data should be logged')
   }))
 
   instance['silent']('hello world')
-  t.end()
 })
 
-test('silent stays a noop after level changes', function (t) {
-  var noop = require('../lib/tools').noop
-  var instance = pino({
+test('silent stays a noop after level changes', async ({is, isNot, fail}) => {
+  const noop = require('../lib/tools').noop
+  const instance = pino({
     level: 'silent'
-  }, sink(function (chunk, enc, cb) {
-    t.fail('no data should be logged')
+  }, sink((result, enc) => {
+    fail('no data should be logged')
   }))
 
   instance.level = 'trace'
-  t.notEqual(instance[instance.level], noop)
+  isNot(instance[instance.level], noop)
 
   instance.level = 'silent'
   instance['silent']('hello world')
-  t.is(instance[instance.level], noop)
-
-  t.end()
+  is(instance[instance.level], noop)
 })
 
-test('exposed levels', function (t) {
-  t.plan(1)
-  t.deepEqual(Object.keys(pino.levels.values), [
+test('exposed levels', async ({same}) => {
+  same(Object.keys(pino.levels.values), [
     'fatal',
     'error',
     'warn',
@@ -221,9 +205,8 @@ test('exposed levels', function (t) {
   ])
 })
 
-test('exposed labels', function (t) {
-  t.plan(1)
-  t.deepEqual(Object.keys(pino.levels.labels), [
+test('exposed labels', async ({same}) => {
+  same(Object.keys(pino.levels.labels), [
     '10',
     '20',
     '30',
@@ -233,18 +216,17 @@ test('exposed labels', function (t) {
   ])
 })
 
-test('setting level in child', function (t) {
-  t.plan(4)
-  var expected = [{
+test('setting level in child', async ({is}) => {
+  const expected = [{
     level: 50,
     msg: 'this is an error'
   }, {
     level: 60,
     msg: 'this is fatal'
   }]
-  var instance = pino(sink(function (chunk, enc, cb) {
-    var current = expected.shift()
-    check(t, chunk, current.level, current.msg)
+  const instance = pino(sink((result, enc, cb) => {
+    const current = expected.shift()
+    check(is, result, current.level, current.msg)
     cb()
   })).child({ level: 30 })
 
diff --git a/test/metadata.test.js b/test/metadata.test.js
index 38f53e8..a2d60d3 100644
--- a/test/metadata.test.js
+++ b/test/metadata.test.js
@@ -1,121 +1,108 @@
 'use strict'
 
-var test = require('tap').test
-var os = require('os')
-var pino = require('../')
-var sink = require('./helper').sink
+const os = require('os')
+const { test } = require('tap')
+const pino = require('../')
 
-var pid = process.pid
-var hostname = os.hostname()
+const { pid } = process
+const hostname = os.hostname()
 
-test('metadata works', function (t) {
-  t.plan(7)
-  var dest = sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      hello: 'world',
-      msg: 'a msg',
-      v: 1
-    })
-  })
-  var now = Date.now()
-  var instance = pino({}, {
+test('metadata works', async ({ok, same, is}) => {
+  const now = Date.now()
+  const instance = pino({}, {
     [Symbol.for('needsMetadata')]: true,
-    write: function (chunk) {
-      t.equal(instance, this.lastLogger)
-      t.equal(30, this.lastLevel)
-      t.equal('a msg', this.lastMsg)
-      t.ok(Number(this.lastTime) >= now)
-      t.deepEqual({ hello: 'world' }, this.lastObj)
-      dest.write(chunk)
+    write (chunk) {
+      is(instance, this.lastLogger)
+      is(30, this.lastLevel)
+      is('a msg', this.lastMsg)
+      ok(Number(this.lastTime) >= now)
+      same({ hello: 'world' }, this.lastObj)
+      const result = JSON.parse(chunk)
+      ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+      delete result.time
+      same(result, {
+        pid: pid,
+        hostname: hostname,
+        level: 30,
+        hello: 'world',
+        msg: 'a msg',
+        v: 1
+      })
     }
   })
 
   instance.info({ hello: 'world' }, 'a msg')
 })
 
-test('child loggers works', function (t) {
-  t.plan(6)
-  var dest = sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      hello: 'world',
-      from: 'child',
-      msg: 'a msg',
-      v: 1
-    })
-  })
-  var instance = pino({}, {
+test('child loggers works', async ({ok, same, is}) => {
+  const instance = pino({}, {
     [Symbol.for('needsMetadata')]: true,
-    write: function (chunk) {
-      t.equal(child, this.lastLogger)
-      t.equal(30, this.lastLevel)
-      t.equal('a msg', this.lastMsg)
-      t.deepEqual({ from: 'child' }, this.lastObj)
-      dest.write(chunk)
+    write (chunk) {
+      is(child, this.lastLogger)
+      is(30, this.lastLevel)
+      is('a msg', this.lastMsg)
+      same({ from: 'child' }, this.lastObj)
+      const result = JSON.parse(chunk)
+      ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+      delete result.time
+      same(result, {
+        pid: pid,
+        hostname: hostname,
+        level: 30,
+        hello: 'world',
+        from: 'child',
+        msg: 'a msg',
+        v: 1
+      })
     }
   })
 
-  var child = instance.child({ hello: 'world' })
+  const child = instance.child({ hello: 'world' })
   child.info({ from: 'child' }, 'a msg')
 })
 
-test('without object', function (t) {
-  t.plan(6)
-  var dest = sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      msg: 'a msg',
-      v: 1
-    })
-  })
-  var instance = pino({}, {
+test('without object', async ({ok, same, is}) => {
+  const instance = pino({}, {
     [Symbol.for('needsMetadata')]: true,
-    write: function (chunk) {
-      t.equal(instance, this.lastLogger)
-      t.equal(30, this.lastLevel)
-      t.equal('a msg', this.lastMsg)
-      t.equal(null, this.lastObj)
-      dest.write(chunk)
+    write (chunk) {
+      is(instance, this.lastLogger)
+      is(30, this.lastLevel)
+      is('a msg', this.lastMsg)
+      is(null, this.lastObj)
+      const result = JSON.parse(chunk)
+      ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+      delete result.time
+      same(result, {
+        pid: pid,
+        hostname: hostname,
+        level: 30,
+        msg: 'a msg',
+        v: 1
+      })
     }
   })
 
   instance.info('a msg')
 })
 
-test('without msg', function (t) {
-  t.plan(6)
-  var dest = sink(function (chunk, enc, cb) {
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than Date.now()')
-    delete chunk.time
-    t.deepEqual(chunk, {
-      pid: pid,
-      hostname: hostname,
-      level: 30,
-      hello: 'world',
-      v: 1
-    })
-  })
-  var instance = pino({}, {
+test('without msg', async ({ok, same, is}) => {
+  const instance = pino({}, {
     [Symbol.for('needsMetadata')]: true,
-    write: function (chunk) {
-      t.equal(instance, this.lastLogger)
-      t.equal(30, this.lastLevel)
-      t.equal(undefined, this.lastMsg)
-      t.deepEqual({ hello: 'world' }, this.lastObj)
-      dest.write(chunk)
+    write (chunk) {
+      is(instance, this.lastLogger)
+      is(30, this.lastLevel)
+      is(undefined, this.lastMsg)
+      same({ hello: 'world' }, this.lastObj)
+      const result = JSON.parse(chunk)
+      ok(new Date(result.time) <= new Date(), 'time is greater than Date.now()')
+      delete result.time
+      same(result, {
+        pid: pid,
+        hostname: hostname,
+        level: 30,
+        hello: 'world',
+        v: 1
+      })
     }
   })
 
diff --git a/test/pretty.test.js b/test/pretty.test.js
index 2baffbb..7f2b2cd 100644
--- a/test/pretty.test.js
+++ b/test/pretty.test.js
@@ -1,74 +1,63 @@
 'use strict'
 
-var Writable = require('stream').Writable
-var test = require('tap').test
-var pino = require('../')
-var path = require('path')
-var writeStream = require('flush-write-stream')
-var fork = require('child_process').fork
-
-test('can be enabled via constructor', function (t) {
-  t.plan(1)
+const { Writable } = require('stream')
+const { test } = require('tap')
+const { join } = require('path')
+const { fork } = require('child_process')
+const writer = require('flush-write-stream')
+const { once } = require('./helper')
+const pino = require('../')
+
+test('can be enabled via constructor', async ({isNot}) => {
   var actual = ''
-  var child = fork(path.join(__dirname, 'fixtures', 'pretty', 'basic.js'), {silent: true})
+  const child = fork(join(__dirname, 'fixtures', 'pretty', 'basic.js'), {silent: true})
 
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
+  child.stdout.pipe(writer((s, enc, cb) => {
     actual += s
     cb()
   }))
-
-  child.on('close', function () {
-    t.notEqual(actual.match(/\(123456 on abcdefghijklmnopqr\): h/), null)
-  })
+  await once(child, 'close')
+  isNot(actual.match(/\(123456 on abcdefghijklmnopqr\): h/), null)
 })
 
-test('can be enabled via constructor with pretty configuration', function (t) {
-  t.plan(1)
+test('can be enabled via constructor with pretty configuration', async ({isNot}) => {
   var actual = ''
-  var child = fork(path.join(__dirname, 'fixtures', 'pretty', 'level-first.js'), {silent: true})
+  const child = fork(join(__dirname, 'fixtures', 'pretty', 'level-first.js'), {silent: true})
 
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
+  child.stdout.pipe(writer((s, enc, cb) => {
     actual += s
     cb()
   }))
-
-  child.on('close', function () {
-    t.notEqual(actual.match(/^INFO.*h/), null)
-  })
+  await once(child, 'close')
+  isNot(actual.match(/^INFO.*h/), null)
 })
 
-test('can be enabled via constructor with prettifier', function (t) {
-  t.plan(1)
+test('can be enabled via constructor with prettifier', async ({isNot}) => {
   var actual = ''
-  var child = fork(path.join(__dirname, 'fixtures', 'pretty', 'pretty-factory.js'), {silent: true})
+  const child = fork(join(__dirname, 'fixtures', 'pretty', 'pretty-factory.js'), {silent: true})
 
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
+  child.stdout.pipe(writer((s, enc, cb) => {
     actual += s
     cb()
   }))
 
-  child.on('close', function () {
-    t.notEqual(actual.match(/^INFO.*h/), null)
-  })
+  await once(child, 'close')
+  isNot(actual.match(/^INFO.*h/), null)
 })
 
-test('does not throw error when enabled with stream specified', function (t) {
+test('does not throw error when enabled with stream specified', async () => {
   pino({prettyPrint: true}, process.stdout)
-  t.end()
 })
 
-test('can send pretty print to custom stream', function (t) {
-  t.plan(1)
-
-  var dest = new Writable({
+test('can send pretty print to custom stream', async ({is}) => {
+  const dest = new Writable({
     objectMode: true,
-    write (formatted, enc, cb) {
-      t.match(formatted, /^INFO.*foo\n$/)
-      cb()
+    write (formatted, enc) {
+      is(/^INFO.*foo\n$/.test(formatted), true)
     }
   })
 
-  var log = pino({
+  const log = pino({
     prettifier: require('pino-pretty'),
     prettyPrint: {
       levelFirst: true
@@ -77,17 +66,14 @@ test('can send pretty print to custom stream', function (t) {
   log.info('foo')
 })
 
-test('ignores `undefined` from prettifier', function (t) {
-  t.plan(1)
+test('ignores `undefined` from prettifier', async ({is}) => {
   var actual = ''
-  var child = fork(path.join(__dirname, 'fixtures', 'pretty', 'skipped-output.js'), {silent: true})
+  const child = fork(join(__dirname, 'fixtures', 'pretty', 'skipped-output.js'), {silent: true})
 
-  child.stdout.pipe(writeStream(function (s, enc, cb) {
+  child.stdout.pipe(writer((s, enc) => {
     actual += s
-    cb()
   }))
 
-  child.on('close', function () {
-    t.is(actual, '')
-  })
+  await once(child, 'close')
+  is(actual, '')
 })
diff --git a/test/redact.test.js b/test/redact.test.js
index cca54f0..bc20ab9 100644
--- a/test/redact.test.js
+++ b/test/redact.test.js
@@ -1,73 +1,64 @@
 'use strict'
 
-var test = require('tap').test
-var pino = require('../')
-var sink = require('./helper').sink
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const pino = require('../')
 
-test('redact option – throws if not array', function (t) {
-  t.throws(() => {
+test('redact option – throws if not array', async ({throws}) => {
+  throws(() => {
     pino({redact: 'req.headers.cookie'})
   })
-  t.end()
 })
 
-test('redact option – throws if array does not only contain strings', function (t) {
-  t.throws(() => {
+test('redact option – throws if array does not only contain strings', async ({throws}) => {
+  throws(() => {
     pino({redact: ['req.headers.cookie', {}]})
   })
-  t.end()
 })
 
-test('redact option – throws if array contains an invalid path', function (t) {
-  t.throws(() => {
+test('redact option – throws if array contains an invalid path', async ({throws}) => {
+  throws(() => {
     pino({redact: ['req,headers.cookie']})
   })
-  t.end()
 })
 
-test('redact.paths option – throws if not array', function (t) {
-  t.throws(() => {
+test('redact.paths option – throws if not array', async ({throws}) => {
+  throws(() => {
     pino({redact: {paths: 'req.headers.cookie'}})
   })
-  t.end()
 })
 
-test('redact.paths option – throws if array does not only contain strings', function (t) {
-  t.throws(() => {
+test('redact.paths option – throws if array does not only contain strings', async ({throws}) => {
+  throws(() => {
     pino({redact: {paths: ['req.headers.cookie', {}]}})
   })
-  t.end()
 })
 
-test('redact.paths option – throws if array contains an invalid path', function (t) {
-  t.throws(() => {
+test('redact.paths option – throws if array contains an invalid path', async ({throws}) => {
+  throws(() => {
     pino({redact: {paths: ['req,headers.cookie']}})
   })
-  t.end()
 })
 
-test('redact.censor option – throws if censor is a function', function (t) {
-  t.throws(() => {
+test('redact.censor option – throws if censor is a function', async ({throws}) => {
+  throws(() => {
     pino({redact: {paths: ['req.headers.cookie'], censor: () => {}}})
   })
-  t.end()
 })
 
-test('redact option – top level key', function (t) {
-  var instance = pino({redact: ['key']}, sink(function (o, enc, cb) {
-    t.equals(o.key, '[Redacted]')
-    t.end()
-  }))
+test('redact option – top level key', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: ['key']}, stream)
   instance.info({
     key: {redact: 'me'}
   })
+  const { key } = await once(stream, 'data')
+  is(key, '[Redacted]')
 })
 
-test('redact option – object', function (t) {
-  var instance = pino({redact: ['req.headers.cookie']}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.end()
-  }))
+test('redact option – object', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: ['req.headers.cookie']}, stream)
   instance.info({
     req: {
       id: 7915,
@@ -82,14 +73,13 @@ test('redact option – object', function (t) {
       remotePort: 58022
     }
   })
+  const { req } = await once(stream, 'data')
+  is(req.headers.cookie, '[Redacted]')
 })
 
-test('redact option – child object', function (t) {
-  var instance = pino({redact: ['req.headers.cookie']}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.end()
-  }))
-
+test('redact option – child object', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: ['req.headers.cookie']}, stream)
   instance.child({
     req: {
       id: 7915,
@@ -104,13 +94,13 @@ test('redact option – child object', function (t) {
       remotePort: 58022
     }
   }).info('message completed')
+  const { req } = await once(stream, 'data')
+  is(req.headers.cookie, '[Redacted]')
 })
 
-test('redact option – interpolated object', function (t) {
-  var instance = pino({redact: ['req.headers.cookie']}, sink(function (o, enc, cb) {
-    t.equals(JSON.parse(o.msg.replace(/test /, '')).req.headers.cookie, '[Redacted]')
-    t.end()
-  }))
+test('redact option – interpolated object', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: ['req.headers.cookie']}, stream)
 
   instance.info('test', {
     req: {
@@ -126,13 +116,13 @@ test('redact option – interpolated object', function (t) {
       remotePort: 58022
     }
   })
+  const { msg } = await once(stream, 'data')
+  is(JSON.parse(msg.replace(/test /, '')).req.headers.cookie, '[Redacted]')
 })
 
-test('redact.paths option – object', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie']}}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.end()
-  }))
+test('redact.paths option – object', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie']}}, stream)
   instance.info({
     req: {
       id: 7915,
@@ -147,14 +137,13 @@ test('redact.paths option – object', function (t) {
       remotePort: 58022
     }
   })
+  const { req } = await once(stream, 'data')
+  is(req.headers.cookie, '[Redacted]')
 })
 
-test('redact.paths option – child object', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie']}}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.end()
-  }))
-
+test('redact.paths option – child object', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie']}}, stream)
   instance.child({
     req: {
       id: 7915,
@@ -169,13 +158,13 @@ test('redact.paths option – child object', function (t) {
       remotePort: 58022
     }
   }).info('message completed')
+  const { req } = await once(stream, 'data')
+  is(req.headers.cookie, '[Redacted]')
 })
 
-test('redact.paths option – interpolated object', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie']}}, sink(function (o, enc, cb) {
-    t.equals(JSON.parse(o.msg.replace(/test /, '')).req.headers.cookie, '[Redacted]')
-    t.end()
-  }))
+test('redact.paths option – interpolated object', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie']}}, stream)
 
   instance.info('test', {
     req: {
@@ -191,13 +180,13 @@ test('redact.paths option – interpolated object', function (t) {
       remotePort: 58022
     }
   })
+  const { msg } = await once(stream, 'data')
+  is(JSON.parse(msg.replace(/test /, '')).req.headers.cookie, '[Redacted]')
 })
 
-test('redact.censor option – sets the redact value', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie'], censor: 'test'}}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, 'test')
-    t.end()
-  }))
+test('redact.censor option – sets the redact value', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie'], censor: 'test'}}, stream)
   instance.info({
     req: {
       id: 7915,
@@ -212,13 +201,13 @@ test('redact.censor option – sets the redact value', function (t) {
       remotePort: 58022
     }
   })
+  const { req } = await once(stream, 'data')
+  is(req.headers.cookie, 'test')
 })
 
-test('redact.remove option – removes both key and value', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie'], remove: true}}, sink(function (o, enc, cb) {
-    t.equals('cookie' in o.req.headers, false)
-    t.end()
-  }))
+test('redact.remove option – removes both key and value', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie'], remove: true}}, stream)
   instance.info({
     req: {
       id: 7915,
@@ -233,24 +222,23 @@ test('redact.remove option – removes both key and value', function (t) {
       remotePort: 58022
     }
   })
+  const { req } = await once(stream, 'data')
+  is('cookie' in req.headers, false)
 })
 
-test('redact.remove – top level key', function (t) {
-  var instance = pino({redact: {paths: ['key'], remove: true}}, sink(function (o, enc, cb) {
-    t.equals('key' in o, false)
-    t.end()
-  }))
+test('redact.remove – top level key', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['key'], remove: true}}, stream)
   instance.info({
     key: {redact: 'me'}
   })
+  const o = await once(stream, 'data')
+  is('key' in o, false)
 })
 
-test('redact.paths preserves original object values after the log write', function (t) {
-  var instance = pino({redact: ['req.headers.cookie']}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.equals(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
-    t.end()
-  }))
+test('redact.paths preserves original object values after the log write', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: ['req.headers.cookie']}, stream)
   const obj = {
     req: {
       id: 7915,
@@ -266,14 +254,14 @@ test('redact.paths preserves original object values after the log write', functi
     }
   }
   instance.info(obj)
+  const o = await once(stream, 'data')
+  is(o.req.headers.cookie, '[Redacted]')
+  is(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
 })
 
-test('redact.paths preserves original object values after the log write', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie']}}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.equals(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
-    t.end()
-  }))
+test('redact.paths preserves original object values after the log write', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie']}}, stream)
   const obj = {
     req: {
       id: 7915,
@@ -289,14 +277,14 @@ test('redact.paths preserves original object values after the log write', functi
     }
   }
   instance.info(obj)
+  const o = await once(stream, 'data')
+  is(o.req.headers.cookie, '[Redacted]')
+  is(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
 })
 
-test('redact.censor preserves original object values after the log write', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie'], censor: 'test'}}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, 'test')
-    t.equals(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
-    t.end()
-  }))
+test('redact.censor preserves original object values after the log write', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie'], censor: 'test'}}, stream)
   const obj = {
     req: {
       id: 7915,
@@ -312,14 +300,14 @@ test('redact.censor preserves original object values after the log write', funct
     }
   }
   instance.info(obj)
+  const o = await once(stream, 'data')
+  is(o.req.headers.cookie, 'test')
+  is(obj.req.headers.cookie, 'SESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1;')
 })
 
-test('redact.remove preserves original object values after the log write', function (t) {
-  var instance = pino({redact: {paths: ['req.headers.cookie'], remove: true}}, sink(function (o, enc, cb) {
-    t.equals('cookie' in o.req.headers, false)
-    t.equals('cookie' in obj.req.headers, true)
-    t.end()
-  }))
+test('redact.remove preserves original object values after the log write', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: {paths: ['req.headers.cookie'], remove: true}}, stream)
   const obj = {
     req: {
       id: 7915,
@@ -335,15 +323,14 @@ test('redact.remove preserves original object values after the log write', funct
     }
   }
   instance.info(obj)
+  const o = await once(stream, 'data')
+  is('cookie' in o.req.headers, false)
+  is('cookie' in obj.req.headers, true)
 })
 
-test('redact – supports last position wildcard paths', function (t) {
-  var instance = pino({redact: ['req.headers.*']}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.equals(o.req.headers.host, '[Redacted]')
-    t.equals(o.req.headers.connection, '[Redacted]')
-    t.end()
-  }))
+test('redact – supports last position wildcard paths', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: ['req.headers.*']}, stream)
   instance.info({
     req: {
       id: 7915,
@@ -358,13 +345,15 @@ test('redact – supports last position wildcard paths', function (t) {
       remotePort: 58022
     }
   })
+  const { req } = await once(stream, 'data')
+  is(req.headers.cookie, '[Redacted]')
+  is(req.headers.host, '[Redacted]')
+  is(req.headers.connection, '[Redacted]')
 })
 
-test('redact – supports intermediate wildcard paths', function (t) {
-  var instance = pino({redact: ['req.*.cookie']}, sink(function (o, enc, cb) {
-    t.equals(o.req.headers.cookie, '[Redacted]')
-    t.end()
-  }))
+test('redact – supports intermediate wildcard paths', async ({is}) => {
+  const stream = sink()
+  const instance = pino({redact: ['req.*.cookie']}, stream)
   instance.info({
     req: {
       id: 7915,
@@ -379,4 +368,6 @@ test('redact – supports intermediate wildcard paths', function (t) {
       remotePort: 58022
     }
   })
+  const { req } = await once(stream, 'data')
+  is(req.headers.cookie, '[Redacted]')
 })
diff --git a/test/serializers.test.js b/test/serializers.test.js
index 26281a5..922c62d 100644
--- a/test/serializers.test.js
+++ b/test/serializers.test.js
@@ -1,120 +1,110 @@
 'use strict'
-var test = require('tap').test
-var pino = require('../')
-var sink = require('./helper').sink
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const pino = require('../')
 
-var parentSerializers = {
-  test: function () { return 'parent' }
+const parentSerializers = {
+  test: () => 'parent'
 }
 
-var childSerializers = {
-  test: function () { return 'child' }
+const childSerializers = {
+  test: () => 'child'
 }
 
-test('serializers override values', function (t) {
-  t.plan(1)
-
-  var parent = pino({ serializers: parentSerializers }, sink(function (o, enc, cb) {
-    t.is(o.test, 'parent')
-    cb()
-  }))
+test('serializers override values', async ({is}) => {
+  const stream = sink()
+  const parent = pino({ serializers: parentSerializers }, stream)
   parent.child({ serializers: childSerializers })
 
   parent.fatal({test: 'test'})
+  const o = await once(stream, 'data')
+  is(o.test, 'parent')
 })
 
-test('child does not overwrite parent serializers', function (t) {
-  t.plan(2)
-
-  var c = 0
-  var parent = pino({ serializers: parentSerializers }, sink(function (o, enc, cb) {
-    c++
-    if (c === 1) t.is(o.test, 'parent')
-    if (c === 2) t.is(o.test, 'child')
-    cb()
-  }))
-  var child = parent.child({ serializers: childSerializers })
+test('child does not overwrite parent serializers', async ({is}) => {
+  const stream = sink()
+  const parent = pino({ serializers: parentSerializers }, stream)
+  const child = parent.child({ serializers: childSerializers })
 
   parent.fatal({test: 'test'})
+
+  const o = once(stream, 'data')
+  is((await o).test, 'parent')
+  const o2 = once(stream, 'data')
   child.fatal({test: 'test'})
+  is((await o2).test, 'child')
 })
 
-test('children inherit parent serializers', function (t) {
-  t.plan(1)
+test('children inherit parent serializers', async ({is}) => {
+  const stream = sink()
+  const parent = pino({ serializers: parentSerializers }, stream)
 
-  var parent = pino({ serializers: parentSerializers }, sink(function (o, enc, cb) {
-    t.is(o.test, 'parent')
-  }))
-
-  var child = parent.child({a: 'property'})
+  const child = parent.child({a: 'property'})
   child.fatal({test: 'test'})
+  const o = await once(stream, 'data')
+  is(o.test, 'parent')
 })
 
-test('children serializers get called', function (t) {
-  t.plan(1)
-
-  var parent = pino({
+test('children serializers get called', async ({is}) => {
+  const stream = sink()
+  const parent = pino({
     test: 'this'
-  }, sink(function (o, enc, cb) {
-    t.is(o.test, 'child')
-    cb()
-  }))
+  }, stream)
 
-  var child = parent.child({ 'a': 'property', serializers: childSerializers })
+  const child = parent.child({ 'a': 'property', serializers: childSerializers })
 
   child.fatal({test: 'test'})
+  const o = await once(stream, 'data')
+  is(o.test, 'child')
 })
 
-test('children serializers get called when inherited from parent', function (t) {
-  t.plan(1)
-
-  var parent = pino({
+test('children serializers get called when inherited from parent', async ({is}) => {
+  const stream = sink()
+  const parent = pino({
     test: 'this',
     serializers: parentSerializers
-  }, sink(function (o, enc, cb) {
-    t.is(o.test, 'pass')
-    cb()
-  }))
+  }, stream)
 
-  var child = parent.child({serializers: {test: function () { return 'pass' }}})
+  const child = parent.child({serializers: {test: function () { return 'pass' }}})
 
   child.fatal({test: 'fail'})
+  const o = await once(stream, 'data')
+  is(o.test, 'pass')
 })
 
-test('non overriden serializers are available in the children', function (t) {
-  t.plan(4)
-  var pSerializers = {
+test('non-overridden serializers are available in the children', async ({is}) => {
+  const stream = sink()
+  const pSerializers = {
     onlyParent: function () { return 'parent' },
     shared: function () { return 'parent' }
   }
 
-  var cSerializers = {
+  const cSerializers = {
     shared: function () { return 'child' },
     onlyChild: function () { return 'child' }
   }
 
-  var c = 0
-
-  var parent = pino({ serializers: pSerializers }, sink(function (o, enc, cb) {
-    c++
-    if (c === 1) t.is(o.shared, 'child')
-    if (c === 2) t.is(o.onlyParent, 'parent')
-    if (c === 3) t.is(o.onlyChild, 'child')
-    if (c === 4) t.is(o.onlyChild, 'test')
-    cb()
-  }))
+  const parent = pino({ serializers: pSerializers }, stream)
 
-  var child = parent.child({ serializers: cSerializers })
+  const child = parent.child({ serializers: cSerializers })
 
+  const o = once(stream, 'data')
   child.fatal({shared: 'test'})
+  is((await o).shared, 'child')
+  const o2 = once(stream, 'data')
   child.fatal({onlyParent: 'test'})
+  is((await o2).onlyParent, 'parent')
+  const o3 = once(stream, 'data')
   child.fatal({onlyChild: 'test'})
+  is((await o3).onlyChild, 'child')
+  const o4 = once(stream, 'data')
   parent.fatal({onlyChild: 'test'})
+  is((await o4).onlyChild, 'test')
 })
 
-test('Symbol.for(\'pino.*\') serializer', function (t) {
-  t.plan(6)
-  var globalSerializer = {
+test('Symbol.for(\'pino.*\') serializer', async ({notSame, is, isNot}) => {
+  const stream = sink()
+  const globalSerializer = {
     [Symbol.for('pino.*')]: function (obj) {
       if (obj.lionel === 'richie') {
         return {hello: 'is', it: 'me', you: 'are', looking: 'for'}
@@ -122,16 +112,29 @@ test('Symbol.for(\'pino.*\') serializer', function (t) {
       return {lionel: 'richie'}
     }
   }
-  var c = 0
-  var logger = pino({serializers: globalSerializer}, sink(function (o, enc, cb) {
-    c++
-    if (c === 1) { t.match(o, {lionel: 'richie'}); t.notMatch(o, ['hello', 'it', 'you', 'looking']) }
-    if (c === 2) { t.match(o, {hello: 'is', it: 'me', you: 'are', looking: 'for'}); t.notMatch(o, ['lionel']) }
-    if (c === 3) { t.match(o, {lionel: 'richie'}); t.notMatch(o, ['pid', 'hostname']) }
-    cb()
-  }))
 
+  const logger = pino({serializers: globalSerializer}, stream)
+
+  const o = once(stream, 'data')
   logger.info({hello: 'is', it: 'me', you: 'are', looking: 'for'})
+  is((await o).lionel, 'richie')
+  isNot((await o).hello, 'is')
+  isNot((await o).it, 'me')
+  isNot((await o).you, 'are')
+  isNot((await o).looking, 'for')
+
+  const o2 = once(stream, 'data')
   logger.info({lionel: 'richie'})
+  is((await o2).lionel, 'richie')
+  is((await o2).hello, 'is')
+  is((await o2).it, 'me')
+  is((await o2).you, 'are')
+  is((await o2).looking, 'for')
+
+  const o3 = once(stream, 'data')
   logger.info('message')
+  is((await o3).lionel, 'richie')
+  is('pid' in (await o3), false)
+  is('hostname' in (await o3), false)
+  notSame(await o3, ['pid', 'hostname'])
 })
diff --git a/test/timestamp.test.js b/test/timestamp.test.js
index cc14ef2..8e942ae 100644
--- a/test/timestamp.test.js
+++ b/test/timestamp.test.js
@@ -1,71 +1,64 @@
 'use strict'
 
-var test = require('tap').test
-var pino = require('../')
-var sink = require('./helper').sink
+const { test } = require('tap')
+const { sink, once } = require('./helper')
+const pino = require('../')
 
-test('pino exposes standard time functions', function (t) {
-  t.plan(4)
-  t.ok(pino.stdTimeFunctions)
-  t.ok(pino.stdTimeFunctions.epochTime)
-  t.ok(pino.stdTimeFunctions.unixTime)
-  t.ok(pino.stdTimeFunctions.nullTime)
+test('pino exposes standard time functions', async ({ok}) => {
+  ok(pino.stdTimeFunctions)
+  ok(pino.stdTimeFunctions.epochTime)
+  ok(pino.stdTimeFunctions.unixTime)
+  ok(pino.stdTimeFunctions.nullTime)
 })
 
-test('pino accepts external time functions', function (t) {
-  t.plan(2)
-  var opts = {
-    timestamp: function () {
-      return ',"time":"none"'
-    }
+test('pino accepts external time functions', async ({is}) => {
+  const opts = {
+    timestamp: () => ',"time":"none"'
   }
-  var instance = pino(opts, sink(function (chunk, enc, cb) {
-    t.equal(chunk.hasOwnProperty('time'), true)
-    t.equal(chunk.time, 'none')
-  }))
+  const stream = sink()
+  const instance = pino(opts, stream)
   instance.info('foobar')
+  const result = await once(stream, 'data')
+  is(result.hasOwnProperty('time'), true)
+  is(result.time, 'none')
 })
 
-test('inserts timestamp by default', function (t) {
-  var instance = pino(sink(function (chunk, enc, cb) {
-    t.equal(chunk.hasOwnProperty('time'), true)
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than timestamp')
-    t.equal(chunk.msg, 'foobar')
-    cb()
-    t.end()
-  }))
+test('inserts timestamp by default', async ({ok, is}) => {
+  const stream = sink()
+  const instance = pino(stream)
   instance.info('foobar')
+  const result = await once(stream, 'data')
+  is(result.hasOwnProperty('time'), true)
+  ok(new Date(result.time) <= new Date(), 'time is greater than timestamp')
+  is(result.msg, 'foobar')
 })
 
-test('omits timestamp with option', function (t) {
-  var instance = pino({timestamp: false}, sink(function (chunk, enc, cb) {
-    t.equal(chunk.hasOwnProperty('time'), false)
-    t.equal(chunk.msg, 'foobar')
-    cb()
-    t.end()
-  }))
+test('omits timestamp with option', async ({is}) => {
+  const stream = sink()
+  const instance = pino({timestamp: false}, stream)
   instance.info('foobar')
+  const result = await once(stream, 'data')
+  is(result.hasOwnProperty('time'), false)
+  is(result.msg, 'foobar')
 })
 
-test('child inserts timestamp by default', function (t) {
-  var logger = pino(sink(function (chunk, enc, cb) {
-    t.equal(chunk.hasOwnProperty('time'), true)
-    t.ok(new Date(chunk.time) <= new Date(), 'time is greater than timestamp')
-    t.equal(chunk.msg, 'foobar')
-    cb()
-    t.end()
-  }))
-  var instance = logger.child({component: 'child'})
+test('child inserts timestamp by default', async ({ok, is}) => {
+  const stream = sink()
+  const logger = pino(stream)
+  const instance = logger.child({component: 'child'})
   instance.info('foobar')
+  const result = await once(stream, 'data')
+  is(result.hasOwnProperty('time'), true)
+  ok(new Date(result.time) <= new Date(), 'time is greater than timestamp')
+  is(result.msg, 'foobar')
 })
 
-test('child omits timestamp with option', function (t) {
-  var logger = pino({timestamp: false}, sink(function (chunk, enc, cb) {
-    t.equal(chunk.hasOwnProperty('time'), false)
-    t.equal(chunk.msg, 'foobar')
-    cb()
-    t.end()
-  }))
-  var instance = logger.child({component: 'child'})
+test('child omits timestamp with option', async ({is}) => {
+  const stream = sink()
+  const logger = pino({timestamp: false}, stream)
+  const instance = logger.child({component: 'child'})
   instance.info('foobar')
+  const result = await once(stream, 'data')
+  is(result.hasOwnProperty('time'), false)
+  is(result.msg, 'foobar')
 })