Experimenting with a loader component in AngularJS

This is a test for a $resource with a loader

describe('Service: MultiCalculationsLoader', function(){

  beforeEach(module('clientApp'));

  var MultiCalculationLoader,
    mockBackend,
    calculation;

  beforeEach(inject(function (_$httpBackend_, Calculation, _MultiCalculationLoader_) {
    MultiCalculationLoader = _MultiCalculationLoader_;
    mockBackend = _$httpBackend_;
    calculation = Calculation;
  }));

  it('should load a list of calculations from a user', function(){
    mockBackend.expectGET('/api/user/600/calculation').respond([{id:5}]);

     var calculations;
     var mockStateParams = {
       userId: 600
     };
    var promise = new MultiCalculationLoader(mockStateParams);

    promise.then(function(res){
      calculations = res
    });

    expect(calculations).toBeUndefined();

    mockBackend.flush();

    expect(calculations).toEqual([{id:5}]);
  });

});

When running the test an error is generated:

Expected [ { id : 5 } ] to equal [ { id : 5 } ].
Error: Expected [ { id : 5 } ] to equal [ { id : 5 } ].
    at null.<anonymous> 

Cannot figure out why. The two arrays seem identical to me. Any suggestions?

Update Here is the code implementation:

 .factory('Calculation', function ($resource) {
    return $resource('/api/user/:userId/calculation/:calcId', {'calcId': '@calcId'});
  })
  .factory('MultiCalculationLoader', function (Calculation, $q) {
    return function ($stateParams) {
      var delay = $q.defer();
      Calculation.query( {userId: $stateParams.userId},function (calcs) {
        delay.resolve(calcs);
      }, function () {
        delay.reject('Unable to fetch calculations');
      });
      return delay.promise;
    };
  })

Answer №1

The expected URL is not matching the actual URL. Here is a revised code snippet that may help:

it('should load a list of calculations from a user', function(){
    //remove the 's' from 'calculations'
    mockBackend.expectGET('/api/user/600/calculation').respond([{id:5}]);

    var calculations;
    var promise = MultiCalculationLoader({userId:600}); //userId = 600
    promise.then(function(res){
      calculations = res
    });

    expect(calculations).toBeUndefined();

    mockBackend.flush();

    expect(calculations).toEqual([{id:5}]);
  });

Another issue is that Angular automatically adds 2 properties to the response:

http://plnkr.co/edit/gIHolGd85SLswzv5VZ1E?p=preview

This problem is similar to: AngularJS + Jasmine: Comparing objects

There is an issue with Angular $resource that converts responses to resource objects. To verify responses from $resource, you can use angular.equals

expect(angular.equals(calculations,[{id:5},{id:6}])).toBe(true);

http://plnkr.co/edit/PrZhk2hkvER2XTBIW7yv?p=preview

You can also create a custom matcher:

beforeEach(function() {
    jasmine.addMatchers({
      toEqualData: function() {
        return {
          compare: function(actual, expected) {
            return {
              pass: angular.equals(actual, expected)
            };
          }
        };
      }
    });
  });

And use it like this:

expect(calculations).toEqualData([{id:5},{id:6}]);

http://plnkr.co/edit/vNfRmc6R1G69kg0DyjZf?p=preview

Answer №2

Sometimes Jasmine equality selectors can be overly specific when all you want to do is check for equality.

I have noticed this issue with the toEqual() method when comparing objects or arrays, but definitely not with the toBe() method.

You could try replacing toEqual() with toMatch().

In unit tests, it's a good idea to use a constant value that you can pass in as both the response and the matchers/equal/toBe's.

describe('Service: MultiCalculationsLoader', function(){

  beforeEach(module('clientApp'));

  var MultiCalculationLoader,
    mockBackend,
    calculation,
    VALUE = [{id:5}];

  beforeEach(inject(function (_$httpBackend_, Calculation, _MultiCalculationLoader_) {
    MultiCalculationLoader = _MultiCalculationLoader_;
    mockBackend = _$httpBackend_;
    calculation = Calculation;
  }));

  it('should load a list of calculation from a user', function(){
    mockBackend.expectGET('/api/user/600/calculations').respond(VALUE);

    var calculations;
    var promise = MultiCalculationLoader();
    promise.then(function(res){
      calculations = res
    });

    expect(calculations).toBeUndefined();

    mockBackend.flush();

    expect(calculations).toEqual(VALUE);
  });

});

By using this method, I believe that .toEqual will work correctly.

Our approach:

Before Block:

httpBackend.when('JSONP', PATH.url + 'products?callback=JSON_CALLBACK&category=123').respond(CATEGORIES[0]);

Test:

describe('Category Method', function () {

        it('Should return the first category when the method category is called', function () {
            var result = '';

            service.category(123).then(function(response) {
                result = response;
            });

            httpBackend.flush();
            expect(result).toEqual(CATEGORIES[0]);

        });
    });

Answer №3

Consider replacing toEqual() with the function toEqualData()

verify(results).toEqualData([{id:5}]);

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

Experiencing problems with web page layout when using bootstrap on IE8?

