Repository: mochajs/mocha

Problem statement:
add --strict flag 
I'd like a `--strict` CLI flag that will cause my tests to exit with non-zero status if
- any test is marked as only
- any test is marked as skipped
- any test is marked as pending



Hints:
This may be a good solution to the problem of accidentally committing these. 

@mochajs/mocha any opinions?

Hmm, I thought skipped tests are actually marked as pending?

People do commit these (looking at you `.only`), so I believe this is useful, and I'm looking forward to it.

Not so sure about the tests marked as skipped/pending.. If I skip tests is because I don't want to run them anymore, not even in prod.. not sure about you.

I would love to have this!

If you do not want a test (even in prod): it's probably because this is a dead/outdated test and need to be deleted from the source code.

cc @mochajs/mocha 

Could we use some different terminology so that it's not confused with node/v8's `--use_strict` ?

How about `--production`

What is the status of this issue? I've been following the related PRs but they seem to be all closed. 

I think this is an important configuration and I was surprised that it didn't exist since some commit could add a `.only` and the test suite would be giving invalid feedback...

Thanks!

@IvanGuardado https://github.com/mochajs/mocha/pull/1935#issuecomment-242995238


Patch:
diff --git a/lib/mocha.js b/lib/mocha.js
--- a/lib/mocha.js
+++ b/lib/mocha.js
@@ -483,6 +483,24 @@ Mocha.prototype.delay = function delay () {
   return this;
 };
 
+/**
+ * Tests marked only fail the suite
+ * @returns {Mocha}
+ */
+Mocha.prototype.forbidOnly = function () {
+  this.options.forbidOnly = true;
+  return this;
+};
+
+/**
+ * Pending tests and tests marked skip fail the suite
+ * @returns {Mocha}
+ */
+Mocha.prototype.forbidPending = function () {
+  this.options.forbidPending = true;
+  return this;
+};
+
 /**
  * Run tests and invoke `fn()` when complete.
  *
@@ -504,6 +522,8 @@ Mocha.prototype.run = function (fn) {
   runner.hasOnly = options.hasOnly;
   runner.asyncOnly = options.asyncOnly;
   runner.allowUncaught = options.allowUncaught;
+  runner.forbidOnly = options.forbidOnly;
+  runner.forbidPending = options.forbidPending;
   if (options.grep) {
     runner.grep(options.grep, options.invert);
   }
diff --git a/lib/runner.js b/lib/runner.js
--- a/lib/runner.js
+++ b/lib/runner.js
@@ -820,6 +820,12 @@ Runner.prototype.run = function (fn) {
 
   // callback
   this.on('end', function () {
+    if (self.forbidOnly && self.hasOnly) {
+      self.failures += self.stats.tests;
+    }
+    if (self.forbidPending) {
+      self.failures += self.stats.pending;
+    }
     debug('end');
     process.removeListener('uncaughtException', uncaught);
     fn(self.failures);


Test patch:
diff --git a/test/integration/fixtures/options/forbid-only/only.js b/test/integration/fixtures/options/forbid-only/only.js
new file mode 100644
--- /dev/null
+++ b/test/integration/fixtures/options/forbid-only/only.js
@@ -0,0 +1,7 @@
+'use strict';
+
+describe('forbid only - test marked with only', function () {
+  it('test1', function () {});
+  it.only('test2', function () {});
+  it('test3', function () {});
+});
diff --git a/test/integration/fixtures/options/forbid-only/passed.js b/test/integration/fixtures/options/forbid-only/passed.js
new file mode 100644
--- /dev/null
+++ b/test/integration/fixtures/options/forbid-only/passed.js
@@ -0,0 +1,7 @@
+'use strict';
+
+describe('forbid only - `.only` is not used', function () {
+  it('test1', function () {});
+  it('test2', function () {});
+  it('test3', function () {});
+});
diff --git a/test/integration/fixtures/options/forbid-pending/passed.js b/test/integration/fixtures/options/forbid-pending/passed.js
new file mode 100644
--- /dev/null
+++ b/test/integration/fixtures/options/forbid-pending/passed.js
@@ -0,0 +1,7 @@
+'use strict';
+
+describe('forbid pending - all test pass', function () {
+  it('test1', function () {});
+  it('test2', function () {});
+  it('test3', function () {});
+});
diff --git a/test/integration/fixtures/options/forbid-pending/pending.js b/test/integration/fixtures/options/forbid-pending/pending.js
new file mode 100644
--- /dev/null
+++ b/test/integration/fixtures/options/forbid-pending/pending.js
@@ -0,0 +1,7 @@
+'use strict';
+
+describe('forbid pending - test without function', function () {
+  it('test1', function () {});
+  it('test2');
+  it('test3', function () {});
+});
diff --git a/test/integration/fixtures/options/forbid-pending/skip.js b/test/integration/fixtures/options/forbid-pending/skip.js
new file mode 100644
--- /dev/null
+++ b/test/integration/fixtures/options/forbid-pending/skip.js
@@ -0,0 +1,7 @@
+'use strict';
+
+describe('forbid pending - test marked with skip', function () {
+  it('test1', function () {});
+  it.skip('test2', function () {});
+  it('test3', function () {});
+});
diff --git a/test/integration/options.spec.js b/test/integration/options.spec.js
--- a/test/integration/options.spec.js
+++ b/test/integration/options.spec.js
@@ -180,4 +180,56 @@ describe('options', function () {
       });
     });
   });
+
+  describe('--forbid-only', function () {
+    before(function () {
+      args = ['--forbid-only'];
+    });
+
+    it('succeeds if there are only passed tests', function (done) {
+      run('options/forbid-only/passed.js', args, function (err, res) {
+        assert(!err);
+        assert.equal(res.code, 0);
+        done();
+      });
+    });
+
+    it('fails if there are tests marked only', function (done) {
+      run('options/forbid-only/only.js', args, function (err, res) {
+        assert(!err);
+        assert.equal(res.code, 1);
+        done();
+      });
+    });
+  });
+
+  describe('--forbid-pending', function () {
+    before(function () {
+      args = ['--forbid-pending'];
+    });
+
+    it('succeeds if there are only passed tests', function (done) {
+      run('options/forbid-pending/passed.js', args, function (err, res) {
+        assert(!err);
+        assert.equal(res.code, 0);
+        done();
+      });
+    });
+
+    it('fails if there are tests marked skip', function (done) {
+      run('options/forbid-pending/skip.js', args, function (err, res) {
+        assert(!err);
+        assert.equal(res.code, 1);
+        done();
+      });
+    });
+
+    it('fails if there are pending tests', function (done) {
+      run('options/forbid-pending/pending.js', args, function (err, res) {
+        assert(!err);
+        assert.equal(res.code, 1);
+        done();
+      });
+    });
+  });
 });