Testing the controller passed to the Angular Material Dialog instance

First, I'm trying to execute a unit test controller, which is passed to an instance of the Angular Material Dialog .

As a general question, does it make sense to test such a controller separately or actually call $mdDialog.show() ?

I am trying to use the first method, but I am encountering some problems mainly related to the way Angular Material associates "locals" with the controller.

Here is the code that I use to trigger a dialog in my source code that works as expected:

 $mdDialog.show({ controller: 'DeviceDetailController', controllerAs: 'vm', locals: {deviceId: "123"}, bindToController: true, templateUrl: 'admin/views/deviceDetail.html', parent: angular.element(document.body), targetEvent: event }); 

I do not believe that the docs have been updated, but from version 0.9.0 or so local residents are available to the controller at the time the constructor function is called (see this issue on Github ). Here is a stripped down version of the controller constructor function under testing, so you can understand why I need a variable that needs to be passed and available when the controller is "created":

 function DeviceDetailController(devicesService) { var vm = this; vm.device = {}; // vm.deviceId = null; //this field is injected when the dialog is created, if there is one. For some reason I can't pre-assign it to null. activate(); ////////// function activate() { if (vm.deviceId != null) { loadDevice(); } } function loadDevice() { devicesService.getDeviceById(vm.deviceId) .then(function(data) { vm.device = data.collection; }; } } 

I am trying to verify that a device is assigned to vm.device when deviceId is passed to the constructor function before it is called.

Test (jasmine and sinus controlled by karma):

 describe('DeviceDetailController', function() { var $controllerConstructor, scope, mockDevicesService; beforeEach(module("admin")); beforeEach(inject(function ($controller, $rootScope) { mockDevicesService = sinon.stub({ getDeviceById: function () {} }); $controllerConstructor = $controller; scope = $rootScope.$new(); })); it('should get a device from devicesService if passed a deviceId', function() { var mockDeviceId = 3; var mockDevice = {onlyIWouldHaveThis: true}; var mockDeviceResponse = {collection: [mockDevice]}; var mockDevicePromise = { then: function (cb) { cb(mockDeviceResponse); } }; var mockLocals = {deviceId: mockDeviceId, $scope: scope}; mockDevicesService.getDeviceById.returns(mockDevicePromise); var ctrlConstructor = $controllerConstructor('DeviceDetailController as vm', mockLocals, true); angular.extend(ctrlConstructor.instance, mockLocals); ctrlConstructor(); expect(scope.vm.deviceId).toBe(mockDeviceId); expect(scope.vm.device).toEqual(mockDevice); }); }); 

When I run this, the first statement passes, and the second one fails ("The expected object ({}) equals the object ({onlyIWouldHaveThis: true}).), Which shows me that deviceId is being entered into the scope controller, but apparently not in time for the if clause in the activate () method to view it.

You will notice that I am trying to imitate the main procedure that Angular Material uses by calling $ controller () with the third argument set to true, which calls $ controller () to return the controller constructor function, as opposed to the resulting controller. Then I should be able to extend the constructor using my local variables (just like Angular Material does in the code above), and then call the constructor function to create an instance of the controller.

I tried several things, including transferring the selection area to the controller, calling $rootScope.$new(true) , without effect (in fact, I cannot say that I fully understand the selection of the area, but $ mdDialog uses it by default).

Any help is appreciated!

+6
source share
1 answer

The first thing I will try is to lose β€œlike vm” from your call to $ controller. You can simply use the return value for your expectation, and not for checking the scope.

Try the following:

 var ctrlConstructor = $controllerConstructor('DeviceDetailController', mockLocals, true); angular.extend(ctrlConstructor.instance, mockLocals); var vm = ctrlConstructor(); expect(vm.deviceId).toBe(mockDeviceId); expect(vm.device).toEqual(mockDevice); 
0
source

All Articles