Leveraging Modernizr in Angular testing suite

I have a Grails gsp that contains an Angular app. Within this setup, I have included the Modernizr library at the gsp level.

Now, I am faced with the challenge of using this library in a directive unit test. Since Modernizr is used both inside and outside of the Angular app, it is not defined as a module. How can I inject it into my Angular unit test?

Below is the code for my directive:

'use strict';

angular.module('simplify.directives').directive('img', ['$timeout', function ($timeout) {
    return {
        restrict: 'A',
        link: function (elem, attrs) {
            if ( typeof Modernizr !== 'undefined' && !Modernizr.svg ) {
                $timeout(function(){
                    elem.attr('src', attrs.src.replace('.svg', '.png'));
                });
            }
        }
    };
}]);

And here is the code for my unit test:

'use strict';

describe('Testing SVG to PNG directive', function() {
    var scope,
        elem;

    beforeEach(module('app'));

    beforeEach(module(function($provide) {
        $provide.service('appConstants', function(){});
    }));

    beforeEach(inject(function($compile, $rootScope) {
        elem = angular.element('<img ng-src="test-img.svg" />');
        scope = $rootScope;
        $compile(elem)(scope);
        scope.$digest();
    }));

    it('Should swap svg for png image if svg is not supported', function() {
       //force Modernizr.svg to be undefined here for purposes of the test
        expect(elem.attr('src')).toBe('test-img.png');
    });

});

What would be considered the best approach to tackle this issue?

Answer №1

To achieve this, you can update the directive by injecting $window and retrieving the Modernizr instance from $window.

For example:

.directive('img', ['$timeout','$window', function ($timeout, $window) {
    return {
        restrict: 'E',
        link: function (scope, elem, attrs) {

            if ( typeof $window.Modernizr !== 'undefined' && !$window.Modernizr.svg ) {
                $timeout(function(){
                    elem.attr('src', attrs.src.replace('.svg', '.png'));
                });
            }
        }
    };
}]); 

In your test, create a mock for Modernizr. Since you are using $timeout, remember to flush the timeout using $timeout.flush() to execute the timeout callback.

describe('Testing SVG to PNG directive', function() {
    var scope,
        elem, 
        ModernizerMock = {svg:false};

    beforeEach(module('app'));

    beforeEach(module(function($provide) {
        $provide.service('appConstants', function(){});
    }));

    beforeEach(inject(function($compile, $rootScope, $timeout, $window) {
        elem = angular.element('<img ng-src="test-img.svg" />');
        scope = $rootScope;
        $window.Modernizr = ModernizerMock; //Set the mock
        $compile(elem)(scope);
        scope.$digest();
        $timeout.flush(); 
    }));

    it('Should swap svg for png image if svg is not supported', function() {
          expect(elem.attr('src')).toBe('test-img.png');
    });
});

Plnkr

If your directive looked like this:

.directive('img', ['$window', function ($window) {
        return {
          restrict: 'E',
          compile: function (elem, attrs) {
            if ( typeof $window.Modernizr !== 'undefined' && !$window.Modernizr.svg ) {
               attrs.$set('ngSrc', attrs.ngSrc.replace('.svg', '.png'));
            }
          }
      };
 }]);

It would require less effort to test without the need for timeout logic. Plnkr

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

Autofill with JavaScript - Dynamic Form Population

Looking to create a form-based HTML page. The objective is to have the second input box automatically populate based on the user's input in the first input box. I've gone through various guides and tried to implement this script, but it doesn&ap ...

Automatically navigate to the bottom of the page by applying the overflow auto feature

I've been working on a chat application using Vue.js. I have set the overflow property to auto for my div element. My goal is to automatically scroll to the bottom of the div so that users won't have to manually click the scrollbar to view the la ...

Is there a way to stop bootstrap popover overflow from spilling out of its container?

I'm currently using Bootstrap's popover feature, but I'm struggling to prevent the popover from overflowing its container. Any suggestions on how to achieve this? Check out the demo on Plunker <!DOCTYPE html> <html> <head&g ...

Incorporate a PHP script into JavaScript using AJAX or alternative methods

I have been trying to complete a page on my website for the past couple of hours with the following objectives in mind. When a button is clicked, the following actions should occur: A download link should appear (done - working) The mySQL table should be ...

