Repository: mochajs/mocha (js)

Issue:
🚀 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_

Pull request:
feat: allow calling hook methods
<!-- 👋 Hi, thanks for sending a PR to mocha! 💖.
Please fill out all fields below and make sure each item is true and [x] checked.
Otherwise we may not be able to review your PR. -->

## PR Checklist

- [x] Addresses an existing open issue: fixes #5202
- [x] That issue was marked as [`status: accepting prs`](https://github.com/mochajs/mocha/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in [CONTRIBUTING.md](https://github.com/mochajs/mocha/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

It seems the only reason this wasn't supported was simply the return value of calling `beforeAll`, etc, was not the hook itself, unlike the result of calling a function like `describe`, which does use the suite as the return value.
I will look into adding tests and maybe some docs


Patch:
diff --git a/.github/release-please/manifest.json b/.github/release-please/manifest.json
index 0ba0782a..711e1825 100644
--- a/.github/release-please/manifest.json
+++ b/.github/release-please/manifest.json
@@ -1,1 +1,1 @@
-{".":"10.8.1"}
+{".":"10.8.2"}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f45fe6d6..66d00fbc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,28 @@
 # Changelog
 
+## [10.8.2](https://github.com/mochajs/mocha/compare/v10.8.1...v10.8.2) (2024-10-30)
+
+
+### 🩹 Fixes
+
+* support errors with circular dependencies in object values with --parallel ([#5212](https://github.com/mochajs/mocha/issues/5212)) ([ba0fefe](https://github.com/mochajs/mocha/commit/ba0fefe10b08a689cf49edc3818026938aa3a240))
+* test link in html reporter ([#5224](https://github.com/mochajs/mocha/issues/5224)) ([f054acc](https://github.com/mochajs/mocha/commit/f054acc1f60714bbe00ad1ab270fb4977836d045))
+
+
+### 📚 Documentation
+
+* indicate 'exports' interface does not work in browsers ([#5181](https://github.com/mochajs/mocha/issues/5181)) ([14e640e](https://github.com/mochajs/mocha/commit/14e640ee49718d587779a9594b18f3796c42cf2a))
+
+
+### 🧹 Chores
+
+* fix docs builds by re-adding eleventy and ignoring gitignore again ([#5240](https://github.com/mochajs/mocha/issues/5240)) ([881e3b0](https://github.com/mochajs/mocha/commit/881e3b0ca2e24284aab2a04f63639a0aa9e0ad1b))
+
+
+### 🤖 Automation
+
+* **deps:** bump the github-actions group with 1 update ([#5132](https://github.com/mochajs/mocha/issues/5132)) ([e536ab2](https://github.com/mochajs/mocha/commit/e536ab25b308774e3103006c044cb996a2e17c87))
+
 ## [10.8.1](https://github.com/mochajs/mocha/compare/v10.8.0...v10.8.1) (2024-10-29)
 
 
diff --git a/docs/index.md b/docs/index.md
index 1eba83ac..cb14bb52 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -334,6 +334,17 @@ describe('my suite', () => {
 
 _If you do not need to use_ Mocha's context, lambdas should work. Be aware that using lambdas will be more painful to refactor if the need eventually arises!
 
+Alternatively, you can override certain context variables, such as test timeouts, by chain-calling methods of the created tests and/or hooks:
+
+```js
+describe('my suite', () => {
+  beforeEach(() => {}).timeout(1000);
+  it('my test', () => {
+    assert.ok(true);
+  }).timeout(1000);
+}).timeout(1000);
+```
+
 ## Hooks
 
 With its default "BDD"-style interface, Mocha provides the hooks `before()`, `after()`, `beforeEach()`, and `afterEach()`. These should be used to set up preconditions and clean up after your tests.
diff --git a/lib/interfaces/common.js b/lib/interfaces/common.js
index ba8b5f85..d6656b8c 100644
--- 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
index 64d7183f..bce00731 100644
--- 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;
 };
 
 /**
diff --git a/package-lock.json b/package-lock.json
index 2d02eee3..321e20d9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "mocha",
-  "version": "10.8.1",
+  "version": "10.8.2",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "mocha",
-      "version": "10.8.1",
+      "version": "10.8.2",
       "license": "MIT",
       "dependencies": {
         "ansi-colors": "^4.1.3",
diff --git a/package.json b/package.json
index 0f868423..95f05b6e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "mocha",
-  "version": "10.8.1",
+  "version": "10.8.2",
   "type": "commonjs",
   "description": "simple, flexible, fun test framework",
   "keywords": [


Test patch:
diff --git a/test/unit/timeout.spec.js b/test/unit/timeout.spec.js
index ed651563..bb758a5e 100644
--- 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);
+    });
   });
 });