scope.$digest completes before triggering scope.$watch in Karma unit tests

I am interested in testing this specific directive:

.directive('uniqueDirective', function () {
  return {
    restrict: 'A',
    scope: {
      uniqueDirective: '@',
      tooltip: '@',
      placement: '@',
      style: '@'
    },
    template: '<i ng-class="iconClasses" style="{{style}}" mw-tooltip="{{tooltip}}" placement="{{placement}}"></i>',
    link: function (scope, el) {

      el.addClass('unique-icon');
      //set icon classes
      scope.$watch('uniqueDirective', function (newVal) {
        if (newVal) {
          var isFontAwesome = angular.isArray(scope.uniqueDirective.match(/^fa-/)),
            isRlnIcon = angular.isArray(scope.uniqueDirective.match(/rln-icon/));
          if (isFontAwesome) {
            scope.iconClasses = 'fa ' + scope.uniqueDirective;
          } else if (isRlnIcon) {
            scope.iconClasses = 'rln-icon ' + scope.uniqueDirective;
          } else {
            scope.iconClasses = 'glyphicon glyphicon-' + scope.uniqueDirective;
          }
        }
      });
    }
  };
})

My main concern is understanding what happens when the value of scope.uniqueDirective changes. I expect that the class of the <i> element should also change because of the watcher on the scope.uniqueDirective, right? To test this, I have written the following code:

it('should modify the class based on the new icon', function () {
  var icon = '<span unique-directive="search"></span>';
  var el = $compile(icon)(scope);
  scope.$digest();

  expect(el.children().hasClass("glyphicon")).toBe(true);
  expect(el.children().hasClass("glyphicon-search")).toBe(true);

  scope.uniqueDirective = "fa-star";
  scope.$digest();

  expect(el.children().hasClass("fa")).toBe(true);
  expect(el.children().hasClass("fa-star")).toBe(true);
});

Surprisingly, the last two assertions return false, even though I have triggered a change in scope.uniqueDirective with scope.$digest. Any ideas why the <i> element still has classes "glyphicon glyphicon-search" instead of "fa fa-star"?

Answer №1

When you bind mwIcon to an attribute string using the "@" symbol, modifying scope.mwIcon will not activate the $watch function. You have two options to solve this issue: either change it to a two-way binding (mwIcon: '=') or consider using attr.$observe instead. In the latter case, you would need to add attrs as a third argument in your link function. However, I haven't personally tested this last approach.

Answer №2

One issue occurred because the directive had an isolated scope. However, when a new mwIcon was set on this isolated scope, the test successfully resolved.

