diff --git a/test/HOWTO.md b/test/HOWTO.md
new file mode 100644
index 0000000..de2a8a0
--- /dev/null
+++ b/test/HOWTO.md
@@ -0,0 +1,67 @@
+Testing HowTo
+=============
+
+Install and run tests
+---------------------
+
+ npm install
+ npm run test
+ npm run lint
+
+QUnit is used for unit tests. Above npm command will run them under karma. You can also run the
+same tests as plain qunit in Firefox (but not Chrome, due to use of iframe):
+
+ firefox qunit_test_runner.html
+
+For linting both jshint and jscs are used. As is customary, they are configured via
+[.jshintrc](.jshintrc) and [.jscsrc](.jscsrc).
+
+
+Anatomy of a unit test
+----------------------
+
+Impress.js likes to use the entire browser window, sets classes on the body element, and so on. For
+this reason, we use an iframe to run each test. QUnit tests are supposed to run inside a
+`
` element. So in our case, the contents of that div is an iframe.
+
+Each test consists of 2 files: A html file that contains a normal impress.js presentation, and
+a js file that contains your QUnit tests. For example, see
+[test/core_tests_presentation.html](test/core_tests_presentation.html) and
+[test/core_tests.js](test/core_tests.js). Note that the QUnit tests run in the parent window.
+
+[test/helpers.js](test/helpers.js) contains helper functions to create the iframe and load the
+html file that contains the impress.js presentation to be tested.
+
+An example test would therefore look like:
+
+ QUnit.test( "Example tests", function( assert ) {
+ loadIframe( "test/core_tests_presentation.html", assert, function() {
+ initPresentation( assert, function() {
+ var iframe = document.getElementById( "presentation-iframe" );
+ var iframeDoc = iframe.contentDocument;
+ var iframeWin = iframe.contentWindow;
+ var step1 = iframeDoc.querySelector( "div#step-1" );
+
+ assert.equal( step1.dataset.x, "0", "data-x attribute set to zero" );
+ assert.equal( step1.dataset.y, "0", "data-y attribute set to zero" );
+
+
+Where to save unit tests?
+-------------------------
+
+Tests related to a plugin are saved in the plugin folder. See for example
+[src/plugins/navigation/navigation_tests.js](src/plugins/navigation/navigation_tests.js).
+
+Tests for impress.js core, or other tests not related to one specific plugin, go under
+[test/](test/).
+
+Adding your js file to the right places
+---------------------------------------
+
+There are 3 files where you need to add your new test so that it gets run. (Yeah, see
+[#658](https://github.com/impress/impress.js/issues/658) for more on that topic...)
+
+1. qunit_test_runner.html
+2. karma.conf.js
+3. karma.conf-sauce.js
+
diff --git a/test/bootstrap.js b/test/bootstrap.js
deleted file mode 100644
index 135fd5f..0000000
--- a/test/bootstrap.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/*jshint browser:true */
-
-// TODO: This is the bootstrap file for *karma*. Poorly named (since karma is
-// only one option, in this repo) but keeping the same name now to avoid
-// unnecessary deviation with upstream.
-// If you just want to run the tests locally, you can open /qunit_test_runner.html in Firefox.
-
-// That's annoying: karma-qunit doesn't provide the qunit-fixture element
-// https://github.com/karma-runner/karma-qunit/issues/18
-
-// This file contains so much HTML, that we will just respectfully disagree about js
-/* jshint quotmark:single */
-/* global document */
-
-var fix = document.createElement( 'div' );
-fix.id = 'qunit-fixture';
-fix.innerHTML = [
-'\n',
-' '
-].join( '' );
diff --git a/test/helpers.js b/test/helpers.js
index 5df30fc..71d31fd 100644
--- a/test/helpers.js
+++ b/test/helpers.js
@@ -12,7 +12,7 @@ var loadIframe = function( src, assert, callback ) {
console.log( 'Begin loadIframe' );
// When running in Karma, the #qunit-fixture appears from somewhere and we can't set its
- // contents in advance.
+ // contents in advance, so we set it now.
var fix = document.getElementById( 'qunit-fixture' );
fix.innerHTML = [
'\n',