-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Filter or grep specific tests to run (like mocha grep pattern) #1865
Comments
From mocha docs:
described ('api', function() {
describe('GET /api/users', function() {
it('respond with an array of users', function() {
// ...
});
});
});
describe('app', function() {
describe('GET /users', function() {
it('respond with an array of users', function() {
// ...
});
});
}); |
This comment has been minimized.
This comment has been minimized.
I personally like the idea of tagging tests, because you don't have to worry about organization as much. It would be nice to find all the tests related to something using only the concept of Tagging, as explained in the mocha wiki below: https://github.com/mochajs/mocha/wiki/Tagging
|
+1! We have a complex system with several services and applications working together. Cypress covers the End-to-end tests on all of this together. So we want to be able to select groups of tests on CI (Gitlab) to not have to run all tests every time but only a relevant selection of the tests. |
This would be a super useful feature especially when we are testing a big app so we want to split our e2e tests somehow into suites after tagging them accordingly. |
This would be really useful. Being able to only run smoke test TCs from different files makes organization easier. |
This would be so useful! |
I've been searching for this nice feature in Cypress and found out this post, thanks to @hannah06 . Here are my thoughts on this feature: I have lots of test cases with different priorities and I want to tag them according to their priorities. Actually, it's not for just a priority like; "Critical", "High", "Medium", "Low", I can use tags like "Functional", "Non-Functional", "Smoke", "UI", etc. So, I can group and run my tests, how I want or how I structure. Sometimes I just want to be able to run only the "Critical" cases, or "Critical" and "UI" cases. By this way, we will be able to structure more dynamic tests. |
I'm using cypress-cucumber-preprocessor which translates Gherkin to JS and supports Cucumber tag expressions. It relies on the For those using pure JS, you could emulate this behavior by wrapping the Mocha
The cucumber-js tag helper API does all of the hard parsing/matching and could be plugged into this solution. If you wanted something more magical feeling, you could write a preprocessor plugin that scans the file for magic comment lines or special |
Here is my workaround: Test example: import TestFilter from '../../support/util/test-filter';
describe('Dashboard', function() {
TestFilter.any(['smoke', 'pr'], () => {
it('loads and validates dashboard page', function() {
cy.dspVisit('/app/dashboard/list');
cy.PageObjects.DashboardPage().validate();
});
});
}); TestFilter class: const TestFilter = {
any(tags, testFn) {
const selectedTags = (Cypress.env('TEST_TAGS') || '').split(';');
const found = tags.some((r) => selectedTags.indexOf(r) >= 0);
if (found) {
testFn();
}
},
notIn(tags, testFn) {
const selectedTags = (Cypress.env('TEST_TAGS') || '').split(';');
const found = tags.some((r) => selectedTags.indexOf(r) >= 0);
if (!found) {
testFn();
}
},
all(tags, testFn) {
const selectedTags = (Cypress.env('TEST_TAGS') || '').split(';');
if (
tags
.map((tag) => {
return tags.length === selectedTags.length && selectedTags.indexOf(tag) !== -1;
})
.reduce((acc, cur) => acc && cur, true)
) {
testFn();
}
}
};
export default TestFilter; And you run your tests by passing in |
any updates on this? would love to have this. thanks! |
I ended up with this after experimenting with it today, coincidentally. It will look through the entire suite and skip anything that doesn't match your tags, including the parents if there's no tests that need to run - plus it doesn't need anything importing in individual tests, which is nice too. I've simplified it slightly from our production code, so let me know if there are any mistakes. Install the cucumber-tag-expressions node module and add or import this in your import { TagExpressionParser } from 'cucumber-tag-expressions';
const tagParser = new TagExpressionParser();
before(function() {
this.test.parent.suites.forEach(checkSuite);
});
const shouldSkip = test => {
const tags = Cypress.env('tags');
if(!tags) return;
const tagger = tagParser.parse(tags);
return !tagger.evaluate(test.fullTitle());
};
const checkSuite = suite => {
if (suite.pending) return;
if (shouldSkip(suite)) {
suite.pending = true;
return;
}
(suite.tests || []).forEach(test => {
if (shouldSkip(test)) test.pending = true;
});
(suite.suites || []).forEach(checkSuite);
}; Then you can use it in your tests by setting a You use the tags in your test names, like so: describe('set of tests @foo', () => {
it('test @bar', () => {...});
it('another test @baz', () => {...});
describe('sub-suite @xyzzy', () => {...});
}); |
if you use JavaScript specs, take a look at the plugin https://github.com/bahmutov/cypress-select-tests that allows one to select tests to run by filename or by substring
|
@jennifer-shehane or anybody else, how do I make use of the
|
@x-yuri It is not supported. This issue is requesting this to be added as a feature. You could use this plugin today as a workaround: https://github.com/bahmutov/cypress-select-tests |
This looks good and works. How I can write a CLI script for it to filter in Jenkins job |
@jennifer-shehane any updates on this? It's very helpful for our project. Thanks! |
I've managed to do this in a simpler way: on('file:preprocessor', file => {
if (config.env.specname && file.filePath.indexOf(config.integrationFolder) > -1) {
const contents = fs.readFileSync(file.filePath, 'utf8');
const modified = contents.replace(
/(^\s.?)(it)\((.*$)/gim,
(a, b, c, d) => `${b}it${RegExp(config.env.specname, 'gmi').test(d) ? '' : '.skip'}(${d}`
);
fs.writeFileSync(file.outputPath, modified, 'utf8');
}
return Promise.resolve(file.outputPath);
}); To use: This will add '.skip' to any tests which do not include the specname defined in the environment variable |
If you want to temporarily focus on a couple of tests: describe('...', function() {
specify('test1', () => {
console.log('test1');
});
specify('test2', () => {
console.log('test2');
});
const t3 = specify('test3', () => {
console.log('test3');
});
console.log(t3.fullTitle());
mocha.grep(/test[12]/);
}); |
Please add tagging |
My current solution without wrapping test code at all: // support/index.js
let testFilter;
global._testFilter = function(x) {
if (typeof x === 'function') {
testFilter = x;
} else {
// `x` must be RegExp
testFilter = function({ fullTitle }) {
return x.test(fullTitle);
};
}
};
// Replace `context`/`it` to collect full title and filter them
let suiteNames = [];
let oldContext = global.context;
global.context = function(name) {
suiteNames.push(name);
let result = oldContext.apply(this, arguments);
suiteNames.pop();
return result;
};
let oldIt = global.it;
global.it = function(name) {
if (!testFilter) return oldIt.apply(this, arguments);
let fullTitle = suiteNames.join(' ') + ' ' + name;
if (!testFilter({ fullTitle })) return;
return oldIt.apply(this, arguments);
}; Then in the beginning of the test file simply add something like But there anyway will be empty contexts. |
ProposalWhen Cypress runner finishes collecting tests its creates a single object and then starts running the tests. We can insert an async operation into this gap. We can pass the tree of collected tests to the user's async function in the plugins file. The user can filter the tests by name in any way desired: using CLI arguments or by looking up which tests to run via API requests, or by reading the names of the tests from a file. // plugins file
// run all tests
on('filter:tests', (rootSuite) => {
// rootSuite
// tests: [test objects]
// suites: [recursive suites]
// each test object has "title"
return Promise.resolve(rootSuite)
}) or run just the first test from the root suite on('filter:tests', (rootSuite) => {
rootSuite.suites.length = 0
rootSuite.tests.length = 1
return Promise.resolve(rootSuite)
}) The runner code on receiving an object from 'filter:tests' callback with filtered tests will go through its normalized tree of tests and remove any tests that are NOT in the returned tree of tests. Inspiration: run-time filtering of Mocha's tests https://glebbahmutov.com/blog/filter-mocha-tests/ |
Would like to see this as well. I'm converting some of my Robot Framework tests over and am missing this feature. I don't think it should be tied to a file name as I want to be able to change 'tags' without renaming things. |
@UncleGus Anyway. The transpiled version looks like this: // support/filterTestByTags.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
(function () {
var _a, _b;
if (!Cypress.env('tags') && !Cypress.env('exclTags')) {
return;
}
var envTags = (_a = Cypress.env('tags')) !== null && _a !== void 0 ? _a : '';
var envExclTags = (_b = Cypress.env('exclTags')) !== null && _b !== void 0 ? _b : '';
var hasTags = envTags !== '';
var hasExclTags = envExclTags !== '';
// Don't filter if both is defined. We do not know what is right
if (hasTags && hasExclTags) {
console.log('Both tags and excluding tags has been defined. Not filtering');
return;
}
var tags = hasTags ? envTags.split(' ') : [];
var exclTags = hasExclTags ? envExclTags.split(' ') : [];
var orgIt = it;
var filterFunction = hasTags ? onlyWithTags : onlyWithoutTags;
var filteredIt = filterFunction;
filteredIt.skip = orgIt.skip;
filteredIt.only = orgIt.only;
filteredIt.retries = orgIt.retries;
it = filteredIt;
function onlyWithTags(title, fn) {
if (tags.find(function (t) { return title.indexOf(t) === -1; })) {
fn = null;
}
orgIt(title, fn);
}
function onlyWithoutTags(title, fn) {
if (exclTags.find(function (t) { return title.indexOf(t) !== -1; })) {
fn = null;
}
orgIt(title, fn);
}
})();
// support/index.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("./commands");
require("./filterTestsByTags"); If you are trying to avoid the types, your code should probably look something like that. |
Hmm, no luck with the transpiled code. It is still just executing all the tests. And switching back to Typescript in v4.4.1 still gets the same error: |
I've just converted my test spec file to Typescript, added the tsconfig.json and all that, and it's still not working. I must be missing something. I also have a number of errors/warnings in the filter file, because the two functions' parameters are not typed, but I don't think that's a significant issue. |
@jennifer-shehane does Cypress dashboard count skipped tests as a record? |
@jennifer-shehane Is someone working on this feature? |
@kirill-golovan No, skipped tests are not counted as part of your Billing. This issue is still in the 'proposal' stage, which means no work has been done on this issue as of today, so we do not have an estimate on when this will be delivered. |
Thanks for this. Sharing my use case, if it helps. We tag our mocha tests that are proving known bugs. We want to keep the test but still allow the pipeline to pass.
|
Ugh. Still no work on this? What do people do in CI to filter their tests? Really missing this after moving from Robot Framework :( |
#1865 (comment) |
@jimpriest I have written up a solution that I use for grepping my tests, maybe it’ll help. |
i may have found a solution using cypress-tags - https://github.com/annaet/cypress-tags |
any update @jennifer-shehane ? |
This feature will add a lot of value to us. If we are able to add multiple tags then each of our team can slice the tests based on their requirements. |
@thviQit thanks for sharing your example. it works for me... except if i have a |
For anyone using @thviQit's workaround, if you want to use After looking at Mocha's source, they're pretty straight forward to replicate: filteredIt.skip = (title) => originalIt(title);
filteredIt.only = (title, fn) => {
const test = originalIt(title, fn);
test.parent.appendOnlyTest(test);
}; This has worked pretty well for me. |
I don't mean to nit pick here, but I'd like to disambiguate between test tags and grep. For grep, which mocha supports using Exposing a similar // npx cypress run --grep=#desktop
it('does something #desktop', () => {...}) // should run
it('does something else', () => {...}) // should not run But for tagging or specifically using test tags (I often compare this to the rspec implementation of test tagging). It would be great if there was an API that didn't need to rely on parsing test title strings. This is so that in a large repo with many thousands of tests, we don't run the risk of accidentally grabbing things that might look like tags but are not intended to be. If the test block itself could support an array / object of tags, eg. // npx cypress run --tag desktop
// the API is clear about what those strings are intended for
it('does something', () => {}, { tags: ['desktop', 'slow' ] })
// or alternatively
it('does something', () => {}, { tags: { desktop: true, slow: true } }) |
Considering that this is issue is from 2018 and Cypress is a paid tool as well, how come this was not yet implemented with so many upvotes?? |
@iljapavlovs the Cypress test runner is free open-source MIT-licensed tool https://docs.cypress.io/faq/questions/general-questions-faq#Is-Cypress-free-and-open-source Right now this is not part of the core, but I think https://github.com/bahmutov/cypress-grep is doing pretty much everything one needs to grep by test title or tags. Please try using this plugin, and if the feedback is positive we can think about moving this into the core.
|
Nice! I haven't looked at this plugin in awhile and didn't know it now supported tags! FWIW Think it would be useful to edit the initial description to mention tags. |
+1 running a single |
+1 upvote for this to be supported natively |
It's really hard to fathom this isn't supported. When you work on adding a test to an existing file, you have to run the whole file to verify the result? Anyone who uses or works on Cypress knows this is a huge miss. |
Current behavior:
Run specific files but cannot choose specific single/multi tests.
Desired behavior:
Choose expected tests to run, like mocha grep pattern.
Though we put a group of tests in a spec file, but sometimes we just want to run parts of them, so we need filter them out.
The text was updated successfully, but these errors were encountered: