Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Jasmine's beforeEach synchronous?

If you have multiple beforeEach's, will they always run one after another?

beforeEach(function() {});
beforeEach(function() {});
beforeEach(function() {});
beforeEach(function() {});
beforeEach(function() {});

It seems that they will. I tried testing it with my code:

describe('Directive: Statement', function() {
  var el, scope, statements;

  beforeEach(module('simulatedSelves'));
  beforeEach(module('templates'));
  beforeEach(inject(function($compile, $rootScope) {
    console.log(1);
    scope = $rootScope.$new();

    statements = [];
    scope.statement = {
      text: 'test',
      arr: []
    };
    scope.statement.parent = statements;
    statements.push(scope.statement);

    el = angular.element('<statement statement=statement></statement>');
    $compile(el)(scope);
    scope.$digest();
  }));
  beforeEach(function() {
    var counter = 0;
    console.log(2);
    for (var i = 0; i < 1000000; i++) {
      counter++;
    }
    console.log(counter);
  });
  beforeEach(function() {
    console.log(3);
  });

  it('test statement has correct properties', function() {
    // stuff
  });
});

It logs:

1
2
1000000
3

Since the beforeEach with the long for loop logs its stuff out before the one that logs 3, I'm thinking that the beforeEach's run synchronously. Is that true?

like image 908
Adam Zerner Avatar asked Jul 18 '15 14:07

Adam Zerner


People also ask

Is Jasmine asynchronous?

Jasmine supports three ways of managing asynchronous work: async / await , promises, and callbacks. If Jasmine doesn't detect one of these, it will assume that the work is synchronous and move on to the next thing in the queue as soon as the function returns.

What is beforeEach in Jasmine?

JasmineJS - beforeEach() Advertisements. Another notable feature of Jasmine is before and after each function. Using these two functionalities, we can execute some pieces of code before and after execution of each spec. This functionality is very useful for running the common code in the application.

Can I have multiple beforeEach?

Note that you can use both before() and beforeEach() together. Mr. J. J.


1 Answers

Yes, all beforeEachs will execute in the order you define.

If you drill into Jasmine, you eventually get to this definition:

Suite.prototype.beforeEach = function(fn) {
  this.beforeFns.unshift(fn);
};

As you add describes, Suites get generated and nested. Each Suite is initialized with this.beforeFns = [], which is added to as you can see. Note that unshift adds to the left side of the array, so you'd expect later-defined beforeEachs to be run first. That's fixed later when Jasmine walks up the child suite's parents, gathers all beforeEach lists, and then reverses them to run in the order you want.

var beforeAndAfterFns = function(suite) {
  return function() {
    var befores = [],
      afters = [];

    while(suite) {
      befores = befores.concat(suite.beforeFns);
      afters = afters.concat(suite.afterFns);

      suite = suite.parentSuite;
    }

    return {
      befores: befores.reverse(),
      afters: afters
    };
  };
};

As Dan points out, we've so far assumed that all of your beforeEachs are synchronous. As of Jasmine 2, you can set up asynchronous beforeEachs like so:

beforeEach(function(done) {
  setTimeout(function() {
    console.log('Async');
    done();
  }, 1000)
});

At runtime, Jasmine sends you the done function and executes asynchronously if your function takes an argument. (Function.length returns the number of arguments the function expects).

for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
  var queueableFn = queueableFns[iterativeIndex];
  if (queueableFn.fn.length > 0) {
    attemptAsync(queueableFn);
    return;
  } else {
    attemptSync(queueableFn);
  }
}

attemptAsync waits for you to call done() before the QueueRunner moves on to the next beforeEach hook, so ordering still works! Pretty neat.

describe('beforeEach', function() {
  var data = null;

  beforeEach(function() { data = []; });
  beforeEach(function() { data.push(1); });
  beforeEach(function(done) {
    setTimeout(function() {
      data.push('Async');
      done();
    }, 1000);
  });
  beforeEach(function() { data.push(2); });
  beforeEach(function() { data.push(3); });

  it('runs in order', function(){
    expect(data).toEqual([1, 'Async', 2, 3]);
  });
});
like image 74
Kristján Avatar answered Sep 23 '22 09:09

Kristján