diff --git a/index.d.ts b/index.d.ts
index cd947a48..fa0aa8cb 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -261,6 +261,28 @@ export function callback(...args: any[]): void;
  * @returns {*}
  */
 export function replace(path: string, f?: any): any;
+/**
+ * Swap out real dependenencies with fake one. Intercept calls to `require`
+ * that dependency module and ensure your subject is handed a fake instead.
+ *
+ * @export
+ * @param {string} path
+ * @param {*} [f]
+ * @returns {*}
+ */
+export function replaceCjs(path: string, f?: any): any;
+/**
+ * Swap out real dependenencies with fake one. Intercept calls to `import`
+ * that dependency module and ensure your subject is handed a fake instead.
+ *
+ * @export
+ * @param {string} path
+ * @param {*} [namedExportStubs]
+ * @param {*} [defaultExportStub]
+ * @returns {Promise<{default?: any, [namedExport: string]: any}>}
+ */
+export function replaceEsm(path: string, namedExportStubs?: any, defaultExportStub?: any):
+  Promise<{default?: any, [namedExport: string]: any}>;
 
 /**
  * Swap out real dependenencies with fake one. Reference to the property will
diff --git a/notypescript/import-esm-car.js b/notypescript/import-esm-car.js
new file mode 100644
index 00000000..55e5098f
--- /dev/null
+++ b/notypescript/import-esm-car.js
@@ -0,0 +1,2 @@
+// @ts-ignore
+module.exports = () => import('../test/safe-esm/fixtures/car.mjs')
diff --git a/package-lock.json b/package-lock.json
index 4b6967f3..50c5216d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2113,18 +2113,25 @@
       "dev": true
     },
     "function-names-at-line": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/function-names-at-line/-/function-names-at-line-1.0.0.tgz",
-      "integrity": "sha1-NEHZntLH77rzioULGTxR4TmlTF8=",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/function-names-at-line/-/function-names-at-line-1.1.0.tgz",
+      "integrity": "sha512-UMY9cMhbFjL15D8/syCW1ceip5sR49TmRwnAhfX5yh9iA1kxe1XeG3Zmq/g/a5CqsJxp448Bh11zY+WU+xe1Iw==",
       "dev": true,
       "requires": {
-        "acorn": "^3.1.0"
+        "acorn": "^7.1.1",
+        "acorn-walk": "^7.1.1"
       },
       "dependencies": {
         "acorn": {
-          "version": "3.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
-          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
+          "version": "7.1.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
+          "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
+          "dev": true
+        },
+        "acorn-walk": {
+          "version": "7.1.1",
+          "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz",
+          "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==",
           "dev": true
         }
       }
@@ -2575,9 +2582,9 @@
       "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
     },
     "is-promise": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
-      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+      "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
       "dev": true
     },
     "is-regex": {
@@ -3990,9 +3997,9 @@
       "dev": true
     },
     "quibble": {
-      "version": "0.5.7",
-      "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.5.7.tgz",
-      "integrity": "sha512-QnHxlD12qhGGjvoEW4PIp8tA80tKjh5CxTg5wLTPp/aqvHElBA+Ag3JN0dWlHY96CUaJqSGmLxTLi+7wbysyZw==",
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.6.0.tgz",
+      "integrity": "sha512-0qRPeygNwjecBDjbXZ8mG5s6Nn8L5cyEG9+pAPDvBnARDM4dAhuux8X+nCUpiuL78MsKlFo7FkQo1oTHne6lwQ==",
       "requires": {
         "lodash": "^4.17.14",
         "resolve": "^1.11.1"
@@ -4270,6 +4277,14 @@
       "dev": true,
       "requires": {
         "is-promise": "^2.1.0"
+      },
+      "dependencies": {
+        "is-promise": {
+          "version": "2.2.2",
+          "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+          "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
+          "dev": true
+        }
       }
     },
     "run-parallel": {
@@ -4396,9 +4411,9 @@
       "dev": true
     },
     "source-map-support": {
-      "version": "0.5.16",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
-      "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
+      "version": "0.5.19",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
       "dev": true,
       "requires": {
         "buffer-from": "^1.0.0",
@@ -4793,13 +4808,13 @@
       }
     },
     "teenytest": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/teenytest/-/teenytest-5.3.0.tgz",
-      "integrity": "sha512-E3T/aA9Z7aiJ8r76BkCOu/Lz/5rsbyKgHKjsX+narzTNANDiqqGBxBfixeE4Nr6ln/TVbWmzww0NsGij+b08bA==",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/teenytest/-/teenytest-6.0.0.tgz",
+      "integrity": "sha512-mr9IF2MkpDPEG3RTulcDpA2N6IkTliF5kHsfALenoxtIew93ClgOOmMUEc1ofKMI2NOfAKqgxuQ2+V4Jh7RfHQ==",
       "dev": true,
       "requires": {
         "async": "^2.6.2",
-        "function-names-at-line": "^1.0.0",
+        "function-names-at-line": "^1.1.0",
         "glob": "^7.1.3",
         "lodash": "^4.17.11",
         "lodash-deeper": "^1.0.0",
@@ -4817,13 +4832,19 @@
           }
         },
         "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "version": "1.2.5",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+          "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
           "dev": true
         }
       }
     },
+    "teenytest-promise": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/teenytest-promise/-/teenytest-promise-1.0.0.tgz",
+      "integrity": "sha1-ekkO7IPene9J4HmKojGfbJGPPlE=",
+      "dev": true
+    },
     "test-exclude": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -4836,15 +4857,27 @@
       }
     },
     "testdouble": {
-      "version": "3.12.5",
-      "resolved": "https://registry.npmjs.org/testdouble/-/testdouble-3.12.5.tgz",
-      "integrity": "sha512-HxATrZ9Olip3bl/oW56uINeMAGDKjy2Q5CdoaCVTxcixN+BIOuPbiLDZ3OaE3d8vKsb4IZZr5Km5fTLZ5ha26g==",
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/testdouble/-/testdouble-3.13.1.tgz",
+      "integrity": "sha512-3fMIiKxi64WfVyPpPH0psKLNV2VDBt2fjNOOmp9g3ZPW6CTtbpAH2GK5Y3m0uK6vkerWOK41orfWNI8R2iDCTw==",
       "dev": true,
       "requires": {
         "lodash": "^4.17.15",
-        "quibble": "^0.5.6",
+        "quibble": "^0.5.7",
         "stringify-object-es5": "^2.5.0",
         "theredoc": "^1.0.0"
+      },
+      "dependencies": {
+        "quibble": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/quibble/-/quibble-0.5.7.tgz",
+          "integrity": "sha512-QnHxlD12qhGGjvoEW4PIp8tA80tKjh5CxTg5wLTPp/aqvHElBA+Ag3JN0dWlHY96CUaJqSGmLxTLi+7wbysyZw==",
+          "dev": true,
+          "requires": {
+            "lodash": "^4.17.14",
+            "resolve": "^1.11.1"
+          }
+        }
       }
     },
     "text-table": {
@@ -4909,15 +4942,15 @@
       }
     },
     "ts-node": {
-      "version": "8.6.2",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz",
-      "integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==",
+      "version": "8.10.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz",
+      "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==",
       "dev": true,
       "requires": {
         "arg": "^4.1.0",
         "diff": "^4.0.1",
         "make-error": "^1.1.1",
-        "source-map-support": "^0.5.6",
+        "source-map-support": "^0.5.17",
         "yn": "3.1.1"
       }
     },
diff --git a/package.json b/package.json
index 97e79d87..9af49ac3 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
     "clean": "rimraf dist lib coverage",
     "clean:hard": "npm run clean && rimraf node_modules \"examples/*/node_modules\"",
     "postclean": "mkdirp dist",