How can I use vanilla JavaScript to retrieve all elements within the body tag while excluding a specific div and its descendants?

My goal is to identify all elements within the body tag, except for one specific element with a class of "hidden" and its children. Here is the variable that stores all elements in the body: allTagsInBody = document.body.getElementsByTagName('*&apos ...

Tips for activating an HTML input field using Javascript

I am currently using localStorage to store a string input by the user as a title, which will be saved for future visits. I would like to implement a button that allows the user to delete the displayed text (from localstorage) and enables the input field fo ...

Verifying the presence of a cookie when the page loads

My goal is to have the browser initially check for a cookie named "yes." If this cookie exists, I would like to show a message. If not, I want to display the following: <input type="button" id='approve' value="approve" onclick="a()"/> &l ...

What could be the reason for the counter not being incremented when the button is clicked

While attempting to increase the counter in my test, I encountered an issue where pressing the button did not change the value. I tried using both fireEvent from React testing library and React test utils, but the value remained at 10. My project is using ...

What is the best way to activate a select list once data retrieval from the server has been successfully completed using an asynchronous call, despite the initial ng-disabled setting being 'true'?

Currently, I have multiple select lists in my HTML form where user inputs are gathered. My objective is as follows: 1) Initially, I want to disable the 'select' list using ng-disabled='true' since the controller does not have the data ...

What is the best way to use Jquery to enclose a portion of a paragraph text within a

How can I wrap the content inside a span that comes after another span, inside a paragraph and a new span? To further illustrate this, consider the following example: <p>foo <span>bar</span> baz</p> The desired outcome is: <p& ...

Communicate with the user currently connected through socket.io by sending a message

I'm struggling to grasp how to send a message using socket.io specifically to the user who has made an HTML request. Further explanations: Server My server runs on expressJS and I utilize router.get and router.post methods to handle my application. ...

Store the label's value as a JSON object in JavaScript

I've encountered a recurring question with no satisfactory answers. Can someone please clarify things for me? Let's take a look at a JSON file: { 'soapenv:Envelope': { '$': { 'xmlns:soapenv': 'http:// ...

Are memory allocations made for empty indices in Typescript Arrays?

I am faced with the challenge of replicating a segment of a server-side database for processing within a typescript web application. My goal is to access specific records by their integer ID in typescript. The issue at hand is that the indices may not be s ...

How to successfully implement ng-show with Html5's <dialog> tags

It's incredible how simple Html5 dialogs are. It feels like they should have been here 15 years ago! I'm having trouble getting ng-show to work with dialogs. Any tips on how to make it happen? <!DOCTYPE html> <html ng-app="project"> ...

Video DTO not defined with the utilization of a brightcove player

Hey there, just a quick question from a newcomer.. I tried following the example at to extract information about the current video DTO in order to display it on my page. However, when accessing it via JS, the value of the video DTO always turns out to be ...

After attempting to update a MYSQL table, a success message is displayed, but the changes do not actually reflect in the

After receiving a successful AJAX message, the data doesn't seem to update in the database. Can anyone provide assistance? This is the HTML code: <div class="row"> <input type="text" ng-model="updateId" class="form ...

What is the benefit of using process.nextTick() prior to executing a mongoose query?

I've observed a considerable number of Mongo (mongoose ORM) Queries being performed inside the process.nextTick() method. Despite the fact that nextTick defers the execution until the next iteration, it puzzles me as to why these queries are implement ...

How can I utilize the pick parameter in nuxtjs3 useFetch for selecting arrays or performing a deep pick?

Currently working on my nuxtjs3 project, where I am extracting data from an API. Specifically using jsonPlaceholder for this task. Extracting data from a single object is not a problem: const { data: useFetchOnly } = await useFetch('https://jsonplace ...

Is it possible to combine EJS compilation and html-loader in the html-webpack-plugin?

I need the html-webpack-plugin to generate my html using my .ejs template that contains <img> tags. The html-loader can update the image URLs in my <img> tags created by Webpack, so I am including it in my configuration: test: /& ...

What is the process of nesting an array of objects within an existing object, and how can additional objects be added to the array if it already exists?

I have a JSON file named questions.json containing an array of objects structured like this: { "id": "2", "ques": "here is my second code ?", "quesBrief": "I can't seem to find it too.", "hashes": "#javascript , #goodlord", "author": "slowde ...