Skip to content

Commit

Permalink
feat: warn the user if the grep tags were not found (#35)
Browse files Browse the repository at this point in the history
* refactor and add a method to get the list of tags

* check grep tags to confirm they were found
  • Loading branch information
bahmutov authored Mar 7, 2023
1 parent ceb7d65 commit a837eda
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 11 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,25 @@ jobs:
--env grepTags=@special \
--expect-exactly ./tests/required-tags/expect-with-required-tag.json
test-tag-not-found:
runs-on: ubuntu-20.04
steps:
- name: Checkout 🛎
uses: actions/checkout@v3

- name: Install Cypress 🧪
uses: cypress-io/github-action@v5
with:
runTests: false

- name: looking for tag that does not exist
# should show a warning and run all specs
run: |
npx cypress-expect run \
--project tests/required-tags \
--env grepTags=@wrong-tag,grepFilterSpecs=true \
--expect-exactly ./tests/required-tags/expect-all.json
test-required-tags-only:
runs-on: ubuntu-20.04
steps:
Expand Down
33 changes: 29 additions & 4 deletions cypress/e2e/unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,32 @@ import {
shouldTestRunTags,
shouldTestRunRequiredTags,
shouldTestRunTitle,
getMentionedTags,
} from '../../src/utils'

describe('utils', () => {
context('getMentionedTags', () => {
it('returns unique tags', () => {
const tags = getMentionedTags('@tag1+@tag2+@tag3')
expect(tags).to.deep.equal(['@tag1', '@tag2', '@tag3'])
})

it('sorts returned tags', () => {
const tags = getMentionedTags('x y a')
expect(tags).to.deep.equal(['a', 'x', 'y'])
})

it('handles -', () => {
const tags = getMentionedTags('@smoke+@screen-b')
expect(tags).to.deep.equal(['@screen-b', '@smoke'])
})

it('handles extra spaces', () => {
const tags = getMentionedTags(' @tag1 -@tag2 ')
expect(tags).to.deep.equal(['@tag1', '@tag2'])
})
})

context('parseTitleGrep', () => {
it('grabs the positive title', () => {
const parsed = parseTitleGrep('hello w')
Expand Down Expand Up @@ -51,7 +74,7 @@ describe('utils', () => {
})

it('returns null for undefined input', () => {
const parsed = parseTitleGrep()
const parsed = parseTitleGrep(undefined)

expect(parsed).to.equal(null)
})
Expand Down Expand Up @@ -271,10 +294,12 @@ describe('utils', () => {
expect(shouldTestRun(parsed, 'hello w'), 'needs tags').to.equal(false)
expect(shouldTestRun(parsed, 'hello no')).to.equal(false)
// not every tag is present
expect(shouldTestRun(parsed, ['@tag1', '@tag2'])).to.equal(false)
expect(shouldTestRun(parsed, ['@tag1', '@tag2', '@tag3'])).to.equal(true)
expect(shouldTestRun(parsed, '', ['@tag1', '@tag2'])).to.equal(false)
expect(shouldTestRun(parsed, '', ['@tag1', '@tag2', '@tag3'])).to.equal(
true,
)
expect(
shouldTestRun(parsed, ['@tag1', '@tag2', '@tag3', '@tag4']),
shouldTestRun(parsed, '', ['@tag1', '@tag2', '@tag3', '@tag4']),
).to.equal(true)

// title matches, but tags do not
Expand Down
4 changes: 3 additions & 1 deletion jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"compilerOptions": {
"types": ["cypress"],
"resolveJsonModule": true
"resolveJsonModule": true,
"moduleResolution": "node",
"target": "ES6"
}
}
36 changes: 30 additions & 6 deletions src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const { getTestNames, findEffectiveTestTags } = require('find-test-names')
const fs = require('fs')
const path = require('path')
const { version } = require('../package.json')
const { parseGrep, shouldTestRun } = require('./utils')
const { parseGrep, shouldTestRun, getMentionedTags } = require('./utils')

const isCypressV9 = (config) => !('specPattern' in config)

Expand Down Expand Up @@ -106,8 +106,12 @@ function cypressGrepPlugin(config) {
debug('%o', greppedSpecs)
} else if (grepTags) {
const parsedGrep = parseGrep(null, grepTags)

debug('parsed grep tags %o', parsedGrep)
const mentionedTags = getMentionedTags(grepTags)
debug('user mentioned tags %o', mentionedTags)
// unique tags found across all specs we search
const foundTags = new Set()

greppedSpecs = specFiles.filter((specFile) => {
const text = fs.readFileSync(specFile, { encoding: 'utf8' })

Expand All @@ -120,6 +124,15 @@ function cypressGrepPlugin(config) {
return Object.keys(testTags).some((testTitle) => {
const effectiveTags = testTags[testTitle].effectiveTags
const requiredTags = testTags[testTitle].requiredTags

// remember all found tags
effectiveTags.forEach((tag) => {
foundTags.add(tag)
})
requiredTags.forEach((tag) => {
foundTags.add(tag)
})

return shouldTestRun(
parsedGrep,
undefined,
Expand All @@ -138,6 +151,17 @@ function cypressGrepPlugin(config) {

debug('found grep tags "%s" in %d specs', grepTags, greppedSpecs.length)
debug('%o', greppedSpecs)

debug('all found tags across the specs %o', ...foundTags)
debug('user mentioned tags %o', mentionedTags)
mentionedTags.forEach((tag) => {
if (!foundTags.has(tag)) {
console.warn(
'cy-grep: could not find the tag "%s" in any of the specs',
tag,
)
}
})
} else {
// we have no tags to grep
debug('will try eliminating specs with required tags')
Expand Down Expand Up @@ -190,10 +214,10 @@ function cypressGrepPlugin(config) {
}
} else {
// hmm, we filtered out all specs, probably something is wrong
console.warn('grep and/or grepTags has eliminated all specs')
grep ? console.warn('grep: %s', grep) : null
grepTags ? console.warn('grepTags: %s', grepTags) : null
console.warn('Will leave all specs to run to filter at run-time')
console.warn('cy-grep: grep and/or grepTags has eliminated all specs')
grep ? console.warn('cy-grep: title: %s', grep) : null
grepTags ? console.warn('cy-grep: tags: %s', grepTags) : null
console.warn('cy-grep: Will leave all specs to run to filter at run-time')
}
}

Expand Down
23 changes: 23 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,28 @@ function parseTagsGrep(s) {
return ORS_filtered
}

/**
* Given a user string of tags to find, with various connectors,
* returns the list of just the tags themselves. Could be used to
* quickly filter test specs or find misspelled tags.
* @returns {string[]} list of unique tags
*/
function getMentionedTags(s) {
if (!s) {
return []
}
const spaced = s.replaceAll(/[+,]/g, ' ')
const tags = spaced
.split(' ')
.map((s) => s.trim())
.filter(Boolean)
// remove any "-" at the start of the tag
// because these are to signal inverted tags
.map((s) => (s.startsWith('-') ? s.slice(1) : s))
const uniqueTags = [...new Set(tags)]
return uniqueTags.sort()
}

function shouldTestRunRequiredTags(parsedGrepTags, requiredTags = []) {
if (!requiredTags.length) {
// there are no tags to check
Expand Down Expand Up @@ -216,4 +238,5 @@ module.exports = {
shouldTestRunTags,
shouldTestRunRequiredTags,
shouldTestRunTitle,
getMentionedTags,
}
8 changes: 8 additions & 0 deletions tests/required-tags/expect-all.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"e2e": {
"spec.cy.js": {
"runs always": "pending",
"runs only when tag \"special\" is on": "pending"
}
}
}

0 comments on commit a837eda

Please sign in to comment.