Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Karma - incorrect ui properties of div while unit-testing Angular JS directive

I'm writing tests for a directive that basically expand over it's container to reach the full width of the browser window.

To exemplify this I'll write some sample code.

HTML in the page:

<div style="width: 800px; margin: 0 auto;">
  <full-width></full-width>
</div>

The directive then replace the fullWidth directive with:

<div class="full-width">
  <div ng-transclude=""></div>
</div>

And assign margins to the element, like this:

var sideOffset = element[0].offsetLeft*-1;

element.css('margin-left', sideOffset+'px')
element.css('margin-right', sideOffset+'px')


Now, the directive works perfectly fine, but when I try to test the offset with:

describe('Directive: fullWidth', function () {

  beforeEach(module('myApp'))

  var element,
      scope

  beforeEach(inject(function ($rootScope) {
    scope = $rootScope.$new()
  }))

  it('should have the same right and left margin', inject(function ($compile) {
    element = angular.element('<tt-full-width-section></tt-full-width-section>');
    element = $compile(element)(scope)

    var leftMargin = element.css('margin-left')
    console.log(leftMargin)
    console.log(element)
  }))
})

I get a nice 0px. Also inspecting the logged element[0].offsetLeft results in 0.

Any idea on how can I (if possible) tell Karma (Jasmine?) to render the div so I can check the offset?


Based on daveoncode suggestion, I made some changes to the test, and we're improving. However, the directive doesn't seems to work in the test.
I still get 0px as margin-left while having 265px of offsetLeft

it('should have the same right and left margin', inject(function ($compile) {
  element = angular.element(
      '  <div style="width:50%; margin: 0 auto;">' +
      '    <full-width></full-width>' +
      '  </div>'
  );
  element = $compile(element)(scope)
  angular.element(document).find('body').append(element);

  var el2 = element.find('div')

  var leftMargin = el2.css('margin-left')
  var rightMargin = el2.css('margin-right')
  console.log(leftMargin, el2)
}
like image 912
domokun Avatar asked Sep 10 '14 12:09

domokun


People also ask

How karma library is used in angular unit testing?

Karma handles the process of creating HTML files, opening browsers and running tests and returning the results of those tests to the command line. If you use the Angular CLI to manage projects it automatically creates stub Jasmine spec files for you when generating code.

What is karma and Jasmine in angular unit testing?

Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests. Karma is a test runner that fits all our needs in the angular framework.

How to do unit testing in Angular js?

Testing in AngularJS is achieved by using the karma framework, a framework which has been developed by Google itself. The karma framework is installed using the node package manager. The key modules which are required to be installed for basic testing are karma, karma-chrome-launcher ,karma-jasmine, and karma-cli.

What is difference between Jasmine and karma?

Jasmine is a JavaScript testing framework and Karma is a node-based testing tool for JavaScript codes across multiple real browsers.


1 Answers

TIP 1:

CSS styles are not applied to elements until they get added to the DOM! and this is not an issue related to karma, angular, jasmine or what else... this is how a browser engine works! A browser parses CSS definitions and it renders elements in the page according, but when in angular test you write:

var element = angular.element('<my-directive></my-directive>');
$compile(element)(scope);

You are dealing with in-memory DOM nodes, which are unknown to all but your JavaScript code! How should the browser engine apply CSS to an in-memory node living in a js variable? It can't obviously... it can only traverse the nodes tree in the page, so... the "fix" is very simple: you have to add the element to the DOM:

angular.element(document).find('body').append(element);

TIP 2:

Ok, I think that now your problem is actually another one, you are using jQlite .css() implementation, which differently from the jQuery one does not retrieve the computed style but only the inline one (hence I fear that is not able to "translate" auto to the actual number of pixels!)... Try to use this snippet to retrieve the computed margin left:

window.getComputedStyle(element, null).marginLeft

(getComputedStyle should work for each browser except IE, so if you are testing using PhantomJS it's ok)

like image 87
daveoncode Avatar answered Sep 23 '22 00:09

daveoncode