diff --git a/circle.yml b/circle.yml
index 139540198046538cd2ae1ee0d83fe260dcfed7db..c5049d1ef53f2e9cfaf11c62885a953bb64f8576 100644
--- a/circle.yml
+++ b/circle.yml
@@ -3,9 +3,5 @@ machine:
     version: 6.9
 
 test:
-  pre:
-    - npm run eslint
-  override:
-    - npm run istanbul
   post:
     - bash <(curl -s https://codecov.io/bash)
diff --git a/lib/config/cli.js b/lib/config/cli.js
index d37066c3858eb872485aabb239b3bbad74bb4f46..aa6856e9a63507a64402da5b958bbaf804ebcef2 100644
--- a/lib/config/cli.js
+++ b/lib/config/cli.js
@@ -1,5 +1,4 @@
-const clearRequire = require('clear-require');
-let commander = require('commander');
+const commander = require('commander');
 const configDefinitions = require('./definitions');
 
 module.exports = {
@@ -16,8 +15,6 @@ function getCliName(option) {
 }
 
 function getConfig(argv) {
-  clearRequire('commander');
-  commander = require('commander'); // eslint-disable-line
   const options = configDefinitions.getOptions();
 
   const config = {};
@@ -28,7 +25,7 @@ function getConfig(argv) {
     string: val => val,
   };
 
-  let program = commander.arguments('[repositories...]');
+  let program = new commander.Command().arguments('[repositories...]');
 
   options.forEach((option) => {
     if (option.cli !== false) {
diff --git a/package.json b/package.json
index 105bfbea990e94dfdaaa144bd5f59343fea8faf6..e4fe5051a127d32365eb185d10719eb3f1bc9668 100644
--- a/package.json
+++ b/package.json
@@ -10,15 +10,13 @@
     "eslint-fix": "eslint --ignore-path .gitignore --fix .",
     "heroku-push": "git push heroku master",
     "heroku-scheduler": "heroku addons:open scheduler",
-    "istanbul": "istanbul cover _mocha test",
-    "mocha": "mocha test",
     "npm-publish": "npm run update-docs && np",
     "prepublish": "npm run build",
-    "pretest": "npm run build",
     "start": "node dist/renovate",
     "start-babel": "babel-node lib/renovate",
     "start-raw": "node --harmony-async-await lib/renovate",
-    "test": "npm run eslint && npm run istanbul",
+    "test": "npm run eslint && npm run jest",
+    "jest": "jest",
     "transpile": "rimraf dist && mkdirp dist && babel lib --out-dir dist",
     "update-docs": "npm run build && bash bin/update-docs.sh"
   },
@@ -41,12 +39,13 @@
     "node": ">=6.9.0"
   },
   "dependencies": {
+    "babel-jest": "18.0.0",
     "changelog": "dylang/changelog#v1.2.0",
-    "clear-require": "2.0.0",
     "commander": "2.9.0",
     "gh-got": "5.0.0",
     "got": "6.7.1",
     "handlebars": "4.0.6",
+    "jest": "18.1.0",
     "json-stringify-pretty-compact": "1.0.2",
     "lodash": "4.17.4",
     "registry-auth-token": "3.1.0",
@@ -63,9 +62,7 @@
     "eslint-config-airbnb-base": "11.1.0",
     "eslint-plugin-import": "2.2.0",
     "eslint-plugin-promise": "3.4.1",
-    "istanbul": "0.4.5",
     "mkdirp": "0.5.1",
-    "mocha": "3.2.0",
     "np": "2.12.0",
     "rimraf": "2.5.4"
   },
@@ -74,6 +71,19 @@
       "transform-async-to-generator"
     ]
   },
+  "jest": {
+    "coverageDirectory": "./coverage",
+    "collectCoverage": true,
+    "collectCoverageFrom": [
+      "lib/**/*.js"
+    ],
+    "coverageReporters": [
+      "json",
+      "lcov",
+      "text-summary"
+    ],
+    "setupTestFrameworkScriptFile": "./test/chai.js"
+  },
   "renovate": {
     "labels": [
       "ready"
diff --git a/test/.eslintrc.js b/test/.eslintrc.js
index 1deb8028f830049b2c8994a9cfeca2360d42d983..e0048625ec30267c17bc10c95bd5671636f62fe8 100644
--- a/test/.eslintrc.js
+++ b/test/.eslintrc.js
@@ -1,8 +1,9 @@
 module.exports = {
     'env': {
-      'mocha': true,
+      'jest': true,
     },
     'rules': {
       'import/no-extraneous-dependencies': 0,
+      'global-require': 0
     },
 };
diff --git a/test/_fixtures/config/argv.js b/test/_fixtures/config/argv.js
index e4944d56168fb16c35881294bc4bc5bd36786468..09f5cec265634159e58ea106faef66fa88979b5e 100644
--- a/test/_fixtures/config/argv.js
+++ b/test/_fixtures/config/argv.js
@@ -1,4 +1,4 @@
-module.exports = [
+module.exports = () => [
   '/usr/local/bin/node',
   '/Users/me/github/renovate/renovate',
 ];
diff --git a/test/_fixtures/package.json/inputs/01.json b/test/_fixtures/package-json/inputs/01.json
similarity index 100%
rename from test/_fixtures/package.json/inputs/01.json
rename to test/_fixtures/package-json/inputs/01.json
diff --git a/test/_fixtures/package.json/inputs/02.json b/test/_fixtures/package-json/inputs/02.json
similarity index 100%
rename from test/_fixtures/package.json/inputs/02.json
rename to test/_fixtures/package-json/inputs/02.json
diff --git a/test/_fixtures/package.json/outputs/011.json b/test/_fixtures/package-json/outputs/011.json
similarity index 100%
rename from test/_fixtures/package.json/outputs/011.json
rename to test/_fixtures/package-json/outputs/011.json
diff --git a/test/_fixtures/package.json/outputs/012.json b/test/_fixtures/package-json/outputs/012.json
similarity index 100%
rename from test/_fixtures/package.json/outputs/012.json
rename to test/_fixtures/package-json/outputs/012.json
diff --git a/test/_fixtures/package.json/outputs/013.json b/test/_fixtures/package-json/outputs/013.json
similarity index 100%
rename from test/_fixtures/package.json/outputs/013.json
rename to test/_fixtures/package-json/outputs/013.json
diff --git a/test/config/cli.js b/test/config/cli.spec.js
similarity index 85%
rename from test/config/cli.js
rename to test/config/cli.spec.js
index ab198b9d4ba7b0313f2357b68fa68ac47616261f..f9a08e36ae60501f369db2e5843c9afc88c5a2b0 100644
--- a/test/config/cli.js
+++ b/test/config/cli.spec.js
@@ -1,7 +1,11 @@
-const cli = require('../../dist/config/cli.js');
-let argv = require('../_fixtures/config/argv');
+const cli = require('../../lib/config/cli.js');
+const getArgv = require('../_fixtures/config/argv');
 
 describe('config/cli', () => {
+  let argv;
+  beforeEach(() => {
+    argv = getArgv();
+  });
   describe('.getCliName(definition)', () => {
     it('generates CLI value', () => {
       const option = {
@@ -30,44 +34,36 @@ describe('config/cli', () => {
       argv.push('--recreate-closed');
       argv.push('true');
       cli.getConfig(argv).should.eql({ recreateClosed: true });
-      argv = argv.slice(0, -2);
     });
     it('supports boolean space false', () => {
       argv.push('--recreate-closed');
       argv.push('false');
       cli.getConfig(argv).should.eql({ recreateClosed: false });
-      argv = argv.slice(0, -2);
     });
     it('supports boolean equals true', () => {
       argv.push('--recreate-closed=true');
       cli.getConfig(argv).should.eql({ recreateClosed: true });
-      argv = argv.slice(0, -1);
     });
     it('supports boolean equals false', () => {
       argv.push('--recreate-closed=false');
       cli.getConfig(argv).should.eql({ recreateClosed: false });
-      argv = argv.slice(0, -1);
     });
     it('supports list single', () => {
       argv.push('--labels=a');
       cli.getConfig(argv).should.eql({ labels: ['a'] });
-      argv = argv.slice(0, -1);
     });
     it('supports list multiple', () => {
       argv.push('--labels=a,b,c');
       cli.getConfig(argv).should.eql({ labels: ['a', 'b', 'c'] });
-      argv = argv.slice(0, -1);
     });
     it('supports string', () => {
       argv.push('--token=a');
       cli.getConfig(argv).should.eql({ token: 'a' });
-      argv = argv.slice(0, -1);
     });
     it('supports repositories', () => {
       argv.push('foo');
       argv.push('bar');
       cli.getConfig(argv).should.eql({ repositories: ['foo', 'bar'] });
-      argv = argv.slice(0, -2);
     });
   });
 });
diff --git a/test/config/env.js b/test/config/env.spec.js
similarity index 97%
rename from test/config/env.js
rename to test/config/env.spec.js
index 5ba461ef95a03b8efef381bd9dc55c5ce6913550..400195cbc185280e5d1b213cbcdc4f6c19320151 100644
--- a/test/config/env.js
+++ b/test/config/env.spec.js
@@ -1,4 +1,4 @@
-const env = require('../../dist/config/env.js');
+const env = require('../../lib/config/env.js');
 
 describe('config/env', () => {
   describe('.getConfig(env)', () => {
diff --git a/test/config/file.js b/test/config/file.spec.js
similarity index 52%
rename from test/config/file.js
rename to test/config/file.spec.js
index 4ea74fe411bde9484979769557f68ed200bcca79..007adadc71b7e5bc1ef2921456dafe872c58662a 100644
--- a/test/config/file.js
+++ b/test/config/file.spec.js
@@ -1,4 +1,5 @@
-const file = require('../../dist/config/file.js');
+const path = require('path');
+const file = require('../../lib/config/file.js');
 const customConfig = require('../_fixtures/config/file');
 
 describe('config/file', () => {
@@ -7,7 +8,8 @@ describe('config/file', () => {
       file.getConfig({}).should.eql({});
     });
     it('parses custom config file', () => {
-      file.getConfig({ RENOVATE_CONFIG_FILE: 'test/_fixtures/config/file.js' }).should.eql(customConfig);
+      const configFile = path.resolve(__dirname, '../_fixtures/config/file.js');
+      file.getConfig({ RENOVATE_CONFIG_FILE: configFile }).should.eql(customConfig);
     });
   });
 });
diff --git a/test/config/index.js b/test/config/index.spec.js
similarity index 70%
rename from test/config/index.js
rename to test/config/index.spec.js
index 2d404c5dc0fd3be30b03b915fccb9378686ad02e..722fbeb600e0ece873cff5a3e989f42cc29bb8f7 100644
--- a/test/config/index.js
+++ b/test/config/index.spec.js
@@ -1,9 +1,15 @@
-const configParser = require('../../dist/config/index.js');
-const defaultArgv = require('../_fixtures/config/argv');
+const argv = require('../_fixtures/config/argv');
 const should = require('chai').should();
 
 describe('config/index', () => {
   describe('.parseConfigs(env, defaultArgv)', () => {
+    let configParser;
+    let defaultArgv;
+    beforeEach(() => {
+      jest.resetModules();
+      configParser = require('../../lib/config/index.js');
+      defaultArgv = argv();
+    });
     it('throws for no token', () => {
       const env = {};
       configParser.parseConfigs.bind(configParser, env, defaultArgv).should.throw('At least one repository must be configured');
@@ -14,13 +20,13 @@ describe('config/index', () => {
     });
     it('supports token in CLI options', () => {
       const env = {};
-      const argv = defaultArgv.concat(['--token=abc']);
-      configParser.parseConfigs.bind(configParser, env, argv).should.throw('At least one repository must be configured');
+      defaultArgv = defaultArgv.concat(['--token=abc']);
+      configParser.parseConfigs.bind(configParser, env, defaultArgv).should.throw('At least one repository must be configured');
     });
     it('supports repositories in CLI', () => {
       const env = {};
-      const argv = defaultArgv.concat(['--token=abc', 'foo']);
-      configParser.parseConfigs(env, argv);
+      defaultArgv = defaultArgv.concat(['--token=abc', 'foo']);
+      configParser.parseConfigs(env, defaultArgv);
       const repos = configParser.getRepositories();
       should.exist(repos);
       repos.should.have.length(1);
diff --git a/test/helpers/handlebars.js b/test/helpers/handlebars.spec.js
similarity index 84%
rename from test/helpers/handlebars.js
rename to test/helpers/handlebars.spec.js
index f24e68929f9b6e7afafa0829d19a4e8a1cf1217a..4557d1164e5fd6e31b44839450b124f33be4a3d5 100644
--- a/test/helpers/handlebars.js
+++ b/test/helpers/handlebars.spec.js
@@ -1,4 +1,4 @@
-const handlebars = require('../../dist/helpers/handlebars');
+const handlebars = require('../../lib/helpers/handlebars');
 
 const template = 'renovate/{{ depName }}-{{ newVersionMajor }}.x';
 const upgrade = {
diff --git a/test/helpers/package-json.js b/test/helpers/package-json.spec.js
similarity index 77%
rename from test/helpers/package-json.js
rename to test/helpers/package-json.spec.js
index af027e22693f3feb0c284738570b2327272c3362..da891e3888aa0c5405d39586aeff4d5785c1a67e 100644
--- a/test/helpers/package-json.js
+++ b/test/helpers/package-json.spec.js
@@ -1,10 +1,15 @@
 const fs = require('fs');
-const packageJson = require('../../dist/helpers/package-json');
+const path = require('path');
+const packageJson = require('../../lib/helpers/package-json');
 
 const defaultTypes = ['dependencies', 'devDependencies', 'optionalDependencies'];
 
-const input01Content = fs.readFileSync('./test/_fixtures/package.json/inputs/01.json', 'utf8');
-const input02Content = fs.readFileSync('./test/_fixtures/package.json/inputs/02.json', 'utf8');
+function readFixture(fixture) {
+  return fs.readFileSync(path.resolve(__dirname, `../_fixtures/package-json/${fixture}`), 'utf8');
+}
+
+const input01Content = readFixture('inputs/01.json');
+const input02Content = readFixture('inputs/02.json');
 
 describe('helpers/package-json', () => {
   describe('.extractDependencies(packageJson, sections)', () => {
@@ -29,19 +34,19 @@ describe('helpers/package-json', () => {
   });
   describe('.setNewValue(currentFileContent, depType, depName, newVersion)', () => {
     it('replaces a dependency value', () => {
-      const outputContent = fs.readFileSync('./test/_fixtures/package.json/outputs/011.json', 'utf8');
+      const outputContent = readFixture('outputs/011.json');
       const testContent =
         packageJson.setNewValue(input01Content, 'dependencies', 'cheerio', '0.22.1');
       testContent.should.equal(outputContent);
     });
     it('replaces only the first instance of a value', () => {
-      const outputContent = fs.readFileSync('./test/_fixtures/package.json/outputs/012.json', 'utf8');
+      const outputContent = readFixture('outputs/012.json');
       const testContent =
         packageJson.setNewValue(input01Content, 'devDependencies', 'angular-touch', '1.6.1');
       testContent.should.equal(outputContent);
     });
     it('replaces only the second instance of a value', () => {
-      const outputContent = fs.readFileSync('./test/_fixtures/package.json/outputs/013.json', 'utf8');
+      const outputContent = readFixture('outputs/013.json');
       const testContent =
         packageJson.setNewValue(input01Content, 'devDependencies', 'angular-sanitize', '1.6.1');
       testContent.should.equal(outputContent);
diff --git a/test/helpers/versions.js b/test/helpers/versions.spec.js
similarity index 97%
rename from test/helpers/versions.js
rename to test/helpers/versions.spec.js
index c35b1949c59b9db883152f8e376b89c70584d1de..318c27fb0383f7acb5cb6c8e2b79020350ee3e18 100644
--- a/test/helpers/versions.js
+++ b/test/helpers/versions.spec.js
@@ -1,6 +1,6 @@
-const versionsHelper = require('../../dist/helpers/versions');
+const versionsHelper = require('../../lib/helpers/versions');
 const qJson = require('../_fixtures/npm/01.json');
-const defaultConfig = require('../../dist/config/defaults').getConfig();
+const defaultConfig = require('../../lib/config/defaults').getConfig();
 
 describe('helpers/versions', () => {
   describe('.determineUpgrades(dep, currentVersion, defaultConfig)', () => {
diff --git a/test/index.spec.js b/test/index.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..9d45856e255746d3501cd4d3a01447236af63995
--- /dev/null
+++ b/test/index.spec.js
@@ -0,0 +1,5 @@
+require('../lib/index');
+
+it('placeholder', () => {
+  // TODO: write tests for this module - this is here so the file shows up in coverage
+});
diff --git a/test/mocha.opts b/test/mocha.opts
deleted file mode 100644
index f41d094e52112b7662597ba45a2edc51d068e441..0000000000000000000000000000000000000000
--- a/test/mocha.opts
+++ /dev/null
@@ -1,2 +0,0 @@
---recursive
---reporter spec
diff --git a/test/worker.spec.js b/test/worker.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..1564f4fca341961ea02878661baea265b064787d
--- /dev/null
+++ b/test/worker.spec.js
@@ -0,0 +1,5 @@
+require('../lib/worker');
+
+it('placeholder', () => {
+  // TODO: write tests for this module - this is here so the file shows up in coverage
+});