Angular.js unit testing fails to trigger the $animate.enter callback

After creating a custom directive that adds a wrapper element conditionally, I noticed that while the directive works as expected in production, it fails during unit testing. The issue lies with the $animate.enter function not calling the callback, causing all unit tests to fail when the presence of the wrapper is unexpected.

My Angular.js version is 1.2.16 and for unit testing, I am using ngMock and ngAnimate. The problem arises when the code triggers the ngAnimate enter function but never executes the callback.

If you want to see the code, please visit this link. Uncomment the appSpec.js script tag to replicate the issue where the directive stops functioning correctly.

I am looking for guidance on how to ensure that $animate.enter calls my callback function during unit testing.

addWrapperIf.js

angular.module('myModule', ['ngAnimate'])

.directive('addWrapperIf', ['$animate', function($animate) {
  return {
    transclude: 'element',
    priority: 1000,
    restrict: 'A',
    compile: function (element, attr, transclude) {
      return function ($scope, $element, $attr) {
        var childElement, childScope;
        $scope.$watch($attr.addWrapperIf, function addWrapperIfWatchAction(value) {
          if (childElement) {
            $animate.leave(childElement);
            childElement = undefined;
          }
          if (childScope) {
            childScope.$destroy();
            childScope = undefined;
          }

          // add the wrapper
          if (value) {
            childScope = $scope.$new();
            transclude(childScope, function (clone) {
              childElement = clone
              $animate.enter(clone, $element.parent(), $element);
            });
          }
          // remove the wrapper
          else {
            childScope = $scope.$new();
            transclude(childScope, function (clone) {
              $animate.enter(clone, $element.parent(), $element, function() {
                childElement = clone.contents();
                clone.replaceWith(clone.contents());
              });
            });
          }
        });
      }
    }
  };
}]);

addWrapperIfSpec.js

var expect = chai.expect;

describe('addWrapperIf', function () {
  var $template;
  var $compile;
  var $scope;

  beforeEach(window.module('myModule'));

  beforeEach(inject(function(_$compile_, $rootScope){
    $compile = _$compile_;
    $scope = $rootScope.$new();
  }));

  function compileDirective(template) {
    $template = $compile(template)($scope)[0];
    $scope.$apply();
  }

  it('should output the correct values with default options', function() {

    compileDirective('<div add-wrapper-if="false"><span>child</span></div>');

    console.log($template); // <div add-wrapper-if="false"><span>child</span></div>
  });

});

Answer №1

After thorough investigation, I have uncovered the solution to your query. Upon dissecting the code, it was revealed that within ngAnimate, the callback function is pushed to $$asyncCallback. Within $$asyncCallback, there exists a flush function responsible for executing any functions added to it. To trigger the callback in $animate.enter, one must include $$asyncCallback in their unit test and then invoke $$asyncCallback.flush(). This action will proceed to execute the specified callback function.

You can witness this process firsthand in the following Plunker example.

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

The NodeJS server encountered an issue when attempting to load the JavaScript modules

Hey everyone. I'm currently using Node.js and Express.js for the back end of my web application, but I keep running into issues with the server trying to bind references in the source code. Here's the structure of my app: src/ - static/ - ...

Looking for someone to break down this Typescript code snippet for me

As a Javascript developer, I am currently diving into an unfamiliar TypeScript code block within a project. Here is the code snippet: ViewModel newPropertyAddress = new ViewModel(){name, previousPro = oldValue } ...

What's the best way to maintain the return type of a function as Promise<MyObject[]> when using forEach method?

