Angular-UI/Bootstrap: Experimenting with a controller incorporating a dialog box

Hello there, I have a controller that utilizes a Dialog from the angular-ui/bootstrap framework:

   function ClientFeatureController($dialog, $scope, ClientFeature, Country, FeatureService) {

        //Get list of client features for selected client (that is set in ClientController)
        $scope.clientFeatures = ClientFeature.query({clientId: $scope.selected.client.id}, function () {
            console.log('getting clientfeatures for clientid: ' + $scope.selected.client.id);
            console.log($scope.clientFeatures);
        });

        //Selected ClientFeature
        $scope.selectedClientFeature = {};

        /**
         * Edit selected clientFeature.
         * @param clientFeature
         */
        $scope.editClientFeature = function (clientFeature) {
            //set selectedClientFeature for data binding
            $scope.selectedClientFeature = clientFeature;

            var dialogOpts = {
                templateUrl: 'partials/clients/dialogs/clientfeature-edit.html',
                controller: 'EditClientFeatureController',
                resolve: {selectedClientFeature: function () {
                    return clientFeature;
                } }
            };
            //open dialog box
            $dialog.dialog(dialogOpts).open().then(function (result) {
                if (result) {
                    $scope.selectedClientFeature = result;
                    $scope.selectedClientFeature.$save({clientId: $scope.selectedClientFeature.client.id}, function (data, headers) {
                        console.log('saved.');
                    }, null);
                }
            });
        };
    });

As someone who is relatively new to testing, I believe it's important to test two specific aspects of this controller:

  1. Confirming that a dialog opens when $scope.editClientFeature() is triggered
  2. Ensuring that $save function is successfully called after the dialog closes and returns a 'result'

My current attempt at writing a test script looks like this:

describe('ClientFeatureController', function () {
    var scope, $dialog, provider;

    beforeEach(function () {
            inject(function ($controller, $httpBackend, $rootScope, _$dialog_) {
            scope = $rootScope;
            $dialog = _$dialog_;

            //mock client
            scope.selected = {};
            scope.selected.client = {
                id: 23805
            };

            $httpBackend.whenGET('http://localhost:3001/client/' + scope.selected.client.id + '/clientfeatures').respond(mockClientFeatures);
            $controller('ClientFeatureController', {$scope: scope});
            $httpBackend.flush();
        });
    });


    it('should inject dialog service from angular-ui-bootstrap module', function () {
        expect($dialog).toBeDefined();
        console.log($dialog); //{}
    });

    var dialog;

    var createDialog = function (opts) {
        dialog = $dialog.dialog(opts);
    };

    describe('when editing a clientfeature', function () {
        createDialog({});
        console.log(dialog); //undefined
//        var res;
//        var d;
//        beforeEach(function () {
//            var dialogOpts = {
//                template: '<div>dummy template</div>'
//            };
//            console.log(dialog);
//            d = $dialog.dialog(dialogOpts);
//            d.open();
//        });
//
//        it('should open a dialog when editing a client feature', function () {
//            expect(d.isOpen()).toBe(true);
//        });
    });

});

Currently, I am facing an issue wherein I cannot create or open a dialog. The error message I receive is as follows:

Chrome 25.0 (Mac) ClientFeatureController when editing a clientfeature encountered a declaration exception FAILED
    TypeError: Cannot call method 'dialog' of undefined

If anyone has experience in writing tests for a similar scenario, I would greatly appreciate any guidance or examples as I am feeling quite lost.

Thank you, Shaun

Answer №1

After facing the same issue, I delved into the GitHub repository and stumbled upon the dialog tests, which served as a helpful starting point for me:

var $dialog,$scope,$httpBackend;
  beforeEach(module('ui.bootstrap.dialog'));
  beforeEach(function(){
    inject(function (_$dialog_, _$httpBackend_, $controller){
      $dialog = _$dialog_;
      $httpBackend = _$httpBackend_;
      $httpBackend.expectGET('/appServer/list')
        .respond([{
            id:1,
            name:'test1'
          },
          {
            id:2,
            name:'test2'
          },
          {
            id:3,
            name:'test3'
          }]);


      //setup controller scope
      scope = {};
      ServerCtrl = $controller('ServerCtrl', {
        $scope: scope,
        $dialog:$dialog
      });
    });
  });

Answer №2

My preference lies in utilizing a proper mock. In instances when one is not accessible, I resort to patching the service.

To put this to the test:

$dialog.messageBox(title, msg, btns)
   .open()
   .then(function (result) {
       if (result == 'ok') {
            // This block of code runs when the user clicks OK
       }
});

If you want to patch $dialog, here's how you can do it:

$dialog.messageBox = function (title, msg, btns) {
    return {
        open: function () {
            return {
                 then: function (callback) {
                      callback('ok'); // The parameter result will be set to 'ok'
                 }
             }
        }
    }
 };

Answer №3

In my personal approach, I make sure to test all services thoroughly. In the event that the ui-bootstrap project lacks a $dialog mock, it is recommended to report this issue and request one. Creating a mock service yourself is a simple task.

The mock service should consist of faux methods that simply return promises. Additionally, it should include a function to clear all asynchronous processes in order to facilitate synchronous testing.

Answer №4

When it comes to testing, I prefer creating my own mock dialog for better clarity. Take a look at this example where I simulate selecting "yes" in a dialog.

Code snippet for testing