-    "compile:browser": "cross-conf-env browserify src/index.js --standalone td --outfile $npm_package_config_build_file -p tsify -p headerify",
+    "compile:browser": "cross-conf-env browserify src/index.js --standalone td --outfile $npm_package_config_build_file -p [ tsify --project tsconfig-browser.json ] -p headerify",
     "compile:node": "tsc",
     "precompile": "npm run clean",
     "compile": "run-s compile:node compile:browser",
@@ -32,10 +32,11 @@
     "style": "run-p style:js style:ts",
     "style:js": "standard --fix",
     "style:ts": "standard --fix --parser @typescript-eslint/parser --plugin @typescript-eslint/eslint-plugin \"**/*.ts\"",
-    "test": "teenytest --helper test/helper.js \"test/**/*.test.{js,ts}\"",
+    "test": "NODE_OPTIONS='--loader=quibble' TS_NODE_IGNORE='(?:^|/)node_modules/,notypescript' ./test/safe-esm/teenytest-proxy.js --helper test/helper.js \"test/**/*.test.{js,ts}\"",
     "test:all": "run-s test test:example",
     "test:unit": "teenytest --helper test/helper.js \"test/unit/**/*.test.{js,ts}\"",
     "test:safe": "teenytest --helper test/helper.js \"test/safe/**/*.test.{js,ts}\"",
