Skip to content

Commit

Permalink
fix: CLI filtering --spec when commas in glob pattern (#19557)
Browse files Browse the repository at this point in the history
* Added is-glob as dependency for packages/server

* Parsed spec argv for glob patterns.

* Removed setGlob parameter.

* Updated glob implementation to revert side effects

* Removed is-glob dependency.

* Wrote parseSpecArgv method

* Added back resolvePath.

* Added unit tests.

* Added jsdoc & comments.

* pushing trivial update to kick off build

Co-authored-by: Matt Henkes <[email protected]>
  • Loading branch information
hang-up and mjhenkes committed Jan 18, 2022
1 parent 2685f82 commit 273b703
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 5 deletions.
116 changes: 114 additions & 2 deletions packages/server/lib/util/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,118 @@ const sanitizeAndConvertNestedArgs = (str, argname) => {
}
}

/**
* Parses the '--spec' cli parameter to return an array of valid patterns.
*
* @param {Strng} pattern pattern to parse
* @returns Array of patterns
*/
const parseSpecArgv = (pattern) => {
const TOKENS = {
OPEN: ['{', '['],
CLOSE: ['}', ']'],
}
const hasToken = [...TOKENS.OPEN, ...TOKENS.CLOSE].some((t) => {
return pattern.includes(t)
})
const hasComma = pattern.includes(',')

/**
* Slice and mutate a string.
*
* @param {String} str String to slice & mutate
* @param {Number} end Index to slice to
* @returns [String, String, Number]
*/
const sliceAndMutate = (str, end) => {
return [
str.slice(0, end),
str.substring(end, str.length),
str.slice(0, end).length,
]
}

/**
* Sanitizes a path's leftover commas.
*
* @param {String} path
* @returns String
*/
const sanitizeFinalPath = (path) => {
return path.split('')[0] === ',' ? path.substring(1, path.length) : path
}

if (!hasToken) {
return [].concat(pattern.split(','))
}

if (!hasComma) {
return pattern
}

// Get comma rules.
let opens = []
let closes = []
const rules = pattern
.split('')
.map((token, index) => {
if (TOKENS.OPEN.includes(token)) {
opens.push(index)
}

if (TOKENS.CLOSE.includes(token)) {
closes.push(index)
}

if (token === ',') {
const isBreakable =
index > opens[opens.length - 1] &&
index > closes[closes.length - 1] &&
opens.length === closes.length

if (isBreakable) {
return {
comma: index,
isBreakable: true,
}
}

return {
comma: index,
isBreakable: false,
}
}

return null
})
.filter(Boolean)

// Perform comma breaking logic.
let carry = pattern
let offset = 0
const partial = rules
.map((rule) => {
if (!rule.isBreakable) {
return null
}

const [res, mutated, offsettedBy] = sliceAndMutate(
carry,
rule.comma - offset,
)

offset = offsettedBy
carry = mutated

return res
})
.filter(Boolean)
.map(sanitizeFinalPath)

// In the end, carry will be left with the last path that hasn't been cut.
return [...partial, sanitizeFinalPath(carry)]
}

module.exports = {
normalizeBackslashes,

Expand Down Expand Up @@ -303,12 +415,12 @@ module.exports = {
spec = spec.substring(1, spec.length - 1)
}

options.spec = strToArray(spec).map(resolvePath)
options.spec = parseSpecArgv(spec).map(resolvePath)
} else {
options.spec = spec.map(resolvePath)
}
} catch (err) {
debug('could not pass config spec value %s', spec)
debug('could not parse config spec value %s', spec)
debug('error %o', err)

return errors.throw('COULD_NOT_PARSE_ARGUMENTS', 'spec', spec, 'spec must be a string or comma-separated list')
Expand Down
13 changes: 13 additions & 0 deletions packages/server/test/unit/util/args_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ describe('lib/util/args', () => {
return snapshot('invalid spec error', stripAnsi(err.message))
}
})

it('should be correctly parsing globs with lists & ranges', function () {
const options = this.setup('--spec', 'cypress/integration/{[!a]*.spec.js,sub1,{sub2,sub3/sub4}}/*.js')

expect(options.spec[0]).to.eq(`${cwd}/cypress/integration/{[!a]*.spec.js,sub1,{sub2,sub3/sub4}}/*.js`)
})

it('should be correctly parsing globs with a mix of lists, ranges & regular paths', function () {
const options = this.setup('--spec', 'cypress/integration/{[!a]*.spec.js,sub1,{sub2,sub3/sub4}}/*.js,cypress/integration/foo.spec.js')

expect(options.spec[0]).to.eq(`${cwd}/cypress/integration/{[!a]*.spec.js,sub1,{sub2,sub3/sub4}}/*.js`)
expect(options.spec[1]).to.eq(`${cwd}/cypress/integration/foo.spec.js`)
})
})

context('--tag', () => {
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -23008,9 +23008,9 @@ is-glob@^3.0.0, is-glob@^3.1.0:
is-extglob "^2.1.0"

is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"

Expand Down

3 comments on commit 273b703

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 273b703 Jan 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/9.3.0/circle-develop-273b7035b09bc763b6d398a848c67a474ba37545/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 273b703 Jan 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/9.3.0/circle-develop-273b7035b09bc763b6d398a848c67a474ba37545/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 273b703 Jan 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/9.3.0/circle-develop-273b7035b09bc763b6d398a848c67a474ba37545/cypress.tgz

Please sign in to comment.