2015-06-26 23 views
7

Ho un semplice uploader di immagini in un sito Web e una funzione javascript che utilizza FileReader e converte l'immagine in base64 per visualizzarlo per l'utente senza caricarlo sul server effettivo.Test di Javascript con mocha il file html5 api?

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

Ora sto cercando di scrivere i test di questo metodo utilizzando Mocha e Chai. Il mio pensiero è che voglio verificare se il file.dataUrl è stato creato correttamente ed è base64. Quindi mi piacerebbe prendere in giro il file locale in qualche modo in ambiente di test (non sono sicuro di come farlo). O non dovrei assolutamente provarlo e supporre che funzioni?

+0

mi chiedo la stessa cosa pure. – frogbandit

risposta

3

La risposta qui dipende un po '. Il tuo metodo "generateThumbs" ha altra logica che caricare un contenuto di file e assegnarlo a una proprietà di un oggetto passato? Oppure ha altre logiche come generare l'anteprima dai dati dell'immagine, leggere le proprietà dei file e assegnarle all'oggetto file? e così via?

In tal caso, quindi, suggerirei di prendere in giro l'oggetto FileReader con il proprio, in modo da poter controllare i risultati del test. Tuttavia, non è la funzionalità FileReaders che desideri testare, è la tua logica. Quindi dovresti assumere che FileReader funzioni e verifica che il tuo codice che dipende da esso funzioni.

Ora, poiché il metodo che hai postato era un po 'piccolo, in tal caso supponevo che funzionasse, rinominare il metodo e lavorare sul test del resto del codice. Ma c'è un posto per avere un tale finto, e devo ammettere che è stato molto divertente per capire come per deridere il target dell'evento, quindi mi darà un esempio qui, utilizzando il metodo di come base:

//This implements the EventTarget interface 
//and let's 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); 
    }); 

} 

Ora abbiamo un piccolo oggetto che si comporta come un FileReader, ma controlliamo il suo comportamento e ora possiamo usare il nostro metodo e iniettarlo, consentendoci così di usare questo simulato per i test e la cosa reale per la produzione.

Così possiamo ora scrivere unit test belle per testare questo fuori: presumo di avere moka e configurazione chai

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); 
    }); 
}); 

Ecco un JSFiddle lavora esempio: https://jsfiddle.net/workingClassHacker/jL4xpwwv/2/

I vantaggi qui sono è possibile creare diverse versioni di questo simulato:

  • cosa succede quando vengono dati dati corretti?
  • cosa succede quando vengono dati dati errati?
  • cosa succede quando la richiamata non viene mai chiamata?
  • cosa succede quando viene inserito un file troppo grande?
  • cosa succede quando viene inserito un certo tipo di mimo?

È possibile offcourse massicciamente semplificare il mock se tutto ciò che serve è che un evento:

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); 
} 

che è come mi sarebbe effettivamente fare questo. E creare molti di questi per scopi diversi.

Versione semplice: https://jsfiddle.net/workingClassHacker/7g44h9fj/3/