UNPKG

chrome-devtools-frontend

Version:
98 lines (91 loc) 3.35 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. 'use strict'; // Rule Definition // ------------------------------------------------------------------------------ /** * @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { type: 'problem', docs: { description: 'Ensure trace engine tests are defined as functions for test timeouts.', category: 'Possible Errors', }, fixable: 'code', messages: { needsFunction: 'Test should use a function keyword, not an arrow function.' }, schema: [] // no options }, create: function(context) { const MOCHA_CALLS_TO_CHECK = new Set([ 'it', 'before', 'beforeEach', 'after', 'afterEach', ]); function walkUpTreeToFindMochaFunctionCall(node) { if(node.type === 'CallExpression' && node.callee.type === 'Identifier' && MOCHA_CALLS_TO_CHECK.has(node.callee.name)) { return node; } if(!node || !node.parent) { return null; } return walkUpTreeToFindMochaFunctionCall(node.parent); } return { MemberExpression(node) { const objectIsTraceLoader = node.object.type === 'Identifier' && node.object.name === 'TraceLoader'; if(!objectIsTraceLoader) { return; } // Find out if this is an await call (which needs the additional test timeout). const callExpression = node.parent; const isAwait = callExpression.parent && callExpression.parent.type === 'AwaitExpression'; if(!isAwait) { return; } // We now know that we have await TraceLoader.[something](); // Now we need to walk up the tree to find the it() call. If we do, // we can then check that its function is defined via a function // and not as an arrow function. const mochaFunctionCall = walkUpTreeToFindMochaFunctionCall(node); if(!mochaFunctionCall) { return; } // This code is within a mocha call. If the call is an `it`, we need // the second argument, otherwise we use the first argument (Mocha // functions like `beforeEach` take only a function as the argument.) const functionArg = mochaFunctionCall.callee.name === 'it' ? mochaFunctionCall.arguments[1] : mochaFunctionCall.arguments[0]; if(!functionArg) { // The node unexpectedly does not have a function passed. The // developer is probably in the middle of writing it, so we should // just stop and leave them to it. return; } if(functionArg.type === 'ArrowFunctionExpression') { context.report({ node: functionArg, messageId: 'needsFunction', fix(fixer) { const rangeToReplace = [ // We want to replace `async () =>` [11 characters] with // `function()`. So we replace the first 11 characters of // the function. functionArg.range[0], functionArg.range[0] + 11, ]; return fixer.replaceTextRange(rangeToReplace, 'async function()'); } }); } } }; } };