TypeScript Jasmine test "Ensuring scope $on is invoked"

I have been searching in various places for ideas on this topic.

How can I unit test $scope.broadcast and $scope.$on using Jasmine?

$scope.$on is not working in Jasmine SpecRunner

Although the information I found has been helpful, it seems like there's still something missing. I am attempting to test a controller that includes a $rootScope.$on in its code. In my unit test, I'm trying to trigger the $broadcast so that the $on function captures it and executes the code. However, my current code is not functioning as intended.

Below is the snippet of my controller:

constructor($state: ng.ui.IStateService, store: angular.a0.storage.IStoreService, jwtHelper: angular.jwt.IJwtHelper, $rootScope: any) {
    this.currentDate = new Date();
    this.state = $state;
    this.store = store;
    this.jwtHelper = jwtHelper;
    this.userFullname = '';

    $rootScope.$on('$stateChangeStart',
        (event: any, toState: any, toParams: any, fromState: any, fromParams: any, error: any) => {
            var jwtToken = this.store.get('token');
            if (jwtToken != null) {
                var decodedToken: any = this.jwtHelper.decodeToken(jwtToken);
                } 
        });

}

And here is my testing script:

 beforeEach(angular.mock.inject(($compile: ng.ICompileService, $rootScope: any, $controller: any, $state: ng.ui.IStateService, jwtHelper: angular.jwt.IJwtHelper) => {

    controllerScope = $rootScope.$new();
    navbarController = $controller('NavbarController', { $scope: controllerScope });
    currentDate = new Date();
    rootScope = $rootScope;
    state = $state;
    jwt = jwtHelper;
}

it('should receive broadcast for user token', () => {
    spyOn(controllerScope, '$on');
    spyOn(jwt, 'decodeToken');
    //state.go('home'); Was trying a different way to trigger the event
    rootScope.$broadcast('$stateChangeStart', [{ toState: 'home' }]);
    expect(controllerScope.$on).toHaveBeenCalled();
    expect(jwt.decodeToken).toHaveBeenCalled();
});

Both spies indicate they are never being called. What could be misaligned in my setup?

Answer №1

Instead of checking if the event listener is triggered, you are verifying if the code that adds the listener is called.

The controllerScope.$on function was executed in your beforeEach, not in your individual test case (it). The spyOn method cannot look back in time to track previous function calls; even if it could, that may not be the intended test scenario.

It's like doing this:

window.addEventListener('mouseMove', someFunctionExpr);
spyOn(window, 'addEventListener');
triggerMouseMoveEvent();
expect(window.addEventListener).toHaveBeenCalled();

I am not familiar with decodeToken / jwt -- since your code does not reference them, it's unclear where they should be expected to be used.

Answer №2

To verify that the event is being broadcast, use

spyOn(scope, '$broadcast').and.callThrough();

If you are testing the controller's logic, it's best to encapsulate it in a function and test it independently from $broadcast / $on (since you're not focusing on Angular's event handling mechanism).

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

Manage both React keyboard and mouse events within a single function

I'm working on enhancing the accessibility of my web app by making it keyboard accessible. However, I am facing an issue when trying to handle both click and keyboard events using the '|' symbol in my function: Property 'key' does ...

JHipster: Displaying a relationship within the same view as the parent entity

Currently building a straightforward application with JHipster. Despite there being a connection between the entities, the framework generates separate views for each one. I want to showcase my entities in a single view instead. For instance: entity Quest ...

Angular 6: TypeError - The function you are trying to use is not recognized as a valid function, even though it should be

I'm currently facing a puzzling issue where I'm encountering the ERROR TypeError: "_this.device.addKeysToObj is not a function". Despite having implemented the function, I can't figure out why it's not functioning properly or callable. ...

What is the best way to retrieve data from a MySQL database in an Angular 7 application with Node.js and showcase it on an Angular component's HTML page?

Despite trying various methods, I am still struggling to understand how to achieve my goal. My main objective is to retrieve data from a MySQL database and then access this information in an Angular component located in the page-one.component.ts file. Alth ...

extracting data from JSON and storing it in an array

JSON: var res = { "response": { "data": { "profilesearchsnippet": [ [ { "profileInfo": { "firstname": "Sundar", ...

Angular 4 HTTP Requests Failing to Retrieve JSON Data

I am currently working with the following method in my Typescript: allPowerPlants(onlyActive: boolean = false, page: number = 1): PowerPlant[] { const params: string = [ `onlyActive=${onlyActive}`, `page=${page}` ].join('&&apo ...

What is the best way to conceal the PrimeNG sidebar (which is set at the parent template) by clicking on a button designated in the child

I am utilizing the PrimeNG sidebar feature that slides to the right and navigates to a child component upon clicking a button. Within the child component, there is a form template with a cancel button. The template for the sidebar can be found below. side ...

What is the best way to locate the nearest marker using the Google Maps Direction Service?

Currently, I am engaged in the development of a Google Maps project where I am integrating markers retrieved from a database onto the map using the drawMarkers function. In addition to this, the Google Maps feature tracks your current location and refreshe ...

Issue: The method onBeforeCompile is not found in the LineDashedMaterialParameters type

I am interested in developing a rotating cube with concealed dashed lines as shown below. https://i.sstatic.net/0U2im.gif However, I encountered the following error message in VS Code (parameter) shader: any Argument of type '{ color: ColorReprese ...

What is the best way to initialize $rootScope prior to each controller in AngularJS?

Currently tackling a debugging task involving multiple pages. During each step, I find myself needing to console log the $rootScope for debugging purposes. I'm wondering if there is a method to display the $rootScope in the console for all controllers ...

Angular front-end rendering with Rails backend integration

Currently, I am working on a medium-sized Rails application and my latest endeavor is to integrate Angular into the system. After reviewing several tutorials, it appears that the most common method for fetching initial data and displaying the first view in ...

Tips for deactivating the highlight on a previously selected menu item when clicking on the next menu option in Angular.js

In my pages, I have a menu where the landing page menu is initially highlighted. However, when I move to the next menu, the previous landing page highlight remains instead of being removed while swapping the menu. I am using Angular.js and angular ui-route ...

What causes a complete set of Jasmine tests to fail collectively, even though they pass when executed in smaller, individual suites

In my protractor configuration file, I have defined suite glob patterns as follows: suites: { all: ['**/*.spec.js'], ui: ['ui/**/*.spec.js'], api: ['api/**/*.spec.js'] }, When I run npm run protractor on my Ma ...

Function modifies global variable

What could be causing the global variable to change when using the function write_ACK_ONLY()? I'm passing the array rxUartBuffer to write_ACK_ONLY() as data = new Array(20), but upon checking the Log Output, it seems that the function is also modifyin ...

Is there a way to modify the orientation of the bootstrap modal when it opens?

I am trying to modify the way my bootstrap reveal modal opens. I have followed the code instructions provided in this resource, but unfortunately my modal is not opening. I am using angularjs. Can someone assist me with troubleshooting the code? Here is m ...

Ways to eliminate extra space within a text area using angular js

Is there a way to eliminate excess white space at the beginning and middle of a text area when a user enters multiple spaces? The whitespace is counted as characters in this context. Actual Results: https://i.sstatic.net/SPSzP.png Expected Results htt ...

Ways to enhance focus on childNodes using Javascript

I am currently working on implementing a navigation system using a UL HTML Element. Here's the code I have so far: let htmlUL = <HTMLElement>document.getElementById('autocomplete_ul_' + this.name); if (arg.keyCode == 40) { // down a ...

Utilize Angular.js to efficiently pass several values within the $scope object

I am a beginner in Angular.js and eager to learn more about it. I recently put together a small project and am trying to pass multiple values with the $scope object, but encountering some issues. Here is an overview of what I am attempting: function List ...

How to use ng-options in AngularJS to select from a nested JSON array

I have a JSON object assigned to the scope as follows: $scope.People = [ { "firstName":"John", "lastName":"Doe", "Choices":[ { "Name":"Dinner", "Options":[ ...

Modifying the name of a file upload in AngularJS

Does anyone know a way to dynamically change the file name in AngularJS? <input type="file" onchange="angular.element(this).scope().filename(this)"> In the filename method, I am attempting to change the file name but the value is not updating. How ...