.controller('AdminListingCtrl', function AdminListingController($scope, $dialog, houseRepository) {
    $scope.houses = houseRepository.query();
    $scope.remove = function (house) {
        var dlg = $dialog.messageBox('Delete house', 'Are you sure?', [
            {label: 'Yep', result: 'yes'},
            {label: 'Nope', result: 'no'}
        ]);
        dlg.open().then(function (result) {
            if (result == 'yes') {
                houseRepository.remove(house.id);
                $scope.houses = houseRepository.query();
            }
        });
    };
}

Testing scenario

    describe('when deleting a house', function () {

        var fakeDialog = {
            open: function()
            {
                return {
                    then: function(callback) {
                        callback("yes");
                    }
                };
            }
        };

        beforeEach(inject(function($dialog) {
            spyOn($dialog, 'messageBox').andReturn(fakeDialog);
        }));

        it('should trigger the remove method in houseRepository', function () {
            scope.remove({id: 99});
            expect(houseRepository.remove).toHaveBeenCalledWith(99);
        });

        // additional tests can be added here
    });

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

Is it possible to select multiple three.js objects by pressing CTRL and clicking on each one

I'm having issues with implementing multiple selection of three.js objects using CTRL-click. While single-select works perfectly, the behavior is problematic when trying to select multiple objects with CTRL-click. The selected array sometimes contains ...

Remove specific data regardless of letter case from the row

I've developed a Google Apps Script that scans specific columns for certain keywords and deletes rows that contain them: function filterRows() { var sheet = SpreadsheetApp.getActiveSheet(); var rows = sheet.getDataRange(); var values = rows.g ...

Interfacing shared memory between a C++ and JavaScript program

Is it feasible to have shared memory that both a C++ program and a JavaScript program can access simultaneously? The goal is for the C++ program to write to memory while the JS program reads from the same location. ...

The file selection feature in the browser is malfunctioning when attempting to upload files using either JQuery or JavaScript

I am experiencing an issue where the file select explorer closes after three clicks using jQuery. Below is my code: header.html: $(document).on('click', '.browse', function(){ var file = $(this).parent().parent().parent().find(&ap ...

In IE the OnFocus and OnBlur style changes are not functioning properly, while they work successfully in Fire Fox

Greetings everyone, I have defined the following styles in my CSS: .on_focus { background-color:yellow; } .off_focus { background-color:white; } Now, within my form, there is this input field: <label>Last Name</label>< ...

Saving data from a web form into a database using AJAX, JSON, and PHP

I have been attempting to save form data in a database, but for some reason my code doesn't seem to be reflecting anything. Below is the code I am using: add.php <form name='reg' > <fieldset> <legend>Student Informati ...

Tips for eliminating the trailing slash from the end of a website article's URL

I've recently delved into learning Gatsby, and I've encountered an issue with the Open Graph tag in my project. The og:image is displaying a different image than the intended thumbnail for the article. Here's an example article - . When try ...

Implementing relationships in microservices with Prisma and NestJS

Schema for User Management service: model User { id String @id @default(uuid()) username String @unique email String @unique password String } Schema for File Management service: model File ...

Unlocking the Secrets of Laravel Blade Integration in a Script File

I am attempting to create a customized store locator application using the guidance provided in this useful tutorial on Google Maps and Laravel 5. While going through various queries related to integrating Google Maps with Laravel, I came across these info ...

NVD3 struggling with handling oversized data

I am facing a major issue with the implementation of a graph using NVD3. It appears that NVD3 struggles to handle datasets containing large values. The graph in question can be viewed at: . The code snippet for the graph is provided below: nv.addGraph(fun ...

Encountering an issue with the combination of SockJS and AngularJS: Error message

Currently experimenting with Angularjs and sockjs, utilizing this helpful resource: https://github.com/bendrucker/angular-sockjs On page load, I aim to transmit data via sockjs, however, encountering an Error: INVALID_STATE_ERR on the client side when att ...

Using jQuery to Extract HTML Content from a JSON Object

I'm completely lost on what I'm doing incorrectly, but the JSON string I have looks like this: jsonp443489({"content":"<!DOCTYPE html><html><head><title>Title</title></head><body><p>Hello World< ...

Could someone please assist me in figuring out the issue with my current three.js code that is preventing it from

Recently, I decided to delve into learning three.js and followed the getting started code on the official documentation. However, I encountered a frustrating issue where the scene refused to render, leaving me completely perplexed. Here is my index.html: ...

The functionality to open the menu by clicking is experiencing issues

I'm attempting to replicate the Apple website layout. HTML structure: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" conte ...

JavaScript does not recognize Bootstrap classes

I am utilizing Bootstrap 5.3.0 and have included it through CDN links in my JS script. This is how I am injecting it using my js file within the existing website's DOM via a chrome extension named Scripty, which serves as a JS injector extension for c ...

Traversing a multidimensional array with jQuery

In my quest to iterate through a multidimensional array, I encountered the need to remove the class "list" from the divs within the array. However, there could be multiple divs with this class on my site. My initial approach involved using two for-loops, ...

Exploring TypeScript and React.js: Navigating the Map Function - Addressing Error ts(7053)

Hello everyone, I have a question and it's my first time asking here. I would appreciate any help in improving. Suppose we have two arrays in Typescript (ReactJs): const array1: String = ["prop1", "prop2"]; const array2: MyType = ...

Just because it's easy doesn't mean it will make a difference in the

I seem to be overlooking something quite simple, but alas, it eludes me. The code I have written is as follows: var count = 0; $(document).on('click', button, function() { var originalLink = button.attr('href'), ...

Develop a PHP component containing an AngularJS routing hyperlink

I have used PHP to dynamically create this HTML element: echo "<button type ='button' class='login-btn login' onclick = 'location.href=\'#!login\';'> Login </ ...

Users should always receive a notification, whether it be a success message or an

When I send data to my json and it returns true, a success message should be displayed. If it does not return true, an error message should be shown. The current issue is that the response should indicate whether it was successful or encountered an error. ...