@bahmutov/cy-grep 1.9.17 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @bahmutov/cy-grep ![cypress version](https://img.shields.io/badge/cypress-12.15.0-brightgreen)
1
+ # @bahmutov/cy-grep ![cypress version](https://img.shields.io/badge/cypress-13.11.0-brightgreen)
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.9.17",
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.13"
19
+ "find-test-names": "1.28.21",
20
+ "globby": "^11.1.0"
19
21
  },
20
22
  "devDependencies": {
21
- "cypress": "13.1.0",
23
+ "cypress": "13.11.0",
22
24
  "cypress-each": "^1.11.0",
23
25
  "cypress-expect": "^3.1.0",
24
- "prettier": "^2.8.1",
25
- "semantic-release": "^21.1.1",
26
+ "prettier": "^3.0.0",
27
+ "semantic-release": "^24.0.0",
26
28
  "stop-only": "^3.3.1",
27
- "typescript": "^4.7.4"
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,