chore: add EsLint rule for no-floating-promises (#10084)

This commit is contained in:
Nikolay Vitkov 2023-04-26 11:53:02 +02:00 committed by GitHub
parent c356e8f8f5
commit e4b57c279a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 660 additions and 347 deletions

View File

@ -13,33 +13,33 @@ module.exports = {
rules: {
// Brackets keep code readable.
curly: [2, 'all'],
curly: ['error', 'all'],
// Brackets keep code readable and `return` intentions clear.
'arrow-body-style': ['error', 'always'],
// Error if files are not formatted with Prettier correctly.
'prettier/prettier': 2,
'prettier/prettier': 'error',
// syntax preferences
'spaced-comment': [
2,
'error',
'always',
{
markers: ['*'],
},
],
eqeqeq: [2],
eqeqeq: ['error'],
'accessor-pairs': [
2,
'error',
{
getWithoutSet: false,
setWithoutGet: false,
},
],
'new-parens': 2,
'func-call-spacing': 2,
'prefer-const': 2,
'new-parens': 'error',
'func-call-spacing': 'error',
'prefer-const': 'error',
'max-len': [
2,
'error',
{
/* this setting doesn't impact things as we use Prettier to format
* our code and hence dictate the line length.
@ -58,27 +58,27 @@ module.exports = {
},
],
// anti-patterns
'no-var': 2,
'no-with': 2,
'no-multi-str': 2,
'no-caller': 2,
'no-implied-eval': 2,
'no-labels': 2,
'no-new-object': 2,
'no-octal-escape': 2,
'no-self-compare': 2,
'no-shadow-restricted-names': 2,
'no-cond-assign': 2,
'no-debugger': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-unreachable': 2,
'no-unsafe-negation': 2,
radix: 2,
'valid-typeof': 2,
'no-var': 'error',
'no-with': 'error',
'no-multi-str': 'error',
'no-caller': 'error',
'no-implied-eval': 'error',
'no-labels': 'error',
'no-new-object': 'error',
'no-octal-escape': 'error',
'no-self-compare': 'error',
'no-shadow-restricted-names': 'error',
'no-cond-assign': 'error',
'no-debugger': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty-character-class': 'error',
'no-unreachable': 'error',
'no-unsafe-negation': 'error',
radix: 'error',
'valid-typeof': 'error',
'no-unused-vars': [
2,
'error',
{
args: 'none',
vars: 'local',
@ -86,11 +86,11 @@ module.exports = {
'([fx]?describe|[fx]?it|beforeAll|beforeEach|afterAll|afterEach)',
},
],
'no-implicit-globals': [2],
'no-implicit-globals': ['error'],
// es2015 features
'require-yield': 2,
'template-curly-spacing': [2, 'never'],
'require-yield': 'error',
'template-curly-spacing': ['error', 'never'],
// ensure we don't have any it.only or describe.only in prod
'mocha/no-exclusive-tests': 'error',
@ -127,6 +127,10 @@ module.exports = {
overrides: [
{
files: ['*.ts'],
parserOptions: {
allowAutomaticSingleRunInference: true,
project: './tsconfig.base.json',
},
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
@ -134,33 +138,33 @@ module.exports = {
plugins: ['eslint-plugin-tsdoc', 'local'],
rules: {
// Keeps comments formatted.
'local/prettier-comments': 2,
'local/prettier-comments': 'error',
// Brackets keep code readable.
curly: [2, 'all'],
curly: ['error', 'all'],
// Brackets keep code readable and `return` intentions clear.
'arrow-body-style': ['error', 'always'],
// Error if comments do not adhere to `tsdoc`.
'tsdoc/syntax': 2,
'tsdoc/syntax': 'error',
// Keeps array types simple only when they are simple for readability.
'@typescript-eslint/array-type': ['error', {default: 'array-simple'}],
'no-unused-vars': 0,
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{argsIgnorePattern: '^_'},
],
'func-call-spacing': 0,
'@typescript-eslint/func-call-spacing': 2,
semi: 0,
'@typescript-eslint/semi': 2,
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-use-before-define': 0,
'func-call-spacing': 'off',
'@typescript-eslint/func-call-spacing': 'error',
semi: 'off',
'@typescript-eslint/semi': 'error',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
// We have to use any on some types so the warning isn't valuable.
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-explicit-any': 'off',
// We don't require explicit return types on basic functions or
// dummy functions in tests, for example
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/explicit-function-return-type': 'off',
// We allow non-null assertions if the value was asserted using `assert` API.
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-non-null-assertion': 'off',
/**
* This is the default options (as per
* https://github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/eslint-plugin/docs/rules/ban-types.md),
@ -182,7 +186,7 @@ module.exports = {
},
],
// By default this is a warning but we want it to error.
'@typescript-eslint/explicit-module-boundary-types': 2,
'@typescript-eslint/explicit-module-boundary-types': 'error',
'no-restricted-syntax': [
'error',
{
@ -191,6 +195,10 @@ module.exports = {
message: '`require` statements are not allowed. Use `import`.',
},
],
'@typescript-eslint/no-floating-promises': [
'error',
{ignoreVoid: true, ignoreIIFE: true},
],
},
},
],

769
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -118,9 +118,9 @@
},
"devDependencies": {
"@actions/core": "1.10.0",
"@commitlint/cli": "17.4.4",
"@commitlint/config-conventional": "17.4.4",
"@microsoft/api-documenter": "7.21.5",
"@commitlint/cli": "17.6.1",
"@commitlint/config-conventional": "17.6.1",
"@microsoft/api-documenter": "7.21.7",
"@microsoft/api-extractor": "7.34.4",
"@microsoft/api-extractor-model": "7.26.4",
"@pptr/testserver": "file:packages/testserver",
@ -140,16 +140,16 @@
"@types/tar-fs": "2.0.1",
"@types/unbzip2-stream": "1.4.0",
"@types/ws": "8.5.4",
"@typescript-eslint/eslint-plugin": "5.54.0",
"@typescript-eslint/parser": "5.54.0",
"@typescript-eslint/eslint-plugin": "5.59.1",
"@typescript-eslint/parser": "5.59.1",
"c8": "7.13.0",
"commitlint": "17.4.4",
"commitlint": "17.6.1",
"commonmark": "0.30.0",
"cross-env": "7.0.3",
"diff": "5.1.0",
"esbuild": "0.17.11",
"eslint": "8.35.0",
"eslint-config-prettier": "8.7.0",
"eslint": "8.39.0",
"eslint-config-prettier": "8.8.0",
"eslint-formatter-codeframe": "7.32.1",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-local": "1.0.0",
@ -171,7 +171,7 @@
"npm-run-all": "4.1.5",
"pixelmatch": "5.3.0",
"pngjs": "7.0.0",
"prettier": "2.8.4",
"prettier": "2.8.8",
"puppeteer": "file:packages/puppeteer",
"rimraf": "3.0.2",
"rollup": "3.18.0",

View File

@ -295,7 +295,7 @@ export class Process {
process.exit(130);
case 'SIGTERM':
case 'SIGHUP':
this.close();
void this.close();
break;
}
};

View File

@ -18,4 +18,4 @@
import {CLI} from './CLI.js';
new CLI().run(process.argv);
void new CLI().run(process.argv);

View File

@ -113,8 +113,8 @@ export class ExecutionContext {
}
scriptInjector.inject(script => {
if (this.#puppeteerUtil) {
this.#puppeteerUtil.then(handle => {
handle.dispose();
void this.#puppeteerUtil.then(handle => {
void handle.dispose();
});
}
this.#puppeteerUtil = promise.then(() => {

View File

@ -115,7 +115,7 @@ export class FrameManager extends EventEmitter {
});
session.on('Page.frameNavigated', event => {
this.#frameNavigatedReceived.add(event.frame.id);
this.#onFrameNavigated(event.frame);
void this.#onFrameNavigated(event.frame);
});
session.on('Page.navigatedWithinDocument', event => {
this.#onFrameNavigatedWithinDocument(event.frameId, event.url);
@ -222,7 +222,7 @@ export class FrameManager extends EventEmitter {
frame.updateClient(target._session()!);
}
this.setupEventListeners(target._session()!);
this.initialize(target._session());
void this.initialize(target._session());
}
/**
@ -275,7 +275,7 @@ export class FrameManager extends EventEmitter {
);
}
if (!this.#frameNavigatedReceived.has(frameTree.frame.id)) {
this.#onFrameNavigated(frameTree.frame);
void this.#onFrameNavigated(frameTree.frame);
} else {
this.#frameNavigatedReceived.delete(frameTree.frame.id);
}

View File

@ -149,7 +149,7 @@ export class IsolatedWorld {
setContext(context: ExecutionContext): void {
this.#contextBindings.clear();
this.#context.resolve(context);
this.#taskManager.rerunAll();
void this.#taskManager.rerunAll();
}
hasContext(): boolean {

View File

@ -393,7 +393,7 @@ export class NetworkManager extends EventEmitter {
[]
);
this.emit(NetworkManagerEmittedEvents.Request, request);
request.finalizeInterceptions();
void request.finalizeInterceptions();
}
#onRequest(
@ -449,7 +449,7 @@ export class NetworkManager extends EventEmitter {
);
this.#networkEventManager.storeRequest(event.requestId, request);
this.emit(NetworkManagerEmittedEvents.Request, request);
request.finalizeInterceptions();
void request.finalizeInterceptions();
}
#onRequestServedFromCache(

View File

@ -253,7 +253,7 @@ export class CDPPage extends Page {
client.on('Page.fileChooserOpened', event => {
return this.#onFileChooser(event);
});
this.#target._isClosedPromise.then(() => {
void this.#target._isClosedPromise.then(() => {
this.#target
._targetManager()
.removeTargetInterceptor(this.#client, this.#onAttachedToTarget);

View File

@ -66,7 +66,7 @@ export class WaitTask<T = unknown> {
this.#signal?.addEventListener(
'abort',
() => {
this.terminate(new AbortError('WaitTask has been aborted.'));
void this.terminate(new AbortError('WaitTask has been aborted.'));
},
{
once: true,
@ -87,13 +87,13 @@ export class WaitTask<T = unknown> {
if (options.timeout) {
this.#timeout = setTimeout(() => {
this.terminate(
void this.terminate(
new TimeoutError(`Waiting failed: ${options.timeout}ms exceeded`)
);
}, options.timeout);
}
this.rerun();
void this.rerun();
}
get result(): Promise<HandleFor<T>> {
@ -153,7 +153,7 @@ export class WaitTask<T = unknown> {
}
await this.#poller.evaluate(poller => {
poller.start();
void poller.start();
});
const result = await this.#poller.evaluateHandle(poller => {
@ -245,7 +245,7 @@ export class TaskManager {
terminateAll(error?: Error): void {
for (const task of this.#tasks) {
task.terminate(error);
void task.terminate(error);
}
this.#tasks.clear();
}

View File

@ -167,7 +167,7 @@ class NoOpTransport
};
emitMessage(message: Bidi.Message.RawCommandRequest) {
this.#onMessage(message);
void this.#onMessage(message);
}
setOnMessage(

View File

@ -286,7 +286,7 @@ export const pQuerySelectorAll = function (
return domSort(
AsyncIterableUtil.flatMap(selectors, selectorParts => {
const query = new PQueryEngine(root, selector, selectorParts);
query.run();
void query.run();
return query.elements;
})
);

View File

@ -175,7 +175,7 @@ export class ProductLauncher {
}
}
} catch (error) {
browserCloseCallback();
void browserCloseCallback();
if (error instanceof BrowsersTimeoutError) {
throw new TimeoutError(error.message);
}

View File

@ -71,7 +71,7 @@ chdir(packageRoot);
await Promise.all([versionJob, injectedJob]);
if (process.env['PUBLISH']) {
job('', async ({inputs}) => {
await job('', async ({inputs}) => {
const version = JSON.parse(await readFile(inputs[0]!, 'utf8')).version;
await writeFile(
inputs[1]!,

View File

@ -76,7 +76,7 @@ declare const handle2: JSHandle<{test: number}>;
}
{
handle.evaluate((value, other) => {
void handle.evaluate((value, other) => {
expectType<unknown>(value);
expectType<{test: number}>(other);
}, handle2);

View File

@ -879,9 +879,9 @@ describe('Page', function () {
const [request] = await Promise.all([
page.waitForRequest(server.PREFIX + '/digits/2.png'),
page.evaluate(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}),
]);
expect(request.url()).toBe(server.PREFIX + '/digits/2.png');
@ -895,9 +895,9 @@ describe('Page', function () {
return request.url() === server.PREFIX + '/digits/2.png';
}),
page.evaluate(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}),
]);
expect(request.url()).toBe(server.PREFIX + '/digits/2.png');
@ -911,9 +911,9 @@ describe('Page', function () {
return request.url() === server.PREFIX + '/digits/2.png';
}),
page.evaluate(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}),
]);
expect(request.url()).toBe(server.PREFIX + '/digits/2.png');
@ -956,9 +956,9 @@ describe('Page', function () {
page.waitForRequest(server.PREFIX + '/digits/2.png', {timeout: 0}),
page.evaluate(() => {
return setTimeout(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}, 50);
}),
]);
@ -974,9 +974,9 @@ describe('Page', function () {
const [response] = await Promise.all([
page.waitForResponse(server.PREFIX + '/digits/2.png'),
page.evaluate(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}),
]);
expect(response.url()).toBe(server.PREFIX + '/digits/2.png');
@ -1020,9 +1020,9 @@ describe('Page', function () {
return response.url() === server.PREFIX + '/digits/2.png';
}),
page.evaluate(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}),
]);
expect(response.url()).toBe(server.PREFIX + '/digits/2.png');
@ -1035,9 +1035,9 @@ describe('Page', function () {
return response.url() === server.PREFIX + '/digits/2.png';
}),
page.evaluate(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}),
]);
expect(response.url()).toBe(server.PREFIX + '/digits/2.png');
@ -1050,9 +1050,9 @@ describe('Page', function () {
page.waitForResponse(server.PREFIX + '/digits/2.png', {timeout: 0}),
page.evaluate(() => {
return setTimeout(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}, 50);
}),
]);
@ -1135,9 +1135,9 @@ describe('Page', function () {
page.waitForNetworkIdle({timeout: 0}),
page.evaluate(() => {
return setTimeout(() => {
fetch('/digits/1.png');
fetch('/digits/2.png');
fetch('/digits/3.png');
void fetch('/digits/1.png');
void fetch('/digits/2.png');
void fetch('/digits/3.png');
}, 50);
}),
]);

View File

@ -405,7 +405,7 @@ describe('waittask specs', function () {
signal: abortController.signal,
});
abortController.abort();
expect(task).rejects.toThrow(/aborted/);
await expect(task).rejects.toThrow(/aborted/);
});
it('should work with removed MutationObserver', async () => {

View File

@ -107,7 +107,7 @@ function spliceIntoSection(
await Promise.all([job1, job2]);
// Generate documentation
job('', async ({inputs, outputs}) => {
const puppeteerDocs = job('', async ({inputs, outputs}) => {
await rm(outputs[0]!, {recursive: true, force: true});
generateDocs(inputs[0]!, outputs[0]!);
spawnAndLog('prettier', '--ignore-path', 'none', '--write', 'docs');
@ -119,7 +119,7 @@ function spliceIntoSection(
.outputs(['docs/api'])
.build();
await job('', async ({inputs, outputs}) => {
const browsersDocs = job('', async ({inputs, outputs}) => {
await rm(outputs[0]!, {recursive: true, force: true});
generateDocs(inputs[0]!, outputs[0]!);
spawnAndLog('prettier', '--ignore-path', 'none', '--write', 'docs');
@ -131,7 +131,9 @@ function spliceIntoSection(
.outputs(['docs/browsers-api'])
.build();
job('', async ({inputs, outputs}) => {
await Promise.all([puppeteerDocs, browsersDocs]);
await job('', async ({inputs, outputs}) => {
const readme = await readFile(inputs[1]!, 'utf-8');
const index = await readFile(inputs[0]!, 'utf-8');
await writeFile(outputs[0]!, index.replace('# API Reference\n', readme));

View File

@ -25,18 +25,18 @@ import {
} from './utils.js';
import {getFilename, extendProcessEnv} from './utils.js';
test('extendProcessEnv', () => {
void test('extendProcessEnv', () => {
const env = extendProcessEnv([{TEST: 'TEST'}, {TEST2: 'TEST2'}]);
assert.equal(env['TEST'], 'TEST');
assert.equal(env['TEST2'], 'TEST2');
});
test('getFilename', () => {
void test('getFilename', () => {
assert.equal(getFilename('/etc/test.ts'), 'test');
assert.equal(getFilename('/etc/test.js'), 'test');
});
test('getTestResultForFailure', () => {
void test('getTestResultForFailure', () => {
assert.equal(
getTestResultForFailure({err: {code: 'ERR_MOCHA_TIMEOUT'}}),
'TIMEOUT'
@ -44,7 +44,7 @@ test('getTestResultForFailure', () => {
assert.equal(getTestResultForFailure({err: {code: 'ERROR'}}), 'FAIL');
});
test('filterByParameters', () => {
void test('filterByParameters', () => {
const expectations: TestExpectation[] = [
{
testIdPattern:
@ -66,7 +66,7 @@ test('filterByParameters', () => {
assert.equal(filterByParameters(expectations, ['other']).length, 0);
});
test('isWildCardPattern', () => {
void test('isWildCardPattern', () => {
assert.equal(isWildCardPattern(''), false);
assert.equal(isWildCardPattern('a'), false);
assert.equal(isWildCardPattern('*'), true);
@ -99,7 +99,7 @@ describe('testIdMatchesExpectationPattern', () => {
['[jshandle.spec] JSHandle should work', false],
];
test('with MochaTest', () => {
void test('with MochaTest', () => {
const test = {
title: 'should work',
file: 'page.spec.ts',
@ -116,7 +116,7 @@ describe('testIdMatchesExpectationPattern', () => {
);
}
});
test('with MochaTestResult', () => {
void test('with MochaTestResult', () => {
const test = {
title: 'should work',
file: 'page.spec.ts',