diff --git a/lib/parser.js b/lib/parser.js index ea74ad0fc..6a6ead165 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -4,7 +4,8 @@ function _interopDefault(ex) { import * as acorn from 'acorn' import parseFunctionModule from 'parse-function' const parseFunction = _interopDefault(parseFunctionModule) -const parser = parseFunction({ parse: acorn.parse, ecmaVersion: 11, plugins: ['objectRestSpread'] }) +const ecmaVersion = 11 +const parser = parseFunction({ parse: acorn.parse, ecmaVersion, plugins: ['objectRestSpread'] }) import output from './output.js' parser.use(destructuredArgs) @@ -17,7 +18,7 @@ export const getParamsToString = function (fn) { function getParams(fn, { warnOnLegacyFormat = false } = {}) { if (fn.isSinonProxy) return [] try { - const reflected = parser.parse(fn) + const reflected = parser.parse(normalizeArrowFn(fn)) if (warnOnLegacyFormat && (reflected.args.length > 1 || reflected.args[0] === 'I')) { output.error('Error: old CodeceptJS v2 format detected. Upgrade your project to the new format -> https://bit.ly/codecept3Up') } @@ -38,6 +39,17 @@ function getParams(fn, { warnOnLegacyFormat = false } = {}) { export { getParams } +function normalizeArrowFn(fn) { + const code = (typeof fn === 'function' ? fn.toString() : String(fn)).trim() + if (!code.includes('=>') || code.startsWith('async')) return fn + try { + if (acorn.parseExpressionAt(code, 0, { ecmaVersion }).type !== 'ArrowFunctionExpression') return fn + } catch { + return fn + } + return `async ${code}` +} + function destructuredArgs() { return (node, result) => { result.destructuredArgs = result.destructuredArgs || [] diff --git a/test/unit/parser_test.js b/test/unit/parser_test.js index 32e39b5d5..78d712cde 100644 --- a/test/unit/parser_test.js +++ b/test/unit/parser_test.js @@ -40,5 +40,19 @@ describe('parser', () => { it('should get params for class method with destructured args', () => { expect(getParams(obj.method5)).to.eql(['locator', 'sec']) }) + + // prettier-ignore + const fixturesOneLineArrows = [ + ['destructured args and a condition', ({ locator, sec }) => { if (true) { return locator } }, ['locator', 'sec']], + ['a single arg and a condition', locator => { if (true) { return locator } }, ['locator']], + ['multiple args and a loop', (locator, sec) => { for (;;) { return locator || sec } }, ['locator', 'sec']], + ['a nested arrow function', ({ locator, sec }) => { [locator].forEach((l) => { if (l) { return sec } }) }, ['locator', 'sec']], + ] + + fixturesOneLineArrows.forEach(([title, fn, params]) => { + it(`should get params for one-line arrow function with ${title}`, () => { + expect(getParams(fn)).to.eql(params) + }) + }) }) })