Here is a code snippet that functions correctly in IE9 and later versions, but encounters issues in IE8: <div class="col-lg-5 col-md-5 col-sm-6 col-xs-6" id="div1"> <div class="panel panel-default" style="" id="panel1"> ...

Issue with displaying value from page in AngularJS modal when clicked

How can I get the data copied from my page's $scope element (thisRequest) into my modal's $scope element (nTask) to display correctly in the modal after clicking a button in AngularJS? You can view the code on this Plunker. Here is an example o ...

AngularJS: Triggering an event before the radio button value is changed

Is there a way to detect the value change of a "radio button" before it actually changes in my application? I need to inform the User about the consequences of changing the value of this radio button within the form. I've experimented with using ngC ...

What is the most effective way to implement multiple ng-models within a single function?

Hello everyone! Currently, I am working on developing a database using indexed db in AngularJS. My main task is to save data into the database and I have a query - Can we utilize multiple ng-models in a single function? Let me provide you with a snippet of ...

Clear previously filtered items

I am currently working on implementing a search functionality using Javascript for my project, but I've hit a snag. After hiding certain items, I'm having trouble making them appear again. JSFiddle The code I have so far is as follows: $(' ...

Angular.js does not trigger validation for input[type='date'] if only a part of the date is entered (such as just the day)

There is an input[type='date'] with no additional validation rules. The issue arises when only a portion of the date is entered (for example, just the day and month). In this case, if you enter '01/02/YYYY', it will be recognized as an ...

Capture the Promise Rejection

During my test with WebdriverIO, I consistently encounter an issue specifically with this line of code: await browser.waitForVisible('#tx-sent li', 15000) Intermittently, a Promise rejection error occurs: Error: Promise was rejected with the ...

Obtaining the NativeElement of a component in Angular 7 Jasmine unit tests

Within the HTML of my main component, there is a my-grid component present. Main.component.html: <my-grid id="myDataGrid" [config]="gridOptions" </my-grid> In main.component.specs.ts, how can I access the NativeElement of my-grid? Cu ...

Error: Surprising token found in ReactJS application on CodeSandbox

Encountering an unexpected token on line 5 error in my ReactJS project when testing it on CodeSandbox. Interestingly, the app runs smoothly without errors on my local machine. import React, { Component } from 'react'; import Header from ' ...

What is the best way to encapsulate a function that uses `this.item.findElement()` from Selenium in a separate file?

I'm currently working on setting up a Selenium Webdriver and Cucumber.js test environment using Node.js. In the homePageSteps.js file, I have a check to verify if a banner exists on a page: Then('there should be a banner', async function() ...

How can I achieve the quickest image loading speed with JavaScript?

If I have a large ecommerce website with 15,000 image elements that need to be added to the HTML, what is the best approach using JavaScript to optimize efficiency and enhance user experience? ...

Include various categories into the div containers of the listed items within the query outcomes

Is there a way to customize div styles based on query results? I want to differentiate the styles of divs in the result list based on their content. For example: I'd like bird names in the result list to have different div styles compared to other a ...

Tips on setting up and managing configuration and registering tasks in Grunt

I've been working on a project that involves using grunt to process my Js and SASS files. The issue I'm facing is that every time I need to make a change, I have to run all the tasks in my gruntfile.js, even if it's just for one module or th ...

Refresh a div using jQuery and include PHP files for dynamic content updating

This is the code I am using to dynamically update divs containing PHP files: $(document).ready(function() { setInterval(function() { $('#ContentLeft').load('live_stats1.php').fadeIn("slow"); $('#ContentRight').load( ...

Build a flexible Yup validation schema using JSON data

I am currently utilizing the power of Yup in conjunction with Formik within my react form setup. The fields within the form are dynamic, meaning their validations need to be dynamic as well. export const formData = [ { id: "name", label: "Full n ...

Is it possible to add a click event to a table row that contains an input checkbox, without interfering with the ability to click the checkbox itself?

I have a table: <table> <tr> <td>Something</td> <td>Something Else</td> <td><input type='checkbox' value='clickme' id='yes'></td> </tr> When a user ...

I'm facing an issue where the ui.router is not functioning properly. I am unsure

I am currently trying to replace ngRoute with ui-router in order to utilize multiple views. Within my template file, I have the following code: <div ui-view></div> In my application file, I have the following configuration: angular.module(&a ...

Pausing repetitive HTTP requests in an Angular 6 project within a do while loop

While waiting for the completion of one API call, I am recursively consuming an external API. The http calls are being made using import {HttpClient} from '@angular/common/http' As a newcomer to the framework, there may be something wrong in the ...

What are the best ways to incorporate mistakes into my JavaScript mortgage calculator?

I am struggling to set up my calculator so that it triggers an error message if the APR goes over 25% or falls below 0. Also, the Loan Term should be greater than 0 and less than or equal to 40, otherwise display an error message. I have attempted differen ...

AngularJS - Showcase a dynamic list of information according to the value chosen

Seeking assistance from anyone willing. I have data in JSON format structured like this { state1: [ member1, member2], state2: [ member3,member4...], ... } There is a dropdown that displays the states listed in the JSON data. When a state is selected, I ...