find-cypress-specs 1.12.1 → 1.13.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 CHANGED
@@ -1,4 +1,4 @@
1
- # find-cypress-specs [![renovate-app badge][renovate-badge]][renovate-app] ![cypress version](https://img.shields.io/badge/cypress-9.4.1-brightgreen) [![ci](https://github.com/bahmutov/find-cypress-specs/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bahmutov/find-cypress-specs/actions/workflows/ci.yml)
1
+ # find-cypress-specs [![renovate-app badge][renovate-badge]][renovate-app] ![cypress version](https://img.shields.io/badge/cypress-9.5.1-brightgreen) [![ci](https://github.com/bahmutov/find-cypress-specs/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bahmutov/find-cypress-specs/actions/workflows/ci.yml)
2
2
 
3
3
  > Find Cypress spec files using the config settings
4
4
 
@@ -70,6 +70,13 @@ Each tag count includes the tests that use the tag directly, and the _effective_
70
70
 
71
71
  You can print the results in JSON format using `--json` or `-j` option.
72
72
 
73
+ ## Test names filtered by a tag
74
+
75
+ ```bash
76
+ $ npx find-cypress-specs --names --tagged <single tag>
77
+ # finds all specs and tests, then filters the output by a single tag
78
+ ```
79
+
73
80
  ## Details
74
81
 
