Jasmine spies falsely report the calling of functions when they have not actually been called

Below is the code snippet I am currently working with:

$scope.deleteJob = function(job) {
    SandboxService.deleteJob(job.id).then(res => {
        if (res.status == 200) {
            ngToast.success();
            $scope.refreshApps();
        }
        else {
            ngToast.danger();
        }
    });
};

Accompanied by the unit test provided here:

it('should display success toast and refresh apps after deletion', () => {
    spyOn(sandboxService, 'deleteJob').and.returnValue(Promise.resolve({status: 500}));
    spyOn(ngToast, 'success');
    spyOn(scope, 'refreshApps');

    let mockJob = {
        'id': 1
    };

    scope.deleteJob(mockJob);

    sandboxService.deleteJob().then(() => {
        expect(ngToast.success).toHaveBeenCalled();
        expect(scope.refreshApps).toHaveBeenCalled();
    });
});

The main functionality involves displaying a success toast and refreshing the page upon successful job deletion. In case of failure, a danger toast is shown.

Although the expected result is for the test to fail due to a status of 500 being returned, surprisingly it passes. This suggests that both ngToast.success() and scope.refreshApps() have been triggered.

Upon inserting some debug logs into the code, it confirms that indeed status: 500 is returned, leading to execution of the else block.

What could possibly be overlooked in this scenario?

Answer №1

A synchronization issue arises due to the asynchronous nature of the deleteJob function. In this case, the test completes before the expect statement is executed. To address this, you can utilize the fakeAsync and tick functions from @angular/core/testing.

it('should show success toast on delete and refresh apps', fakeAsync(() => {
    ...

    sandboxService.deleteJob();
    tick();

    expect(ngToast.success).toHaveBeenCalled();
    expect(scope.refreshApps).toHaveBeenCalled();
}));

An issue arises when you spy on the deleteJob function below, causing ngToast.success and scope.refreshApps not to be called during the test execution, resulting in a failure.

 spyOn(sandboxService, 'deleteJob').and.returnValue(Promise.resolve({status: 500}));

Answer №2

@uminder's response highlighted that the test was completing before the expect functions were executed, illustrating the asynchronous nature of the process. This was confirmed by adding some logs within the test.

The remedy involved introducing a parameter in the test to be invoked upon completion:

it('should display success toast when deleting and refreshing apps', (done) => {
    spyOn(sandboxService, 'deleteJob').and.returnValue(Promise.resolve({status: 200}));
    spyOn(ngToast, 'success');
    spyOn(scope, 'refreshApps');

    let mockJob = {
        'id': 1
    };

    scope.deleteJob(mockJob);

    sandboxService.deleteJob().then(() => {
        expect(ngToast.success).toHaveBeenCalled();
        expect(scope.refreshApps).toHaveBeenCalled();
        done();
    });
});

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

Tips on using CSS to hide elements on a webpage with display:none

<div class="span9"> <span class="disabled">&lt;&lt; previous</span><span class="current numbers">1</span> <span class="numbers"><a href="/index/page:2">2</a></span> <span class="num ...

The ScriptManager.RegisterStartupScript function does not execute a second time when used inside an UpdatePanel

My aspx page <span> <asp:UpdatePanel ID="upPlayBtn" runat="server" > <ContentTemplate> <asp:Button runat="server" id="btn" Text="Play" OnClick="btnPlay" /> </ContentTemplate> </asp:UpdatePanel> </span> ...

Javascript-generated HTML elements are invisible

I am attempting to create a "circle of fifths" using html, css, and javascript. I am following this tutorial: https://blog.logrocket.com/interactive-svg-circle-of-fifths/ Although I am using the astro framework, I don't believe my issue is related to ...

Ways to verify the timeframe between two specific dates

