cypress-tags icon indicating copy to clipboard operation
cypress-tags copied to clipboard

CYPRESS_INCLUDE_TAGS doesn't work for describe() wrapping it() in a function

Open kkaarreell opened this issue 4 years ago • 7 comments

Having a test with the following structure

const test_step = (value) => {
  it(`test step ${value}`, () => { console.log(value) })
}

describe(['foo'], 'my test set', () => {
  test_step(1)
  test_step(2)
})

CYPRESS_INCLUDE_TAGS cannot be used for filtering on the describe() level. E.g. CYPRESS_INCLUDE_TAGS=foo won't run anything. I believe this is because it() is not in fact inside the describe() block and therefore the tag inheritance doesn't work properly.

kkaarreell avatar Mar 17 '21 20:03 kkaarreell

So I tried something like this (EDITED)

--- node_modules/cypress-tags/dist/index.js.orig	2021-03-18 10:32:32.728237041 +0100
+++ node_modules/cypress-tags/dist/index.js	2021-03-18 10:33:50.571008469 +0100
@@ -55,7 +55,8 @@
 };
 // Use include and exclude tags to determine if current node should be skipped
 const calculateSkipChildren = (includeTags, excludeTags, tags) => {
-    const includeTest = includeTags.length === 0 || tags.some(tag => includeTags.includes(tag));
+    const itOutsideDescribe = tags.includes('__inIt')? !tags.includes('__inDescribe'): false
+    const includeTest = itOutsideDescribe ? true : includeTags.length === 0 || tags.some(tag => includeTags.includes(tag));
     const excludeTest = excludeTags.length > 0 && tags.some(tag => excludeTags.includes(tag));
     return !(includeTest && !excludeTest);
 };
@@ -121,7 +122,7 @@
                     // Describe / Context block
                     if (firstArgIsTag || typescript_1.default.isArrayLiteralExpression(firstArg)) {
                         // First arg is single tag or tags list
-                        const result = removeTagsFromNode(node, tags, includeTags, excludeTags)
+                        const result = removeTagsFromNode(node, tags.concat('__inDescribe'), includeTags, excludeTags)
                         skipNode = result.skipNode;
                         returnNode = result.node;
                         tags = result.tags;
@@ -131,13 +132,13 @@
                     // It block
                     if (firstArgIsTag || typescript_1.default.isArrayLiteralExpression(firstArg)) {
                         // First arg is single tag or tags list
-                        const result = removeTagsFromNode(node, tags, includeTags, excludeTags);
+                        const result = removeTagsFromNode(node, tags.concat('__inIt'), includeTags, excludeTags);
                         skipNode = result.skipNode;
                         returnNode = result.node;
                     }
                     else if (isTitle(firstArg)) {
                         // First arg is title
-                        skipNode = calculateSkipChildren(includeTags, excludeTags, tags);
+                        skipNode = calculateSkipChildren(includeTags, excludeTags, tags.concat('__inIt'));
                     }
                 }
             }

The idea behind it is that we add extra tag __inDescribe to describe() node and __inIt tag to it() node. Then for a node we check if it has __inIt but not __inDescribe which would mean that it() is not inside the describe() block but standalone. For such nodes we do evaluation only based on the CYPRESS_EXCLUDE_TAGS list since we can assume that if it ends up being executed during a test run it means that the parent describe() node passed tag filtering already and therefore even the it() node would passed due to tag inheritance.

I did some testing on the following test file but I must admit that this is rather naive approach and there could be something I am missing. Also, I do not know whether before() and similar blocks are being handled by cypress-tags in any way.

const step = () => {

  it(['baz1'], 'baz1 step', () => {
    console.log('baz1 step')
  })

  it(['baz2'], 'baz2 step', () => {
    console.log('baz2 step')
  })

}

describe(['foo'], 'foo test', () => {

  step()
  it(['foo1'], 'foo step', () => console.log('foo step'))
  it('foo - no tag step', () => console.log('foo - no tag step'))

})

describe(['bar'], 'bar test', () => {

  step()
  it(['bar1'], 'bar', () => console.log('bar step'))
  it('bar - no tag step', () => console.log('bar - no tag step'))

})

After a bit more of testing, I am going to create a PR for this.

kkaarreell avatar Mar 17 '21 21:03 kkaarreell

Hi @kkaarreell

Thanks for raising this. I can confirm that I can replicate the issue.

I'll be happy to take a look at a PR if you can get something working for this. Otherwise, I'll try to find some time to have a look at this in the future.

annaet avatar Mar 28 '21 14:03 annaet

Hi @annaet, basically I wanted to go with the patch above, which fixed my use case but may not work for other rare cases. In the PR I wanted to update the test suite too but I couldn't make it work and then I had to focus on something different. I am sorry but I am afraid I won't be able do do it any time soon.

kkaarreell avatar Mar 28 '21 15:03 kkaarreell

No problem - I'll leave this ticket open for the next time I have some time to work on this!

annaet avatar Mar 28 '21 16:03 annaet

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar May 27 '21 16:05 stale[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Aug 09 '21 23:08 stale[bot]

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Oct 09 '21 09:10 stale[bot]