使用 Jasmine 和 Angular 测试 FileReader

Testing FileReader with Jasmine and Angular

我有一个基于此处示例的非常简单的指令:

https://veamospues.wordpress.com/2014/01/27/reading-files-with-angularjs/

但我正在努力使用 Jasmine 正确测试指令,因为我似乎无法按预期触发事件。

我的指令:

var fileReaderModule = angular.module('fileReaderModule', []);

fileReaderModule.controller('fileReaderCtrl', [ '$scope', function($scope) {
    $scope.setContent = function($fileContent) {
        $scope.content = $fileContent;
        console.log($fileContent);
    };

    $scope.getContent = function() {
        console.info("content:", $scope.content);
        return $scope.content;
    };
} ]);

fileReaderModule.directive('onReadFile', function($parse) {
    return {
        restrict : 'A',
        scope : false,
        link : function(scope, element, attrs) {
            var fn = $parse(attrs.onReadFile);

            element.on('change', function(onChangeEvent) {
                var reader = new FileReader();

                reader.addEventListener("load", function(onLoadEvent) {
                    scope.$apply(function() {
                        fn(scope, {
                            $fileContent : onLoadEvent.target.result
                        });
                    });
                }, false);

                reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]);
            });
        }
    };
});

我的测试规格:

    describe("Test suite for the fileReaderModule angular module", function() {
    var scope, rootScope, compile, fileReaderController, element, eventListener, windowMock;

    beforeEach(function() {
        module('fileReaderModule');
        inject(function($rootScope, $compile, $controller, $window) {
            rootScope = $rootScope;
            scope = $rootScope.$new();
            compile = $compile;
            windowMock = $window;
            $fileReaderController = $controller('fileReaderCtrl', {
                '$scope' : scope
            });
        });
    });
    describe("Tests focused on the fileReaderCtrl controller", function() {
        it("should set the file contents correctly", function() {
            scope.setContent('1');
            expect(scope.content).toEqual('1');
            })
        it("should get the file contents correctly", function() {
            scope.content = 'test';
            expect(scope.getContent()).toEqual('test');
            })
        it("should set and then get the file contents correctly", function() {
            scope.setContent('test');
            expect(scope.getContent()).toEqual('test');
            })
    });
    describe("Tests focused on the onReadFile directive", function() {
        beforeEach(function() {
            eventListener = jasmine.createSpy();
            spyOn(windowMock, "FileReader").andReturn({
                addEventListener: eventListener,
                readAsText : function(file) {
                  // do nothing.
                }
            });
        });
       it("should set the file contents correctly", function() {
            var elm = compile('<div on-read-file="name"></div>')(scope);
            scope.$digest();
            scope.$broadcast('change', ['file.txt']);
            scope.$broadcast('load', ['file.txt']);
            expect(windowMock.FileReader).toHaveBeenCalled();
            })
    });
});

有关完整示例,请查看此 jsfiddle:

http://jsfiddle.net/KramKroc/noddv7ny/1/

您正在调用 scope.$broadcast('change'),但此 angular 事件没有侦听器。相反,您可以在新元素上调度自定义事件:

var elm = compile('<div on-read-file="name"></div>')(scope);
var div = elm[0];
div.files = ['file.txt'];
div.dispatchEvent(new CustomEvent('change'));
expect(windowMock.FileReader).toHaveBeenCalled();

检查this fiddle

如果您想测试读取文件作为文本,您可以在模拟的 readAsText 函数中调用 onload 函数:

    spyOn(window, 'FileReader').and.returnValue({
      readAsText: function(file) {
        this.onload({
          target: {
            result: 'text content'
          }
        });
      }
    });