Repository: mochajs/mocha

Problem statement:
🚀 Feature: Allow to set timeout on before/after/beforeEach/afterEach in declaration
### Feature Request Checklist

- [X] I have read and agree to Mocha's [Code of Conduct](https://github.com/mochajs/mocha/blob/main/.github/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/mochajs/mocha/blob/main/.github/CONTRIBUTING.md)
- [X] I have searched for [related issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue) and [issues with the `faq` label](https://github.com/mochajs/mocha/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Afaq%20), but none matched my issue.
- [ ] I want to provide a PR to resolve this

### Overview

`it` returns a `TestFunction` that has a `timeout` method. This is useful for setting timeouts in slow tests, without needing to define the test code inside a `function() {}` block.
An analogous feature would be useful for the `before/beforeEach/after/afterEach` hooks. The current workaround would be:

```javascript
before(function() {
  this.timeout(3000);
});
```

### Suggested Solution

`before/beforeEach/after/afterEach` could return a `HookFunction`, analogous to `TestFunction`, which has a `timeout` method. The code above could be rewritten:

```javascript
before(() => {}).timeout(3000);
```

### Alternatives

None

### Additional Info

_No response_


Hints:
👍 Agreed, I'm surprised they didn't have this already! This took me a bit to parse through as someone who doesn't use those APIs much. Putting a summary here for clarity...

There are two ways to describe a timeout:

* `this.timeout(...);`: allowed for _hooks_ (`before(...)`, etc.) as well as _tests_ (`it(...)`, etc.)
* test.timeout(...): only allowed for _tests_

Assuming I'm understanding correctly, this issue is asking to allow `hook.timeout(...)`. Doing so would mirror the `test.timeout(...)` already allowed.
@JoshuaKGoldberg thanks for summarizing it more clearly than the original post 🙂

ok, I just looked into the codebase, and I think this will be very simple to implement, but I am not sure about potential implications. I will send a PR shortly

Patch:
diff --git a/lib/interfaces/common.js b/lib/interfaces/common.js
--- a/lib/interfaces/common.js
+++ b/lib/interfaces/common.js
@@ -57,7 +57,7 @@ module.exports = function (suites, context, mocha) {
      * @param {Function} fn
      */
     before: function (name, fn) {
-      suites[0].beforeAll(name, fn);
+      return suites[0].beforeAll(name, fn);
     },
 
     /**
@@ -67,7 +67,7 @@ module.exports = function (suites, context, mocha) {
      * @param {Function} fn
      */
     after: function (name, fn) {
-      suites[0].afterAll(name, fn);
+      return suites[0].afterAll(name, fn);
     },
 
     /**
@@ -77,7 +77,7 @@ module.exports = function (suites, context, mocha) {
      * @param {Function} fn
      */
     beforeEach: function (name, fn) {
-      suites[0].beforeEach(name, fn);
+      return suites[0].beforeEach(name, fn);
     },
 
     /**
@@ -87,7 +87,7 @@ module.exports = function (suites, context, mocha) {
      * @param {Function} fn
      */
     afterEach: function (name, fn) {
-      suites[0].afterEach(name, fn);
+      return suites[0].afterEach(name, fn);
     },
 
     suite: {
diff --git a/lib/suite.js b/lib/suite.js
--- a/lib/suite.js
+++ b/lib/suite.js
@@ -257,7 +257,7 @@ Suite.prototype.beforeAll = function (title, fn) {
   var hook = this._createHook(title, fn);
   this._beforeAll.push(hook);
   this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_ALL, hook);
-  return this;
+  return hook;
 };
 
 /**
@@ -281,7 +281,7 @@ Suite.prototype.afterAll = function (title, fn) {
   var hook = this._createHook(title, fn);
   this._afterAll.push(hook);
   this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_ALL, hook);
-  return this;
+  return hook;
 };
 
 /**
@@ -305,7 +305,7 @@ Suite.prototype.beforeEach = function (title, fn) {
   var hook = this._createHook(title, fn);
   this._beforeEach.push(hook);
   this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_EACH, hook);
-  return this;
+  return hook;
 };
 
 /**
@@ -329,7 +329,7 @@ Suite.prototype.afterEach = function (title, fn) {
   var hook = this._createHook(title, fn);
   this._afterEach.push(hook);
   this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_EACH, hook);
-  return this;
+  return hook;
 };
 
 /**


Test patch:
diff --git a/test/unit/timeout.spec.js b/test/unit/timeout.spec.js
--- a/test/unit/timeout.spec.js
+++ b/test/unit/timeout.spec.js
@@ -70,5 +70,31 @@ describe('timeouts', function () {
         });
       });
     });
+
+    describe('chaining calls', function () {
+      before(function (done) {
+        setTimeout(function () {
+          done();
+        }, 50);
+      }).timeout(1500);
+
+      it('should allow overriding via chaining', function (done) {
+        setTimeout(function () {
+          done();
+        }, 50);
+      }).timeout(1500);
+
+      describe('suite-level', function () {
+        it('should work with timeout(0)', function (done) {
+          setTimeout(done, 1);
+        });
+
+        describe('nested suite', function () {
+          it('should work with timeout(0)', function (done) {
+            setTimeout(done, 1);
+          });
+        });
+      }).timeout(1000);
+    });
   });
 });