75
82
  Cypress uses the resolved [configuration values](https://on.cypress.io/configuration) to find the spec files to run. It searches the `integrationFolder` for all patterns listed in `testFiles` and removes any files matching the `ignoreTestFiles` patterns.
package/bin/find.js CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  const arg = require('arg')
4
4
  const { getSpecs, collectResults, findChangedFiles } = require('../src')
5
+ const { pickTaggedTestsFrom } = require('../src/tagged')
6
+ const { addCounts } = require('../src/count')
7
+ const { stringAllInfo } = require('../src/print')
8
+
5
9
  const fs = require('fs')
6
10
  const pluralize = require('pluralize')
7
11
  const { getTestNames, formatTestList, countTags } = require('find-test-names')
@@ -16,6 +20,8 @@ const args = arg({
16
20
  // find the specs that have changed against this Git branch
17
21
  '--branch': String,
18
22
  '--count': Boolean,
23
+ // filter all tests to those that have the given tag
24
+ '--tagged': String,
19
25
 
20
26
  // aliases
21
27
  '-n': '--names',
@@ -34,43 +40,23 @@ if (args['--names'] || args['--tags']) {
34
40
  console.log('no specs found')
35
41
  } else {
36
42
  console.log('')
37
- let testsN = 0
38
- let pendingTestsN = 0
39
-
40
43
  // counts the number of tests for each tag across all specs
41
44
  const tagTestCounts = {}
42
-
43
45
  const jsonResults = {}
44
46
 
45
47
  specs.forEach((filename) => {
46
- jsonResults[filename] = []
48
+ jsonResults[filename] = {
49
+ counts: {
50
+ tests: 0,
51
+ pending: 0,
52
+ },
53
+ tests: [],
54
+ }
47
55
  const source = fs.readFileSync(filename, 'utf8')
48
56
  const result = getTestNames(source, true)
49
57
  // enable if need to debug the parsed test
50
58
  // console.dir(result.structure, { depth: null })
51
-
52
- testsN += result.testCount
53
- const testCount = pluralize('test', result.testNames.length, true)
54
- pendingTestsN += result.pendingTestCount
55
-
56
- if (args['--names']) {
57
- if (args['--json']) {
58
- collectResults(result.structure, jsonResults[filename])
59
- } else {
60
- if (result.pendingTestCount) {
61
- console.log(
62
- '%s (%s, %d pending)',
63
- filename,
64
- testCount,
65
- result.pendingTestCount,
66
- )
67
- } else {
68
- console.log('%s (%s)', filename, testCount)
69
- }
70
- console.log(formatTestList(result.structure))
71
- console.log('')
72
- }
73
- }
59
+ collectResults(result.structure, jsonResults[filename].tests)
74
60
 
75
61
  if (args['--tags']) {
76
62
  const specTagCounts = countTags(result.structure)
@@ -84,24 +70,22 @@ if (args['--names'] || args['--tags']) {
84
70
  }
85
71
  })
86
72
 
73
+ addCounts(jsonResults)
74
+
87
75
  if (args['--names']) {
76
+ if (args['--tagged']) {
77
+ // filter all collected tests to those that have the given tag
78
+ debug('filtering all tests by tag "%s"', args['--tagged'])
79
+ pickTaggedTestsFrom(jsonResults, args['--tagged'])
80
+ // recompute the number of tests
81
+ addCounts(jsonResults)
82
+ }
83
+
88
84
  if (args['--json']) {
89
85
  console.log(JSON.stringify(jsonResults, null, 2))
90
86
  } else {
91
- if (pendingTestsN) {
92
- console.log(
93
- 'found %s (%s, %d pending)',
94
- pluralize('spec', specs.length, true),
95
- pluralize('test', testsN, true),
96
- pendingTestsN,
97
- )
98
- } else {
99
- console.log(
100
- 'found %s (%s)',
101
- pluralize('spec', specs.length, true),
102
- pluralize('test', testsN, true),
103
- )
104
- }
87
+ const str = stringAllInfo(jsonResults)
88
+ console.log(str)
105
89
  }
106
90
  console.log('')
107
91
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "find-cypress-specs",
3
- "version": "1.12.1",
3
+ "version": "1.13.0",
4
4
  "description": "Find Cypress spec files using the config settings",
5
5
  "main": "src",
6
6
  "files": [
@@ -20,6 +20,7 @@
20
20
  "demo-names-and-tags": "node ./bin/find --names --tags",
21
21
  "demo-names-and-tags-json": "node ./bin/find --names --tags --json",
22
22
  "demo-names-json": "node ./bin/find --names --json",
23
+ "demo-names-tagged": "node ./bin/find --names --tagged @user",
23
24
  "print-changed-specs": "node ./bin/find --branch main",
24
25
  "count-changed-specs": "node ./bin/find --branch main --count",
25
26
  "semantic-release": "semantic-release"
@@ -39,7 +40,7 @@
39
40
  "homepage": "https://github.com/bahmutov/find-cypress-specs#readme",
40
41
  "devDependencies": {
41
42
  "ava": "^4.0.0",
42
- "cypress": "9.4.1",
43
+ "cypress": "9.5.1",
43
44
  "execa-wrap": "^1.4.0",
44
45
  "prettier": "^2.5.1",
45
46
  "semantic-release": "19.0.2"
package/src/count.js ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * For each file and each
3
+ */
4
+ function addCounts(json) {
5
+ Object.keys(json).forEach((filename) => {
6
+ const fileInfo = json[filename]
7
+ if (!fileInfo.counts) {
8
+ fileInfo.counts = {
9
+ tests: 0,
10
+ pending: 0,
11
+ }
12
+ }
13
+
14
+ fileInfo.counts.tests =
15
+ countTests(fileInfo.tests) + countTests(fileInfo.suites)
16
+ fileInfo.counts.pending =
17
+ countPendingTests(fileInfo.tests) + countPendingTests(fileInfo.suites)
18
+ })
19
+ }
20
+
21
+ function countTests(testsOrSuites) {
22
+ if (!testsOrSuites) {
23
+ return 0
24
+ }
25
+
26
+ return testsOrSuites.reduce((count, test) => {
27
+ if (test.type === 'test') {
28
+ return count + 1
29
+ } else if (test.type === 'suite') {
30
+ return count + countTests(test.tests) + countTests(test.suites)
31
+ }
32
+ }, 0)
33
+ }
34
+
35
+ function countPendingTests(testsOrSuites) {
36
+ if (!testsOrSuites) {
37
+ return 0
38
+ }
39
+
40
+ return testsOrSuites.reduce((count, test) => {
41
+ if (test.type === 'test') {
42
+ return test.pending ? count + 1 : count
43
+ } else if (test.type === 'suite') {
44
+ if (test.pending) {
45
+ // all tests inside should count as pending
46
+ return count + countTests(test.tests) + countTests(test.suites)
47
+ }
48
+
49
+ return (
50
+ count + countPendingTests(test.tests) + countPendingTests(test.suites)
51
+ )
52
+ }
53
+ }, 0)
54
+ }
55
+
56
+ module.exports = { addCounts }
package/src/print.js ADDED
@@ -0,0 +1,50 @@
1
+ const pluralize = require('pluralize')
2
+ const { formatTestList } = require('find-test-names')
3
+
4
+ /**
5
+ * Outputs a string representation of the json test results object,
6
+ * like a tree of suites and tests.
7
+ */
8
+ function stringFileTests(fileName, fileInfo) {
9
+ const testCount = pluralize('test', fileInfo.counts.tests, true)
10
+ const headerLine = fileInfo.counts.pending
11
+ ? `${fileName} (${testCount}, ${fileInfo.counts.pending} pending)`
12
+ : `${fileName} (${testCount})`
13
+
14
+ const body = formatTestList(fileInfo.tests)
15
+
16
+ return headerLine + '\n' + body + '\n'
17
+ }
18
+
19
+ function stringAllInfo(allInfo) {
20
+ let fileCount = 0
21
+ let testCount = 0
22
+ let pendingTestCount = 0
23
+
24
+ const allInfoString = Object.keys(allInfo)
25
+ .map((fileName) => {
26
+ const fileInfo = allInfo[fileName]
27
+ fileCount += 1
28
+ testCount += fileInfo.counts.tests
29
+ pendingTestCount += fileInfo.counts.pending
30
+ return stringFileTests(fileName, fileInfo)
31
+ })
32
+ .join('\n')
33
+
34
+ // footer line is something like
35
+ // found 2 specs (4 tests, 1 pending)
36
+ let footer = `found ${pluralize('spec', fileCount, true)}`
37
+ const testWord = pluralize('test', testCount, true)
38
+ if (pendingTestCount) {
39
+ footer += ` (${testWord}, ${pendingTestCount} pending)`
40
+ } else {
41
+ footer += ` (${testWord})`
42
+ }
43
+
44
+ return allInfoString + '\n' + footer
45
+ }
46
+
47
+ module.exports = {
48
+ stringFileTests,
49
+ stringAllInfo,
50
+ }
package/src/tagged.js ADDED
@@ -0,0 +1,54 @@
1
+ const { addCounts } = require('./count')
2
+
3
+ // note: modifies the tests in place
4
+ function pickTaggedTests(tests, tag) {
5
+ if (!Array.isArray(tests)) {
6
+ return false
7
+ }
8
+ const filteredTests = tests.filter((test) => {
9
+ if (test.type === 'test') {
10
+ return test.tags && test.tags.includes(tag)
11
+ } else if (test.type === 'suite') {
12
+ if (test.tags && test.tags.includes(tag)) {
13
+ return true
14
+ }
15
+
16
+ // maybe there is some test inside this suite
17
+ // with the tag? Filter all other tests
18
+ return (
19
+ pickTaggedTests(test.tests, tag) || pickTaggedTests(test.suites, tag)
20
+ )
21
+ }
22
+ })
23
+ tests.length = 0
24
+ tests.push(...filteredTests)
25
+ return filteredTests.length > 0
26
+ }
27
+
28
+ function removeEmptyNodes(json) {
29
+ Object.keys(json).forEach((filename) => {
30
+ const fileTests = json[filename].tests
31
+ if (!fileTests.length) {
32
+ delete json[filename]
33
+ }
34
+ })
35
+ return json
36
+ }
37
+
38
+ /**
39
+ * Takes an object of tests collected from all files,
40
+ * and removes all tests that do not have the given tag applied.
41
+ * Modifies the given object in place.
42
+ */
43
+ function pickTaggedTestsFrom(json, tag) {
44
+ Object.keys(json).forEach((filename) => {
45
+ const fileTests = json[filename].tests
46
+ pickTaggedTests(fileTests, tag)
47
+ })
48
+
49
+ const result = removeEmptyNodes(json)
50
+ addCounts(result)
51
+ return result
52
+ }
53
+
54
+ module.exports = { pickTaggedTestsFrom, removeEmptyNodes, pickTaggedTests }