@bahmutov/cy-grep 1.9.17 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -1
- package/package.json +8 -6
- package/src/file-utils.js +35 -0
- package/src/plugin.js +18 -0
- package/src/support.js +24 -0
package/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# @bahmutov/cy-grep 
|
2
2
|
|
3
3
|
> Filter tests using substring or tag
|
4
4
|
|
@@ -55,10 +55,12 @@ Watch the video [intro to cypress-grep plugin](https://www.youtube.com/watch?v=H
|
|
55
55
|
- [NOT tags](#not-tags)
|
56
56
|
- [Tags in test suites](#tags-in-test-suites)
|
57
57
|
- [Grep untagged tests](#grep-untagged-tests)
|
58
|
+
- [Access the tags in the test](#access-the-tags-in-the-test)
|
58
59
|
- [Pre-filter specs (grepFilterSpecs)](#pre-filter-specs-grepfilterspecs)
|
59
60
|
- [Omit filtered tests (grepOmitFiltered)](#omit-filtered-tests-grepomitfiltered)
|
60
61
|
- [Disable grep](#disable-grep)
|
61
62
|
- [Burn (repeat) tests](#burn-repeat-tests)
|
63
|
+
- [grepExtraSpecs](#grepextraspecs)
|
62
64
|
- [Required tags](#required-tags)
|
63
65
|
- [Negative grep](#negative-grep)
|
64
66
|
- [TypeScript support](#typescript-support)
|
@@ -407,6 +409,22 @@ Sometimes you want to run only the tests without any tags, and these tests are i
|
|
407
409
|
$ npx cypress run --env grepUntagged=true
|
408
410
|
```
|
409
411
|
|
412
|
+
### Access the tags in the test
|
413
|
+
|
414
|
+
You can check the current test's tags (including its parent suites) by checking the `Cypress.env('testTags')` list
|
415
|
+
|
416
|
+
```js
|
417
|
+
describe('parent', { tags: ['@p1', '@p2'] }, () => {
|
418
|
+
describe('child', { tags: '@c1' }, () => {
|
419
|
+
it('has all effective test tags', { tags: '@t1' }, () => {
|
420
|
+
const tags = Cypress.env('testTags')
|
421
|
+
// includes tags from the parent suites and the test itself
|
422
|
+
expect(tags, 'tags').to.deep.equal(['@p1', '@p2', '@c1', '@t1'])
|
423
|
+
})
|
424
|
+
})
|
425
|
+
})
|
426
|
+
```
|
427
|
+
|
410
428
|
## Pre-filter specs (grepFilterSpecs)
|
411
429
|
|
412
430
|
By default, when using `grep` and `grepTags` all specs are executed, and inside each the filters are applied. This can be very wasteful, if only a few specs contain the `grep` in the test titles. Thus when doing the positive `grep`, you can pre-filter specs using the `grepFilterSpecs=true` parameter.
|
@@ -488,6 +506,14 @@ You can pass the number of times to run the tests via environment name `burn` or
|
|
488
506
|
|
489
507
|
If you do not specify the "grep" or "grep tags" option, the "burn" will repeat _every_ test.
|
490
508
|
|
509
|
+
## grepExtraSpecs
|
510
|
+
|
511
|
+
Sometimes you want to pre-filter specs using tags AND then run extra specs without any filtering. You can set the list of specs / patterns using the `grepExtraSpecs` env string. For example, to filter specs using tag `@a` plus run the spec "b.cy.js":
|
512
|
+
|
513
|
+
```
|
514
|
+
npx cypress run --env grepTags=@a,grepExtraSpecs=cypress/e2e/b.cy.js
|
515
|
+
```
|
516
|
+
|
491
517
|
## Required tags
|
492
518
|
|
493
519
|
Sometimes you might want to run a test or a suite of tests _only_ if a specific tag or tags are present. For example, you might have a test that cleans the data. This test is meant to run nightly, not on every test run. Thus you can set a `required` tag:
|
@@ -708,6 +734,7 @@ To see how to debug this plugin, watch the video [Debug cypress-grep Plugin](htt
|
|
708
734
|
- [cypress-select-tests](https://github.com/bahmutov/cypress-select-tests)
|
709
735
|
- [cypress-skip-test](https://github.com/cypress-io/cypress-skip-test)
|
710
736
|
- 📝 Read the blog post [Cypress GitHub Actions Slash Command](https://glebbahmutov.com/blog/cypress-slash-command/)
|
737
|
+
- plugin [dennisbergevin/cypress-plugin-last-failed](https://github.com/dennisbergevin/cypress-plugin-last-failed)
|
711
738
|
|
712
739
|
## cy-grep vs cypress-grep vs @cypress/grep
|
713
740
|
|
package/package.json
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "@bahmutov/cy-grep",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.11.0",
|
4
4
|
"description": "Filter Cypress tests using title or tags",
|
5
5
|
"main": "src/support.js",
|
6
6
|
"scripts": {
|
7
7
|
"cy:run": "cypress run --config specPattern='**/unit.js'",
|
8
8
|
"cy:open": "cypress open --e2e -b electron --config specPattern='**/unit.js'",
|
9
|
+
"cy:open:tags": "cypress open --e2e -b electron --config specPattern='cypress/e2e/test-tags/*.cy.js'",
|
9
10
|
"badges": "npx -p dependency-version-badge update-badge cypress",
|
10
11
|
"semantic-release": "semantic-release",
|
11
12
|
"deps": "npm audit --report --omit dev",
|
@@ -15,16 +16,17 @@
|
|
15
16
|
"cypress-plugin-config": "^1.2.0",
|
16
17
|
"debug": "^4.3.2",
|
17
18
|
"find-cypress-specs": "^1.35.1",
|
18
|
-
"find-test-names": "1.28.
|
19
|
+
"find-test-names": "1.28.21",
|
20
|
+
"globby": "^11.1.0"
|
19
21
|
},
|
20
22
|
"devDependencies": {
|
21
|
-
"cypress": "13.
|
23
|
+
"cypress": "13.11.0",
|
22
24
|
"cypress-each": "^1.11.0",
|
23
25
|
"cypress-expect": "^3.1.0",
|
24
|
-
"prettier": "^
|
25
|
-
"semantic-release": "^
|
26
|
+
"prettier": "^3.0.0",
|
27
|
+
"semantic-release": "^24.0.0",
|
26
28
|
"stop-only": "^3.3.1",
|
27
|
-
"typescript": "^
|
29
|
+
"typescript": "^5.0.0"
|
28
30
|
},
|
29
31
|
"peerDependencies": {
|
30
32
|
"cypress": ">=8"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
// @ts-check
|
2
|
+
|
3
|
+
const globby = require('globby')
|
4
|
+
const debug = require('debug')('cy-grep')
|
5
|
+
|
6
|
+
function resolveFilePattern(pattern) {
|
7
|
+
if (pattern.includes('*')) {
|
8
|
+
const globbyOptions = {
|
9
|
+
sort: true,
|
10
|
+
objectMode: false,
|
11
|
+
}
|
12
|
+
debug('globby options "%s" %o', pattern, globbyOptions)
|
13
|
+
|
14
|
+
const files = globby.sync(pattern, globbyOptions)
|
15
|
+
debug('found %d file(s) %o', files.length, files)
|
16
|
+
return files
|
17
|
+
} else {
|
18
|
+
return pattern
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
function resolveFilePatterns(patterns) {
|
23
|
+
const extraSpecsList = patterns
|
24
|
+
.split(',')
|
25
|
+
.map((s) => s.trim())
|
26
|
+
.filter(Boolean)
|
27
|
+
debug('extra specs list %o', extraSpecsList)
|
28
|
+
|
29
|
+
return extraSpecsList.flatMap(resolveFilePattern)
|
30
|
+
}
|
31
|
+
|
32
|
+
module.exports = {
|
33
|
+
resolveFilePattern,
|
34
|
+
resolveFilePatterns,
|
35
|
+
}
|
package/src/plugin.js
CHANGED
@@ -7,6 +7,7 @@ const fs = require('fs')
|
|
7
7
|
const path = require('path')
|
8
8
|
const { version } = require('../package.json')
|
9
9
|
const { parseGrep, shouldTestRun, getMentionedTags } = require('./utils')
|
10
|
+
const { resolveFilePatterns } = require('./file-utils')
|
10
11
|
const minimatch = require('minimatch')
|
11
12
|
|
12
13
|
const MINIMATCH_OPTIONS = { dot: true, matchBase: true }
|
@@ -224,6 +225,23 @@ function cypressGrepPlugin(config) {
|
|
224
225
|
})
|
225
226
|
}
|
226
227
|
|
228
|
+
const extraSpecsPattern = config.env.grepExtraSpecs
|
229
|
+
if (extraSpecsPattern) {
|
230
|
+
debug('processing the extra specs pattern "%s"', extraSpecsPattern)
|
231
|
+
const extraSpecs = resolveFilePatterns(extraSpecsPattern)
|
232
|
+
// update the config env object with resolved extra specs
|
233
|
+
const resolvedExtraSpecs = []
|
234
|
+
extraSpecs.forEach((specFilename) => {
|
235
|
+
if (!greppedSpecs.includes(specFilename)) {
|
236
|
+
greppedSpecs.push(specFilename)
|
237
|
+
resolvedExtraSpecs.push(specFilename)
|
238
|
+
debug('added extra spec %s', specFilename)
|
239
|
+
}
|
240
|
+
})
|
241
|
+
|
242
|
+
config.env.grepExtraSpecs = resolvedExtraSpecs
|
243
|
+
}
|
244
|
+
|
227
245
|
if (greppedSpecs.length) {
|
228
246
|
if (isCypressV9(config)) {
|
229
247
|
debug('setting selected %d specs (< v10)', greppedSpecs.length)
|
package/src/support.js
CHANGED
@@ -16,6 +16,22 @@ debug.log = console.info.bind(console)
|
|
16
16
|
// preserve the real "it" function
|
17
17
|
const _it = it
|
18
18
|
const _describe = describe
|
19
|
+
// keeps all collected test tags by the full test title
|
20
|
+
// includes both the test tags and the suite tags
|
21
|
+
// and the required test tags
|
22
|
+
const testTree = {}
|
23
|
+
|
24
|
+
beforeEach(() => {
|
25
|
+
// set the test tags for the current test
|
26
|
+
const testTitle = Cypress.currentTest.titlePath.join(' ')
|
27
|
+
const info = testTree[testTitle]
|
28
|
+
if (info) {
|
29
|
+
const allTags = info.effectiveTestTags.concat(info.requiredTestTags)
|
30
|
+
Cypress.env('testTags', allTags)
|
31
|
+
} else {
|
32
|
+
Cypress.env('testTags', null)
|
33
|
+
}
|
34
|
+
})
|
19
35
|
|
20
36
|
/**
|
21
37
|
* Wraps the "it" and "describe" functions that support tags.
|
@@ -42,6 +58,8 @@ function registerCyGrep() {
|
|
42
58
|
getPluginConfigValue('grepUntagged') ||
|
43
59
|
getPluginConfigValue('grep-untagged')
|
44
60
|
|
61
|
+
const extraSpecs = getPluginConfigValue('grepExtraSpecs')
|
62
|
+
|
45
63
|
// if (!grep && !grepTags && !burnSpecified && !grepUntagged) {
|
46
64
|
// nothing to do, the user has no specified the "grep" string
|
47
65
|
// debug('Nothing to grep, version %s', version)
|
@@ -109,6 +127,11 @@ function registerCyGrep() {
|
|
109
127
|
configRequiredTags = [configRequiredTags]
|
110
128
|
}
|
111
129
|
|
130
|
+
if (extraSpecs?.length && extraSpecs.includes(Cypress.spec.relative)) {
|
131
|
+
// the user wants to run all tests in this extra spec file
|
132
|
+
return _it(name, options, callback)
|
133
|
+
}
|
134
|
+
|
112
135
|
const nameToGrep = suiteStack
|
113
136
|
.map((item) => item.name)
|
114
137
|
.concat(name)
|
@@ -122,6 +145,7 @@ function registerCyGrep() {
|
|
122
145
|
.concat(configRequiredTags)
|
123
146
|
.filter(Boolean)
|
124
147
|
debug({ nameToGrep, effectiveTestTags, requiredTestTags })
|
148
|
+
testTree[nameToGrep] = { effectiveTestTags, requiredTestTags }
|
125
149
|
|
126
150
|
const shouldRun = shouldTestRun(
|
127
151
|
parsedGrep,
|