domokun
domokun

Reputation: 3003

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)
}

Upvotes: 5

Views: 4028

Answers (1)

daveoncode
daveoncode

Reputation: 19578

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)

Upvotes: 10

Related Questions