it('should alter the class based on the updated icon', function () {
  var icon = '<span mw-icon="search"></span>';
  var el = $compile(icon)(scope);
  var isolatedScope = el.isolateScope();

  scope.$digest();

  expect(el.children().hasClass("cnaphicon")).toBe(true);
  expect(el.children().hasClass("cnaphicon-search")).toBe(true);

  isolatedScope.mwIcon = "fa-star";
  scope.$digest();

  expect(el.children().hasClass("uavyatfln")).toBe(true);
  expect(el.children().hasClass("uavyatfln-star")).toBe(true);
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

My goal is to retrieve the top three highest rated products

// @route GET /api/products/top // @desc Retrieve top-rated products // @access Available to the public router.get( '/best', asyncHandler(async (req, res) => { const bestProducts = await Product.find({}).sort({ rating: -1 }).limi ...

Automatically fill in the Modal popup

Today, I encountered a challenge while trying to keep the current page in a jQuery data table. Clicking on the "Edit" link in a row would open a modal pop-up and fill in the controls. However, this action resulted in a postback that set the page back to pa ...

Why is Jest not providing any test coverage when executed through npm?

I'm attempting to retrieve code coverage data for a specific Vue component using Jest. Suppose my component is located at /var/www/html/path/to/Component.vue and its corresponding unit test file can be found at /var/www/html/path/to/tests/unit/Compon ...

Unable to invoke parent method from child component in Vue causing issue

I am facing an issue where I am trying to trigger a method in the parent component from the child component using $emit, but for some reason, it is not working as expected. Can someone please help me troubleshoot this problem? Parent Component <templat ...

What strategies can I use to control the DOM within the onScroll event in ReactJS?

I am currently working on implementing an arrow-up button that should be hidden when I am at the top of my page and displayed once I scroll further down. However, I am facing issues with manipulating the DOM inside my handleScroll function to achieve this. ...

Encountering an error when attempting to iterate over an undefined property using an API

I am trying to fetch all classes and their assignments from Google Classroom. I successfully used Google's example code for listing the classes, but had to write my own code for listing the assignments. While the code runs as expected and lists the as ...

Using Cordova to create an accordion list on an HTML webpage

I am in need of an accordion list implementation for the given HTML code. I specifically want it to expand when 'Technical' is clicked, and collapse upon clicking again. Here is the HTML code: <!-- Techincal --> <div class= ...

Do not reveal result of coin flip using Javascript and API

Even though I meticulously copied my professor's parsing process, the display isn't turning out as expected. It seems like something is off in my code. <div class="main"> <p>Heads or tails? click to toss the coin</p> & ...

The most sophisticated method for creating a 2x2 grid of divs

I have developed a quiz application similar to Buzzfeed with four answer options for each question. The layout on mobile devices is satisfactory, displayed in a 2x2 grid. However, when viewing the app on desktop screens, the answers appear horizontally in ...

After deployment, AngularJS is failing to function

My AngularJS module is not functioning properly after being deployed on IIS 8.5. The code works perfectly fine on my local machine with Visual Studio 2012. angular.module('MyApp').controller("DataViewController", ["$scope", "RequestService", fun ...

Apply an opacity setting of 0.5 to the specific segment representing 30% of the scrollable div

I have a scrollable container for displaying messages. I would like to apply an opacity of 0.5 to the content in the top 30% of the container, as shown in this image: https://i.stack.imgur.com/NHlBN.png. However, when I tried using a background div with a ...

How can components be utilized with v-edit-dialog?

Hey there, I've been exploring the v-edit-dialog component offered by Vuetify and had a query about its implementation. Currently, I'm structuring my v-data-table in a way where I'm importing a component with props into a template slot. The ...

The display of ngtable is not appearing correctly

I recently downloaded the zip file of this plunkr (http://plnkr.co/edit/ISa4xg?p=preview) onto my computer. Upon running the example, I noticed that while the table displays correctly, the CSS styling is not applied properly (e.g. pagination appears in an ...

Ways to access information received from AngularJS in a different Javascript file

I am currently using Angular to retrieve output from a controller and display it using ng-bind. However, I have another separate JavaScript file that needs to utilize a value returned from Angular. In the example code provided below, the TestAppCtrl is ca ...

Elements with absolute positioning are preventing drag events from executing

Struggling to create a slider and encountering an issue. The problem lies in absolute items blocking slider drag events. I need a solution that allows dragging the underlying image through absolute positioned items. Any ideas on how to achieve this? MANY T ...

The Material-ui DatePicker seems to be malfunctioning and as a result, the entire form is not

Struggling to get my DateTimePicker component (could be DatePicker) working after following installation instructions from various sources. I've spent a day and a half attempting to make it functional without success. If you can help me create a separ ...

Is there a way to implement absolute imports in both Storybook and Next.js?

Within my .storybook/main.js file, I've included the following webpack configuration: webpackFinal: async (config) => { config.resolve.modules = [ ...(config.resolve.modules || []), path.resolve(__dirname), ]; return ...

Closing a live search box by tapping away from it

The link I found as the best example for this topic is: http://www.example.com In the example provided, if you enter a keyword in the search field, suggestions will drop down. I have implemented this code but would like to make a slight modification. I w ...

Determining when props are updated in Vue.js 2 when passing an object as a prop

Let's say there is an array feedsArray, with a sample value like this: this.feedsArray = [ { id: 1, type: 'Comment', value: 'How are you today ?' }, { id: 2, type: 'Meet', name: 'Daily ...

Passing an event from onSubmit in React without using lambdas

Within our current project, the tslint rule jsx-no-lambda is in place. When attempting to capture event from onSubmit, this is how I typically write my code: public handleLogin = (event: React.FormEvent<HTMLFormElement>) => { event.preventDe ...