mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-28 10:49:48 -05:00
fix: CLI filtering --spec when commas in glob pattern (#19557)
* 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 <mjhenkes@gmail.com>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user