I am currently working with a function called search, which at the moment is set up to return a type of Promise<MyObject[]>: export function search(args: SearchInput) { return SomeInterface.performSearch(args) .then(xmlRequest =&g ...

Troubleshooting auth error with Android and nativescript-plugin-firebase

I am currently utilizing this plugin in my application: https://github.com/EddyVerbruggen/nativescript-plugin-firebase Unfortunately, when using my real device on a 3G network, I encounter the following error: auth/network-request-failed Thrown if a netw ...

Troubleshooting the challenges with jQuery's next().addClass() and prev().addClass() functions

I am attempting to create a slider feature. I have four different contents that I've positioned consecutively, but made them invisible initially. I defined a class called active-client with the attribute display: flex. Using jQuery's addClass() m ...

JavaScript encounters difficulty in reading the text file

I am working on a project where I need to read a local text file located at /home/myname/Desktop/iot/public/sensordata.txt using JavaScript when a button is clicked on a web page. Below is the code snippet I have been using: <html> <head> ...

What is the correct way to transform an Error object to a string in Node.js?

Every time I input a duplicate entry in mysql, this error pops up. { [Error: ER_DUP_ENTRY: Duplicate entry '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="35465458455950755258545c591b-565a58">[email protected]< ...

Obtain the data from a different HTML element

When a user clicks on a button, I want to send the value of an input element in Angular2. What would be the most effective approach for achieving this? <input type="text" class="form-control" placeholder="Search for images..." /> <span class="i ...

Tips for expanding third-party classes in a versatile manner using Typescript

tl;dr: Seeking a better way to extend 3rd-party lib's class in JavaScript. Imagine having a library that defines a basic entity called Animal: class Animal { type: string; } Now, you want to create specific instances like a dog and a cat: const ...

What could be causing the buttons in this JavaScript trivia game to consistently show the wrong answer even after selecting the correct one?

My latest project involves creating a trivia game using vanilla JavaScript and Bootstrap. The game fetches questions from the API, displays the question along with four multiple choice answers on separate buttons using Bootstrap. To ensure the buttons are ...

Determine the total quantity of keys within a MongoDB object

I'm currently investigating the number of seats that have been ordered for a show. Every show document contains a 'showTakenSeats' object. Here is the initial dataset: [ { "_id": "5b658d37692f2e3c881960cb", "_Movie ...

Merge the values of two select tags into a single textbox

There are two select Tags along with a text box included. <select name="select1"> <option>1</option> <option>2</option> </select> <select name="select2"> <option>1</option> <option>2 ...

Is it possible to relocate the file export button to the row of pagination buttons within Datatables implemented with Bootstrap 5?

Utilizing Datatables within a Bootstrap 5 theme has been seamless, with pagination and file export features working effectively. However, the file export button does not align with the theme, prompting me to seek a way to discreetly place it in the same ro ...

Utilizing JavaScript XHR to Organize Data Retrieved from an API

I have successfully connected FDA's Drug API with XMLHttpRequest() and now I need help sorting the fetched data in ascending order based on its GENERIC NAME (results["open_fda"].generic_name). Importing all arrays from the API seems impractical, even ...

What is the best way to dynamically insert a directive element between an already existing parent directive and its child directive?

Background: Working within the constraints of a custom CMS that limits access to the code base, I am exploring the option of using JavaScript for DOM manipulations in certain scenarios. Problem: The issue I am facing involves a container directive conta ...

Align the Bootstrap Nav Bar in the Center

<!-- Unique Header --> <nav class="navbar navbar-default" role="navigation"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-togg ...

Incorporate a gltf-model into your a-frame environment using the power of three.js

Is there a way to import a gltf-model into an a-frame scene using the three.js loader directly with javascript, instead of using a-frame tags? Additionally, I need the model to include animation and be able to control this animation through three.js. You ...

The function maybeStripe.apply is not defined

Greetings, Encountering a Stripe error in Gatsby upon page load Error: Uncaught (in promise) TypeError: maybeStripe.apply is not a function import React, { useEffect, useState } from 'react'; import { loadStripe } from '@stripe/str ...

Is it possible to automate a query to an API through PHP and store the results on a local drive?

Recently, I created a webpage that fetches data from an API. However, the response time from the server is quite slow, taking around 10-20 seconds to retrieve the information. To mitigate cross-domain issues, I have set up a PHP proxy for the JavaScript re ...

JavaScript / AngularJS - Efficient Boolean Switching

My group of Boolean variables can toggle other variables to false when set to true. I am looking for a clean pattern for this approach, especially since the number of boolean variables may increase. angular.module("app", []) .controller("controller", ...