+    "test:esm": "NODE_OPTIONS='--loader=quibble' TS_NODE_IGNORE='(?:^|/)node_modules/,notypescript' ./test/safe-esm/teenytest-proxy.js --helper test/helper.js test/safe-esm/replace.test.js",
     "test:ci": "npm run compile && run-p style test:all && echo \"All done!\"",
     "test:example": "run-p test:example:babel test:example:jest test:example:jest-broken test:example:plain-html test:example:node test:example:node-ava test:example:webpack",
     "test:example:babel": "./script/run-examples babel",
@@ -78,12 +79,13 @@
   },
   "teenytest": {
     "plugins": [
-      "test/support/tdify-plugin.js"
+      "test/support/tdify-plugin.js",
+      "teenytest-promise"
     ]
   },
   "dependencies": {
     "lodash": "^4.17.15",
-    "quibble": "^0.5.7",
+    "quibble": "^0.6.0",
     "stringify-object-es5": "^2.5.0",
     "theredoc": "^1.0.0"
   },
@@ -97,14 +99,16 @@
     "dedent": "^0.7.0",
     "headerify": "^1.0.1",
     "is-number": "^7.0.0",
+    "is-promise": "^4.0.0",
     "mkdirp": "^1.0.3",
     "npm-run-all": "^4.1.5",
     "nyc": "^15.0.0",
     "rimraf": "^3.0.2",
     "standard": "^14.3.1",
-    "teenytest": "^5.3.0",
+    "teenytest": "^6.0.0",
+    "teenytest-promise": "^1.0.0",
     "testdouble": "^3.12.5",
-    "ts-node": "^8.6.2",
+    "ts-node": "^8.10.1",
     "tsify": "^4.0.1",
     "typescript": "^3.8.2"
   },
diff --git a/src/index.js b/src/index.js
index 63af80d0..01634b95 100644
--- a/src/index.js
+++ b/src/index.js
@@ -5,7 +5,7 @@ import imitate from './imitate'
 import when from './when'
 import verify from './verify'
 import matchers from './matchers'
-import replace from './replace'
+import replace, { replaceEsm } from './replace'
 import explain from './explain'
 import reset from './reset'
 import config from './config'
@@ -23,6 +23,7 @@ module.exports = {
   verify,
   matchers,
   replace,
+  replaceEsm,
   explain,
   reset,
   config,
diff --git a/src/replace/index.js b/src/replace/index.js
index 761d639c..8a4f41d5 100644
--- a/src/replace/index.js
+++ b/src/replace/index.js
@@ -1,6 +1,6 @@
 import _ from '../wrap/lodash'
 import * as quibble from 'quibble'
-import replaceModule from './module'
+import replaceModule, { replaceEsModule } from './module'
 import replaceProperty from './property'
 
 quibble.ignoreCallsFromThisFile()
@@ -12,3 +12,9 @@ export default function (target) {
     return replaceProperty(...arguments)
   }
 }
