Testing Javascript using mocha html5 api file?

I have a simple image downloader on a website and a javascript function that uses FileReader and converts the image to base64 to display it for the user without uploading it to the actual server.

 function generateThumb(file) { var fileReader = new FileReader(); fileReader.readAsDataURL(file); fileReader.onload = function (e) { // Converts the image to base64 file.dataUrl = e.target.result; }; } 

Now I am trying to write tests for this method using Mocha and Chai . I think I want to check if file.dataUrl created file.dataUrl , and that is base64. Therefore, I would like to somehow mock a local file in a test environment (not sure how to do this). Or should I not check this at all and assume that it works?

+7
javascript filereader mocha html5-filesystem
source share
1 answer

The answer here is a little dependent. Does your generateThumbs method have a different logic than loading the contents of files and assigning this property to a passed object? Or does it have other logic, such as creating a sketch from image data, reading file properties and assigning them to a file? and so on?

If so, I would say that you are mocking the FileReader object with your own so that you can control the results of your tests. However, this is not the FileReaders function that you want to test, it is your own logic. Therefore, you should assume that FileReader is working and testing that your code, which depends on it, is working.

Now, since the method you posted is a bit on the small side, in this case, I would just assume that it works, rename this method and work on testing the rest of your code. But there is room for such a layout, and I must admit that it was quite interesting to figure out how to mock the purpose of the event, so I will give an example here, using your method as the basis:

 //This implements the EventTarget interface //and let us control when, where and what triggers events //and what they return //it takes in a spy and some fake return data var FakeFileReader = function(spy, fakeData) { this.listeners = {}; this.fakeData = fakeData; this.spy = spy; this.addEventListener('load', function () { this.spy.loaded = true; }); }; //Fake version of the method we depend upon FakeFileReader.prototype.readAsDataURL = function(file){ this.spy.calledReadAsDataURL = true; this.spy.file = file; this.result = this.fakeData; this.dispatchEvent({type:'load'}); //assume file is loaded, and send event }; FakeFileReader.prototype.listeners = null; FakeFileReader.prototype.addEventListener = function(type, callback) { if(!(type in this.listeners)) { this.listeners[type] = []; } this.listeners[type].push(callback); }; FakeFileReader.prototype.removeEventListener = function(type, callback) { if(!(type in this.listeners)) { return; } var stack = this.listeners[type]; for(var i = 0, l = stack.length; i < l; i++) { if(stack[i] === callback){ stack.splice(i, 1); return this.removeEventListener(type, callback); } } }; FakeFileReader.prototype.dispatchEvent = function(event) { if(!(event.type in this.listeners)) { return; } var stack = this.listeners[event.type]; event.target = this; for(var i = 0, l = stack.length; i < l; i++) { stack[i].call(this, event); } }; // Your method function generateThumb(file, reader){ reader.readAsDataURL(file); reader.addEventListener('load', function (e) { file.dataUrl = base64(e.target.result); }); } 

Now we have a nice little object that behaves like a FileReader, but we control its behavior, and now we can use our method and implement it, which allows us to use this layout for testing and the real thing for production.

So now we can write some good unit tests to check this out: I assume you have mocha and chai installed

 describe('The generateThumb function', function () { var file = { src: 'image.file'}; var readerSpy = {}; var testData = 'TESTDATA'; var reader = new FakeFileReader(readerSpy, testData); it('should call the readAsDataURL function when given a file name and a FileReader', function () { generateThumb(file, reader); expect(readerSpy.calledReadAsDataURL).to.be.true; expect(readerSpy.loaded).to.be.true; }); it('should load the file and convert the data to base64', function () { var expectedData = 'VEVTVERBVEE='; generateThumb(file, reader); expect(readerSpy.file.src).to.equal(file.src); expect(readerSpy.file.dataUrl).to.equal(expectedData); }); }); 

Here is a JSFiddle working example: https://jsfiddle.net/workingClassHacker/jL4xpwwv/2/

The benefits are here - you can create several versions of this layout:

  • What happens when the correct data is specified?
  • What happens when invalid data is provided?
  • What happens when a callback is never called?
  • What happens when an oversized file is placed?
  • what happens when a particular mime type is given?

You can opt out of mass simplification of the layout if all you need is a single event:

 function FakeFileReader(spy, testdata){ return { readAsDataURL:function (file) { spy.file = file; spy.calledReadAsDataURL = true; spy.loaded = true; this.target = {result: testdata}; this.onload(this); } }; } function generateThumb(file, reader){ reader.onload = function (e) { file.dataUrl = base64(e.target.result); }; reader.readAsDataURL(file); } 

Here is how I would do it. And create some of them for different purposes.

Simple version: https://jsfiddle.net/workingClassHacker/7g44h9fj/3/

+3
source share

All Articles