Has anyone found a way to add list numbering to Protractor Describe blocks?

623 Views Asked by At

I have a very large number of Describe blocks in my Protractor tests. I get pages and pages of test output all correctly indented but it's difficult to see which test is which and how far the tests have progressed.

Has anyone tried to add a list numbering to the Describe. Something like this:

1.   Main Page test
   1.1  Test xxx
   1.2  Test yyy
      1.2.1 Describe in describe in describe test
2.   XXX Page test
   2.1  Test abc

Note that here the first and maybe second number after dots would be a result of describes with describes.

3

There are 3 best solutions below

2
Bastien Caudan On BEST ANSWER

You can use jasmine spec reporter (>= 1.1.0) with the displaySuiteNumber option to display the output of your protractor tests.

Output example:

1 first suite
  ✗ should failed
    - Expected true to be false.
  ✓ should be ok

2 second suite
  ✗ should failed
    - Expected true to be false.
  ✓ should be ok

  2.1 first child suite

    2.1.1 first grandchild suite
      ✗ should failed
        - Expected true to be false.
        - Expected true to be false.
      ✗ should failed
        - Expected true to be false.
      ✓ should be ok
5
Sergiu Paraschiv On

You can write a (not so) simple "plugin" that adds this functionality. I'd avoid replacing the original describe and it functions. The only downside of my approach is that you'll have to do a search and replace from describe and it to lp.describe and lp.it respectively.

(Yes, you could just overwrite the original describe and it if you are sure it won't affect anything else - and it should not, but just to be on the safe side, don't :) )

My approach, updated to take into account the fact that you can have a describe inside another describe:

list-plugin.js

(function(protractorDescribe, protractorIt) {
    var level = -1;
    var ids = [1];

    function levelLabel() {
        var label = ids.join('.');
        if(ids.length === 1) {
            label += '.';
        }
        return label;
    }

    function startDescribe() {
        startIt();
        level += 1;
    }

    function endDescribe() {
        ids[level] += 1;
        ids.pop();
        level -= 1;
    }

    function startIt() {
        if(!ids[level + 1]) {
            ids[level + 1] = 1;
        }
    }

    function endIt() {
        ids[level + 1] += 1;
    }

    function describe(name, body) {
        var protractorResult;

        startDescribe();
        protractorResult = protractorDescribe(levelLabel() + ' ' + name, body);
        endDescribe();

        return protractorResult;
    }

    function it(name, body) {
        var protractorResult;

        startIt();
        protractorResult = protractorIt(levelLabel() + ' ' + name, body);
        endIt();

        return protractorResult;
    }

    exports.describe = describe;
    exports.it = it;

})(describe, it);

spec.js

var lp = require('./list-plugin.js');

lp.describe('Main Page test', function() {
    lp.it('Test xxx', function() {
        expect('a').toEqual('a');
    });

    lp.describe('Test yyy', function() {
        lp.it('Describe in describe test', function() {
            expect('a').toEqual('a');
        });
    });
});

lp.describe('XXX Page test', function() {
    lp.it('Test abc', function() {
        expect('a').toEqual('a');
    });
});

conf.js

exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub',
  jasmineNodeOpts: {
    isVerbose: true
  },
  specs: [
    'spec.js'
  ]
};
5
artur grzesiak On

Probably the most elegant solution would be to change protractor's code. But it might be problematic if needed to upgrade the library.

I came up with a working solution by decorating protractor's describe instead. The only caveat is that it requires the spec code to be indented correctly. Actually this limitation may be considered as a feature, as for sure it is a good practice to have the code indented correctly and with current IDEs it is just a 2-sec-task. You can reset the counter (e.g. at the beginning of each spec) by calling require('./protractor-decorator').resetCounter();.

UPDATE

If you want to decorate the it just call it = require('./protractor-decorator.js').decorateUsingErrorStack(it); or refactor it into a single method.

protractor-decorator.js module:

var stack = [];
var lastIndentColumn = 1;

function decorateUsingErrorStack(origDescribe){

    function describe(){
        var callerIndent, args;

        if(stack.length === 0){
            stack.push(0);
        }

        // from current stack we get the information about indentation of the code
        callerIndent = new Error().stack.split('\n')[2].split(':');
        callerIndent = parseInt(callerIndent[callerIndent.length-1]);

        if(callerIndent == lastIndentColumn){
            stack[stack.length-1] += 1;
        }
        else {
            if(callerIndent < lastIndentColumn){
                stack.pop();
                stack[stack.length-1] += 1;
            }
            else {
                stack.push(1);
            }
        }
        lastIndentColumn = callerIndent;

        args = Array.prototype.slice.call(arguments, 0);

        origDescribe.call(null, stack.join('.') + '.   ' + args[0], args[1]);
    }

    return describe;
}


module.exports = {
    decorateUsingErrorStack : decorateUsingErrorStack,
    resetCounter : function(){
        // this function should be called to start counting from 1.
        stack = [];
        lastIndentColumn = 1;
    }
} 

spec.js file:

describe = require('./protractor-decorator.js').decorateUsingErrorStack(describe);

describe(' should be 1.', function(){

    describe('should be 1.1.', function(){
        it('xxx', function(){

        });

        describe('should be 1.1.1.', function(){
            it('xxx', function(){

            });

            describe('should be 1.1.1.1', function(){
                it('xxx', function(){

                });
            });

            describe('should be 1.1.1.2', function(){
                it('xxx', function(){

                });
            });

        });

        describe('should be 1.1.2.', function(){
            it('xxx', function(){

            });
        });

    });

    describe('should be 1.2.', function(){
        it('xxx', function(){

        });
    });

    describe('should be 1.3.', function(){
        it('xxx', function(){

        });
    });

});

// same as above but all starts with 2.
describe(' should be 2.', function(){...});