diff --git a/config/jest/environment.js b/config/jest/environment.js
deleted file mode 100644
index e7c1df906c697e9cc395ec123fdc1ba80d0acd1e..0000000000000000000000000000000000000000
--- a/config/jest/environment.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// Currently, Jest mocks setTimeout() and similar functions by default:
-// https://facebook.github.io/jest/docs/timer-mocks.html
-// We think this is confusing, so we disable this feature.
-// If you see value in it, run `jest.useFakeTimers()` in individual tests.
-beforeEach(() => {
-  jest.useRealTimers();
-});
diff --git a/package.json b/package.json
index 1694ded2b127032b31709c04bcbe77a27b19f0fd..ee3f741fabccf364fee1fd489ff37e15154898ad 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
     "create-react-app": "node global-cli/index.js --scripts-version \"$PWD/`npm pack`\"",
     "e2e": "tasks/e2e.sh",
     "start": "node scripts/start.js --debug-template",
-    "test": "node scripts/test.js --debug-template"
+    "test": "node scripts/test.js --debug-template --watch --env=jsdom"
   },
   "files": [
     "PATENTS",
@@ -31,7 +31,7 @@
     "autoprefixer": "6.4.0",
     "babel-core": "6.14.0",
     "babel-eslint": "6.1.2",
-    "babel-jest": "14.1.0",
+    "babel-jest": "15.0.0",
     "babel-loader": "6.2.5",
     "babel-plugin-transform-class-properties": "6.11.5",
     "babel-plugin-transform-object-rest-spread": "6.8.0",
@@ -61,7 +61,7 @@
     "html-loader": "0.4.3",
     "html-webpack-plugin": "2.22.0",
     "http-proxy-middleware": "0.17.0",
-    "jest": "14.1.0",
+    "jest": "15.0.1",
     "json-loader": "0.5.4",
     "object-assign": "4.1.0",
     "opn": "4.0.2",
@@ -80,8 +80,7 @@
   "devDependencies": {
     "bundle-deps": "1.0.0",
     "react": "^15.3.0",
-    "react-dom": "^15.3.0",
-    "react-test-renderer": "^15.3.0"
+    "react-dom": "^15.3.0"
   },
   "optionalDependencies": {
     "fsevents": "1.0.14"
diff --git a/scripts/eject.js b/scripts/eject.js
index 55661d1928570ff9eb4223db0548237ec8eae350..74d1cf09f12042fc857b70e081eb366deb65c022 100644
--- a/scripts/eject.js
+++ b/scripts/eject.js
@@ -41,7 +41,6 @@ prompt(
     path.join('config', 'webpack.config.prod.js'),
     path.join('config', 'jest', 'CSSStub.js'),
     path.join('config', 'jest', 'FileStub.js'),
-    path.join('config', 'jest', 'environment.js'),
     path.join('config', 'jest', 'transform.js'),
     path.join('scripts', 'build.js'),
     path.join('scripts', 'start.js'),
@@ -99,17 +98,19 @@ prompt(
   });
 
   console.log('Updating scripts');
+  delete appPackage.scripts['eject'];
   Object.keys(appPackage.scripts).forEach(function (key) {
-    appPackage.scripts[key] = 'node ./scripts/' + key + '.js'
+    appPackage.scripts[key] = appPackage.scripts[key]
+      .replace(/react-scripts test/g, 'jest')
+      .replace(/react-scripts (\w+)/g, 'node scripts/$1.js');
   });
-  delete appPackage.scripts['eject'];
 
-  appPackage.scripts.test = 'jest';
+  // Add Jest config
   appPackage.jest = createJestConfig(
     filePath => path.join('<rootDir>', filePath)
   );
 
-  // explicitly specify ESLint config path for editor plugins
+  // Explicitly specify ESLint config path for editor plugins
   appPackage.eslintConfig = {
     extends: './config/eslint.js',
   };
diff --git a/scripts/init.js b/scripts/init.js
index 14ace414295d6edaa1c5022be064f7e84167cbe8..9402b930e6e195c5faa4bc4c39e9d18679a84e66 100644
--- a/scripts/init.js
+++ b/scripts/init.js
@@ -23,10 +23,12 @@ module.exports = function(appPath, appName, verbose, originalDirectory) {
   appPackage.devDependencies = appPackage.devDependencies || {};
 
   // Setup the script rules
-  appPackage.scripts = {};
-  ['start', 'build', 'eject', 'test'].forEach(function(command) {
-    appPackage.scripts[command] = 'react-scripts ' + command;
-  });
+  appPackage.scripts = {
+    'start': 'react-scripts start',
+    'build': 'react-scripts build',
+    'test': 'react-scripts test --watch --env=jsdom',
+    'eject': 'react-scripts eject'
+  };
 
   // explicitly specify ESLint config path for editor plugins
   appPackage.eslintConfig = {
@@ -69,7 +71,6 @@ module.exports = function(appPath, appName, verbose, originalDirectory) {
     'install',
     'react',
     'react-dom',
-    'react-test-renderer',
     '--save',
     verbose && '--verbose'
   ].filter(function(e) { return e; });
diff --git a/scripts/test.js b/scripts/test.js
index f11cda5a4288a7eda4d6e255cbcf500317ffef5c..b173656b5db9f40636a6d5e73931956270a8e8fc 100644
--- a/scripts/test.js
+++ b/scripts/test.js
@@ -16,9 +16,10 @@ const paths = require('../config/paths');
 
 const argv = process.argv.slice(2);
 
-const index = argv.indexOf('--debug-template');
-if (index !== -1) {
-  argv.splice(index, 1);
+// Don't pass this option to Jest
+const debugTemplateIndex = argv.indexOf('--debug-template');
+if (debugTemplateIndex !== -1) {
+  argv.splice(debugTemplateIndex, 1);
 }
 
 argv.push('--config', JSON.stringify(createJestConfig(
diff --git a/scripts/utils/createJestConfig.js b/scripts/utils/createJestConfig.js
index 8b6bfd5249266833ed5906ad8d3f015da3b7571c..21b8ca5436439de5f1c77864a840ae9e0c72e1e0 100644
--- a/scripts/utils/createJestConfig.js
+++ b/scripts/utils/createJestConfig.js
@@ -9,25 +9,14 @@
 
 module.exports = (resolve, rootDir) => {
   const config = {
-    automock: false,
     moduleNameMapper: {
       '^[./a-zA-Z0-9$_-]+\\.(jpg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm)$': resolve('config/jest/FileStub.js'),
       '^[./a-zA-Z0-9$_-]+\\.css$': resolve('config/jest/CSSStub.js')
     },
-    persistModuleRegistryBetweenSpecs: true,
     scriptPreprocessor: resolve('config/jest/transform.js'),
-    setupFiles: [
-      resolve('config/polyfills.js')
-    ],
-    setupTestFrameworkScriptFile: resolve('config/jest/environment.js'),
-    testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/build/'],
-    // Allow three popular conventions:
-    // **/__tests__/*.js
-    // **/*.test.js
-    // **/*.spec.js
-    testRegex: '(__tests__/.*|\\.(test|spec))\\.js$',
-    testEnvironment: 'node',
-    verbose: true
+    setupFiles: [resolve('config/polyfills.js')],
+    testPathIgnorePatterns: ['<rootDir>/(build|docs|node_modules)/'],
+    testEnvironment: 'node'
   };
   if (rootDir) {
     config.rootDir = rootDir;
diff --git a/tasks/e2e.sh b/tasks/e2e.sh
index 6e6c20c9420319fb05e0337b1d03e55498414d01..1e841d8699abf967b87c3d0ec8a37dbd3775497f 100755
--- a/tasks/e2e.sh
+++ b/tasks/e2e.sh
@@ -12,7 +12,8 @@ cd "$(dirname "$0")"
 function cleanup {
   echo 'Cleaning up.'
   cd $initial_path
-  rm ../template/src/__tests__/__snapshots__/App-test.js.snap
+  # Uncomment when snapshot testing is enabled by default:
+  # rm ../template/src/__snapshots__/App.test.js.snap
   rm -rf $temp_cli_path $temp_app_path
 }
 
@@ -53,12 +54,9 @@ perl -i -p0e 's/bundledDependencies.*?]/bundledDependencies": []/s' package.json
 npm install
 scripts_path=$PWD/`npm pack`
 
-# lint
+# Lint
 ./node_modules/.bin/eslint --ignore-path .gitignore ./
 
-# Test local start command
-npm start -- --smoke-test
-
 # Test local build command
 npm run build
 
@@ -69,9 +67,13 @@ test -e build/static/css/*.css
 test -e build/static/media/*.svg
 test -e build/favicon.ico
 
-# Run tests
-npm run test
-test -e template/src/__tests__/__snapshots__/App-test.js.snap
+# Run tests, overriding watch option to disable it
+npm test -- --watch=no
+# Uncomment when snapshot testing is enabled by default:
+# test -e template/src/__snapshots__/App.test.js.snap
+
+# Test local start command
+npm start -- --smoke-test
 
 # Pack CLI
 cd global-cli
@@ -99,9 +101,10 @@ test -e build/static/css/*.css
 test -e build/static/media/*.svg
 test -e build/favicon.ico
 
-# Run tests
-npm run test
-test -e src/__tests__/__snapshots__/App-test.js.snap
+# Run tests, overriding watch option to disable it
+npm test -- --watch=no
+# Uncomment when snapshot testing is enabled by default:
+# test -e src/__snapshots__/App.test.js.snap
 
 # Test the server
 npm start -- --smoke-test
@@ -117,9 +120,10 @@ test -e build/static/css/*.css
 test -e build/static/media/*.svg
 test -e build/favicon.ico
 
-# Run tests
-npm run test
-test -e src/__tests__/__snapshots__/App-test.js.snap
+# Run tests, overriding watch option to disable it
+npm test -- --watch=no
+# Uncomment when snapshot testing is enabled by default:
+# test -e src/__snapshots__/App.test.js.snap
 
 # Test the server
 npm start -- --smoke-test
diff --git a/template/src/App.test.js b/template/src/App.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..55dbf38ce2cb7a89f4b87d3f0a963f7276fc0997
--- /dev/null
+++ b/template/src/App.test.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+
+describe('App', () => {
+  it('renders without crashing', () => {
+    const div = document.createElement('div');
+    ReactDOM.render(<App />, div);
+  });
+});
diff --git a/template/src/__tests__/App-test.js b/template/src/__tests__/App-test.js
deleted file mode 100644
index 7d36ff192a2678a026c631cefe90491d02299621..0000000000000000000000000000000000000000
--- a/template/src/__tests__/App-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import App from '../App';
-import renderer from 'react-test-renderer';
-
-describe('App', () => {
-  it('renders a welcome view', () => {
-    const instance = renderer.create(<App />);
-    const tree = instance.toJSON();
-    expect(tree).toMatchSnapshot();
-  });
-});