Merge pull request #70 from ryanxcharles/feature/command-line-3
Command Line Interface #3
This commit is contained in:
commit
4e4dd249a8
10 changed files with 295 additions and 53 deletions
22
API.js
22
API.js
|
|
@ -10,23 +10,13 @@ API.prototype._init = function(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
self.opts = opts;
|
self.opts = opts;
|
||||||
|
|
||||||
var Wallet = require('soop').load('./js/models/core/Wallet', {
|
var WalletFactory = require('soop').load('./js/models/core/WalletFactory', {
|
||||||
Storage: opts.Storage || require('./test/mocks/FakeStorage'),
|
Storage: opts.Storage || require('./test/mocks/FakeStorage'),
|
||||||
Network: opts.Network || require('./js/models/network/WebRTC'),
|
Network: opts.Network || require('./js/models/network/Base'),
|
||||||
Blockchain: opts.Blockchain || require('./js/models/blockchain/Insight')
|
Blockchain: opts.Blockchain || require('./js/models/blockchain/Insight')
|
||||||
});
|
});
|
||||||
|
|
||||||
var config = {
|
this.walletFactory = new WalletFactory(opts);
|
||||||
wallet: {
|
|
||||||
requiredCopayers: opts.requiredCopayers || 3,
|
|
||||||
totalCopayers: opts.totalCopayers || 5,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var walletConfig = opts.walletConfig || config;
|
|
||||||
var walletOpts = opts.walletOpts || {};
|
|
||||||
|
|
||||||
self.wallet = self.opts.wallet || Wallet.factory.create(walletConfig, walletOpts);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
API._coerceArgTypes = function(args, argTypes) {
|
API._coerceArgTypes = function(args, argTypes) {
|
||||||
|
|
@ -179,13 +169,13 @@ API.prototype.getCommands = decorate('getCommands', [
|
||||||
['callback', 'function']
|
['callback', 'function']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
API.prototype._cmd_getPublicKeyRingId = function(callback) {
|
API.prototype._cmd_getWalletIds = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
return callback(null, self.wallet.publicKeyRing.walletId);
|
return callback(null, self.walletFactory.getWalletIds());
|
||||||
};
|
};
|
||||||
|
|
||||||
API.prototype.getPublicKeyRingId = decorate('getPublicKeyRingId', [
|
API.prototype.getWalletIds = decorate('getWalletIds', [
|
||||||
['callback', 'function']
|
['callback', 'function']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,10 @@ var main = function() {
|
||||||
var api = new API(commander);
|
var api = new API(commander);
|
||||||
|
|
||||||
var args = commander.args;
|
var args = commander.args;
|
||||||
|
var command = args[0];
|
||||||
|
var commandArgs = args.slice(1);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var command = args[0];
|
|
||||||
var commandArgs = args.slice(1);
|
|
||||||
|
|
||||||
if (command[0] == '_' || typeof api[command] != 'function')
|
if (command[0] == '_' || typeof api[command] != 'function')
|
||||||
throw new Error('invalid command');
|
throw new Error('invalid command');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,6 @@ WalletFactory.prototype.create = function(opts) {
|
||||||
opts.totalCopayers = totalCopayers;
|
opts.totalCopayers = totalCopayers;
|
||||||
var w = new Wallet(opts);
|
var w = new Wallet(opts);
|
||||||
w.store();
|
w.store();
|
||||||
this.addWalletId(w.id);
|
|
||||||
return w;
|
return w;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -156,28 +155,11 @@ WalletFactory.prototype.openRemote = function(peedId) {
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletFactory.prototype.getWalletIds = function() {
|
WalletFactory.prototype.getWalletIds = function() {
|
||||||
var ids = this.storage.getGlobal('walletIds');
|
return this.storage.getWalletIds();
|
||||||
return ids || [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletFactory.prototype._delWalletId = function(walletId) {
|
|
||||||
var ids = this.getWalletIds();
|
|
||||||
var index = ids.indexOf(walletId);
|
|
||||||
if (index === -1) return;
|
|
||||||
ids.splice(index, 1); // removes walletId
|
|
||||||
this.storage.setGlobal('walletIds', ids);
|
|
||||||
};
|
|
||||||
|
|
||||||
WalletFactory.prototype.remove = function(walletId) {
|
WalletFactory.prototype.remove = function(walletId) {
|
||||||
WalletFactory._delWalletId(walletId);
|
// TODO remove wallet contents
|
||||||
// TODO remove wallet contents, not only the id (Wallet.remove?)
|
|
||||||
};
|
|
||||||
|
|
||||||
WalletFactory.prototype.addWalletId = function(walletId) {
|
|
||||||
var ids = this.getWalletIds();
|
|
||||||
if (ids.indexOf(walletId) !== -1) return;
|
|
||||||
ids.push(walletId);
|
|
||||||
this.storage.setGlobal('walletIds', ids);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ Storage.prototype.set = function(walletId,v) {
|
||||||
Storage.prototype.remove = function(walletId, k) {
|
Storage.prototype.remove = function(walletId, k) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Storage.prototype.getWalletIds = function() {
|
||||||
|
};
|
||||||
|
|
||||||
// remove all values
|
// remove all values
|
||||||
Storage.prototype.clearAll = function() {
|
Storage.prototype.clearAll = function() {
|
||||||
};
|
};
|
||||||
|
|
|
||||||
102
js/models/storage/File.js
Normal file
102
js/models/storage/File.js
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
'use strict';
|
||||||
|
var imports = require('soop').imports();
|
||||||
|
var fs = imports.fs || require('fs');
|
||||||
|
|
||||||
|
function Storage(opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
this.data = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Storage.prototype.load = function(walletId, callback) {
|
||||||
|
fs.readFile(walletId, function(err, data) {
|
||||||
|
if (err) return callback(err);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.data[walletId] = JSON.parse(data);
|
||||||
|
} catch (err) {
|
||||||
|
if (callback)
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
return callback(null);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage.prototype.save = function(walletId, callback) {
|
||||||
|
var data = JSON.stringify(this.data[walletId]);
|
||||||
|
|
||||||
|
//TODO: update to use a queue to ensure that saves are made sequentially
|
||||||
|
fs.writeFile(walletId, data, function(err) {
|
||||||
|
if (callback)
|
||||||
|
return callback(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage.prototype._read = function(k) {
|
||||||
|
var split = k.split('::');
|
||||||
|
var walletId = split[0];
|
||||||
|
var key = split[1];
|
||||||
|
return this.data[walletId][key];
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage.prototype._write = function(k, v, callback) {
|
||||||
|
var split = k.split('::');
|
||||||
|
var walletId = split[0];
|
||||||
|
var key = split[1];
|
||||||
|
if (!this.data[walletId])
|
||||||
|
this.data[walletId] = {};
|
||||||
|
this.data[walletId][key] = v;
|
||||||
|
this.save(walletId, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
// get value by key
|
||||||
|
Storage.prototype.getGlobal = function(k) {
|
||||||
|
return this._read(k);
|
||||||
|
};
|
||||||
|
|
||||||
|
// set value for key
|
||||||
|
Storage.prototype.setGlobal = function(k, v, callback) {
|
||||||
|
this._write(k, v, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove value for key
|
||||||
|
Storage.prototype.removeGlobal = function(k, callback) {
|
||||||
|
var split = k.split('::');
|
||||||
|
var walletId = split[0];
|
||||||
|
var key = split[1];
|
||||||
|
delete this.data[walletId][key];
|
||||||
|
this.save(walletId, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage.prototype._key = function(walletId, k) {
|
||||||
|
return walletId + '::' + k;
|
||||||
|
};
|
||||||
|
|
||||||
|
// get value by key
|
||||||
|
Storage.prototype.get = function(walletId, k) {
|
||||||
|
return this.getGlobal(this._key(walletId, k));
|
||||||
|
};
|
||||||
|
|
||||||
|
// set value for key
|
||||||
|
Storage.prototype.set = function(walletId, k, v, callback) {
|
||||||
|
this.setGlobal(this._key(walletId,k), v, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove value for key
|
||||||
|
Storage.prototype.remove = function(walletId, k, callback) {
|
||||||
|
this.removeGlobal(this._key(walletId, k), callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
Storage.prototype.getWalletIds = function() {
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove all values
|
||||||
|
Storage.prototype.clearAll = function(callback) {
|
||||||
|
this.data = {};
|
||||||
|
this.save(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = require('soop')(Storage);
|
||||||
|
|
@ -52,6 +52,21 @@ Storage.prototype.remove = function(walletId, k) {
|
||||||
this.removeGlobal(this._key(walletId,k));
|
this.removeGlobal(this._key(walletId,k));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Storage.prototype.getWalletIds = function() {
|
||||||
|
var walletIds = [];
|
||||||
|
|
||||||
|
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];
|
||||||
|
walletIds.push(walletId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return walletIds;
|
||||||
|
};
|
||||||
|
|
||||||
// remove all values
|
// remove all values
|
||||||
Storage.prototype.clearAll = function() {
|
Storage.prototype.clearAll = function() {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
"uglifyify": "~1.2.3",
|
"uglifyify": "~1.2.3",
|
||||||
"soop": "~0.1.5",
|
"soop": "~0.1.5",
|
||||||
"bitcore": "git://github.com/maraoz/bitcore.git#5e636f6b9c7f8e629b1a502025556e886c3b75e1",
|
"bitcore": "git://github.com/maraoz/bitcore.git#5e636f6b9c7f8e629b1a502025556e886c3b75e1",
|
||||||
"chai": "~1.9.1"
|
"chai": "~1.9.1",
|
||||||
|
"sinon": "~1.9.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,8 @@ FakeStorage.prototype.clear = function() {
|
||||||
delete this['storage'];
|
delete this['storage'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FakeStorage.prototype.getWalletIds = function() {
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = require('soop')(FakeStorage);
|
module.exports = require('soop')(FakeStorage);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@ var chai = chai || require('chai');
|
||||||
var should = chai.should();
|
var should = chai.should();
|
||||||
var copay = copay || require('../copay');
|
var copay = copay || require('../copay');
|
||||||
var API = API || copay.API;
|
var API = API || copay.API;
|
||||||
|
var Storage = Storage || require('../test/mocks/FakeStorage');
|
||||||
|
|
||||||
describe('API', function() {
|
describe('API', function() {
|
||||||
|
|
||||||
it('should have a command called "echo"', function() {
|
it('should have a command called "echo"', function() {
|
||||||
var api = new API();
|
|
||||||
|
var api = new API({Storage: Storage});
|
||||||
should.exist(api.echo);
|
should.exist(api.echo);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -22,7 +24,7 @@ describe('API', function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw an error for all commands when called with wrong number of arguments', function() {
|
it('should throw an error for all commands when called with wrong number of arguments', function() {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
for (var i in API.prototype) {
|
for (var i in API.prototype) {
|
||||||
var f = API.prototype[i];
|
var f = API.prototype[i];
|
||||||
if (i[0] != '_' && typeof f == 'function') {
|
if (i[0] != '_' && typeof f == 'function') {
|
||||||
|
|
@ -49,7 +51,7 @@ describe('API', function() {
|
||||||
|
|
||||||
describe('#echo', function() {
|
describe('#echo', function() {
|
||||||
it('should echo a string', function(done) {
|
it('should echo a string', function(done) {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
var str = 'mystr';
|
var str = 'mystr';
|
||||||
api.echo(str, function(err, result) {
|
api.echo(str, function(err, result) {
|
||||||
result.should.equal(str);
|
result.should.equal(str);
|
||||||
|
|
@ -60,7 +62,7 @@ describe('API', function() {
|
||||||
|
|
||||||
describe('#echoNumber', function() {
|
describe('#echoNumber', function() {
|
||||||
it('should echo a number', function(done) {
|
it('should echo a number', function(done) {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
var num = 500;
|
var num = 500;
|
||||||
api.echoNumber(num, function(err, result) {
|
api.echoNumber(num, function(err, result) {
|
||||||
result.should.equal(num);
|
result.should.equal(num);
|
||||||
|
|
@ -72,7 +74,7 @@ describe('API', function() {
|
||||||
|
|
||||||
describe('#echoObject', function() {
|
describe('#echoObject', function() {
|
||||||
it('should echo an object', function(done) {
|
it('should echo an object', function(done) {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
var obj = {test:'test'};
|
var obj = {test:'test'};
|
||||||
api.echoObject(obj, function(err, result) {
|
api.echoObject(obj, function(err, result) {
|
||||||
result.test.should.equal(obj.test);
|
result.test.should.equal(obj.test);
|
||||||
|
|
@ -84,7 +86,7 @@ describe('API', function() {
|
||||||
|
|
||||||
describe('#getArgTypes', function() {
|
describe('#getArgTypes', function() {
|
||||||
it('should get the argTypes of echo', function(done) {
|
it('should get the argTypes of echo', function(done) {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
api.getArgTypes('echo', function(err, result) {
|
api.getArgTypes('echo', function(err, result) {
|
||||||
result[0][1].should.equal('string');
|
result[0][1].should.equal('string');
|
||||||
done();
|
done();
|
||||||
|
|
@ -94,7 +96,7 @@ describe('API', function() {
|
||||||
|
|
||||||
describe('#getCommands', function() {
|
describe('#getCommands', function() {
|
||||||
it('should get all the commands', function(done) {
|
it('should get all the commands', function(done) {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
var n = 0;
|
var n = 0;
|
||||||
|
|
||||||
for (var i in api)
|
for (var i in api)
|
||||||
|
|
@ -108,11 +110,11 @@ describe('API', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getPublicKeyRingId', function() {
|
describe('#getWalletIds', function() {
|
||||||
it('should get a public key ring ID', function(done) {
|
it('should get the wallet ids', function(done) {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
api.getPublicKeyRingId(function(err, result) {
|
api.getWalletIds(function(err, result) {
|
||||||
result.length.should.be.greaterThan(5);
|
result.length.should.be.greaterThan(-1);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -120,7 +122,7 @@ describe('API', function() {
|
||||||
|
|
||||||
describe('#help', function() {
|
describe('#help', function() {
|
||||||
it('should call _cmd_getCommands', function(done) {
|
it('should call _cmd_getCommands', function(done) {
|
||||||
var api = new API();
|
var api = new API({Storage: Storage});
|
||||||
api._cmd_getCommands = function(callback) {
|
api._cmd_getCommands = function(callback) {
|
||||||
(typeof arguments[0]).should.equal('function');
|
(typeof arguments[0]).should.equal('function');
|
||||||
callback(null, ['item']);
|
callback(null, ['item']);
|
||||||
|
|
|
||||||
144
test/test.storage.File.js
Normal file
144
test/test.storage.File.js
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var chai = chai || require('chai');
|
||||||
|
var should = chai.should();
|
||||||
|
var Storage = Storage || require('../js/models/storage/File.js');
|
||||||
|
var sinon = sinon || require('sinon');
|
||||||
|
|
||||||
|
describe('Storage/File', function() {
|
||||||
|
it('should exist', function() {
|
||||||
|
should.exist(Storage);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#load', function(done) {
|
||||||
|
it('should call fs.readFile', function(done) {
|
||||||
|
var fs = {}
|
||||||
|
fs.readFile = function(filename, callback) {
|
||||||
|
filename.should.equal('myfilename');
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs});
|
||||||
|
var storage = new Storage({password: 'password'});
|
||||||
|
storage.load('myfilename', function(err) {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#save', function(done) {
|
||||||
|
it('should call fs.writeFile', function(done) {
|
||||||
|
var fs = {}
|
||||||
|
fs.writeFile = function(filename, data, callback) {
|
||||||
|
filename.should.equal('myfilename');
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs});
|
||||||
|
var storage = new Storage({password: 'password'});
|
||||||
|
storage.save('myfilename', function(err) {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#_read', function() {
|
||||||
|
it('should return the value of a key', function() {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.data = {'walletId':{'test':'data'}};
|
||||||
|
storage._read('walletId::test').should.equal('data');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#_write', function() {
|
||||||
|
it('should save the value of a key and then run save', function(done) {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.save = function(walletId, callback) {
|
||||||
|
storage.data[walletId]['key'].should.equal('value');
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
storage._write('walletId::key', 'value', function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#getGlobal', function() {
|
||||||
|
it('should call storage._read', function() {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.data = {'walletId':{'test':'test'}};
|
||||||
|
storage._read = sinon.spy();
|
||||||
|
storage.getGlobal('walletId::test');
|
||||||
|
storage._read.calledOnce.should.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#setGlobal', function() {
|
||||||
|
it('should store a global key', function(done) {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.save = function(walletId, callback) {
|
||||||
|
storage.data[walletId]['key'].should.equal('value');
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
storage.setGlobal('walletId::key', 'value', function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#removeGlobal', function() {
|
||||||
|
it('should remove a global key', function(done) {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.data = {'walletId':{'key':'value'}};
|
||||||
|
storage.save = function(walletId, callback) {
|
||||||
|
should.not.exist(storage.data[walletId]['key']);
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
storage.removeGlobal('walletId::key', function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#_key', function() {
|
||||||
|
it('should merge the wallet id and item key', function() {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage._key('wallet', 'key').should.equal('wallet::key');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#get', function() {
|
||||||
|
it('should call getGlobal with the correct key', function() {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.getGlobal = sinon.spy();
|
||||||
|
storage.get('wallet', 'key');
|
||||||
|
storage.getGlobal.calledOnce.should.equal(true);
|
||||||
|
storage.getGlobal.calledWith('wallet::key').should.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#set', function() {
|
||||||
|
it('should call setGlobal with the correct key', function() {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.setGlobal = sinon.spy();
|
||||||
|
storage.set('wallet', 'key');
|
||||||
|
storage.setGlobal.calledOnce.should.equal(true);
|
||||||
|
storage.setGlobal.calledWith('wallet::key').should.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#remove', function() {
|
||||||
|
it('should call removeGlobal with the correct key', function() {
|
||||||
|
var storage = new Storage();
|
||||||
|
storage.removeGlobal = sinon.spy();
|
||||||
|
storage.remove('wallet', 'key');
|
||||||
|
storage.removeGlobal.calledOnce.should.equal(true);
|
||||||
|
storage.removeGlobal.calledWith('wallet::key').should.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#clearAll', function() {
|
||||||
|
it('should set data to {}', function() {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue