Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally ignore individual tests with Karma / Jasmine

Tags:

I have some tests that fail in PhantomJS but not other browsers.

I'd like these tests to be ignored when run with PhantomJS in my watch task (so new browser windows don't take focus and perf is a bit faster), but in my standard test task and my CI pipeline, I want all the tests to run in Chrome, Firefox, etc...

I've considered a file-naming convention like foo.spec.dont-use-phantom.js and excluding those in my Karma config, but this means that I will have to separate out the individual tests that are failing into their own files, separating them from their logical describe blocks and having more files with weird naming conventions would generally suck.

In short:

Is there a way I can extend Jasmine and/or Karma and somehow annotate individual tests to only run with certain configurations?

like image 878
Zach Lysobey Avatar asked Aug 25 '15 22:08

Zach Lysobey


People also ask

How do I ignore test cases in Jasmine?

Jasmine also allows the developers to skip one or more than one test cases. These techniques can be applied at the Spec level or the Suite level. Depending on the level of application, this block can be called as a Skipping Spec and Skipping Suite respectively.

How do you ignore a test case in karma?

Just rename the tests that you want to disable from it(...) to xit(...) function xit: A temporarily disabled it. The spec will report as pending and will not be executed.

How do you use karma in Jasmine test cases?

We can run Jasmine tests in a browser ourselves by setting up and loading a HTML file, but more commonly we use a command-line tool called Karma. Karma handles the process of creating HTML files, opening browsers and running tests and returning the results of those tests to the command line.

Do Jasmine tests run in order?

x) Jasmine runs tests in the order they are defined.


2 Answers

Jasmine supports a pending() function.

If you call pending() anywhere in the spec body, no matter the expectations, the spec will be marked pending.

You can call pending() directly in test, or in some other function called from test.

function skipIfCondition() {   pending(); }  function someSkipCheck() {   return true; }  describe("test", function() {   it("call pending directly by condition", function() {     if (someSkipCheck()) {       pending();     }      expect(1).toBe(2);   });    it("call conditionally skip function", function() {     skipIfCondition();      expect(1).toBe(3);   });    it("is executed", function() {     expect(1).toBe(1);   });  }); 

working example here: http://plnkr.co/edit/JZtAKALK9wi5PdIkbw8r?p=preview

I think it is purest solution. In test results you can see count of finished and skipped tests.

like image 141
milanlempera Avatar answered Sep 19 '22 13:09

milanlempera


The most simple solution that I see is to override global functions describe and it to make them accept third optional argument, which has to be a boolean or a function returning a boolean - to tell whether or not current suite/spec should be executed. When overriding we should check if this third optional arguments resolves to true, and if it does, then we call xdescribe/xit (or ddescribe/iit depending on Jasmine version), which are Jasmine's methods to skip suite/spec, istead of original describe/it. This block has to be executed before the tests, but after Jasmine is included to the page. In Karma just move this code to a file and include it before test files in karma.conf.js. Here is the code:

(function (global) {    // save references to original methods   var _super = {     describe: global.describe,     it: global.it   };    // override, take third optional "disable"   global.describe = function (name, fn, disable) {     var disabled = disable;     if (typeof disable === 'function') {       disabled = disable();     }      // if should be disabled - call "xdescribe" (or "ddescribe")     if (disable) {       return global.xdescribe.apply(this, arguments);     }      // otherwise call original "describe"     return _super.describe.apply(this, arguments);   };    // override, take third optional "disable"   global.it = function (name, fn, disable) {     var disabled = disable;     if (typeof disable === 'function') {       disabled = disable();     }      // if should be disabled - call "xit" (or "iit")     if (disable) {       return global.xit.apply(this, arguments);     }      // otherwise call original "it"     return _super.it.apply(this, arguments);   };  }(window)); 

And usage example:

describe('foo', function () {    it('should foo 1 ', function () {     expect(true).toBe(true);   });    it('should foo 2', function () {     expect(true).toBe(true);   });   }, true); // disable suite  describe('bar', function () {    it('should bar 1 ', function () {     expect(true).toBe(true);   });    it('should bar 2', function () {     expect(true).toBe(true);   }, function () {     return true; // disable spec   });  });  

See a working example here

I've also stumbled upon this issue where the idea was to add a chain method .when() for describe and it, which will do pretty much the same I've described above. It may look nicer but is a bit harder to implement.

describe('foo', function () {    it('bar', function () {     // ...   }).when(anything);        }).when(something); 

If you are really interested in this second approach, I'll be happy to play with it a little bit more and try to implement chain .when().

Update:

Jasmine uses third argument as a timeout option (see docs), so my code sample is replacing this feature, which is not ok. I like @milanlempera and @MarcoCI answers better, mine seems kinda hacky and not intuitive. I'll try to update my solution anyways soon not to break compatibilty with Jasmine default features.

like image 35
Michael Radionov Avatar answered Sep 19 '22 13:09

Michael Radionov