+
+export function replaceEsm (_modulePath, _namedExportReplacement, _defaultExportReplacement) {
+  // Sending arguments instead of the above arguments is crucial because `replaceEsModule`
+  // uses arguments.length to figure out what to do.
+  return replaceEsModule(...arguments)
+}
diff --git a/src/replace/module/index.js b/src/replace/module/index.js
index ac31e312..e049dc68 100644
--- a/src/replace/module/index.js
+++ b/src/replace/module/index.js
@@ -7,7 +7,7 @@ import fakeName from './fake-name'
 
 quibble.ignoreCallsFromThisFile()
 
-export default function replaceModule (path, stub) {
+export default function replaceCjsModule (path, stub) {
   if (typeof jest === 'object') return jestModule(...arguments)
   if (arguments.length > 1) { return quibble(path, stub) }
   const realThing = requireActual(path)
@@ -15,3 +15,20 @@ export default function replaceModule (path, stub) {
   quibble(path, fakeThing)
   return fakeThing
 }
+
+export async function replaceEsModule (path, namedExportsStub, defaultExportStub) {
+  if (typeof jest === 'object') {
+    throw new Error(`stubbing ES modules (${path}) under Jest is not yet supported`)
+  }
+  if (arguments.length > 1) {
+    return quibble.esm(path, namedExportsStub, defaultExportStub)
+  }
+
+  const { modulePath, module } = await quibble.esmImportWithPath(path)
+  const { default: fakeDefaultExport = undefined, ...fakeNamedExports } =
+    imitate(module, fakeName(path, module))
+
+  await quibble.esm(modulePath, fakeNamedExports, fakeDefaultExport)
+
+  return { default: fakeDefaultExport, ...fakeNamedExports }
+}
diff --git a/test/safe-esm/fixtures/car.mjs b/test/safe-esm/fixtures/car.mjs
new file mode 100644
index 00000000..fcf6fe17
--- /dev/null
+++ b/test/safe-esm/fixtures/car.mjs
@@ -0,0 +1,22 @@
+import Passenger from './passenger.mjs'
+import isPromise from 'is-promise'
+import honk from './honk.mjs'
+import turn from './turn.mjs'
+import brake from './brake.mjs'
+import * as lights from './lights.mjs'
+import shift, { neutral } from './shift.mjs'
+
+export default {
+  seatPassenger: function () {
+    return new Passenger().sit()
+  },
+  honk,
+  turn,
+  brake,
+  lights,
+  shift,
+  neutral,
+  isASpeed: function (thing) {
+    return isPromise(thing)
+  }
+}
diff --git a/test/safe-esm/fixtures/es6class.mjs b/test/safe-esm/fixtures/es6class.mjs
new file mode 100644
index 00000000..7f00fe64
--- /dev/null
+++ b/test/safe-esm/fixtures/es6class.mjs
@@ -0,0 +1,7 @@
+class ES6Class {
+  foo () { return 'og foo' }
+
+  bar () { return 'og bar' }
+}
+
+export default ES6Class
diff --git a/test/safe-esm/fixtures/honk.mjs b/test/safe-esm/fixtures/honk.mjs
new file mode 100644
index 00000000..b2c47c36
--- /dev/null
+++ b/test/safe-esm/fixtures/honk.mjs
@@ -0,0 +1,3 @@
+export default function () {
+  throw 'honk' // eslint-disable-line
+}
diff --git a/test/safe-esm/fixtures/lights.mjs b/test/safe-esm/fixtures/lights.mjs
new file mode 100644
index 00000000..c62901f0
--- /dev/null
+++ b/test/safe-esm/fixtures/lights.mjs
@@ -0,0 +1,13 @@
+export const count = 4
+export function headlight () {
+  throw 'headlight' // eslint-disable-line
+}
+export function turnSignal () {
+  throw 'turnSignal' // eslint-disable-line
+}
+
+export class Brights {
+  beBright () {
+    throw 'too bright!' // eslint-disable-line
+  }
+}
diff --git a/test/safe-esm/fixtures/passenger.mjs b/test/safe-esm/fixtures/passenger.mjs
new file mode 100644
index 00000000..06c5ce9d
--- /dev/null
+++ b/test/safe-esm/fixtures/passenger.mjs
@@ -0,0 +1,5 @@
+export default class Passenger {
+  sit () {
+    throw 'i am sitting' // eslint-disable-line
+  }
+}
diff --git a/test/safe-esm/fixtures/shift.mjs b/test/safe-esm/fixtures/shift.mjs
new file mode 100644
index 00000000..0864b246
--- /dev/null
+++ b/test/safe-esm/fixtures/shift.mjs
@@ -0,0 +1,7 @@
+export default function shift () {
+  return 'Faster'
+}
+
+export function neutral () {
+  return 'Coast'
+}
diff --git a/test/safe-esm/fixtures/turn.mjs b/test/safe-esm/fixtures/turn.mjs
new file mode 100644
index 00000000..cfca7f83
--- /dev/null
+++ b/test/safe-esm/fixtures/turn.mjs
@@ -0,0 +1 @@
+export default function turn () {}
diff --git a/test/safe-esm/replace.test.js b/test/safe-esm/replace.test.js
new file mode 100644
index 00000000..041c370f
--- /dev/null
+++ b/test/safe-esm/replace.test.js
@@ -0,0 +1,66 @@
+let passenger, lights, car, isPromise
+module.exports = {
+  'Node.js-specific ESM module replacement': {
+    async beforeEach () {
+      ;({ default: passenger } = await td.replaceEsm('./fixtures/passenger.mjs'))
+      await td.replaceEsm('./fixtures/honk.mjs')
+      await td.replaceEsm('./fixtures/turn.mjs')
+      await td.replaceEsm('./fixtures/shift.mjs')
+      await td.replaceEsm('./fixtures/brake.mjs', undefined, 'ANYTHING I WANT')
+      lights = await td.replaceEsm('./fixtures/lights.mjs')
+      isPromise = await td.replaceEsm('is-promise')
+      ;({ default: car } = await require('../../notypescript/import-esm-car.js')())
+    },
+    'quibbling prototypal constructors get created with td.object(Type)' () {
+      td.when(passenger.prototype.sit()).thenReturn('ow')
+
+      const result = car.seatPassenger()
+
+      assert._isEqual(result, 'ow')
+    },
+    'quibbling plain old functions with td.function()' () {
+      assert._isEqual(car.honk.toString(), '[test double for "./fixtures/honk.mjs: .default"]')
+    },
+    'naming the doubles of functions with names' () {
+      td.when(car.turn()).thenReturn('wee')
+      td.when(car.shift()).thenReturn('Vroom')
+
+      assert._isEqual(car.turn(), 'wee')
+      assert._isEqual(car.turn.toString(), '[test double for "./fixtures/turn.mjs: .default"]')
+      assert._isEqual(car.shift(), 'Vroom')
+    },
+    'faking property on exported function' () {
+      td.when(car.neutral()).thenReturn('Clunk')
+
+      assert._isEqual(car.neutral(), 'Clunk')
+    },
+    'manually stubbing an entry' () {
+      assert._isEqual(car.brake, 'ANYTHING I WANT')
+    },
+    'an object of funcs' () {
+      assert._isEqual(car.lights.headlight.toString(), '[test double for "./fixtures/lights.mjs: .headlight"]')
+      assert._isEqual(car.lights.turnSignal.toString(), '[test double for "./fixtures/lights.mjs: .turnSignal"]')
+      assert._isEqual(car.lights.count, 4)
+    },
+    'and classes on objects on funcs' () {
+      td.when(lights.Brights.prototype.beBright(1)).thenReturn('yow')
+
+      assert._isEqual((new car.lights.Brights()).beBright(1), 'yow')
+    },
+    'faking a 3rd party module' () {
+      td.when(isPromise.default('a speed')).thenReturn(true)
+
+      assert._isEqual(car.isASpeed('a speed'), true)
+    },
+    async 'post-reset usage' () {
+      td.reset()
+
+      try {
+        await require('../../notypescript/import-esm-car.js')()
+        assert.fail('should have errored!')
+      } catch (e) {
+        assert._isEqual(e.message.split("'")[0], 'Cannot find module ')
+      }
+    }
+  }
+}
diff --git a/test/safe-esm/teenytest-proxy.js b/test/safe-esm/teenytest-proxy.js
new file mode 100755
index 00000000..1909e71e
--- /dev/null
+++ b/test/safe-esm/teenytest-proxy.js
@@ -0,0 +1,9 @@
+#!/usr/bin/env node
+
+// This file is needed because of bugs in ESM in Node.js (around loaders):
+// https://github.com/nodejs/node/issues/33226
+// https://github.com/nodejs/node/issues/33303
+//
+// Once these bugs are solved, we can go back to running teenytest regularly for ESM tests
+
+require('../../node_modules/.bin/teenytest')
diff --git a/test/safe/replace.test.js b/test/safe/replace.test.js
index 21207f29..f76003ea 100644
--- a/test/safe/replace.test.js
+++ b/test/safe/replace.test.js
@@ -188,7 +188,7 @@ module.exports = {
       }
     }
   },
