diff --git a/docs/TESTING.md b/docs/TESTING.md
index 789397a7f08ad3c5bd167ee72c1bdc401b85e4b6..e052624a3fdda0df31ef32317101ebcb242ff0a8 100644
--- a/docs/TESTING.md
+++ b/docs/TESTING.md
@@ -2,15 +2,61 @@
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-Developer tests should be run before committing code. There are two test suites.
+Developer tests should be run before committing code. There are two test interfaces:
 
   - `npm test`
 
   - Load http://localhost:10002/test/index.html into a world wide web browser
 
-Note that for mysql, you will need to grant `browserid` privileges to create tables.
-You can then run the mysql suite with, e.g., 
+## Web Interface
 
-    NODE_ENV=test_mysql MYSQL_USER=browserid MYSQL_PASSWORD=browserid npm test
+The test URL (`localhost:10002/test`) takes an optional `filter`
+argument that can be used to restrict the test suite to one module.
+For example, to run only the `shared/xhr` tests, visit:
 
-  
+```
+http://localhost:10002/test/?filter=shared/xhr
+```
+
+The filter matches substrings, so you can also filter by `shared` to
+get `shared/xhr`, `shared/user`, etc.
+
+Test module names are listed on the web page on the left-hand side.
+
+## Shell Interface
+
+### MySQL
+
+Running tests with `npm test` will use a json database by default.  To
+test using MySQL, you will need to grant `browserid` privileges to
+create tables.  You can then run the mysql suite with, e.g.,
+
+```bash
+NODE_ENV=test_mysql MYSQL_USER=browserid MYSQL_PASSWORD=browserid npm test
+```
+
+### Test Suites
+
+There are two test suites:
+
+- `back`
+- `front`
+
+By default the test runner will run them all. You can limit it to one
+suite by setting `WHAT_TESTS` in your environment.  For example:
+
+```bash
+WHAT_TESTS=front npm test
+```
+
+The front-end tests are run via PhantomJS.
+
+### Filtering
+
+As in the web tests, you can tell the runner to run only tests whose
+modules match a given name.  Specify this in your environment with
+`FRONTEND_TEST_FILTER`.  For example:
+
+```bash
+WHAT_TESTS=front FRONTEND_TEST_FILTER=shared/user npm test
+```
diff --git a/scripts/test b/scripts/test
index 9b6069a6eb2f0ad7187e961f14dd5144352444ae..5ed56ae46ea30267cf024104e78ec7c1ef0c51f9 100755
--- a/scripts/test
+++ b/scripts/test
@@ -22,6 +22,9 @@ if (!process.env['WHAT_TESTS']) {
 if (whatTests[0] == 'all') whatTests = [ 'back_mysql', 'back', 'front' ];
 
 var ec = 0;
+var frontend_test_filter = process.env['FRONTEND_TEST_FILTER'] ?
+                           ' (filter: ' + process.env['FRONTEND_TEST_FILTER'] + ')' :
+                           '';
 function run() {
   if (!whatTests.length) process.exit(ec);
 
@@ -29,7 +32,7 @@ function run() {
 
   const availConf = {
     front: {
-      what: "Front end unit tests under PhantomJS",
+      what: "Front end unit tests under PhantomJS" + frontend_test_filter,
       node_env: 'test_json',
       script: 'test_frontend'
     },
diff --git a/scripts/test_frontend b/scripts/test_frontend
index 879af173a0d8caf7d0cf3a4c37df6f9fc311b893..19f2c66a133f80b8185c73105bc8e80bb56175c5 100755
--- a/scripts/test_frontend
+++ b/scripts/test_frontend
@@ -35,8 +35,10 @@ start_stop.addStartupBatches(suite);
 suite.addBatch({
   "frontend unit tests": {
     topic: function() {
+      var filter = process.env['FRONTEND_TEST_FILTER'] ?
+                   '?filter=' + process.env['FRONTEND_TEST_FILTER'] : '';
       var kid = spawn('phantomjs', [ path.join(__dirname, 'phantomrunner.js'),
-                                     'http://127.0.0.1:10002/test' ]);
+                                     'http://127.0.0.1:10002/test/'+filter ]);
       kid.stdout.on('data', function(d) { process.stdout.write(d); });
       kid.stderr.on('data', function(d) { process.stderr.write(d); });
       kid.on('exit', this.callback);