I have angular controller, which should work with images. It have a watcher for property file
in scope. If property will contain array of files, these files (only first file) should be read by FileReader
and converted to base64 string and added to page. Something like this:
$scope.$watch('file', function (files) {
if (files && files.length > 0) {
if (files[0].type && files[0].type.match('image.*')) {
var reader = new FileReader();
reader.onload = function (e) {
render(e.target.result);
};
reader.readAsDataURL(files[0]);
}
}
});
and render
function:
function render (src) {
var image = new Image();
image.addEventListener('load', function () {
if (image.width < MIN_SIZE || image.height < MIN_SIZE) {
$scope.error = $filter('localize')('UploaderWindow_ImageSizeError');
$scope.$apply();
} else {
new global.ICropper('original-image', {
gap: 0,
keepSquare: true,
image: src,
preview: ['cropped-image']
});
}
});
image.addEventListener('error', function () {
$scope.error = $filter('localize')('UploaderWindow_SelectImage');
$scope.$apply();
});
image.src = src;
};
ICropper should create img
element in DOM with base64 in src
attribute.
The problem is, I have unit test for this functionality. Test case:
it('Should render new image from file input', function () {
var imageData = image.split(',')[1],
imageType = image.split(',')[0].replace('data:', '').replace(';base64', ''),
file = base64toBlob(imageData, imageType);
expect(originalImage.lastElementChild).toBe(null);
runs(function () {
$scope.file = [file];
$scope.$apply();
});
waitsFor(function () {
return originalImage.lastElementChild;
}, 'waiting_original_form');
runs(function () {
expect(originalImage.lastElementChild.src).toBe(image);
});
});
Variable image
contains valid base64 string, originalImage.lastElementChild
- img element, which should be created by ICropper. The body of base64toBlob
function:
function base64toBlob (b64Data, contentType) {
var binary = atob(b64Data.replace(/\s/g, '')),
binaryLength = binary.length,
buffer = new ArrayBuffer(binaryLength),
view = new Uint8Array(buffer);
for (var i = 0; i < binaryLength; i++) {
view[i] = binary.charCodeAt(i);
}
return new Blob([view], {type: contentType});
}
This test successfully passed in Chrome, but not in PhantomJS:
timeout: timed out after 5000 msec waiting for waiting_original_form
I think, it's because load event for image not fired, error fired instead. But I don't understand why? I know, that Blob
not defined in PhantomJS, so I use this polyfill: https://github.com/eligrey/Blob.js