Skip to content
This repository was archived by the owner on Mar 29, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ jobs:
--env grepTags="high smoke" \
--expect-exactly expects/tags-or.json

- name: Tags OR specs using commas 🧪
env:
# Cypress CLI has problems parsing --env values with commas
# so pass the value using an environment variable
CYPRESS_grepTags: 'high,smoke'
run: |
npx cypress-expect \
--config testFiles="tags/*.spec.js" \
--expect-exactly expects/tags-or.json

- name: Tags AND specs 🧪
run: |
npx cypress-expect \
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# cypress-grep

[![ci status][ci image]][ci url] [![badges status][badges image]][badges url] [![renovate-app badge][renovate-badge]][renovate-app] ![cypress version](https://img.shields.io/badge/cypress-8.7.0-brightgreen)

> Filter tests using substring

```shell
Expand Down Expand Up @@ -183,6 +185,13 @@ You can select tests to run or skip using tags by passing `--env grepTags=...` v
--env grep=hello,grepTags=smoke
```

If you can pass commas in the environment variable `grepTags`, you can use `,` to separate the tags

```
# enable the tests with tag "one" or "two"
CYPRESS_grepTags=one,two npx cypress run
```

### Tags in the test config object

Cypress tests can have their own [test config object](https://on.cypress.io/configuration#Test-Configuration), and when using this plugin you can put the test tags there, either as a single tag string or as an array of tags.
Expand Down Expand Up @@ -301,8 +310,7 @@ If you have `tsconfig.json` file, add this library to the types list
The tags are also applied to the "describe" blocks. In that case, the tests look up if any of their outer suites are enabled.

```js
describe('block with config tag', { tags: '@smoke' }, () => {
})
describe('block with config tag', { tags: '@smoke' }, () => {})
```

```
Expand Down
58 changes: 46 additions & 12 deletions cypress/integration/unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('utils', () => {
])
})

it('parses OR tags', () => {
it('parses OR tags spaces', () => {
// run tests with tag1 OR tag2 or tag3
const parsed = parseTagsGrep('@tag1 @tag2 @tag3')
expect(parsed).to.deep.equal([
Expand All @@ -86,6 +86,16 @@ describe('utils', () => {
])
})

it('parses OR tags commas', () => {
// run tests with tag1 OR tag2 or tag3
const parsed = parseTagsGrep('@tag1,@tag2,@tag3')
expect(parsed).to.deep.equal([
[{ tag: '@tag1', invert: false }],
[{ tag: '@tag2', invert: false }],
[{ tag: '@tag3', invert: false }],
])
})

it('parses inverted tag', () => {
const parsed = parseTagsGrep('-@tag1')
expect(parsed).to.deep.equal([[{ tag: '@tag1', invert: true }]])
Expand All @@ -99,6 +109,30 @@ describe('utils', () => {
])
})

it('forgives extra spaces', () => {
const parsed = parseTagsGrep(' @tag1 -@tag2 ')
expect(parsed).to.deep.equal([
[{ tag: '@tag1', invert: false }],
[{ tag: '@tag2', invert: true }],
])
})

it('parses tag1 but not tag2 with comma', () => {
const parsed = parseTagsGrep('@tag1,-@tag2')
expect(parsed).to.deep.equal([
[{ tag: '@tag1', invert: false }],
[{ tag: '@tag2', invert: true }],
])
})

it('filters out empty tags', () => {
const parsed = parseTagsGrep(',, @tag1,-@tag2,, ,, ,')
expect(parsed).to.deep.equal([
[{ tag: '@tag1', invert: false }],
[{ tag: '@tag2', invert: true }],
])
})

// would need to change the tokenizer
it.skip('parses tag1 but not tag2', () => {
const parsed = parseTagsGrep('@tag1-@tag2')
Expand Down Expand Up @@ -319,22 +353,22 @@ describe('utils', () => {
).to.be.true
})

it("Multiple invert strings and a simple one", () => {
const t = checkName("-name;-hey;number")
expect(t("number should only be matches without a n-a-m-e")).to.be.true
it('Multiple invert strings and a simple one', () => {
const t = checkName('-name;-hey;number')
expect(t('number should only be matches without a n-a-m-e')).to.be.true
expect(t("number can't be name")).to.be.false
expect(t("The man needs a name")).to.be.false
expect(t("number hey name")).to.be.false
expect(t("numbers hey name")).to.be.false
expect(t("number hsey nsame")).to.be.true
expect(t("This wont match")).to.be.false
expect(t('The man needs a name')).to.be.false
expect(t('number hey name')).to.be.false
expect(t('numbers hey name')).to.be.false
expect(t('number hsey nsame')).to.be.true
expect(t('This wont match')).to.be.false
})

it("Only inverted strings", () => {
const t = checkName("-name;-hey")
it('Only inverted strings', () => {
const t = checkName('-name;-hey')
expect(t("I'm matched")).to.be.true
expect(t("hey! I'm not")).to.be.false
expect(t("My name is weird")).to.be.false
expect(t('My name is weird')).to.be.false
})
})

Expand Down
2 changes: 1 addition & 1 deletion src/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function cypressGrepPlugin(config) {

const grepTags = config.env.grepTags || config.env['grep-tags']
if (grepTags) {
console.log('cypress-grep: filtering using tag "%s"', grepTags)
console.log('cypress-grep: filtering using tag(s) "%s"', grepTags)
}

const grepBurn =
Expand Down
46 changes: 26 additions & 20 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,30 @@ function parseTagsGrep(s) {
return []
}

// top level split - using space, each part is OR
const ORS = s.split(' ').map((part) => {
// now every part is an AND
const parsed = part.split('+').map((tag) => {
if (tag.startsWith('-')) {
// top level split - using space or comma, each part is OR
const ORS = s
.split(/[ ,]/)
// remove any empty tags
.filter(Boolean)
.map((part) => {
// now every part is an AND
const parsed = part.split('+').map((tag) => {
if (tag.startsWith('-')) {
return {
tag: tag.slice(1),
invert: true,
}
}

return {
tag: tag.slice(1),
invert: true,
tag,
invert: false,
}
}
})

return {
tag,
invert: false,
}
return parsed
})

return parsed
})

return ORS
}

Expand Down Expand Up @@ -111,12 +115,14 @@ function shouldTestRunTitle(parsedGrep, testName) {
return true
}

const inverted = parsedGrep.filter(g => g.invert)
const straight = parsedGrep.filter(g => !g.invert)
const inverted = parsedGrep.filter((g) => g.invert)
const straight = parsedGrep.filter((g) => !g.invert)

return inverted.every(titleGrep => !testName.includes(titleGrep.title))
&& (!straight.length || straight
.some(titleGrep => testName.includes(titleGrep.title)))
return (
inverted.every((titleGrep) => !testName.includes(titleGrep.title)) &&
(!straight.length ||
straight.some((titleGrep) => testName.includes(titleGrep.title)))
)
}

// note: tags take precedence over the test name
Expand Down