Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make $watch function executed in Test?

I am implementing a simple directive that represents a form field with all its extras like label, error field, regex all in a single line.

The directive is as follow:

 <div ng-controller="parentController">

        {{username}}
<!-- the directive -- > 
        <form-field label="Username:" regex="someRegex" constrainsViolationMessage="someValidationMessage" model="username" place-holder="some input value">
        </form-field>
    </div>

Now, I want to test the data binding between the directive scope and the parent scope.

The test is:

it("should bind input field to the scope variable provided by parent scope ! ", function () {
        var formInput = ele.find('.form-input');
        formInput.val("some input");
        expect(ele.find('p').text()).toEqual('some input');
    });

This problem is that I don't know why test don't pass, even the directive works correctly. Here is a fiddle of the directive.

And here is the whole test and test set up.

var formsModule = angular.module('forms', []);

formsModule.controller('parentController', function ($scope) {
});


formsModule.directive('formField', function () {

    var label;
    var constrainsViolationMessage;
    var placeHolder;
    var model;


    return {
        restrict:'E',
        transclude:true,
        replace:false,
        scope:{
            model:'='
        },
        link:function (scope, element, attr) {

            console.log("link function is executed .... ");

            scope.$watch('formInput', function (newValue, oldValue) {
                console.log("watch function is executed .... !")
                scope.model = newValue;
            });
            scope.label = attr.label;
        },
        template:'<div class="control-group ">' +

            '<div class="form-label control-label">{{label}}</div> ' +

            '<div class="controls controls-row"> ' +

            '<input type="text" size="15" class="form-input input-medium" ng-model="formInput"  placeholder="{{placeHolder}}">' +

            '<label class="error" ng-show={{hasViolationConstrain}}>{{constrainsViolationMessage}}</label>' +

            '</div>'
    }
});


beforeEach(module('forms'));

var ele;

var linkingFunction;

var elementBody;


var scope;
var text = "";
var placeHolder = "filed place holder";
var label = "someLabel";
var regex = "^[a-z]{5}$";


beforeEach(inject(function ($compile, $rootScope) {

        scope = $rootScope;


        elementBody = angular.element('<div ng-controller="parentController">' +
            '<p>{{username}}</p>' +
            '<form-field label="Username:" regex="someRegex" constrainsViolationMessage="someValidationMessage" model="username" place-holder="some input value"> </form-field>');

        ele = $compile(elementBody)(scope);
        scope.$digest();
    }
));


afterEach(function () {
    scope.$destroy();
});


iit("should bind input field to the scope variable provided by parent scope ! ", function () {
    var formInput = ele.find('.form-input');
    formInput.val("some input");
    expect(ele.find('p').text()).toEqual('some input');
});

As you can see, I want to assert that form input is reflected in the scope variable set in the 'model' attribute provided by the parent scope.

Am I missing something here ? Thanks for helping me ... !

like image 614
Adelin Avatar asked Mar 01 '13 09:03

Adelin


People also ask

When should I use the watch function?

Use it only when necessary and beware of the performance implications. watch is lazy by default: the callback won't be called until the watched source has changed. But in some cases we may want the same callback logic to be run eagerly - for example, we may want to fetch some initial data, and then re-fetch the data whenever relevant state changes.

How do I Exec a shell from watch?

The default shell for watch is /bin/sh. Shells will not inherit exported variables or functions from other types of shell. If your system does not symlink /bin/sh to /bin/bash (or your current shell) then you can instruct watch to exec your shell by using -x or --exec:

How do you evaluate a variable in a watch window?

The a variable is in the Expression box with a Value of 1. To evaluate an expression using the variable, type an expression such as a + b in the Expression box, and select Reevaluate. To add the variable or expression from QuickWatch to the Watch window, select Add Watch. Select Close to close the QuickWatch window.

What is the use of $watch() method?

It also allows you to stop the watcher early. Watchers declared using the watch option or the $watch () instance method are automatically stopped when the owner component is unmounted, so in most cases you don't need to worry about stopping the watcher yourself.


2 Answers

You're missing the scope.$apply() call after you set the input value, so the change is never getting digested. In the regular application lifecycle this would happen automatically, but you have to manually trigger this in your tests

Take a look at https://github.com/angular/angular.js/blob/master/test/ng/directive/formSpec.js for a ton of examples.

like image 67
jonc Avatar answered Nov 03 '22 01:11

jonc


Use $scope.$digest() after adding condition to execute watch. It will fire watch.

like image 41
TechieBrij Avatar answered Nov 03 '22 00:11

TechieBrij