diff --git a/eslint.config.js b/eslint.config.js index 7b2525d696ac..41e9b54a4d00 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -413,6 +413,8 @@ const base = { // promise: // avoid calling `cb()` inside of a `then()` or `catch()` 'promise/no-callback-in-promise': ERROR, + // disallow creating new promises with paths that resolve multiple times (no-multiple-resolved) + 'promise/no-multiple-resolved': ERROR, // avoid nested `then()` or `catch()` statements 'promise/no-nesting': ERROR, // avoid calling new on a `Promise` static method @@ -424,7 +426,10 @@ const base = { // avoid wrapping values in `Promise.resolve` or `Promise.reject` when not needed 'promise/no-return-wrap': ERROR, // enforce consistent param names when creating new promises - 'promise/param-names': ERROR, + 'promise/param-names': [ERROR, { + resolvePattern: '^resolve', + rejectPattern: '^reject', + }], // ensures the proper number of arguments are passed to `Promise` functions 'promise/valid-params': ERROR, diff --git a/package-lock.json b/package-lock.json index ce8213316708..4d8ff2263a3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsonc": "^2.4.0", "eslint-plugin-n": "^15.3.0", - "eslint-plugin-promise": "^6.0.1", + "eslint-plugin-promise": "^6.1.0", "eslint-plugin-qunit": "^7.3.1", "eslint-plugin-regexp": "^1.9.0", "eslint-plugin-sonarjs": "~0.16.0", @@ -8183,9 +8183,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.279", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.279.tgz", - "integrity": "sha512-xs7vEuSZ84+JsHSTFqqG0TE3i8EAivHomRQZhhcRvsmnjsh5C2KdhwNKf4ZRYtzq75wojpFyqb62m32Oam57wA==" + "version": "1.4.281", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.281.tgz", + "integrity": "sha512-yer0w5wCYdFoZytfmbNhwiGI/3cW06+RV7E23ln4490DVMxs7PvYpbsrSmAiBn/V6gode8wvJlST2YfWgvzWIg==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -8960,9 +8960,9 @@ } }, "node_modules/eslint-plugin-promise": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", - "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.0.tgz", + "integrity": "sha512-NYCfDZF/KHt27p06nFAttgWuFyIDSUMnNaJBIY1FY9GpBFhdT2vMG64HlFguSgcJeyM5by6Yr5csSOuJm60eXQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -26422,9 +26422,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.279", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.279.tgz", - "integrity": "sha512-xs7vEuSZ84+JsHSTFqqG0TE3i8EAivHomRQZhhcRvsmnjsh5C2KdhwNKf4ZRYtzq75wojpFyqb62m32Oam57wA==" + "version": "1.4.281", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.281.tgz", + "integrity": "sha512-yer0w5wCYdFoZytfmbNhwiGI/3cW06+RV7E23ln4490DVMxs7PvYpbsrSmAiBn/V6gode8wvJlST2YfWgvzWIg==" }, "elliptic": { "version": "6.5.4", @@ -27116,9 +27116,9 @@ } }, "eslint-plugin-promise": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", - "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.0.tgz", + "integrity": "sha512-NYCfDZF/KHt27p06nFAttgWuFyIDSUMnNaJBIY1FY9GpBFhdT2vMG64HlFguSgcJeyM5by6Yr5csSOuJm60eXQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index cda38eb02edb..1f00c95b0dfc 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsonc": "^2.4.0", "eslint-plugin-n": "^15.3.0", - "eslint-plugin-promise": "^6.0.1", + "eslint-plugin-promise": "^6.1.0", "eslint-plugin-qunit": "^7.3.1", "eslint-plugin-regexp": "^1.9.0", "eslint-plugin-sonarjs": "~0.16.0", diff --git a/tests/pure/es.promise.all-settled.js b/tests/pure/es.promise.all-settled.js index b9ea5cca1832..c58f3e91dd9d 100644 --- a/tests/pure/es.promise.all-settled.js +++ b/tests/pure/es.promise.all-settled.js @@ -26,6 +26,7 @@ QUnit.test('Promise.allSettled, resolved', assert => { QUnit.test('Promise.allSettled, rejected', assert => { assert.expect(1); const async = assert.async(); + // eslint-disable-next-line promise/valid-params -- required for testing Promise.allSettled().catch(() => { assert.required('rejected as expected'); async(); diff --git a/tests/pure/es.promise.any.js b/tests/pure/es.promise.any.js index 0474bd21d1cf..26ba270db65d 100644 --- a/tests/pure/es.promise.any.js +++ b/tests/pure/es.promise.any.js @@ -37,6 +37,7 @@ QUnit.test('Promise.any, rejected #1', assert => { QUnit.test('Promise.any, rejected #2', assert => { assert.expect(1); const async = assert.async(); + // eslint-disable-next-line promise/valid-params -- required for testing Promise.any().catch(() => { assert.required('rejected as expected'); async(); diff --git a/tests/pure/esnext.async-iterator.drop.js b/tests/pure/esnext.async-iterator.drop.js index 51786e74eb23..67b35f3583fb 100644 --- a/tests/pure/esnext.async-iterator.drop.js +++ b/tests/pure/esnext.async-iterator.drop.js @@ -22,7 +22,8 @@ QUnit.test('AsyncIterator#drop', assert => { return drop.call(createIterator([1, 2, 3]), 0).toArray(); }).then(it => { assert.arrayEqual(it, [1, 2, 3], 'zero'); - }).then(() => async()); + async(); + }); assert.throws(() => drop.call(undefined, 1), TypeError); assert.throws(() => drop.call(null, 1), TypeError); diff --git a/tests/pure/esnext.async-iterator.take.js b/tests/pure/esnext.async-iterator.take.js index 927c7d85fd54..6bbb82e89e24 100644 --- a/tests/pure/esnext.async-iterator.take.js +++ b/tests/pure/esnext.async-iterator.take.js @@ -22,7 +22,8 @@ QUnit.test('AsyncIterator#take', assert => { return take.call(createIterator([1, 2, 3]), 0).toArray(); }).then(it => { assert.arrayEqual(it, [], 'zero'); - }).then(() => async()); + async(); + }); assert.throws(() => take.call(undefined, 1), TypeError); assert.throws(() => take.call(null, 1), TypeError); diff --git a/tests/pure/esnext.iterator.to-async.js b/tests/pure/esnext.iterator.to-async.js index 33b733b0db6b..48a6e48630f2 100644 --- a/tests/pure/esnext.iterator.to-async.js +++ b/tests/pure/esnext.iterator.to-async.js @@ -21,8 +21,7 @@ QUnit.test('Iterator#toAsync', assert => { Iterator.from([1, 2, 3]).toAsync().map(it => Promise.resolve(it)).toArray().then(it => { assert.arrayEqual(it, [1, 2, 3]); - }).then(() => { - return Iterator.from(new Set([1, 2, 3])).toAsync().map(it => Promise.resolve(it)).toArray(); + return Iterator.from(new Set([1, 2, 3])).toAsync().map(el => Promise.resolve(el)).toArray(); }).then(it => { assert.arrayEqual(it, [1, 2, 3]); async(); diff --git a/tests/pure/web.set-immediate.js b/tests/pure/web.set-immediate.js index 608990f59f38..144f54fd8bbb 100644 --- a/tests/pure/web.set-immediate.js +++ b/tests/pure/web.set-immediate.js @@ -8,6 +8,7 @@ QUnit.test('setImmediate / clearImmediate', assert => { assert.expect(6); assert.isFunction(setImmediate, 'setImmediate is function'); assert.isFunction(clearImmediate, 'clearImmediate is function'); + timeLimitedPromise(1e3, res => { setImmediate(() => { called = true; @@ -18,7 +19,9 @@ QUnit.test('setImmediate / clearImmediate', assert => { }).catch(() => { assert.avoid('setImmediate works'); }).then(assert.async()); + assert.false(called, 'setImmediate is async'); + timeLimitedPromise(1e3, res => { setImmediate((a, b) => { res(a + b); @@ -28,6 +31,7 @@ QUnit.test('setImmediate / clearImmediate', assert => { }).catch(() => { assert.avoid('setImmediate works with additional args'); }).then(assert.async()); + timeLimitedPromise(50, res => { clearImmediate(setImmediate(res)); }).then(() => { diff --git a/tests/tests/es.promise.all-settled.js b/tests/tests/es.promise.all-settled.js index 891871ac8cd8..98bdfef06ff9 100644 --- a/tests/tests/es.promise.all-settled.js +++ b/tests/tests/es.promise.all-settled.js @@ -26,6 +26,7 @@ QUnit.test('Promise.allSettled, resolved', assert => { QUnit.test('Promise.allSettled, rejected', assert => { assert.expect(1); const async = assert.async(); + // eslint-disable-next-line promise/valid-params -- required for testing Promise.allSettled().catch(() => { assert.required('rejected as expected'); async(); diff --git a/tests/tests/es.promise.any.js b/tests/tests/es.promise.any.js index 91e5fc7a5339..69d566514953 100644 --- a/tests/tests/es.promise.any.js +++ b/tests/tests/es.promise.any.js @@ -36,6 +36,7 @@ QUnit.test('Promise.any, rejected #1', assert => { QUnit.test('Promise.any, rejected #2', assert => { assert.expect(1); const async = assert.async(); + // eslint-disable-next-line promise/valid-params -- required for testing Promise.any().catch(() => { assert.required('rejected as expected'); async(); diff --git a/tests/tests/esnext.async-iterator.drop.js b/tests/tests/esnext.async-iterator.drop.js index 01194670daa9..e178501b5511 100644 --- a/tests/tests/esnext.async-iterator.drop.js +++ b/tests/tests/esnext.async-iterator.drop.js @@ -22,7 +22,8 @@ QUnit.test('AsyncIterator#drop', assert => { return drop.call(createIterator([1, 2, 3]), 0).toArray(); }).then(it => { assert.arrayEqual(it, [1, 2, 3], 'zero'); - }).then(() => async()); + async(); + }); assert.throws(() => drop.call(undefined, 1), TypeError); assert.throws(() => drop.call(null, 1), TypeError); diff --git a/tests/tests/esnext.async-iterator.take.js b/tests/tests/esnext.async-iterator.take.js index 39d855a1e1ba..6f32b3cbac1e 100644 --- a/tests/tests/esnext.async-iterator.take.js +++ b/tests/tests/esnext.async-iterator.take.js @@ -22,7 +22,8 @@ QUnit.test('AsyncIterator#take', assert => { return take.call(createIterator([1, 2, 3]), 0).toArray(); }).then(it => { assert.arrayEqual(it, [], 'zero'); - }).then(() => async()); + async(); + }); assert.throws(() => take.call(undefined, 1), TypeError); assert.throws(() => take.call(null, 1), TypeError); diff --git a/tests/tests/esnext.iterator.to-async.js b/tests/tests/esnext.iterator.to-async.js index 8fef4abddd82..7c70340c3b10 100644 --- a/tests/tests/esnext.iterator.to-async.js +++ b/tests/tests/esnext.iterator.to-async.js @@ -19,8 +19,7 @@ QUnit.test('Iterator#toAsync', assert => { [1, 2, 3].values().toAsync().map(it => Promise.resolve(it)).toArray().then(it => { assert.arrayEqual(it, [1, 2, 3]); - }).then(() => { - return new Set([1, 2, 3]).values().toAsync().map(it => Promise.resolve(it)).toArray(); + return new Set([1, 2, 3]).values().toAsync().map(el => Promise.resolve(el)).toArray(); }).then(it => { assert.arrayEqual(it, [1, 2, 3]); async(); diff --git a/tests/tests/web.set-immediate.js b/tests/tests/web.set-immediate.js index 4a5b3fe2ac86..10e2a360a027 100644 --- a/tests/tests/web.set-immediate.js +++ b/tests/tests/web.set-immediate.js @@ -7,6 +7,7 @@ QUnit.test('setImmediate / clearImmediate', assert => { assert.isFunction(clearImmediate, 'clearImmediate is function'); assert.name(setImmediate, 'setImmediate'); assert.name(clearImmediate, 'clearImmediate'); + timeLimitedPromise(1e3, resolve => { setImmediate(() => { called = true; @@ -17,7 +18,9 @@ QUnit.test('setImmediate / clearImmediate', assert => { }).catch(() => { assert.avoid('setImmediate works'); }).then(assert.async()); + assert.false(called, 'setImmediate is async'); + timeLimitedPromise(1e3, resolve => { setImmediate((a, b) => { resolve(a + b); @@ -27,6 +30,7 @@ QUnit.test('setImmediate / clearImmediate', assert => { }).catch(() => { assert.avoid('setImmediate works with additional args'); }).then(assert.async()); + timeLimitedPromise(50, resolve => { clearImmediate(setImmediate(resolve)); }).then(() => { diff --git a/tests/tests/web.url-search-params.js b/tests/tests/web.url-search-params.js index 1e0f15b8bc38..9f3887e79cf5 100644 --- a/tests/tests/web.url-search-params.js +++ b/tests/tests/web.url-search-params.js @@ -857,8 +857,10 @@ QUnit.test('URLSearchParams#@@toStringTag', assert => { if (typeof Request == 'function') { QUnit.test('URLSearchParams with Request', assert => { + const async = assert.async(); new Request('http://zloirock.ru', { body: new URLSearchParams({ foo: 'baz' }), method: 'POST' }).text().then(text => { assert.same(text, 'foo=baz'); - }).then(assert.async()); + async(); + }); }); }