-  'Node.js-specific module replacement': {
+  'Node.js-specific CJS module replacement': {
 
     beforeEach () {
       passenger = td.replace('./fixtures/passenger')
diff --git a/test/unit/imitate/overwrite-children/gather-props.test.js b/test/unit/imitate/overwrite-children/gather-props.test.js
index 9125f913..0f99cff0 100644
--- a/test/unit/imitate/overwrite-children/gather-props.test.js
+++ b/test/unit/imitate/overwrite-children/gather-props.test.js
@@ -63,7 +63,7 @@ module.exports = {
     })
     assert.deepEqual(result.bar, {
       value: Thing.prototype.bar,
-      enumerable: true, // TODO: should be false for native ES class, compiled to ES5 & this will return true
+      enumerable: false,
       writable: true,
       configurable: true
     })
diff --git a/test/unit/index.test.js b/test/unit/index.test.js
index e4b56df9..d245796b 100644
--- a/test/unit/index.test.js
+++ b/test/unit/index.test.js
@@ -5,7 +5,7 @@ module.exports = () => {
   const func = td.replace('../../src/function').default
   const object = td.replace('../../src/object').default
   const constructor = td.replace('../../src/constructor').default
-  const replace = td.replace('../../src/replace').default
+  const { default: replace, replaceEsm } = td.replace('../../src/replace')
   const imitate = td.replace('../../src/imitate').default
   // Stubbing & Verifying
   const when = td.replace('../../src/when').default
@@ -27,6 +27,7 @@ module.exports = () => {
     object: object,
     constructor: constructor,
     replace: replace,
+    replaceEsm: replaceEsm,
     imitate: imitate,
     when: when,
     verify: verify,
diff --git a/tsconfig-browser.json b/tsconfig-browser.json
new file mode 100644
index 00000000..24ef1745
--- /dev/null
+++ b/tsconfig-browser.json
@@ -0,0 +1,14 @@
+{
+  "compilerOptions": {
+    "allowJs": true,
+    "target": "es5",
+    "lib": ["es2015"],
+    "noImplicitAny": false,
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "outDir": "lib"
+  },
+  "include": [
+    "src/**/*"
+  ]
+}
diff --git a/tsconfig.json b/tsconfig.json
index 24ef1745..539e926c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,14 +1,14 @@
 {
   "compilerOptions": {
     "allowJs": true,
-    "target": "es5",
-    "lib": ["es2015"],
+    "target": "es2017",
+    "lib": ["es2017"],
     "noImplicitAny": false,
     "module": "commonjs",
     "moduleResolution": "node",
-    "outDir": "lib"
+    "outDir": "lib",
   },
   "include": [
-    "src/**/*"
+    "src/**/*.js"
   ]
 }
