From 46feadf57c2a42100918b035bd4fbf6df9ffae98 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 16 Jun 2014 15:51:19 -0300 Subject: [PATCH 1/6] delete Wallet WIP --- css/main.css | 1 - index.html | 3 + js/controllers/backup.js | 68 ++++++++++-------- js/directives.js | 21 +++++- js/models/core/WalletFactory.js | 103 ++++++++++++++-------------- js/models/storage/LocalEncrypted.js | 21 ++++++ 6 files changed, 134 insertions(+), 83 deletions(-) diff --git a/css/main.css b/css/main.css index 2ac4d575c..3e6504ec0 100644 --- a/css/main.css +++ b/css/main.css @@ -219,7 +219,6 @@ small.has-error { font-weight: bold; } - .totalAmount { line-height: 120%; margin-top:2px; diff --git a/index.html b/index.html index f96b27ae7..21c99b85a 100644 --- a/index.html +++ b/index.html @@ -727,6 +727,9 @@ +
+
Delete this wallet from this computer
+
diff --git a/js/controllers/backup.js b/js/controllers/backup.js index 92cc40f9b..8452c2f69 100644 --- a/js/controllers/backup.js +++ b/js/controllers/backup.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('BackupController', - function($scope, $rootScope, $location, $window, $timeout, $modal) { + function($scope, $rootScope, $location, $window, $timeout, $modal, controllerUtils, walletFactory) { $scope.title = 'Backup'; var _getEncryptedWallet = function() { @@ -11,10 +11,12 @@ angular.module('copayApp.controllers').controller('BackupController', $scope.download = function() { var timestamp = +(new Date); - var walletName = ($rootScope.wallet.name ? $rootScope.wallet.name : '') + '-' + $rootScope.wallet.id ; + var walletName = ($rootScope.wallet.name ? $rootScope.wallet.name : '') + '-' + $rootScope.wallet.id; var filename = walletName + '-' + timestamp + '.json.aes'; var wallet = _getEncryptedWallet(); - var blob = new Blob([wallet], {type: 'text/plain;charset=utf-8'}); + var blob = new Blob([wallet], { + type: 'text/plain;charset=utf-8' + }); // show a native save dialog if we are in the shell // and pass the wallet to the shell to convert to node Buffer if (window.cshell) { @@ -27,43 +29,49 @@ angular.module('copayApp.controllers').controller('BackupController', saveAs(blob, filename); }; - $scope.openModal = function () { - var modalInstance = $modal.open({ - templateUrl: 'backupModal.html', - controller: ModalInstanceCtrl, - }); + $scope.openModal = function() { + var modalInstance = $modal.open({ + templateUrl: 'backupModal.html', + controller: ModalInstanceCtrl, + }); - modalInstance.result.then(sendEmail); - }; + modalInstance.result.then(sendEmail); + }; - var sendEmail = function(email) { - var body = _getEncryptedWallet(); - var subject = ($rootScope.wallet.name ? $rootScope.wallet.name + ' - ' : '') + $rootScope.wallet.id; - var href = 'mailto:' + email + '?' - + 'subject=[Copay Backup] ' + subject + '&' - + 'body=' + body; + $scope.deleteWallet = function() { + var w=$rootScope.wallet; + w.disconnect(); + walletFactory.remove(w.id, function() { + controllerUtils.logout(); + }); + }; - if (window.cshell) { - return window.cshell.send('backup:email', href); - } + var sendEmail = function(email) { + var body = _getEncryptedWallet(); + var subject = ($rootScope.wallet.name ? $rootScope.wallet.name + ' - ' : '') + $rootScope.wallet.id; + var href = 'mailto:' + email + '?' + 'subject=[Copay Backup] ' + subject + '&' + 'body=' + body; - var newWin = $window.open(href, '_blank', 'scrollbars=yes,resizable=yes,width=10,height=10'); + if (window.cshell) { + return window.cshell.send('backup:email', href); + } - if (newWin) { - $timeout(function() { - newWin.close(); - }, 1000); - } - }; -}); + var newWin = $window.open(href, '_blank', 'scrollbars=yes,resizable=yes,width=10,height=10'); -var ModalInstanceCtrl = function ($scope, $modalInstance) { + if (newWin) { + $timeout(function() { + newWin.close(); + }, 1000); + } + }; + }); - $scope.submit = function (form) { +var ModalInstanceCtrl = function($scope, $modalInstance) { + + $scope.submit = function(form) { $modalInstance.close($scope.email); }; - $scope.cancel = function () { + $scope.cancel = function() { $modalInstance.dismiss('cancel'); }; }; diff --git a/js/directives.js b/js/directives.js index d54858f97..c8ef3c573 100644 --- a/js/directives.js +++ b/js/directives.js @@ -202,4 +202,23 @@ angular.module('copayApp.directives') }); } }; - }); + }) +// From https://gist.github.com/asafge/7430497 +.directive('ngReallyClick', [ + + function() { + return { + restrict: 'A', + link: function(scope, element, attrs) { + element.bind('click', function() { + var message = attrs.ngReallyMessage; + if (message && confirm(message)) { + scope.$apply(attrs.ngReallyClick); + } + }); + } + } + } +]) + +; diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 6c00cc96a..7ee3fa00a 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -1,9 +1,9 @@ 'use strict'; -var imports = require('soop').imports(); -var Storage = imports.Storage; -var Network = imports.Network; -var Blockchain = imports.Blockchain; +var imports = require('soop').imports(); +var Storage = imports.Storage; +var Network = imports.Network; +var Blockchain = imports.Blockchain; var TxProposals = require('./TxProposals'); var PublicKeyRing = require('./PublicKeyRing'); @@ -23,13 +23,13 @@ function WalletFactory(config, version) { this.network = new Network(config.network); this.blockchain = new Blockchain(config.blockchain); - this.networkName = config.networkName; - this.verbose = config.verbose; + this.networkName = config.networkName; + this.verbose = config.verbose; this.walletDefaults = config.wallet; - this.version = version; + this.version = version; } -WalletFactory.prototype.log = function(){ +WalletFactory.prototype.log = function() { if (!this.verbose) return; if (console) { console.log.apply(console, arguments); @@ -39,18 +39,18 @@ WalletFactory.prototype.log = function(){ WalletFactory.prototype._checkRead = function(walletId) { var s = this.storage; - var ret = - s.get(walletId, 'publicKeyRing') && - s.get(walletId, 'txProposals') && - s.get(walletId, 'opts') && - s.get(walletId, 'privateKey'); + var ret = + s.get(walletId, 'publicKeyRing') && + s.get(walletId, 'txProposals') && + s.get(walletId, 'opts') && + s.get(walletId, 'privateKey'); return !!ret; }; WalletFactory.prototype.fromObj = function(obj) { // not stored options - obj.opts.reconnectDelay = this.walletDefaults.reconnectDelay; + obj.opts.reconnectDelay = this.walletDefaults.reconnectDelay; var w = Wallet.fromObj(obj, this.storage, this.network, this.blockchain); if (!w) return false; @@ -69,33 +69,35 @@ WalletFactory.prototype.fromEncryptedObj = function(base64, password) { }; WalletFactory.prototype.read = function(walletId) { - if (! this._checkRead(walletId)) + if (!this._checkRead(walletId)) return false; var obj = {}; var s = this.storage; obj.id = walletId; - obj.opts = s.get(walletId, 'opts'); - obj.publicKeyRing = s.get(walletId, 'publicKeyRing'); - obj.txProposals = s.get(walletId, 'txProposals'); - obj.privateKey = s.get(walletId, 'privateKey'); + obj.opts = s.get(walletId, 'opts'); + obj.publicKeyRing = s.get(walletId, 'publicKeyRing'); + obj.txProposals = s.get(walletId, 'txProposals'); + obj.privateKey = s.get(walletId, 'privateKey'); var w = this.fromObj(obj); return w; }; WalletFactory.prototype.create = function(opts) { - opts = opts || {}; - this.log('### CREATING NEW WALLET.' + - (opts.id ? ' USING ID: ' + opts.id : ' NEW ID') + - (opts.privateKey ? ' USING PrivateKey: ' + opts.privateKey.getId() : ' NEW PrivateKey') - ); + opts = opts || {}; + this.log('### CREATING NEW WALLET.' + + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID') + + (opts.privateKey ? ' USING PrivateKey: ' + opts.privateKey.getId() : ' NEW PrivateKey') + ); - opts.privateKey = opts.privateKey || new PrivateKey({ networkName: this.networkName }); + opts.privateKey = opts.privateKey || new PrivateKey({ + networkName: this.networkName + }); var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers; - var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers; + var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers; opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({ networkName: this.networkName, @@ -120,10 +122,10 @@ WalletFactory.prototype.create = function(opts) { opts.verbose = this.verbose; opts.spendUnconfirmed = opts.spendUnconfirmed || this.walletDefaults.spendUnconfirmed; - opts.reconnectDelay = opts.reconnectDelay || this.walletDefaults.reconnectDelay; + opts.reconnectDelay = opts.reconnectDelay || this.walletDefaults.reconnectDelay; opts.requiredCopayers = requiredCopayers; - opts.totalCopayers = totalCopayers; - opts.version = opts.version || this.version; + opts.totalCopayers = totalCopayers; + opts.version = opts.version || this.version; var w = new Wallet(opts); w.store(); return w; @@ -133,27 +135,22 @@ WalletFactory.prototype.create = function(opts) { WalletFactory.prototype._checkVersion = function(inVersion) { var thisV = this.version.split('.'); var thisV0 = parseInt(thisV[0]); - var inV = inVersion.split('.'); - var inV0 = parseInt(inV[0]); + var inV = inVersion.split('.'); + var inV0 = parseInt(inV[0]); //We only check for major version differences - if( thisV0 < inV0 ) { + if (thisV0 < inV0) { throw new Error('Major difference in software versions' + - '. Received:' + inVersion + - '. Current version:' + this.version + - '. Aborting.'); + '. Received:' + inVersion + + '. Current version:' + this.version + + '. Aborting.'); } }; WalletFactory.prototype._checkNetwork = function(inNetworkName) { - if( this.networkName !== inNetworkName ) { - throw new Error('This Wallet is configured for ' - + inNetworkName - + ' while currently Copay is configured for: ' - + this.networkName - + '. Check your settings.' - ); + if (this.networkName !== inNetworkName) { + throw new Error('This Wallet is configured for ' + inNetworkName + ' while currently Copay is configured for: ' + this.networkName + '. Check your settings.'); } }; @@ -175,14 +172,16 @@ WalletFactory.prototype.open = function(walletId, opts) { WalletFactory.prototype.getWallets = function() { var ret = this.storage.getWallets(); ret.forEach(function(i) { - i.show = i.name ? ( (i.name + ' <'+i.id+'>') ) : i.id; + i.show = i.name ? ((i.name + ' <' + i.id + '>')) : i.id; }); return ret; }; -WalletFactory.prototype.remove = function(walletId) { - // TODO remove wallet contents - this.log('TODO: remove wallet contents'); +WalletFactory.prototype.remove = function(walletId, cb) { + var s = this.storage; + this.log('## DELETING WALLET ID:'+ walletId); //TODO + s.get(walletId, 'opts'); + return cb(); }; WalletFactory.prototype.decodeSecret = function(secret) { @@ -198,9 +197,11 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras var s = self.decodeSecret(secret); if (!s) return cb('badSecret'); - + //Create our PrivateK - var privateKey = new PrivateKey({ networkName: this.networkName }); + var privateKey = new PrivateKey({ + networkName: this.networkName + }); this.log('\t### PrivateKey Initialized'); var opts = { copayerId: privateKey.getId(), @@ -219,13 +220,13 @@ WalletFactory.prototype.joinCreateSession = function(secret, nickname, passphras return cb(connectedOnce ? 'walletFull' : 'joinError'); }); self.network.on('data', function(sender, data) { - if (data.type ==='walletId') { - if (data.networkName !== self.networkName ){ + if (data.type === 'walletId') { + if (data.networkName !== self.networkName) { return cb('badNetwork'); } data.opts.privateKey = privateKey; - data.opts.nickname = nickname; + data.opts.nickname = nickname; data.opts.passphrase = passphrase; data.opts.id = data.walletId; var w = self.create(data.opts); diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index 3ab93e160..308ae59a8 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -147,6 +147,27 @@ Storage.prototype.getWallets = function() { return wallets; }; +Storage.prototype.deleteWallet = function(walletId) { + var walletIds = []; + var uniq = {}; + for (var i = 0; i < localStorage.length; i++) { + var key = localStorage.key(i); + var split = key.split('::'); + if (split.length == 2) { + var walletId = split[0]; + + if (walletId === 'nameFor') continue; + + if (typeof uniq[walletId] === 'undefined') { + walletIds.push(walletId); + uniq[walletId] = 1; + } + } + } + +}; + + //obj contains keys to be set Storage.prototype.setFromObj = function(walletId, obj) { for (var k in obj) { From 2c60fd91c0c67b3f871c148741aba5518414a157 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Mon, 16 Jun 2014 17:37:33 -0300 Subject: [PATCH 2/6] implements delete wallet, in backuptab --- js/controllers/backup.js | 4 +- js/models/core/WalletFactory.js | 6 +- js/models/storage/LocalEncrypted.js | 21 ++--- test/mocks/FakeStorage.js | 88 +++++++++++++++--- test/mocks/FakeWallet.js | 34 +++++-- test/test.WalletFactory.js | 28 +++++- test/unit/controllers/controllersSpec.js | 113 ++++++++++++++++------- 7 files changed, 217 insertions(+), 77 deletions(-) diff --git a/js/controllers/backup.js b/js/controllers/backup.js index 8452c2f69..e7020574c 100644 --- a/js/controllers/backup.js +++ b/js/controllers/backup.js @@ -39,9 +39,9 @@ angular.module('copayApp.controllers').controller('BackupController', }; $scope.deleteWallet = function() { - var w=$rootScope.wallet; + var w = $rootScope.wallet; w.disconnect(); - walletFactory.remove(w.id, function() { + walletFactory.delete(w.id, function() { controllerUtils.logout(); }); }; diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index 7ee3fa00a..c55ab059a 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -177,10 +177,10 @@ WalletFactory.prototype.getWallets = function() { return ret; }; -WalletFactory.prototype.remove = function(walletId, cb) { +WalletFactory.prototype.delete = function(walletId, cb) { var s = this.storage; - this.log('## DELETING WALLET ID:'+ walletId); //TODO - s.get(walletId, 'opts'); + this.log('## DELETING WALLET ID:' + walletId); //TODO + s.deleteWallet(walletId); return cb(); }; diff --git a/js/models/storage/LocalEncrypted.js b/js/models/storage/LocalEncrypted.js index 308ae59a8..e47c0194c 100644 --- a/js/models/storage/LocalEncrypted.js +++ b/js/models/storage/LocalEncrypted.js @@ -135,7 +135,6 @@ Storage.prototype.getWalletIds = function() { Storage.prototype.getWallets = function() { var wallets = []; - var uniq = {}; var ids = this.getWalletIds(); for (var i in ids) { @@ -148,23 +147,19 @@ Storage.prototype.getWallets = function() { }; Storage.prototype.deleteWallet = function(walletId) { - var walletIds = []; - var uniq = {}; + var toDelete = {}; + toDelete['nameFor::' + walletId] = 1; + for (var i = 0; i < localStorage.length; i++) { var key = localStorage.key(i); var split = key.split('::'); - if (split.length == 2) { - var walletId = split[0]; - - if (walletId === 'nameFor') continue; - - if (typeof uniq[walletId] === 'undefined') { - walletIds.push(walletId); - uniq[walletId] = 1; - } + if (split.length == 2 && split[0] === walletId) { + toDelete[key] = 1; } } - + for (var i in toDelete) { + this.removeGlobal(i); + } }; diff --git a/test/mocks/FakeStorage.js b/test/mocks/FakeStorage.js index 77fe38213..73b6f92c2 100644 --- a/test/mocks/FakeStorage.js +++ b/test/mocks/FakeStorage.js @@ -1,40 +1,98 @@ - -var FakeStorage = function(){ +var FakeStorage = function() { this.storage = {}; -}; +}; -FakeStorage.prototype._setPassphrase = function (password) { +FakeStorage.prototype._setPassphrase = function(password) { this.storage.passphrase = password; }; -FakeStorage.prototype.setGlobal = function (id, payload) { +FakeStorage.prototype.setGlobal = function(id, payload) { this.storage[id] = payload; }; FakeStorage.prototype.getGlobal = function(id) { return this.storage[id]; -} +}; -FakeStorage.prototype.set = function (wid, id, payload) { - this.storage[wid + '-' + id] = payload; + +FakeStorage.prototype.removeGlobal = function(id) { + delete this.storage[id]; +}; + + +FakeStorage.prototype.set = function(wid, id, payload) { + this.storage[wid + '::' + id] = payload; }; FakeStorage.prototype.get = function(wid, id) { - return this.storage[wid + '-' +id]; -} + return this.storage[wid + '::' + id]; +}; FakeStorage.prototype.clear = function() { delete this['storage']; -} +}; + +FakeStorage.prototype.getWalletIds = function() { + var walletIds = []; + var uniq = {}; + + for (var ii in this.storage) { + var split = ii.split('::'); + if (split.length == 2) { + var walletId = split[0]; + if (walletId !== 'nameFor' && typeof uniq[walletId] === 'undefined') { + walletIds.push(walletId); + uniq[walletId] = 1; + } + } + } + return walletIds; +}; + +FakeStorage.prototype.deleteWallet = function(walletId) { + var toDelete = {}; + toDelete['nameFor::' + walletId] = 1; + + for (var key in this.storage) { + var split = key.split('::'); + if (split.length == 2 && split[0] === walletId) { + toDelete[key] = 1; + } + } + for (var i in toDelete) { + this.removeGlobal(i); + } +}; + + +FakeStorage.prototype.getName = function(walletId) { + return this.getGlobal('nameFor::' + walletId); +}; + + +FakeStorage.prototype.setName = function(walletId, name) { + this.setGlobal('nameFor::' + walletId, name); +}; + FakeStorage.prototype.getWallets = function() { - return []; + var wallets = []; + var ids = this.getWalletIds(); + + for (var i in ids) { + wallets.push({ + id: ids[i], + name: this.getName(ids[i]), + }); + } + return wallets; }; FakeStorage.prototype.setFromObj = function(walletId, obj) { - for (var i in obj) { - this.storage[walletId + '-' + i] = obj[i]; - }; + for (var k in obj) { + this.set(walletId, k, obj[k]); + } + this.setName(walletId, obj.opts.name); }; module.exports = require('soop')(FakeStorage); diff --git a/test/mocks/FakeWallet.js b/test/mocks/FakeWallet.js index ec7f4fade..67abb2482 100644 --- a/test/mocks/FakeWallet.js +++ b/test/mocks/FakeWallet.js @@ -1,20 +1,22 @@ - -var FakeWallet = function(){ - this.balance=10000; - this.safeBalance=1000; - this.balanceByAddr={'1CjPR7Z5ZSyWk6WtXvSFgkptmpoi4UM9BC': 1000}; +var FakeWallet = function() { + this.id = 'testID'; + this.balance = 10000; + this.safeBalance = 1000; + this.balanceByAddr = { + '1CjPR7Z5ZSyWk6WtXvSFgkptmpoi4UM9BC': 1000 + }; }; -FakeWallet.prototype.set = function(balance, safeBalance, balanceByAddr){ - this.balance=balance; +FakeWallet.prototype.set = function(balance, safeBalance, balanceByAddr) { + this.balance = balance; this.safeBalance = safeBalance; this.balanceByAddr = balanceByAddr; }; -FakeWallet.prototype.getAddressesInfo=function(){ +FakeWallet.prototype.getAddressesInfo = function() { var ret = []; - for(var ii in this.balanceByAddr){ + for (var ii in this.balanceByAddr) { ret.push({ address: ii, isChange: false, @@ -24,10 +26,22 @@ FakeWallet.prototype.getAddressesInfo=function(){ }; -FakeWallet.prototype.getBalance=function(cb){ +FakeWallet.prototype.getBalance = function(cb) { return cb(null, this.balance, this.balanceByAddr, this.safeBalance); }; +FakeWallet.prototype.setEnc = function(enc) { + this.enc = enc; +}; + +FakeWallet.prototype.toEncryptedObj = function() { + return this.enc; +}; + +FakeWallet.prototype.disconnect = function() { + this.disconnectCalled = 1; +}; + // This mock is meant for karma, module.exports is not necesary. try { module.exports = require('soop')(FakeWallet); diff --git a/test/test.WalletFactory.js b/test/test.WalletFactory.js index aeec5faed..2944c25de 100644 --- a/test/test.WalletFactory.js +++ b/test/test.WalletFactory.js @@ -75,7 +75,7 @@ describe('WalletFactory model', function() { should.exist(w.publicKeyRing.getCopayerId); should.exist(w.txProposals.toObj); should.exist(w.privateKey.toObj); - + JSON.stringify(w.toObj()).should.equal(o); }); @@ -98,7 +98,7 @@ describe('WalletFactory model', function() { "wallet": { "requiredCopayers": 2, "totalCopayers": 3, - "reconnectDelay":100, + "reconnectDelay": 100, "spendUnconfirmed": 1, "verbose": 0 }, @@ -122,4 +122,28 @@ describe('WalletFactory model', function() { }); + it('should be able to get current wallets', function() { + var wf = new WalletFactory(config, '0.0.1'); + var w = wf.create({ + name: 'test wallet' + }); + var ws = wf.getWallets(); + ws.length.should.equal(1); + ws[0].name.should.equal('test wallet'); + }); + + it('should be able to delete wallet', function(done) { + var wf = new WalletFactory(config, '0.0.1'); + var w = wf.create({ + name: 'test wallet' + }); + var ws = wf.getWallets(); + ws.length.should.equal(1); + wf.delete(ws[0].id, function() { + ws = wf.getWallets(); + ws.length.should.equal(0); + done(); + }); + }); + }); diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index 82bdaad05..be4bb09f6 100644 --- a/test/unit/controllers/controllersSpec.js +++ b/test/unit/controllers/controllersSpec.js @@ -1,6 +1,14 @@ // // test/unit/controllers/controllersSpec.js // + +// Replace saveAs plugin +saveAsLastCall = null; +saveAs = function(o) { + saveAsLastCall = o; +}; + + describe("Unit: Controllers", function() { var scope; @@ -9,6 +17,48 @@ describe("Unit: Controllers", function() { beforeEach(module('copayApp.services')); beforeEach(module('copayApp.controllers')); + var config = { + requiredCopayers: 3, + totalCopayers: 5, + spendUnconfirmed: 1, + reconnectDelay: 100, + networkName: 'testnet', + }; + + + + describe.only('Backup Controller', function() { + var ctrl; + beforeEach(inject(function($controller, $rootScope) { + scope = $rootScope.$new(); + + $rootScope.wallet = new FakeWallet(config); + ctrl = $controller('BackupController', { + $scope: scope, + $modal: {}, + }); + })); + + it('should have a Backup controller', function() { + expect(scope.title).equal('Backup'); + }); + + it(' Backup controller #download', function() { + scope.wallet.setEnc('1234567'); + expect(saveAsLastCall).equal(null); + scope.download(); + expect(saveAsLastCall.size).equal(7); + expect(saveAsLastCall.type).equal('text/plain;charset=utf-8'); + }); + + + it(' Backup controller #delete', function() { + expect(scope.wallet).not.equal(undefined); + scope.deleteWallet(); + expect(scope.wallet).equal(undefined); + }); + }); + describe('Address Controller', function() { var addressCtrl; beforeEach(inject(function($controller, $rootScope) { @@ -55,15 +105,15 @@ describe("Unit: Controllers", function() { beforeEach(inject(function($controller, $injector) { $httpBackend = $injector.get('$httpBackend'); $httpBackend.when('GET', GH) - .respond( [{ - name: "v100.1.6", - zipball_url: "https://api.github.com/repos/bitpay/copay/zipball/v0.0.6", - tarball_url: "https://api.github.com/repos/bitpay/copay/tarball/v0.0.6", - commit: { - sha: "ead7352bf2eca705de58d8b2f46650691f2bc2c7", - url: "https://api.github.com/repos/bitpay/copay/commits/ead7352bf2eca705de58d8b2f46650691f2bc2c7" - } - }]); + .respond([{ + name: "v100.1.6", + zipball_url: "https://api.github.com/repos/bitpay/copay/zipball/v0.0.6", + tarball_url: "https://api.github.com/repos/bitpay/copay/tarball/v0.0.6", + commit: { + sha: "ead7352bf2eca705de58d8b2f46650691f2bc2c7", + url: "https://api.github.com/repos/bitpay/copay/commits/ead7352bf2eca705de58d8b2f46650691f2bc2c7" + } + }]); })); var rootScope; @@ -86,32 +136,31 @@ describe("Unit: Controllers", function() { $httpBackend.flush(); }); - it('should hit github for version', function() { - $httpBackend.expectGET(GH); - scope.$apply(); - $httpBackend.flush(); - }); + it('should hit github for version', function() { + $httpBackend.expectGET(GH); + scope.$apply(); + $httpBackend.flush(); + }); - it('should check version ', function() { - $httpBackend.expectGET(GH); - scope.$apply(); - $httpBackend.flush(); - expect(scope.updateVersion.class).equal('error'); - expect(scope.updateVersion.version).equal('v100.1.6'); - }); + it('should check version ', function() { + $httpBackend.expectGET(GH); + scope.$apply(); + $httpBackend.flush(); + expect(scope.updateVersion.class).equal('error'); + expect(scope.updateVersion.version).equal('v100.1.6'); + }); - it('should check blockChainStatus', function() { - $httpBackend.expectGET(GH); - $httpBackend.flush(); - rootScope.insightError=1; - scope.$apply(); - expect(rootScope.insightError).equal(1); - scope.$apply(); - expect(rootScope.insightError).equal(1); - scope.$apply(); - }); + it('should check blockChainStatus', function() { + $httpBackend.expectGET(GH); + $httpBackend.flush(); + rootScope.insightError = 1; + scope.$apply(); + expect(rootScope.insightError).equal(1); + scope.$apply(); + expect(rootScope.insightError).equal(1); + scope.$apply(); + }); }); }); - From 718ae69576921d94465f9c99106c2f5e1a887414 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 17 Jun 2014 11:33:43 -0300 Subject: [PATCH 3/6] add notification saying backup was created --- js/services/backupService.js | 7 +++++-- js/services/notifications.js | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/js/services/backupService.js b/js/services/backupService.js index 982d3376a..5485a0e12 100644 --- a/js/services/backupService.js +++ b/js/services/backupService.js @@ -1,6 +1,8 @@ 'use strict'; -var BackupService = function() {}; +var BackupService = function($notification) { + this.notifications = $notification; +}; BackupService.prototype.getName = function(wallet) { return (wallet.name ? (wallet.name+'-') : '') + wallet.id; @@ -11,6 +13,7 @@ BackupService.prototype.download = function(wallet) { var timestamp = +(new Date()); var walletName = this.getName(wallet); var filename = walletName + '-' + timestamp + '-keybackup.json.aes'; + this.notifications.success('Backup created', 'Encrypted backup file saved.'); var blob = new Blob([ew], { type: 'text/plain;charset=utf-8' }); @@ -44,4 +47,4 @@ BackupService.prototype.sendEmail = function(email, wallet) { } }; -angular.module('copayApp.services').value('backupService', new BackupService()); +angular.module('copayApp.services').service('backupService', BackupService); diff --git a/js/services/notifications.js b/js/services/notifications.js index c37aee391..11804689d 100644 --- a/js/services/notifications.js +++ b/js/services/notifications.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('notifications', []). - factory('$notification', ['$timeout',function($timeout){ + factory('$notification', ['$timeout',function($timeout, $rootScope){ var notifications = JSON.parse(localStorage.getItem('$notifications')) || [], queue = []; @@ -197,7 +197,9 @@ angular.module('notifications', []). clear: function(){ notifications = []; this.save(); - } + }, + + init: function() {} }; }]). From 710c9c965765ed2e747264727567c668a61ad16b Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Tue, 17 Jun 2014 14:02:39 -0300 Subject: [PATCH 4/6] fix tests --- js/models/core/WalletFactory.js | 6 ++-- package.json | 3 +- test/mocks/FakeStorage.js | 5 +++ test/test.WalletFactory.js | 59 ++++++++++++++++++++------------- 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index c55ab059a..490b1b6a6 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -19,9 +19,9 @@ function WalletFactory(config, version) { var self = this; config = config || {}; - this.storage = new Storage(config.storage); - this.network = new Network(config.network); - this.blockchain = new Blockchain(config.blockchain); + this.storage = config.storageObj || new Storage(config.storage); + this.network = config.networkObj || new Network(config.network); + this.blockchain = config.blockchainObj || new Blockchain(config.blockchain); this.networkName = config.networkName; this.verbose = config.verbose; diff --git a/package.json b/package.json index d8871d000..626a0d965 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "cli-color": "0.3.2" }, "dependencies": { - "mocha": "^1.18.2" + "mocha": "^1.18.2", + "mocha-lcov-reporter": "0.0.1" } } diff --git a/test/mocks/FakeStorage.js b/test/mocks/FakeStorage.js index 73b6f92c2..9ea94c1b0 100644 --- a/test/mocks/FakeStorage.js +++ b/test/mocks/FakeStorage.js @@ -1,4 +1,9 @@ var FakeStorage = function() { + this.reset(); +}; + + +FakeStorage.prototype.reset = function(password) { this.storage = {}; }; diff --git a/test/test.WalletFactory.js b/test/test.WalletFactory.js index 2944c25de..23beca06c 100644 --- a/test/test.WalletFactory.js +++ b/test/test.WalletFactory.js @@ -3,28 +3,14 @@ var chai = chai || require('chai'); var should = chai.should(); +var copay = copay || require('../copay'); +var sinon = require('sinon'); var FakeNetwork = require('./mocks/FakeNetwork'); -var Insight = require('../js/models/blockchain/Insight'); +var FakeBlockchain = require('./mocks/FakeBlockchain'); var FakeStorage = require('./mocks/FakeStorage'); +var WalletFactory = require('../js/models/core/WalletFactory'); -var WalletFactory = typeof copay === 'undefined' ? require('soop').load('../js/models/core/WalletFactory', { - Network: FakeNetwork, - Blockchain: Insight, - Storage: FakeStorage, -}) : copay.WalletFactory; - -var blanket = require("blanket")({ - "pattern": "/js/" -}); - - -var addCopayers = function(w) { - for (var i = 0; i < 4; i++) { - w.publicKeyRing.addCopayer(); - } -}; - -describe('WalletFactory model', function() { +describe.only('WalletFactory model', function() { var config = { wallet: { requiredCopayers: 3, @@ -38,12 +24,34 @@ describe('WalletFactory model', function() { }, networkName: 'testnet', passphrase: 'test', + storageObj: new FakeStorage(), + networkObj: new FakeNetwork(), + blockchainObj: new FakeBlockchain(), }; - it('should create the factory', function() { - var wf = new WalletFactory(config); - should.exist(wf); + beforeEach(function() { + config.storageObj.reset(); }); + + it('should create the factory', function() { + var wf = new WalletFactory(config, '0.0.1'); + should.exist(wf); + wf.networkName.should.equal(config.networkName); + wf.walletDefaults.should.deep.equal(config.wallet); + wf.version.should.equal('0.0.1'); + }); + + it('should log', function() { + var c2 = JSON.parse(JSON.stringify(config)); + c2.verbose = 1; + var wf = new WalletFactory(c2, '0.0.1'); + var spy = sinon.spy(console, 'log'); + wf.log('ok'); + sinon.assert.callCount(spy, 1); + spy.getCall(0).args[0].should.equal('ok'); + }); + + it('#_checkRead should return false', function() { var wf = new WalletFactory(config); wf._checkRead('dummy').should.equal(false); @@ -111,7 +119,10 @@ describe('WalletFactory model', function() { "port": 3001 }, "verbose": 0, - "themes": ["default"] + "themes": ["default"], + storageObj: new FakeStorage(), + networkObj: new FakeNetwork(), + blockchainObj: new FakeBlockchain(), }; var wf = new WalletFactory(sconfig, '0.0.1'); var opts = { @@ -124,6 +135,8 @@ describe('WalletFactory model', function() { it('should be able to get current wallets', function() { var wf = new WalletFactory(config, '0.0.1'); + var ws = wf.getWallets(); + var w = wf.create({ name: 'test wallet' }); From 0afd80bbd9e2b9146c721f6f6fa7cd2d3f1576eb Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Tue, 17 Jun 2014 16:44:09 -0300 Subject: [PATCH 5/6] fix matis comments --- js/services/notifications.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/js/services/notifications.js b/js/services/notifications.js index 11804689d..c37aee391 100644 --- a/js/services/notifications.js +++ b/js/services/notifications.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('notifications', []). - factory('$notification', ['$timeout',function($timeout, $rootScope){ + factory('$notification', ['$timeout',function($timeout){ var notifications = JSON.parse(localStorage.getItem('$notifications')) || [], queue = []; @@ -197,9 +197,7 @@ angular.module('notifications', []). clear: function(){ notifications = []; this.save(); - }, - - init: function() {} + } }; }]). From a83aa869fd9214ec761616ba4f02deb5c9bbd374 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Tue, 17 Jun 2014 23:16:15 -0300 Subject: [PATCH 6/6] remove .only --- js/models/core/WalletFactory.js | 2 -- test/unit/controllers/controllersSpec.js | 9 ++++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/js/models/core/WalletFactory.js b/js/models/core/WalletFactory.js index a47e23230..6ecc70b46 100644 --- a/js/models/core/WalletFactory.js +++ b/js/models/core/WalletFactory.js @@ -160,8 +160,6 @@ WalletFactory.prototype._checkNetwork = function(inNetworkName) { } }; - - WalletFactory.prototype.open = function(walletId, opts) { opts = opts || {}; opts.id = walletId; diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index be4bb09f6..e8d281163 100644 --- a/test/unit/controllers/controllersSpec.js +++ b/test/unit/controllers/controllersSpec.js @@ -27,7 +27,7 @@ describe("Unit: Controllers", function() { - describe.only('Backup Controller', function() { + describe('Backup Controller', function() { var ctrl; beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); @@ -39,11 +39,11 @@ describe("Unit: Controllers", function() { }); })); - it('should have a Backup controller', function() { + it('Should have a Backup controller', function() { expect(scope.title).equal('Backup'); }); - it(' Backup controller #download', function() { + it('Backup controller #download', function() { scope.wallet.setEnc('1234567'); expect(saveAsLastCall).equal(null); scope.download(); @@ -51,8 +51,7 @@ describe("Unit: Controllers", function() { expect(saveAsLastCall.type).equal('text/plain;charset=utf-8'); }); - - it(' Backup controller #delete', function() { + it('Backup controller #delete', function() { expect(scope.wallet).not.equal(undefined); scope.deleteWallet(); expect(scope.wallet).equal(undefined);