Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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')
}
Expand All @@ -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 || []
Expand Down
14 changes: 14 additions & 0 deletions test/unit/parser_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
})
})
Loading