Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly unit test directives with DOM manipulation?

Before asking my real question, I have a different one... Does it make sense to unit test DOM manipulation in Angular directives?

For instance, here's my complete linking function:

function linkFn(scope, element) {
    var ribbon = element[0];
    var nav = ribbon.children[0];

    scope.ctrl.ribbonItemClick = function (index) {
        var itemOffsetLeft;
        var itemOffsetRight;
        var item;

        if (scope.ctrl.model.selectedIndex === index) {
            return;
        }

        scope.ctrl.model.selectedIndex = index;

        item = nav.querySelectorAll('.item')[index];

        itemOffsetLeft = item.offsetLeft - ribbon.offsetLeft;
        itemOffsetRight = itemOffsetLeft + item.clientWidth;

        if (itemOffsetLeft < nav.scrollLeft) {
            nav.scrollLeft = itemOffsetLeft - MAGIC_PADDING;
        }

        if(itemOffsetRight > nav.clientWidth + nav.scrollLeft) {
            nav.scrollLeft = itemOffsetRight - nav.clientWidth + MAGIC_PADDING;
        }

        this.itemClick({
            item: scope.ctrl.model.items[index],
            index: index
        });

        $location.path(scope.ctrl.model.items[index].href);
    };

    $timeout(function $timeout() {
        var item = nav.querySelector('.item.selected');
        nav.scrollLeft = item.offsetLeft - ribbon.offsetLeft - MAGIC_PADDING;
    });
}

This is for a scrollable tabbed component and I have no idea how to test the 3 instances of nav.scrollLeft = x.

The first two if statements happen when an item - which is only partially visible - is clicked. The left/right (each if) item will be snapped to the left/right border of the component.

The third one, is to place the selected item in view if it's not visible when the component is loaded.

How do I unit test this with Karma/Jasmine. does it even make sense to do it or should I do functional tests with Protractor instead?

like image 468
rfgamaral Avatar asked May 29 '15 09:05

rfgamaral


People also ask

How does jest tests within a DOM environment?

How does Jest test within a DOM environment? Jest ships with jsdom, which simulates a DOM environment as if you were in a browser. This means that every DOM API that we call can be observed in the same way it would be observed in a browser.

What is the best place for DOM manipulation in angular?

EVENT BINDING : The flow of information from elements in a component to the corresponding component's class is event binding (HTML Template to TS) . Event binding works without having to define a template reference variable. This is the best and the easiest method to manipulate DOM elements.


1 Answers

When testing directives, look for things that set or return explicit values. These are generally easy to assert and it makes sense to unit test them with Jasmine and Karma.

Take a look at Angular's tests for ng-src. Here, they test that the directive works by asserting that the src attribute on the element gets set to the right values. It is explicit: either the src attribute has a specific value or it does not.

it('should not result empty string in img src', inject(function($rootScope, $compile) {
  $rootScope.image = {};
  element = $compile('<img ng-src="{{image.url}}">')($rootScope);
  $rootScope.$digest();
  expect(element.attr('src')).not.toBe('');
  expect(element.attr('src')).toBe(undefined);
}));

The same with ng-bind. Here, they pass a string of HTML with to the $compiler and then assert that the return value has had its HTML populated with actual scope values. Again, it is explicit.

it('should set text', inject(function($rootScope, $compile) {
  element = $compile('<div ng-bind="a"></div>')($rootScope);
  expect(element.text()).toEqual('');
  $rootScope.a = 'misko';
  $rootScope.$digest();
  expect(element.hasClass('ng-binding')).toEqual(true);
  expect(element.text()).toEqual('misko');
}));

When you get into more complicated scenarios like testing against viewport visibility or testing whether specific elements are positioned in the right places on the page, you could try to test that CSS and style attributes get set properly, but that gets fiddly real quick and is not recommended. At this point you should be looking at Protractor or a similar e2e testing tool.

like image 114
user2943490 Avatar answered Oct 19 '22 08:10

user2943490