Reputation: 496
I've a very simple directive based on the example here:
https://veamospues.wordpress.com/2014/01/27/reading-files-with-angularjs/
But I'm struggling with getting the directive tested correctly with Jasmine as I cannot seem to get the events to be triggered as I expected.
My directive:
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]);
});
}
};
});
My test spec:
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();
})
});
});
For the full example, take a look at this jsfiddle:
http://jsfiddle.net/KramKroc/noddv7ny/1/
Upvotes: 0
Views: 4399
Reputation: 1652
If you want to test the reading files as text you can call the onload function in your mocked readAsText
function:
spyOn(window, 'FileReader').and.returnValue({
readAsText: function(file) {
this.onload({
target: {
result: 'text content'
}
});
}
});
Upvotes: 1
Reputation: 5825
You are calling scope.$broadcast('change')
, but there are no listeners for this angular event. Instead you could dispatch a custom event on the new element:
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();
Check this fiddle.
Upvotes: 1