Having two distinctive arrays: accomodation: [ { id: 1, name: "Senator Hotel Fnideq", address: "Route de Ceuta, 93100 Fnidek, Morocco", checkin: "September 1", fullCheckinDate: "2021-09-01", ...

Open the JSON file and showcase its contents using Angular

I am attempting to read a JSON file and populate a table with the values. I've experimented with this.http.get('./data/file.json') .map(response => response.json()) .subscribe(result => this.results =result, function(error) ...

DotJem AngularJS routing: Unable to find the 'pagename' within the '$root' directory

Every time I launch the website, everything seems fine at first, but then all the links turn out to be broken. Although they are clickable and lead to the correct URL, the content related to that specific page doesn't appear. Interestingly, if I copy ...

Guide on utilizing $q for retrieving a promise from a $broadcast within angularJS

Currently, the controller code I've written is structured like so: $scope.spAPI.load(id).then(function(result){ var deferred = $q.defer(); if(result !== undefined){ deferred.resolve($rootScope.$broadcast("onSpLoaded", result)); } return de ...

Utilizing JavaScript to Parse RSS XML Feeds Across Domains

Looking to parse an RSS (XML) file without relying on the Google RSS feed. I have attempted using JSONP, but it resulted in downloading the file and throwing an error "Uncaught SyntaxError: Unexpected token < ". $.ajax({ type: "GET", ur ...

The CSS navigation bar is not properly aligned in the center

This menu was constructed by me: JSBIN EDIT ; JSBIN DEMO Upon closer inspection, it appears that the menu is not centered in the middle of the bar; rather, it is centered higher up. My goal is to have it positioned lower, right in the middle. I ...

Using async/await with Fetch to send POST parameters for text/html content

Is there a way to POST parameters for content type text/html without sending it as an object? In my specific scenario, I need to include extra data that is not part of a form and is read from a cookie. When posting with body : {} or body: JSON.Stringify( ...

Find the total number of records in fnClick: (datatables.net)

I am struggling with some code where I need to retrieve the total number of records. I posted about it on the datatables.net forum but unfortunately, no one was able to help me... tableTools: { "sSwfPath": window.STATIC_BASE + "scripts/datatable/s ...

Having Trouble Loading Vue Devtools in Vue Electron Builder

I'm encountering an issue with loading Vue Devtools in my Electron application integrated with Vue. This is my first time working with this combination, and I suspect there might be a dependency problem causing the Devtools not to load within the Elec ...

A see-through object appears only properly when viewed from one specific angle

I am currently working with THREE.js and the WebGL renderer, facing an issue with a self-transparent object in my scene. This object is composed of a single geometry with a basic material that includes a texture and has the transparent: true property enabl ...

React.js Filter Component

I'm currently trying to create a filter for my "localtypes", but I'm encountering an issue where the console in my browser is displaying an empty array. My goal is to access the localtypes properties of the API that I am working with. I attempte ...

Removing information from a MongoDB database with the help of AngularJS and Node.js

Having trouble deleting data in MongoDB using AngularJS and Node.js, as I keep encountering the error "Cannot DELETE /api/manage-product" in the console. .html file <tbody> <tr ng-repeat="product in vm.result"> ...

The key length specified in crypto.createCipheriv is not valid

After utilizing NodeJS v8.11.0, I managed to create a base64-encoded key with the following code: const secret = 'shezhuansauce'; const key = crypto.createHash('sha256').update(String(secret)).digest('base64'); //output is RE ...

Creating a dropdown menu for an extensive list of 100 menu items: a step-by-step guide

In my React JS front-end project, I have implemented a drop-down menu using Material-UI. Currently, the menu items are hardcoded which works fine for a small number of items. However, this approach becomes cumbersome when dealing with a larger number of ...

The Module Design Pattern in Jquery

In my project, there is a jQuery module pattern that I am having trouble understanding its purpose. There is also a custom plugin called jquery.skInit.js (function($) { $.fn.skInit = function() { return this.each(function(i,element) { var e = ...

NextJS version 14 now throws an error when attempting to use FormData that is

const FormPage = () => { const [categories, setCategories] = useState([]); const [productName, setProductName] = useState(); const [categoryID, setCategoryID] = useState(); const [productDescription, setProductDescription] = useState() ...

An issue occurred while evaluating the Pre-request Script: Unable to access the 'get' property of an undefined object

I need help accessing the response of my POST request in Postman using a Pre-request Script. Script below : var mobiles = postman.environment.get("mobiles"); if (!mobiles) { mobiles =["8824444866","8058506668"]; } var currentMobile = mobiles. ...