Testing component that opens md-dialog

2019-07-10 07:41发布

问题:

I am trying to write a unit test for an Angular component that opens a dialog, but am unable to do so because I cannot trigger the closing of the dialog.

How can I cause the md dialog to resolve from the test case?

I have created a repository with a basic example where the problem can be reproduced, and copied the central bits below. There is an index.html to manually verify that the code is working, a test case that displays the problem and an example of how the tests are written in the md code.

Repository - https://github.com/gseabrook/md-dialog-test-issue

The component is extremely basic

angular
.module('test', ['ngMaterial'])
.component('dialogTest', {
    template: '<button ng-click="showDialog()">Show Dialog</button>',
    controller: function($scope, $mdDialog) {
        var self = this;

        $scope.showDialog = function() {
            self.dialogOpen = true;

            var confirm = $mdDialog.confirm()
                .title('Dialog title')
                .ok('OK')
                .cancel('Cancel');

            $mdDialog.show(confirm).then(function(result) {
                self.dialogOpen = false;
            }, function() {
                self.dialogOpen = false;
            });
        }
    }
});

And the test is also very simple

it("should open then close the dialog", function() {
    var controller = element.controller("dialogTest");

    expect(controller.dialogOpen).toEqual(undefined);

    expect(element.find('button').length).toEqual(1);
    element.find('button').triggerHandler('click');

    expect(controller.dialogOpen).toBeTruthy();

    rootScope.$apply();
    material.flushInterimElement();

    element.find('button').eq(2).triggerHandler('click');

    rootScope.$apply();
    material.flushInterimElement();

    expect(controller.dialogOpen).toBeFalsy();
});

回答1:

I managed to resolve the issue by setting the root element as the problem seemed to be related to element being compiled in the test being unconnected with the root element that angular-material appended the dialog too.

I've updated the github repository with the full code, but the important bits are

beforeEach(module(function($provide) {
    rootElem = angular.element("<div></div>")
    $provide.value('$rootElement', rootElem);
}));

beforeEach(inject(function(_$rootScope_, _$compile_, $mdDialog, _$material_) {
    ...
    element = getCompiledElement();
    angular.element(window.document.body).append(rootElem);
    angular.element(rootElem).append(element);
}));