1
0
mirror of https://github.com/moparisthebest/mail synced 2024-12-23 07:48:48 -05:00

Merge pull request #29 from whiteout-io/dev/no-jquery

Dev/no jquery
This commit is contained in:
Tankred Hase 2014-03-03 17:12:28 +01:00
commit 386fbfa307
6 changed files with 241 additions and 239 deletions

View File

@ -4,8 +4,7 @@
define(function(require) { define(function(require) {
'use strict'; 'use strict';
var $ = require('jquery'), var ImapClient = require('imap-client'),
ImapClient = require('imap-client'),
mailreader = require('mailreader'), mailreader = require('mailreader'),
PgpMailer = require('pgpmailer'), PgpMailer = require('pgpmailer'),
EmailDAO = require('js/dao/email-dao'), EmailDAO = require('js/dao/email-dao'),
@ -149,32 +148,31 @@ define(function(require) {
}; };
self.getCertficate = function(localCallback) { self.getCertficate = function(localCallback) {
var xhr;
if (self.certificate) { if (self.certificate) {
localCallback(null, self.certificate); localCallback(null, self.certificate);
return; return;
} }
// fetch pinned local ssl certificate // fetch pinned local ssl certificate
xhr = new XMLHttpRequest(); var ca = new RestDAO({
xhr.open('GET', '/ca/Google_Internet_Authority_G2.pem'); baseUri: '/ca'
xhr.onload = function() { });
if (xhr.readyState === 4 && xhr.status === 200 && xhr.responseText) {
self.certificate = xhr.responseText; ca.get({
localCallback(null, self.certificate); uri: '/Google_Internet_Authority_G2.pem',
} else { type: 'text'
}, function(err, cert) {
if (err || !cert) {
localCallback({ localCallback({
errMsg: 'Could not fetch pinned certificate!' errMsg: 'Could not fetch pinned certificate!'
}); });
return;
} }
};
xhr.onerror = function() { self.certificate = cert;
localCallback({ localCallback(null, self.certificate);
errMsg: 'Could not fetch pinned certificate!' return;
}); });
};
xhr.send();
}; };
self.isOnline = function() { self.isOnline = function() {
@ -277,29 +275,24 @@ define(function(require) {
} }
// fetch gmail user's email address from the Google Authorization Server endpoint // fetch gmail user's email address from the Google Authorization Server endpoint
$.ajax({ var googleEndpoint = new RestDAO({
url: 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' + token, baseUri: 'https://www.googleapis.com'
type: 'GET', });
dataType: 'json',
success: function(info) {
if (!info || !info.email) {
callback({
errMsg: 'Error looking up email address on google api!'
});
return;
}
// cache the email address on the device googleEndpoint.get({
self._appConfigStore.storeList([info.email], itemKey, function(err) { uri: '/oauth2/v1/tokeninfo?access_token=' + token
callback(err, info.email); }, function(err, info) {
}); if (err || !info || !info.email) {
},
error: function(xhr, textStatus, err) {
callback({ callback({
errMsg: xhr.status + ': ' + xhr.statusText, errMsg: 'Error looking up email address on google api!'
err: err
}); });
return;
} }
// cache the email address on the device
self._appConfigStore.storeList([info.email], itemKey, function(err) {
callback(err, info.email);
});
}); });
} }
}; };
@ -310,35 +303,34 @@ define(function(require) {
self.fetchOAuthToken = function(callback) { self.fetchOAuthToken = function(callback) {
// get OAuth Token from chrome // get OAuth Token from chrome
chrome.identity.getAuthToken({ chrome.identity.getAuthToken({
'interactive': true 'interactive': true
}, }, onToken);
function(token) {
if ((chrome && chrome.runtime && chrome.runtime.lastError) || !token) { function onToken(token) {
if ((chrome && chrome.runtime && chrome.runtime.lastError) || !token) {
callback({
errMsg: 'Error fetching an OAuth token for the user!'
});
return;
}
// get email address for the token
self.queryEmailAddress(token, function(err, emailAddress) {
if (err || !emailAddress) {
callback({ callback({
errMsg: 'Error fetching an OAuth token for the user!', errMsg: 'Error looking up email address on login!',
err: chrome.runtime.lastError err: err
}); });
return; return;
} }
// get email address for the token // init the email dao
self.queryEmailAddress(token, function(err, emailAddress) { callback(null, {
if (err || !emailAddress) { emailAddress: emailAddress,
callback({ token: token
errMsg: 'Error looking up email address on login!',
err: err
});
return;
}
// init the email dao
callback(null, {
emailAddress: emailAddress,
token: token
});
}); });
} });
); }
}; };
self.buildModules = function() { self.buildModules = function() {

View File

@ -1,8 +1,7 @@
define(function(require) { define(function(require) {
'use strict'; 'use strict';
var $ = require('jquery'), var config = require('js/app-config').config;
config = require('js/app-config').config;
var RestDAO = function(options) { var RestDAO = function(options) {
if (options && options.baseUri) { if (options && options.baseUri) {
@ -18,7 +17,7 @@ define(function(require) {
* @param {String} options.type (optional) The type of data that you're expecting back from the server: json, xml, text. Default: json. * @param {String} options.type (optional) The type of data that you're expecting back from the server: json, xml, text. Default: json.
*/ */
RestDAO.prototype.get = function(options, callback) { RestDAO.prototype.get = function(options, callback) {
var acceptHeader; var xhr, acceptHeader;
if (typeof options.uri === 'undefined') { if (typeof options.uri === 'undefined') {
callback({ callback({
@ -44,66 +43,97 @@ define(function(require) {
return; return;
} }
$.ajax({ xhr = new XMLHttpRequest();
url: this._baseUri + options.uri, xhr.open('GET', this._baseUri + options.uri);
type: 'GET', xhr.setRequestHeader('Accept', acceptHeader);
dataType: options.type,
headers: { xhr.onload = function() {
'Accept': acceptHeader if (xhr.readyState === 4 && xhr.status === 200) {
}, var res;
success: function(res, textStatus, xhr) { if (options.type === 'json') {
res = JSON.parse(xhr.responseText);
} else {
res = xhr.responseText;
}
callback(null, res, xhr.status); callback(null, res, xhr.status);
}, return;
error: function(xhr, textStatus, err) {
callback({
code: xhr.status,
errMsg: xhr.statusText,
err: err
});
} }
});
callback({
code: xhr.status,
errMsg: xhr.statusText
});
};
xhr.onerror = function(e) {
callback({
errMsg: 'Error: ' + e.error
});
};
xhr.send();
}; };
/** /**
* PUT (create/update) request * PUT (create/update) request
*/ */
RestDAO.prototype.put = function(item, uri, callback) { RestDAO.prototype.put = function(item, uri, callback) {
$.ajax({ var xhr;
url: this._baseUri + uri,
type: 'PUT', xhr = new XMLHttpRequest();
data: JSON.stringify(item), xhr.open('PUT', this._baseUri + uri);
contentType: 'application/json', xhr.setRequestHeader('Content-Type', 'application/json');
success: function(res, textStatus, xhr) {
callback(null, res, xhr.status); xhr.onload = function() {
}, if (xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 201 || xhr.status === 304)) {
error: function(xhr, textStatus, err) { callback(null, xhr.responseText, xhr.status);
callback({ return;
code: xhr.status,
errMsg: xhr.statusText,
err: err
});
} }
});
callback({
code: xhr.status,
errMsg: xhr.statusText
});
};
xhr.onerror = function(e) {
callback({
errMsg: 'Error: ' + e.error
});
};
xhr.send(JSON.stringify(item));
}; };
/** /**
* DELETE (remove) request * DELETE (remove) request
*/ */
RestDAO.prototype.remove = function(uri, callback) { RestDAO.prototype.remove = function(uri, callback) {
$.ajax({ var xhr;
url: this._baseUri + uri,
type: 'DELETE', xhr = new XMLHttpRequest();
success: function(res, textStatus, xhr) { xhr.open('DELETE', this._baseUri + uri);
callback(null, res, xhr.status);
}, xhr.onload = function() {
error: function(xhr, textStatus, err) { if (xhr.readyState === 4 && xhr.status === 200) {
callback({ callback(null, xhr.responseText, xhr.status);
code: xhr.status, return;
errMsg: xhr.statusText,
err: err
});
} }
});
callback({
code: xhr.status,
errMsg: xhr.statusText
});
};
xhr.onerror = function(e) {
callback({
errMsg: 'Error: ' + e.error
});
};
xhr.send();
}; };
return RestDAO; return RestDAO;

File diff suppressed because one or more lines are too long

View File

@ -14,7 +14,6 @@
lawnchair: 'lawnchair/lawnchair-git', lawnchair: 'lawnchair/lawnchair-git',
lawnchairSQL: 'lawnchair/lawnchair-adapter-webkit-sqlite-git', lawnchairSQL: 'lawnchair/lawnchair-adapter-webkit-sqlite-git',
lawnchairIDB: 'lawnchair/lawnchair-adapter-indexed-db-git', lawnchairIDB: 'lawnchair/lawnchair-adapter-indexed-db-git',
jquery: 'jquery/jquery-2.0.3.min',
angular: 'angular/angular.min', angular: 'angular/angular.min',
angularRoute: 'angular/angular-route.min', angularRoute: 'angular/angular-route.min',
angularTouch: 'angular/angular-touch.min', angularTouch: 'angular/angular-touch.min',

View File

@ -5,14 +5,8 @@ define(function(require) {
EmailDAO = require('js/dao/email-dao'), EmailDAO = require('js/dao/email-dao'),
OutboxBO = require('js/bo/outbox'), OutboxBO = require('js/bo/outbox'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'), DeviceStorageDAO = require('js/dao/devicestorage-dao'),
$ = require('jquery'),
expect = chai.expect; expect = chai.expect;
var appControllerTest = {
user: 'test@exmaple.com',
passphrase: 'asdf'
};
describe('App Controller unit tests', function() { describe('App Controller unit tests', function() {
var emailDaoStub, outboxStub, appConfigStoreStub, isOnlineStub, var emailDaoStub, outboxStub, appConfigStoreStub, isOnlineStub,
identityStub; identityStub;
@ -27,11 +21,6 @@ define(function(require) {
isOnlineStub = sinon.stub(controller, 'isOnline'); isOnlineStub = sinon.stub(controller, 'isOnline');
sinon.stub($, 'get');
sinon.stub($, 'ajax').yieldsTo('success', {
email: appControllerTest.user
});
window.chrome = window.chrome || {}; window.chrome = window.chrome || {};
window.chrome.identity = window.chrome.identity || {}; window.chrome.identity = window.chrome.identity || {};
if (typeof window.chrome.identity.getAuthToken !== 'function') { if (typeof window.chrome.identity.getAuthToken !== 'function') {
@ -41,8 +30,6 @@ define(function(require) {
}); });
afterEach(function() { afterEach(function() {
$.get.restore();
$.ajax.restore();
identityStub.restore(); identityStub.restore();
isOnlineStub.restore(); isOnlineStub.restore();
}); });
@ -180,30 +167,49 @@ define(function(require) {
}); });
describe('fetchOAuthToken', function() { describe('fetchOAuthToken', function() {
it('should work the first time', function(done) { var queryEmailAddressStub;
appConfigStoreStub.listItems.yields(null, []);
appConfigStoreStub.storeList.yields();
identityStub.yields('token42');
controller.fetchOAuthToken(function(err) { beforeEach(function() {
// buildModules
queryEmailAddressStub = sinon.stub(controller, 'queryEmailAddress');
});
afterEach(function() {
queryEmailAddressStub.restore();
});
it('should work', function(done) {
identityStub.yields('token42');
queryEmailAddressStub.yields(null, 'bob@asdf.com');
controller.fetchOAuthToken(function(err, res) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(appConfigStoreStub.listItems.calledOnce).to.be.true; expect(res.emailAddress).to.equal('bob@asdf.com');
expect(appConfigStoreStub.storeList.calledOnce).to.be.true; expect(res.token).to.equal('token42');
expect(queryEmailAddressStub.calledOnce).to.be.true;
expect(identityStub.calledOnce).to.be.true; expect(identityStub.calledOnce).to.be.true;
expect($.ajax.calledOnce).to.be.true;
done(); done();
}); });
}); });
it('should work when the email address is cached', function(done) { it('should fail due to chrome api error', function(done) {
appConfigStoreStub.listItems.yields(null, ['asdf']); identityStub.yields();
identityStub.yields('token42');
controller.fetchOAuthToken(function(err) { controller.fetchOAuthToken(function(err) {
expect(err).to.not.exist; expect(err).to.exist;
expect(appConfigStoreStub.listItems.calledOnce).to.be.true; expect(identityStub.calledOnce).to.be.true;
done();
});
});
it('should fail due error querying email address', function(done) {
identityStub.yields('token42');
queryEmailAddressStub.yields();
controller.fetchOAuthToken(function(err) {
expect(err).to.exist;
expect(queryEmailAddressStub.calledOnce).to.be.true;
expect(identityStub.calledOnce).to.be.true; expect(identityStub.calledOnce).to.be.true;
expect($.ajax.called).to.be.false;
done(); done();
}); });
}); });

View File

@ -2,21 +2,24 @@ define(function(require) {
'use strict'; 'use strict';
var RestDAO = require('js/dao/rest-dao'), var RestDAO = require('js/dao/rest-dao'),
$ = require('jquery'),
expect = chai.expect; expect = chai.expect;
describe('Rest DAO unit tests', function() { describe('Rest DAO unit tests', function() {
var restDao; var restDao, xhrMock, requests;
beforeEach(function() { beforeEach(function() {
restDao = new RestDAO(); restDao = new RestDAO();
xhrMock = sinon.useFakeXMLHttpRequest();
requests = [];
xhrMock.onCreate = function(xhr) {
requests.push(xhr);
};
}); });
afterEach(function() { afterEach(function() {
if (typeof $.ajax.callCount !== 'undefined') { xhrMock.restore();
$.ajax.restore();
}
}); });
describe('contructor', function() { describe('contructor', function() {
@ -38,96 +41,86 @@ define(function(require) {
}); });
describe('get', function() { describe('get', function() {
it('should work with json as default type', function(done) { it('should work with json as default type', function() {
var spy = sinon.stub($, 'ajax').yieldsTo('success', { restDao.get({
foo: 'bar' uri: '/asdf'
}, 'success', { }, function(err, data, status) {
status: 200 expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
var req = requests[0];
expect(req.requestHeaders.Accept).to.equal('application/json');
expect(status).to.equal(200);
}); });
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/json"
}, '{"foo": "bar"}');
});
it('should work with jsonz', function() {
restDao.get({ restDao.get({
uri: '/asdf', uri: '/asdf',
type: 'json' type: 'json'
}, function(err, data, status) { }, function(err, data, status) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(data.foo).to.equal('bar'); expect(data.foo).to.equal('bar');
expect(spy.calledWith(sinon.match(function(request) { var req = requests[0];
return request.headers.Accept === 'application/json' && request.dataType === 'json'; expect(req.requestHeaders.Accept).to.equal('application/json');
}))).to.be.true;
expect(status).to.equal(200); expect(status).to.equal(200);
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/json"
}, '{"foo": "bar"}');
}); });
it('should work with json', function(done) { it('should work with plain text', function() {
var spy = sinon.stub($, 'ajax').yieldsTo('success', {
foo: 'bar'
}, 'success', {
status: 200
});
restDao.get({
uri: '/asdf',
type: 'json'
}, function(err, data, status) {
expect(err).to.not.exist;
expect(data.foo).to.equal('bar');
expect(spy.calledWith(sinon.match(function(request) {
return request.headers.Accept === 'application/json' && request.dataType === 'json';
}))).to.be.true;
expect(status).to.equal(200);
done();
});
});
it('should work with plain text', function(done) {
var spy = sinon.stub($, 'ajax').yieldsTo('success', 'foobar!', 'success', {
status: 200
});
restDao.get({ restDao.get({
uri: '/asdf', uri: '/asdf',
type: 'text' type: 'text'
}, function(err, data, status) { }, function(err, data, status) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(data).to.equal('foobar!'); expect(data).to.equal('foobar!');
expect(spy.calledWith(sinon.match(function(request) { var req = requests[0];
return request.headers.Accept === 'text/plain' && request.dataType === 'text'; expect(req.requestHeaders.Accept).to.equal('text/plain');
}))).to.be.true;
expect(status).to.equal(200); expect(status).to.equal(200);
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "text/plain"
}, 'foobar!');
}); });
it('should work with xml', function(done) { it('should work with xml', function() {
var spy = sinon.stub($, 'ajax').yieldsTo('success', '<foo>bar</foo>', 'success', {
status: 200
});
restDao.get({ restDao.get({
uri: '/asdf', uri: '/asdf',
type: 'xml' type: 'xml'
}, function(err, data, status) { }, function(err, data, status) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(data).to.equal('<foo>bar</foo>'); // that's probably not right, but in the unit test, it is :) expect(data).to.equal('<foo>bar</foo>');
expect(spy.calledWith(sinon.match(function(request) { var req = requests[0];
return request.headers.Accept === 'application/xml' && request.dataType === 'xml'; expect(req.requestHeaders.Accept).to.equal('application/xml');
}))).to.be.true;
expect(status).to.equal(200); expect(status).to.equal(200);
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(200, {
"Content-Type": "application/xml"
}, '<foo>bar</foo>');
}); });
it('should fail for missing uri parameter', function(done) { it('should fail for missing uri parameter', function() {
restDao.get({}, function(err, data) { restDao.get({}, function(err, data) {
expect(err).to.exist; expect(err).to.exist;
expect(err.code).to.equal(400); expect(err.code).to.equal(400);
expect(data).to.not.exist; expect(data).to.not.exist;
done();
}); });
}); });
it('should fail for unhandled data type', function(done) { it('should fail for unhandled data type', function() {
restDao.get({ restDao.get({
uri: '/asdf', uri: '/asdf',
type: 'snafu' type: 'snafu'
@ -135,84 +128,72 @@ define(function(require) {
expect(err).to.exist; expect(err).to.exist;
expect(err.code).to.equal(400); expect(err.code).to.equal(400);
expect(data).to.not.exist; expect(data).to.not.exist;
done();
}); });
}); });
it('should fail for server error', function(done) { it('should fail for server error', function() {
sinon.stub($, 'ajax').yieldsTo('error', {
status: 500
}, {
statusText: 'Internal error'
}, {});
restDao.get({ restDao.get({
uri: '/asdf' uri: '/asdf'
}, function(err, data) { }, function(err, data) {
expect(err).to.exist; expect(err).to.exist;
expect(err.code).to.equal(500); expect(err.code).to.equal(500);
expect(data).to.not.exist; expect(data).to.not.exist;
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
}); });
}); });
describe('put', function() { describe('put', function() {
it('should fail', function(done) { it('should fail', function() {
sinon.stub($, 'ajax').yieldsTo('error', {
status: 500
}, {
statusText: 'Internal error'
}, {});
restDao.put('/asdf', {}, function(err) { restDao.put('/asdf', {}, function(err) {
expect(err).to.exist; expect(err).to.exist;
expect(err.code).to.equal(500); expect(err.code).to.equal(500);
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
}); });
it('should work', function(done) { it('should work', function() {
var spy = sinon.stub($, 'ajax').yieldsTo('success', undefined, 'success', {
status: 201
});
restDao.put('/asdf', {}, function(err, res, status) { restDao.put('/asdf', {}, function(err, res, status) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(res).to.not.exist; expect(res).to.equal('');
expect(spy.callCount).to.equal(1);
expect(status).to.equal(201); expect(status).to.equal(201);
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(201);
}); });
}); });
describe('remove', function() { describe('remove', function() {
it('should fail', function(done) { it('should fail', function() {
sinon.stub($, 'ajax').yieldsTo('error', {
status: 500
}, {
statusText: 'Internal error'
}, {});
restDao.remove('/asdf', function(err) { restDao.remove('/asdf', function(err) {
expect(err).to.exist; expect(err).to.exist;
expect(err.code).to.equal(500); expect(err.code).to.equal(500);
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(500, {
"Content-Type": "text/plain"
}, 'Internal error');
}); });
it('should work', function(done) { it('should work', function() {
var spy = sinon.stub($, 'ajax').yieldsTo('success', undefined, 'success', {
status: 204
});
restDao.remove('/asdf', function(err, res, status) { restDao.remove('/asdf', function(err, res, status) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(res).to.not.exist; expect(res).to.equal('');
expect(spy.callCount).to.equal(1); expect(status).to.equal(200);
expect(status).to.equal(204);
done();
}); });
expect(requests.length).to.equal(1);
requests[0].respond(200);
}); });
}); });