diff --git a/.gitignore b/.gitignore index 260610f..cb9305b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules +npm-debug.log .DS_Store *-browserified.js +test/new-unit/lib/ diff --git a/.jshintrc b/.jshintrc index 811935d..c442cc7 100644 --- a/.jshintrc +++ b/.jshintrc @@ -31,7 +31,16 @@ "start", "chrome", "define", - "self" + "self", + "describe", + "it", + "chai", + "sinon", + "mocha", + "before", + "beforeEach", + "after", + "afterEach" ], "globals": { diff --git a/Gruntfile.js b/Gruntfile.js index 6c55a0e..eb7bd31 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -40,7 +40,7 @@ module.exports = function(grunt) { }, jshint: { - all: ['Gruntfile.js', 'src/*.js', 'src/js/**/*.js', 'test/unit/*.js', 'test/integration/*.js'], + all: ['Gruntfile.js', 'src/*.js', 'src/js/**/*.js', 'test/new-unit/*.js', 'test/unit/*.js', 'test/integration/*.js'], options: { jshintrc: '.jshintrc' } @@ -56,6 +56,15 @@ module.exports = function(grunt) { ] } } + }, + + mocha: { + all: { + options: { + urls: ['http://localhost:<%= connect.test.options.port %>/test/new-unit/index.html'], + run: false + } + } } }); @@ -63,10 +72,11 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-connect'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-qunit'); + grunt.loadNpmTasks('grunt-mocha'); // Default task(s). grunt.registerTask('dev', ['connect:dev']); - grunt.registerTask('test', ['jshint', 'connect:test', 'qunit']); + grunt.registerTask('test', ['jshint', 'connect:test', 'mocha', 'qunit']); grunt.registerTask('prod', ['connect:prod']); }; \ No newline at end of file diff --git a/package.json b/package.json index 94f7716..882f461 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,13 @@ }, "devDependencies": { "grunt": "~0.4.1", + "mocha": "~1.12.0", + "chai": "~1.7.2", + "sinon": "~1.7.3", "grunt-contrib-connect": "~0.3.0", - "grunt-contrib-jshint": "~0.5.3", - "grunt-contrib-qunit": "~0.2.1" + "grunt-contrib-jshint": "~0.6.3", + "grunt-contrib-qunit": "~0.2.2", + "grunt-mocha-test": "~0.6.3", + "grunt-mocha": "~0.4.1" } } \ No newline at end of file diff --git a/res/copy-deps.sh b/res/copy-deps.sh index 0d21a5d..33fb41b 100755 --- a/res/copy-deps.sh +++ b/res/copy-deps.sh @@ -19,4 +19,10 @@ cd ./node_modules/smtp-client/ node build.js && cp ./src-gen/*.js ../../src/lib/ cd ../../ +# copy test dependencies +mkdir ./test/new-unit/lib/ +cp ./node_modules/mocha/mocha.css ./node_modules/mocha/mocha.js ./test/new-unit/lib/ +cp ./node_modules/chai/chai.js ./test/new-unit/lib/ +cp ./node_modules/sinon/pkg/sinon.js ./test/new-unit/lib/ + echo "\n--> finished copying dependencies.\n" diff --git a/src/js/app-controller.js b/src/js/app-controller.js index 6304c4c..52332ee 100644 --- a/src/js/app-controller.js +++ b/src/js/app-controller.js @@ -156,8 +156,6 @@ define(['jquery', 'ImapClient', 'SmtpClient', 'js/dao/email-dao', 'js/dao/keycha // init email dao var account = new app.model.Account({ - imapOptions: imapOptions, - smtpOptions: smtpOptions, emailAddress: userId, symKeySize: app.config.symKeySize, symIvSize: app.config.symIvSize, diff --git a/src/js/dao/email-dao.js b/src/js/dao/email-dao.js index 2664eca..87557fc 100644 --- a/src/js/dao/email-dao.js +++ b/src/js/dao/email-dao.js @@ -1,16 +1,21 @@ -/** - * A high-level Data-Access Api for handling Email synchronization - * between the cloud service and the device's local storage - */ -define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao', - 'js/dao/devicestorage-dao', 'js/app-config', 'js/model/account-model' -], function(_, util, crypto, jsonDB, devicestorage, app) { +define(function(require) { 'use strict'; - var EmailDAO = function(cloudstorage, keychain, imapClient, smtpClient) { + var _ = require('underscore'), + util = require('cryptoLib/util'), + crypto = require('js/crypto/crypto'), + jsonDB = require('js/dao/lawnchair-dao'), + devicestorage = require('js/dao/devicestorage-dao'), + app = require('js/app-config'); + require('js/model/account-model'); + + /** + * A high-level Data-Access Api for handling Email synchronization + * between the cloud service and the device's local storage + */ + var EmailDAO = function(keychain, imapClient, smtpClient) { var self = this; - self._cloudstorage = cloudstorage; self._keychain = keychain; self._imapClient = imapClient; self._smtpClient = smtpClient; @@ -35,8 +40,11 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-da // login IMAP client if existent if (self._imapClient) { - self._imapClient.login(function() { - console.log('logged into imap.'); + self._imapClient.login(function(err) { + if (err) { + callback(err); + return; + } initKeychain(); }); } else { diff --git a/src/js/model/account-model.js b/src/js/model/account-model.js index f78439d..c9ad68d 100644 --- a/src/js/model/account-model.js +++ b/src/js/model/account-model.js @@ -23,4 +23,5 @@ define(['backbone', 'js/app-config', 'js/model/folder-model'], function(Backbone }); + return app.model.Account; }); \ No newline at end of file diff --git a/test/new-unit/cloudstorage-dao-test.js b/test/new-unit/cloudstorage-dao-test.js new file mode 100644 index 0000000..1f25187 --- /dev/null +++ b/test/new-unit/cloudstorage-dao-test.js @@ -0,0 +1,20 @@ +define(function() { + 'use strict'; + + var expect = chai.expect; + + describe('Cloudstorage DAO unit tests', function() { + + beforeEach(function() {}); + + afterEach(function() {}); + + describe('init', function() { + it('should fail due to error in imap login', function() { + expect(true).to.be.ok; + }); + }); + + }); + +}); \ No newline at end of file diff --git a/test/new-unit/email-dao-test.js b/test/new-unit/email-dao-test.js new file mode 100644 index 0000000..bbe43ec --- /dev/null +++ b/test/new-unit/email-dao-test.js @@ -0,0 +1,79 @@ +define(function(require) { + 'use strict'; + + var KeychainDAO = require('js/dao/keychain-dao'), + EmailDAO = require('js/dao/email-dao'), + SmtpClient = require('SmtpClient'), + ImapClient = require('ImapClient'), + Account = require('js/model/account-model'), + app = require('js/app-config'), + expect = chai.expect; + + var emaildaoTest = { + user: "whiteout.test@t-online.de", + passphrase: 'asdf', + asymKeySize: 512 + }; + + describe('Email DAO unit tests', function() { + + var emailDao, account, + keychainStub, imapClientStub, smtpClientStub; + + beforeEach(function() { + account = new Account({ + emailAddress: emaildaoTest.user, + symKeySize: app.config.symKeySize, + symIvSize: app.config.symIvSize, + asymKeySize: emaildaoTest.asymKeySize + }); + + keychainStub = sinon.createStubInstance(KeychainDAO); + imapClientStub = sinon.createStubInstance(ImapClient); + smtpClientStub = sinon.createStubInstance(SmtpClient); + + emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub); + }); + + afterEach(function() {}); + + describe('init', function() { + + it('should fail due to error in imap login', function(done) { + imapClientStub.login.yields(42); + + emailDao.init(account, emaildaoTest.passphrase, function(err) { + expect(err).to.equal(42); + done(); + }); + }); + + it('should fail due to error in getUserKeyPair', function(done) { + imapClientStub.login.yields(); + keychainStub.getUserKeyPair.yields(42); + + emailDao.init(account, emaildaoTest.passphrase, function(err) { + expect(imapClientStub.login.calledOnce).to.be.true; + expect(err).to.equal(42); + done(); + }); + }); + + it('should initialize', function(done) { + imapClientStub.login.yields(); + keychainStub.getUserKeyPair.yields(); + keychainStub.putUserKeyPair.yields(); + + emailDao.init(account, emaildaoTest.passphrase, function(err) { + expect(imapClientStub.login.calledOnce).to.be.true; + expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; + expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; + expect(err).to.not.exist; + done(); + }); + }); + }); + + }); + +}); \ No newline at end of file diff --git a/test/new-unit/index.html b/test/new-unit/index.html new file mode 100644 index 0000000..7649fac --- /dev/null +++ b/test/new-unit/index.html @@ -0,0 +1,19 @@ + + + + + JavaScript Unit Tests + + + + +
+ + + + + + + + + diff --git a/test/new-unit/main.js b/test/new-unit/main.js new file mode 100644 index 0000000..64ef977 --- /dev/null +++ b/test/new-unit/main.js @@ -0,0 +1,32 @@ +'use strict'; + +require(['../../src/require-config'], function() { + require.config({ + baseUrl: '../../src/lib' + }); + + // Start the main app logic. + require(['js/app-config', 'cordova'], function(app) { + // clear session storage of failed tests, so async order is correct after fail & refresh + window.sessionStorage.clear(); + window.Worker = undefined; + + app.config.workerPath = '../../src/js'; + + startTests(); + }); +}); + +function startTests() { + mocha.setup('bdd'); + + require( + [ + 'test/new-unit/email-dao-test', + 'test/new-unit/cloudstorage-dao-test' + ], function() { + //Tests loaded, run tests + mocha.run(); + } + ); +} \ No newline at end of file diff --git a/test/unit/main.js b/test/unit/main.js index 4ea19d5..0ec2add 100644 --- a/test/unit/main.js +++ b/test/unit/main.js @@ -25,8 +25,7 @@ function startTests() { 'test/unit/lawnchair-dao-test', 'test/unit/keychain-dao-test', 'test/unit/crypto-test', - 'test/unit/devicestorage-dao-test', - 'test/unit/email-dao-test' + 'test/unit/devicestorage-dao-test' ], function() { //Tests loaded, run tests QUnit.start();