Jasmine test case failing due to undefined variable even though it should be in scope

I am currently working on testing a controller that listens for an event to perform certain actions. The event handler relies on a crucial global variable named Main. Despite my efforts to mock all dependencies in the unit test, an error is being thrown by Karma stating:

ReferenceError: Main is not defined

Below is the Angular code snippet :

App.controller('AppController', ['$scope', function($scope){
    $scope.$on('$viewContentLoaded', function() {
        Main.initComponents(); // initialize core components
    });
}]);

Here is the content of the spec file:

describe("App", function () {
    var scope, AppController, Main;
    describe("Login", function () {
        beforeEach(module("App"));
        beforeEach(inject(['$rootScope', '$controller', function($rootScope, $controller){
            scope = $rootScope.$new();
            Main = jasmine.createSpyObj("Main",["initComponents"]);
            AppController = $controller('AppController', {$scope : scope});
        }]));
        it("should call initComponents() on Main module upon receiving $viewContentLoaded event", inject(['$rootScope', function ($rootScope) {
            $rootScope.$broadcast('$viewContentLoaded');
            expect(Main.initComponents).toHaveBeenCalled();
        }]));
    });
});

And here's the configuration from karma.conf.js:

module.exports = function(config){
    config.set({

        basePath : './',

        files : [
            'app/bower_components/angular/angular.js',
            'app/bower_components/oclazyload/dist/oclazyLoad.min.js',
            'app/bower_components/angular-ui-router/release/angular-ui-router.min.js',
            'app/bower_components/angular-mocks/angular-mocks.js',
            'app/**/app.js',
            'app/**/controllers.js',
            'app/**/services.js',
            'app/**/directives.js',
            'app/**/filters.js',
            'app/**/routes.js',
            'app/**/specs.js'
        ],

        autoWatch : true,

        frameworks: ['jasmine'],

        browsers : ['Chrome'],

        plugins : [
            'karma-chrome-launcher',
            'karma-firefox-launcher',
            'karma-jasmine',
            'karma-junit-reporter'
        ],

        junitReporter : {
            outputFile: 'test_out/unit.xml',
            suite: 'unit'
        }

    });
};

Can anyone please assist me with identifying the issue? Thank you.

Answer №1

This issue arises from a variable visibility problem caused by the scope in which the variables are declared.

In order for your $viewContentLoaded handler to function correctly, it requires access to a Main object that is not defined within the current scope or any of its parent scopes in the scope chain. The mocked Main object created using createSpyObj is contained within the scope of your App test suite defined with describe(). Looking at your code snippet:

describe("App", function () {
    var scope, AppController, Main; 
    /* remaining code */
}

From the above example, Main is a locally scoped variable defined within the describe() method, making it only accessible within that particular function or any nested functions inside it.

Any functions outside of describe(), such as your event handler ($on) in Main JS, will be unaware of the existence of this variable. This explains why you encounter an error when trying to execute that handler.

To address this issue, you can properly initialize Main in two ways:

  1. You can do so prior to registering your event handler, either before creating your Angular Module or inside the controller itself.
  2. You can transform Main into an Angular service within the same module and inject it into your controller as demonstrated below.

Main JS

 App.service('Main', function(){

 });

 App.controller('AppController', ['$scope', 'Main', function($scope, Main){
        $scope.$on('$viewContentLoaded', function() {
            Main.initComponents(); // initialize core components
        });
 }]);

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

Discover a revolutionary Android app that provides detailed indoor maps and step-by-step walking directions

I am looking to enhance a custom Google map by adding sidewalks for walking, while keeping all of its original features intact. Additionally, I want to create a detailed interior map of a building on a college campus, complete with classroom locations on ...

Top method for designing a "busy waiting" animation with customizable positioning using jQuery? (i.e., display it in the proximity of the activity)

I am planning to incorporate a busy waiting spinner on my website, following the method outlined in this post: How to show loading spinner in jQuery? - as it is considered the cleanest and simplest approach: $('#loadingDiv') .hide() / ...

Data not being properly set in the form

Check out this chunk of HTML code: <html> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"> </script> <script> function getCords(){ ...

Utilizing Angular Dependency Injection to Share Data Among Modules Through a Service

After reading about dependency injection in Angular, I decided to test it out. However, when trying to inject the module, I encountered an issue with passing values from one module to another and outputting them on the console. (Update: The issue has been ...

`How to resolve page timeout issue caused by looping when using Response.Redirect?`

Currently, I am in the process of building a page that involves creating a large number of files within a folder. Once the task is completed, I compress the folder into a zip file and provide the client with a download link. To keep track of these files, I ...

"Autocomplete disable" feature malfunctioning on the final input field of all web pages

I'm dealing with a web application that has a login page. The username and password fields have the autocomplete attribute set to "off," as well as other variations like nope, new-password etc. However, it's still not working in Chrome version 62 ...

Error: $(...).DataTable function is not recognized - DataTables requires $.noConflict(true) to function properly

Recently I stumbled upon DataTables and decided to experiment with it. My goal for the page is to search and display posts based on user-defined parameters, updating the table content with JSON without having to refresh the entire page. However, I'm e ...

Adjust the dimensions of the canvas without disrupting the existing artwork

I am currently working on a pixel art application where I am facing an issue with saving images from the canvas. The saved image appears small and pixelated when I try to resize it. I would like to resize the image to larger dimensions, but I am unsure of ...

Mastering the art of two-way data binding in Ionic and AngularJS

TOOLS I USE : Currently, I am utilizing Ionic while working on a project. My primary tools include Chrome and Ubuntu OS. My current endeavor involves creating a demo project centered around data binding. Feel free to review my Plunkr demonstration here. ...

Should a Service Worker be automatically installed on each page reload, or only when a user navigates to a new page?

Currently in the process of developing a PWA. I have encountered an issue where the service worker seems to be installing on every page reload or when navigating to a different page within my app. It appears that many files are being cached during the inst ...

setting a variable with data retrieved from an AJAX call using jQuery

Here's a snippet of jquery code that I'm working with: var example = "example"; $.ajax({ url: root + "/servletPath", type: "GET", success: function (response) { alert(response); // displays the correct value example ...

Ways to retrieve information from a callback method

Struggling to access the data returned from the getChildren method in the caller function. The code snippet below shows my predicament: I've implemented these functions within a controller and provided all necessary objects var baseMethod = function ...

Transfer PHP's uniqid() function to real-time using JavaScript with jQuery

Seeking a compact JavaScript(jQuery) code snippet to achieve this: date("r",hexdec(substr(uniqid(),0,8))); Your assistance is highly appreciated. Thank you. ...

Encountered an unanticipated symbol at column 2 while using the Angular Google Recaptcha

I have integrated the Angular Google Recaptcha directive into my application from https://github.com/VividCortex/angular-recaptcha. However, upon running my application, I encountered an error stating that I am using my public key instead of my private key ...

Challenge encountered when attempting to detect multiple submit buttons using jQuery

I am currently attempting to identify which of the four submit buttons was clicked using jQuery 1.7.2. When any one of three specific buttons is clicked, I want an alert box to appear displaying the value of that particular button. Below is the HTML code s ...

Enclose the final portion of the content within a span element as an option

I could use some assistance. Currently, I have a variety of products in an online store with different options such as size and color. To demonstrate, I created a sample on this fiddle: https://jsfiddle.net/04wbfL28/2/ Here is the HTML snippet: < ...

Update the onclick function for anchor element

I'm struggling with making changes to <a> tags. The task at hand is to update the onclick event for this tag while keeping the href attribute as a valid link. As an example, consider the following link: <a href="http://en.wikipedia.org"> ...

Should commas be used in variables?

Could this be converted in a different way? $('#id').testfunction({ 'source' : [ {'source':'pathimage.jpg','title':'Title 1','description':'This is a description 1.'}, ...

The initial request is replaced by new information

Trying to fetch data for autocomplete in Laravel. Controller: public function collection_search(Request $request) { $term = $request->search; $serveurapObj = new Serveurap(); $result = $serveurapObj->collectionAutocomplete(); ...

Encountered an issue while attempting to include multiple JavaScript sources. Please review your configuration settings for the javascripts.join

While setting up a basic app using phoenix-elixir and brunch, encountering the following error: 23 Mar 10:18:10 - warn: node_modules/phoenix/priv/static/phoenix.js compiled, but not written. Check your javascripts.joinTo config 23 Mar 10:18:10 - war ...