diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index e4bf2260..d4ddc86c 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -9,12 +9,12 @@ "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" }, "babel-runtime": { - "version": "5.8.19", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.19.tgz", + "version": "5.8.20", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.20.tgz", "dependencies": { "core-js": { - "version": "0.9.18", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-0.9.18.tgz" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.0.1.tgz" } } }, @@ -22,6 +22,16 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.0.7.tgz" }, + "es6-promisify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-2.0.0.tgz", + "dependencies": { + "es6-promise": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz" + } + } + }, "extend": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz" @@ -108,7 +118,6 @@ }, "sjcl-extended": { "version": "1.0.3", - "from": "sjcl-extended@git://github.com/ripple/sjcl-extended.git#d8cf8b22e7d97193c54e1f65113e3edcf200ca17", "resolved": "git://github.com/ripple/sjcl-extended.git#d8cf8b22e7d97193c54e1f65113e3edcf200ca17", "dependencies": { "sjcl": { diff --git a/package.json b/package.json index 1f5e0023..39f9736b 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "async": "~0.9.0", "babel-runtime": "^5.5.4", "bignumber.js": "^2.0.3", + "es6-promisify": "^2.0.0", "extend": "~1.2.1", "https-proxy-agent": "^1.0.0", "is-my-json-valid": "^2.12.0", diff --git a/src/api/common/index.js b/src/api/common/index.js index 60cbc0eb..2ae6c412 100644 --- a/src/api/common/index.js +++ b/src/api/common/index.js @@ -9,8 +9,10 @@ module.exports = { dropsToXrp: utils.dropsToXrp, xrpToDrops: utils.xrpToDrops, toRippledAmount: utils.toRippledAmount, - wrapCatch: utils.wrapCatch, composeAsync: utils.composeAsync, + wrapCatch: utils.wrapCatch, convertExceptions: utils.convertExceptions, - convertKeysFromSnakeCaseToCamelCase: utils.convertKeysFromSnakeCaseToCamelCase + convertKeysFromSnakeCaseToCamelCase: + utils.convertKeysFromSnakeCaseToCamelCase, + promisify: utils.promisify }; diff --git a/src/api/common/schemas/settings-transaction.json b/src/api/common/schemas/settings-transaction.json index 680bbd40..d55959f3 100644 --- a/src/api/common/schemas/settings-transaction.json +++ b/src/api/common/schemas/settings-transaction.json @@ -10,6 +10,6 @@ "address": {"$ref": "address"}, "sequence": {"$ref": "sequence"} }, - "required": ["type", "id", "address", "sequence", "specification", "outcome"], + "required": ["type", "id", "address", "sequence", "specification"], "additionalProperties": false } diff --git a/src/api/common/utils.js b/src/api/common/utils.js index 57a6f8c3..7df94262 100644 --- a/src/api/common/utils.js +++ b/src/api/common/utils.js @@ -4,6 +4,7 @@ const _ = require('lodash'); const BigNumber = require('bignumber.js'); const core = require('../../core'); const errors = require('./errors'); +const es6promisify = require('es6-promisify'); type Amount = {currency: string, issuer: string, value: string} @@ -85,13 +86,18 @@ function convertKeysFromSnakeCaseToCamelCase(obj: any): any { return obj; } +function promisify(asyncFunction: AsyncFunction): Function { + return es6promisify(wrapCatch(asyncFunction)); +} + module.exports = { core, dropsToXrp, xrpToDrops, toRippledAmount, - wrapCatch, composeAsync, + wrapCatch, convertExceptions, - convertKeysFromSnakeCaseToCamelCase + convertKeysFromSnakeCaseToCamelCase, + promisify }; diff --git a/src/api/ledger/accountinfo.js b/src/api/ledger/accountinfo.js index 971db053..1f6fc575 100644 --- a/src/api/ledger/accountinfo.js +++ b/src/api/ledger/accountinfo.js @@ -18,7 +18,7 @@ function formatAccountInfo(response) { }); } -function getAccountInfo(account, options, callback) { +function getAccountInfoAsync(account, options, callback) { validate.address(account); validate.getAccountInfoOptions(options); @@ -31,4 +31,8 @@ function getAccountInfo(account, options, callback) { composeAsync(formatAccountInfo, callback)); } -module.exports = utils.wrapCatch(getAccountInfo); +function getAccountInfo(account: string, options={}) { + return utils.promisify(getAccountInfoAsync.bind(this))(account, options); +} + +module.exports = getAccountInfo; diff --git a/src/api/ledger/balances.js b/src/api/ledger/balances.js index 9fdf05b9..b21418e0 100644 --- a/src/api/ledger/balances.js +++ b/src/api/ledger/balances.js @@ -24,7 +24,13 @@ function formatBalances(balances) { balances.trustlines.map(getTrustlineBalanceAmount)); } -function getBalances(account, options, callback) { +function getTrustlinesAsync(account, options, callback) { + getTrustlines.bind(this)(account, options) + .then(data => callback(null, data)) + .catch(callback); +} + +function getBalancesAsync(account, options, callback) { validate.address(account); validate.getBalancesOptions(options); @@ -32,8 +38,12 @@ function getBalances(account, options, callback) { || this.remote.getLedgerSequence(); async.parallel({ xrp: _.partial(utils.getXRPBalance, this.remote, account, ledgerVersion), - trustlines: _.partial(getTrustlines.bind(this), account, options) + trustlines: _.partial(getTrustlinesAsync.bind(this), account, options) }, composeAsync(formatBalances, callback)); } -module.exports = utils.wrapCatch(getBalances); +function getBalances(account: string, options={}) { + return utils.promisify(getBalancesAsync.bind(this))(account, options); +} + +module.exports = getBalances; diff --git a/src/api/ledger/orderbook.js b/src/api/ledger/orderbook.js index 79c9b271..0902280b 100644 --- a/src/api/ledger/orderbook.js +++ b/src/api/ledger/orderbook.js @@ -62,7 +62,7 @@ function formatBidsAndAsks(orderbook, offers) { return {bids, asks}; } -function getOrderbook(account, orderbook, options, callback) { +function getOrderbookAsync(account, orderbook, options, callback) { validate.address(account); validate.orderbook(orderbook); validate.getOrderbookOptions(options); @@ -76,4 +76,9 @@ function getOrderbook(account, orderbook, options, callback) { callback)); } -module.exports = utils.wrapCatch(getOrderbook); +function getOrderbook(account: string, orderbook: Object, options={}) { + return utils.promisify(getOrderbookAsync.bind(this))( + account, orderbook, options); +} + +module.exports = getOrderbook; diff --git a/src/api/ledger/orders.js b/src/api/ledger/orders.js index 7671b5c2..63d1d3d5 100644 --- a/src/api/ledger/orders.js +++ b/src/api/ledger/orders.js @@ -20,7 +20,7 @@ function requestAccountOffers(remote, address, ledgerVersion, options, }), callback)); } -function getOrders(account, options, callback) { +function getOrdersAsync(account, options, callback) { validate.address(account); validate.getOrdersOptions(options); @@ -33,4 +33,8 @@ function getOrders(account, options, callback) { (order) => order.properties.sequence), callback)); } -module.exports = utils.wrapCatch(getOrders); +function getOrders(account: string, options={}) { + return utils.promisify(getOrdersAsync.bind(this))(account, options); +} + +module.exports = getOrders; diff --git a/src/api/ledger/pathfind.js b/src/api/ledger/pathfind.js index 5d260e6f..f895d75f 100644 --- a/src/api/ledger/pathfind.js +++ b/src/api/ledger/pathfind.js @@ -103,7 +103,7 @@ function formatResponse(pathfind, paths) { } } -function getPaths(pathfind, callback) { +function getPathsAsync(pathfind, callback) { validate.pathfind(pathfind); const address = pathfind.source.address; @@ -113,4 +113,8 @@ function getPaths(pathfind, callback) { ], composeAsync(_.partial(formatResponse, pathfind), callback)); } -module.exports = utils.wrapCatch(getPaths); +function getPaths(pathfind: Object) { + return utils.promisify(getPathsAsync.bind(this))(pathfind); +} + +module.exports = getPaths; diff --git a/src/api/ledger/settings.js b/src/api/ledger/settings.js index bd58f6fe..03c659bb 100644 --- a/src/api/ledger/settings.js +++ b/src/api/ledger/settings.js @@ -24,7 +24,7 @@ function formatSettings(response) { return _.assign({}, parsedFlags, parsedFields); } -function getSettings(account, options, callback) { +function getSettingsAsync(account, options, callback) { validate.address(account); validate.getSettingsOptions(options); @@ -37,4 +37,8 @@ function getSettings(account, options, callback) { composeAsync(formatSettings, callback)); } -module.exports = utils.wrapCatch(getSettings); +function getSettings(account: string, options={}) { + return utils.promisify(getSettingsAsync.bind(this))(account, options); +} + +module.exports = getSettings; diff --git a/src/api/ledger/transaction.js b/src/api/ledger/transaction.js index d8d0e673..92a2e297 100644 --- a/src/api/ledger/transaction.js +++ b/src/api/ledger/transaction.js @@ -36,7 +36,7 @@ function isTransactionInRange(tx, options) { || tx.ledger_index <= options.maxLedgerVersion); } -function getTransaction(identifier, options, callback) { +function getTransactionAsync(identifier, options, callback) { validate.identifier(identifier); validate.getTransactionOptions(options); @@ -71,4 +71,8 @@ function getTransaction(identifier, options, callback) { ], callbackWrapper); } -module.exports = utils.wrapCatch(getTransaction); +function getTransaction(identifier: string, options={}) { + return utils.promisify(getTransactionAsync.bind(this))(identifier, options); +} + +module.exports = getTransaction; diff --git a/src/api/ledger/transactions.js b/src/api/ledger/transactions.js index 96b82d50..8469d48b 100644 --- a/src/api/ledger/transactions.js +++ b/src/api/ledger/transactions.js @@ -98,27 +98,27 @@ function getTransactionsInternal(remote, address, options, callback) { utils.getRecursive(getter, options.limit, composeAsync(format, callback)); } -function getTransactions(account, options, callback) { +function getTransactionsAsync(account, options, callback) { validate.address(account); validate.getTransactionsOptions(options); const defaults = {maxLedgerVersion: this.remote.getLedgerSequence()}; if (options.start) { - getTransaction.bind(this)(options.start, {}, (error, tx) => { - if (error) { - callback(error); - return; - } + getTransaction.bind(this)(options.start).then(tx => { const ledgerVersion = tx.outcome.ledgerVersion; const bound = options.earliestFirst ? {minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion}; const newOptions = _.assign(defaults, options, {startTx: tx}, bound); getTransactionsInternal(this.remote, account, newOptions, callback); - }); + }).catch(callback); } else { const newOptions = _.assign(defaults, options); getTransactionsInternal(this.remote, account, newOptions, callback); } } -module.exports = utils.wrapCatch(getTransactions); +function getTransactions(account: string, options={}) { + return utils.promisify(getTransactionsAsync.bind(this))(account, options); +} + +module.exports = getTransactions; diff --git a/src/api/ledger/trustlines.js b/src/api/ledger/trustlines.js index 1a142aa9..7f47b823 100644 --- a/src/api/ledger/trustlines.js +++ b/src/api/ledger/trustlines.js @@ -29,7 +29,7 @@ function getAccountLines(remote, address, ledgerVersion, options, marker, limit, }); } -function getTrustlines(account: string, options: {currency: string, +function getTrustlinesAsync(account: string, options: {currency: string, counterparty: string, limit: number, ledgerVersion: number}, callback: () => void): void { validate.address(account); @@ -42,4 +42,8 @@ function getTrustlines(account: string, options: {currency: string, utils.getRecursive(getter, options.limit, callback); } -module.exports = utils.wrapCatch(getTrustlines); +function getTrustlines(account: string, options={}) { + return utils.promisify(getTrustlinesAsync.bind(this))(account, options); +} + +module.exports = getTrustlines; diff --git a/src/api/ledger/utils.js b/src/api/ledger/utils.js index 46d80534..3ccb135d 100644 --- a/src/api/ledger/utils.js +++ b/src/api/ledger/utils.js @@ -13,7 +13,8 @@ function clamp(value: number, min: number, max: number): number { return Math.min(Math.max(value, min), max); } -function getXRPBalance(remote: any, address: string, ledgerVersion?: number, callback: Callback): void { +function getXRPBalance(remote: any, address: string, ledgerVersion?: number, + callback: Callback): void { remote.requestAccountInfo({account: address, ledger: ledgerVersion}, composeAsync((data) => dropsToXrp(data.account_data.Balance), callback)); } @@ -22,7 +23,8 @@ type Getter = (marker: ?string, limit: number, callback: Callback) => void // If the marker is omitted from a response, you have reached the end // getter(marker, limit, callback), callback(error, {marker, results}) -function getRecursiveRecur(getter: Getter, marker?: string, limit: number, callback: Callback): void { +function getRecursiveRecur(getter: Getter, marker?: string, limit: number, + callback: Callback): void { getter(marker, limit, (error, data) => { if (error) { return callback(error); @@ -105,7 +107,7 @@ module.exports = { renameCounterpartyToIssuerInOrder, getRecursive, hasCompleteLedgerRange, - wrapCatch: common.wrapCatch, + promisify: common.promisify, clamp: clamp, common: common }; diff --git a/src/api/server/server.js b/src/api/server/server.js index ae389896..b2048bab 100644 --- a/src/api/server/server.js +++ b/src/api/server/server.js @@ -8,14 +8,6 @@ const common = require('../common'); // If a ledger is not received in this time, consider the connection offline const CONNECTION_TIMEOUT = 1000 * 30; -function connect(callback: (err: any, data: any) => void): void { - this.remote.connect(callback); -} - -function disconnect(callback: (err: any, data: any) => void): void { - this.remote.disconnect(callback); -} - function isUpToDate(remote): boolean { const server = remote.getServer(); return Boolean(server) && (remote._stand_alone @@ -26,7 +18,7 @@ function isConnected(): boolean { return Boolean(this.remote._ledger_current_index) && isUpToDate(this.remote); } -function getServerInfo(callback: (err: any, data: any) => void): void { +function getServerInfoAsync(callback: (err: any, data: any) => void): void { this.remote.requestServerInfo((error, response) => { if (error) { const message = _.get(error, ['remote', 'error_message'], error.message); @@ -45,6 +37,22 @@ function getLedgerVersion(): number { return this.remote.getLedgerSequence(); } +function connect() { + return common.promisify(callback => { + this.remote.connect(() => callback(null)); + })(); +} + +function disconnect() { + return common.promisify(callback => { + this.remote.disconnect(() => callback(null)); + })(); +} + +function getServerInfo() { + return common.promisify(getServerInfoAsync.bind(this))(); +} + module.exports = { connect, disconnect, diff --git a/src/api/transaction/order.js b/src/api/transaction/order.js index e6dc36a2..aac4ca72 100644 --- a/src/api/transaction/order.js +++ b/src/api/transaction/order.js @@ -30,9 +30,14 @@ function createOrderTransaction(account, order) { return transaction; } -function prepareOrder(account, order, instructions, callback) { +function prepareOrderAsync(account, order, instructions, callback) { const transaction = createOrderTransaction(account, order); utils.createTxJSON(transaction, this.remote, instructions, callback); } -module.exports = utils.wrapCatch(prepareOrder); +function prepareOrder(account: string, order: Object, instructions={}) { + return utils.promisify(prepareOrderAsync.bind(this))( + account, order, instructions); +} + +module.exports = prepareOrder; diff --git a/src/api/transaction/ordercancellation.js b/src/api/transaction/ordercancellation.js index 912973c9..77a81592 100644 --- a/src/api/transaction/ordercancellation.js +++ b/src/api/transaction/ordercancellation.js @@ -13,9 +13,16 @@ function createOrderCancellationTransaction(account, sequence) { return transaction; } -function prepareOrderCancellation(account, sequence, instructions, callback) { +function prepareOrderCancellationAsync(account, sequence, instructions, + callback) { const transaction = createOrderCancellationTransaction(account, sequence); utils.createTxJSON(transaction, this.remote, instructions, callback); } -module.exports = utils.wrapCatch(prepareOrderCancellation); +function prepareOrderCancellation(account: string, sequence: number, + instructions={}) { + return utils.promisify(prepareOrderCancellationAsync.bind(this))( + account, sequence, instructions); +} + +module.exports = prepareOrderCancellation; diff --git a/src/api/transaction/payment.js b/src/api/transaction/payment.js index 32344d23..2a4b033a 100644 --- a/src/api/transaction/payment.js +++ b/src/api/transaction/payment.js @@ -81,9 +81,14 @@ function createPaymentTransaction(account, payment) { return transaction; } -function preparePayment(account, payment, instructions, callback) { +function preparePaymentAsync(account, payment, instructions, callback) { const transaction = createPaymentTransaction(account, payment); utils.createTxJSON(transaction, this.remote, instructions, callback); } -module.exports = utils.wrapCatch(preparePayment); +function preparePayment(account: string, payment: Object, instructions={}) { + return utils.promisify(preparePaymentAsync.bind(this))( + account, payment, instructions); +} + +module.exports = preparePayment; diff --git a/src/api/transaction/settings.js b/src/api/transaction/settings.js index 5d8237ee..f5fee470 100644 --- a/src/api/transaction/settings.js +++ b/src/api/transaction/settings.js @@ -90,9 +90,14 @@ function createSettingsTransaction(account, settings) { return transaction; } -function prepareSettings(account, settings, instructions, callback) { +function prepareSettingsAsync(account, settings, instructions, callback) { const transaction = createSettingsTransaction(account, settings); utils.createTxJSON(transaction, this.remote, instructions, callback); } -module.exports = utils.wrapCatch(prepareSettings); +function prepareSettings(account: string, settings: Object, instructions={}) { + return utils.promisify(prepareSettingsAsync.bind(this))( + account, settings, instructions); +} + +module.exports = prepareSettings; diff --git a/src/api/transaction/submit.js b/src/api/transaction/submit.js index faac2b38..7b702df4 100644 --- a/src/api/transaction/submit.js +++ b/src/api/transaction/submit.js @@ -4,7 +4,8 @@ const utils = require('./utils'); const validate = utils.common.validate; const Request = utils.common.core.Request; -function submit(txBlob: string, callback: (err: any, data: any) => void): void { +function submitAsync(txBlob: string, callback: (err: any, data: any) => void): + void { validate.blob(txBlob); const request = new Request(this.remote, 'submit'); request.message.tx_blob = txBlob; @@ -14,4 +15,8 @@ function submit(txBlob: string, callback: (err: any, data: any) => void): void { callback)); } +function submit(txBlob: string) { + return utils.promisify(submitAsync.bind(this))(txBlob); +} + module.exports = submit; diff --git a/src/api/transaction/trustline.js b/src/api/transaction/trustline.js index 235d92b3..27c98790 100644 --- a/src/api/transaction/trustline.js +++ b/src/api/transaction/trustline.js @@ -32,9 +32,14 @@ function createTrustlineTransaction(account, trustline) { return transaction; } -function prepareTrustline(account, trustline, instructions, callback) { +function prepareTrustlineAsync(account, trustline, instructions, callback) { const transaction = createTrustlineTransaction(account, trustline); utils.createTxJSON(transaction, this.remote, instructions, callback); } -module.exports = utils.wrapCatch(prepareTrustline); +function prepareTrustline(account: string, trustline: Object, instructions={}) { + return utils.promisify(prepareTrustlineAsync.bind(this))( + account, trustline, instructions); +} + +module.exports = prepareTrustline; diff --git a/src/api/transaction/utils.js b/src/api/transaction/utils.js index 4b9aff43..20e844e9 100644 --- a/src/api/transaction/utils.js +++ b/src/api/transaction/utils.js @@ -65,6 +65,6 @@ function createTxJSON(transaction: any, remote: any, instructions: any, module.exports = { setTransactionBitFlags: setTransactionBitFlags, createTxJSON: createTxJSON, - wrapCatch: common.wrapCatch, - common: common + common: common, + promisify: common.promisify }; diff --git a/test/api-test.js b/test/api-test.js index 79c29622..3d72af41 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -31,17 +31,12 @@ const orderbook = { } }; -function checkResult(expected, schemaName, done, error, response) { - if (error) { - done(error); - return; - } +function checkResult(expected, schemaName, response) { // console.log(JSON.stringify(response, null, 2)); assert.deepEqual(response, expected); if (schemaName) { schemaValidator.schemaValidate(schemaName, response); } - done(); } function withDeterministicPRNG(f) { @@ -56,100 +51,97 @@ describe('RippleAPI', function() { beforeEach(setupAPI.setup); afterEach(setupAPI.teardown); - it('preparePayment', function(done) { + it('preparePayment', function() { const localInstructions = _.defaults({ maxFee: '0.000012' }, instructions); - this.api.preparePayment(address, requests.preparePayment, localInstructions, - _.partial(checkResult, responses.preparePayment, 'tx', done)); + return this.api.preparePayment( + address, requests.preparePayment, localInstructions).then( + _.partial(checkResult, responses.preparePayment, 'tx')); }); - it('preparePayment with all options specified', function(done) { + it('preparePayment with all options specified', function() { const localInstructions = { maxLedgerVersion: this.api.getLedgerVersion() + 100, fee: '0.000012' }; - this.api.preparePayment(address, requests.preparePaymentAllOptions, - localInstructions, - _.partial(checkResult, responses.preparePaymentAllOptions, 'tx', done)); + return this.api.preparePayment( + address, requests.preparePaymentAllOptions, localInstructions).then( + _.partial(checkResult, responses.preparePaymentAllOptions, 'tx')); }); - it('preparePayment without counterparty set', function(done) { - const localInstructions = _.defaults({ - sequence: 23 - }, instructions); - this.api.preparePayment(address, requests.preparePaymentNoCounterparty, - localInstructions, - _.partial(checkResult, responses.preparePaymentNoCounterparty, - 'tx', done)); + it('preparePayment without counterparty set', function() { + const localInstructions = _.defaults({sequence: 23}, instructions); + return this.api.preparePayment( + address, requests.preparePaymentNoCounterparty, localInstructions).then( + _.partial(checkResult, responses.preparePaymentNoCounterparty, 'tx')); }); - it('prepareOrder - buy order', function(done) { - this.api.prepareOrder(address, requests.prepareOrder, instructions, - _.partial(checkResult, responses.prepareOrder, 'tx', done)); + it('prepareOrder - buy order', function() { + return this.api.prepareOrder(address, requests.prepareOrder, instructions) + .then(_.partial(checkResult, responses.prepareOrder, 'tx')); }); - it('prepareOrder - sell order', function(done) { - this.api.prepareOrder(address, requests.prepareOrderSell, instructions, - _.partial(checkResult, responses.prepareOrderSell, 'tx', done)); + it('prepareOrder - sell order', function() { + return this.api.prepareOrder( + address, requests.prepareOrderSell, instructions).then( + _.partial(checkResult, responses.prepareOrderSell, 'tx')); }); - it('prepareOrderCancellation', function(done) { - this.api.prepareOrderCancellation(address, 23, instructions, - _.partial(checkResult, responses.prepareOrderCancellation, 'tx', - done)); + it('prepareOrderCancellation', function() { + return this.api.prepareOrderCancellation(address, 23, instructions).then( + _.partial(checkResult, responses.prepareOrderCancellation, 'tx')); }); - it('prepareTrustline', function(done) { - this.api.prepareTrustline(address, requests.prepareTrustline, - instructions, _.partial(checkResult, responses.prepareTrustline, - 'tx', done)); + it('prepareTrustline', function() { + return this.api.prepareTrustline( + address, requests.prepareTrustline, instructions).then( + _.partial(checkResult, responses.prepareTrustline, 'tx')); }); - it('prepareSettings', function(done) { - this.api.prepareSettings(address, requests.prepareSettings, instructions, - _.partial(checkResult, responses.prepareSettings.flags, 'tx', done)); + it('prepareSettings', function() { + return this.api.prepareSettings( + address, requests.prepareSettings, instructions).then( + _.partial(checkResult, responses.prepareSettings.flags, 'tx')); }); - it('prepareSettings - regularKey', function(done) { + it('prepareSettings - regularKey', function() { const regularKey = {regularKey: 'rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD'}; - this.api.prepareSettings(address, regularKey, instructions, - _.partial(checkResult, responses.prepareSettings.regularKey, - 'tx', done)); + return this.api.prepareSettings(address, regularKey, instructions).then( + _.partial(checkResult, responses.prepareSettings.regularKey, 'tx')); }); - it('prepareSettings - flag set', function(done) { + it('prepareSettings - flag set', function() { const settings = {requireDestinationTag: true}; - this.api.prepareSettings(address, settings, instructions, - _.partial(checkResult, responses.prepareSettings.flagSet, 'tx', done)); + return this.api.prepareSettings(address, settings, instructions).then( + _.partial(checkResult, responses.prepareSettings.flagSet, 'tx')); }); - it('prepareSettings - flag clear', function(done) { + it('prepareSettings - flag clear', function() { const settings = {requireDestinationTag: false}; - this.api.prepareSettings(address, settings, instructions, - _.partial(checkResult, responses.prepareSettings.flagClear, 'tx', done)); + return this.api.prepareSettings(address, settings, instructions).then( + _.partial(checkResult, responses.prepareSettings.flagClear, 'tx')); }); - it('prepareSettings - string field clear', function(done) { + it('prepareSettings - string field clear', function() { const settings = {walletLocator: null}; - this.api.prepareSettings(address, settings, instructions, - _.partial(checkResult, responses.prepareSettings.fieldClear, 'tx', done)); + return this.api.prepareSettings(address, settings, instructions).then( + _.partial(checkResult, responses.prepareSettings.fieldClear, 'tx')); }); - it('prepareSettings - integer field clear', function(done) { + it('prepareSettings - integer field clear', function() { const settings = {walletSize: null}; - this.api.prepareSettings(address, settings, instructions, (e, data) => { - assert(data); - assert.strictEqual(data.WalletSize, 0); - done(e); - }); + return this.api.prepareSettings(address, settings, instructions) + .then(data => { + assert(data); + assert.strictEqual(data.WalletSize, 0); + }); }); - it('prepareSettings - set transferRate', function(done) { + it('prepareSettings - set transferRate', function() { const settings = {transferRate: 1}; - this.api.prepareSettings(address, settings, instructions, - _.partial(checkResult, responses.prepareSettings.setTransferRate, - 'tx', done)); + return this.api.prepareSettings(address, settings, instructions).then( + _.partial(checkResult, responses.prepareSettings.setTransferRate, 'tx')); }); it('sign', function() { @@ -161,255 +153,260 @@ describe('RippleAPI', function() { }); }); - it('submit', function(done) { - this.api.submit(responses.sign.signedTransaction, - _.partial(checkResult, responses.submit, 'submit', done)); + it('submit', function() { + return this.api.submit(responses.sign.signedTransaction).then( + _.partial(checkResult, responses.submit, 'submit')); }); - it('getBalances', function(done) { - this.api.getBalances(address, {}, - _.partial(checkResult, responses.getBalances, 'getBalances', done)); + it('getBalances', function() { + return this.api.getBalances(address).then( + _.partial(checkResult, responses.getBalances, 'getBalances')); }); - it('getTransaction - payment', function(done) { - this.api.getTransaction(hashes.VALID_TRANSACTION_HASH, {}, + it('getTransaction - payment', function() { + return this.api.getTransaction(hashes.VALID_TRANSACTION_HASH).then( _.partial(checkResult, responses.getTransaction.payment, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - settings', function(done) { + it('getTransaction - settings', function() { const hash = '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA1B'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.settings, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - order', function(done) { + it('getTransaction - order', function() { const hash = '10A6FB4A66EE80BED46AAE4815D7DC43B97E944984CCD5B93BCF3F8538CABC51'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.order, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - order cancellation', function(done) { + it('getTransaction - order cancellation', function() { const hash = '809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.orderCancellation, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - trustline set', function(done) { + it('getTransaction - trustline set', function() { const hash = '635A0769BD94710A1F6A76CDE65A3BC661B20B798807D1BBBDADCEA26420538D'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.trustline, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - trustline frozen off', function(done) { + it('getTransaction - trustline frozen off', function() { const hash = 'FE72FAD0FA7CA904FB6C633A1666EDF0B9C73B2F5A4555D37EEF2739A78A531B'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.trustlineFrozenOff, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - not validated', function(done) { + it('getTransaction - not validated', function() { const hash = '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA10'; - this.api.getTransaction(hash, {}, (error, data) => { - assert.deepEqual(data, responses.getTransaction.notValidated); - done(error); - }); + return this.api.getTransaction(hash).then( + _.partial(checkResult, responses.getTransaction.notValidated, + 'getTransaction')); }); - it('getTransaction - tracking on', function(done) { + it('getTransaction - tracking on', function() { const hash = '8925FC8844A1E930E2CC76AD0A15E7665AFCC5425376D548BB1413F484C31B8C'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.trackingOn, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - tracking off', function(done) { + it('getTransaction - tracking off', function() { const hash = 'C8C5E20DFB1BF533D0D81A2ED23F0A3CBD1EF2EE8A902A1D760500473CC9C582'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.trackingOff, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - set regular key', function(done) { + it('getTransaction - set regular key', function() { const hash = '278E6687C1C60C6873996210A6523564B63F2844FB1019576C157353B1813E60'; - this.api.getTransaction(hash, {}, + return this.api.getTransaction(hash).then( _.partial(checkResult, responses.getTransaction.setRegularKey, - 'getTransaction', done)); + 'getTransaction')); }); - it('getTransaction - not found in range', function(done) { + it('getTransaction - not found in range', function() { const hash = '809335DD3B0B333865096217AA2F55A4DF168E0198080B3A090D12D88880FF0E'; const options = { minLedgerVersion: 32570, maxLedgerVersion: 32571 }; - this.api.getTransaction(hash, options, (error) => { + return this.api.getTransaction(hash, options).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); - done(); }); }); - it('getTransaction - not found by hash', function(done) { - this.api.getTransaction(hashes.NOTFOUND_TRANSACTION_HASH, {}, (error) => { + it('getTransaction - not found by hash', function() { + const hash = hashes.NOTFOUND_TRANSACTION_HASH; + return this.api.getTransaction(hash).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); - done(); }); }); - it('getTransaction - missing ledger history', function(done) { + it('getTransaction - missing ledger history', function() { + const hash = hashes.NOTFOUND_TRANSACTION_HASH; // make gaps in history this.api.remote.getServer().emit('message', ledgerClosed); - this.api.getTransaction(hashes.NOTFOUND_TRANSACTION_HASH, {}, (error) => { + return this.api.getTransaction(hash).then(() => { + assert(false, 'Should throw MissingLedgerHistoryError'); + }).catch(error => { assert(error instanceof this.api.errors.MissingLedgerHistoryError); - done(); }); }); - it('getTransaction - ledger_index not found', function(done) { + it('getTransaction - ledger_index not found', function() { const hash = '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA11'; - this.api.getTransaction(hash, {}, (error) => { + return this.api.getTransaction(hash).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); assert(error.message.indexOf('ledger_index') !== -1); - done(); }); }); - it('getTransaction - transaction ledger not found', function(done) { + it('getTransaction - transaction ledger not found', function() { const hash = '4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA12'; - this.api.getTransaction(hash, {}, (error) => { + return this.api.getTransaction(hash).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); assert(error.message.indexOf('ledger not found') !== -1); - done(); }); }); - it('getTransaction - ledger missing close time', function(done) { + it('getTransaction - ledger missing close time', function() { const hash = '0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A04'; - this.api.getTransaction(hash, {}, (error) => { + return this.api.getTransaction(hash).then(() => { + assert(false, 'Should throw ApiError'); + }).catch(error => { assert(error instanceof this.api.errors.ApiError); - done(); }); }); - it('getTransactions', function(done) { + it('getTransactions', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 2}; - this.api.getTransactions(address, options, + return this.api.getTransactions(address, options).then( _.partial(checkResult, responses.getTransactions, - 'getTransactions', done)); + 'getTransactions')); }); - it('getTransactions - earliest first', function(done) { + it('getTransactions - earliest first', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 2, earliestFirst: true }; const expected = _.cloneDeep(responses.getTransactions) .sort(utils.compareTransactions); - this.api.getTransactions(address, options, - _.partial(checkResult, expected, 'getTransactions', done)); + return this.api.getTransactions(address, options).then( + _.partial(checkResult, expected, 'getTransactions')); }); - it('getTransactions - earliest first with start option', function(done) { + it('getTransactions - earliest first with start option', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 2, start: hashes.VALID_TRANSACTION_HASH, earliestFirst: true }; - this.api.getTransactions(address, options, (error, data) => { + return this.api.getTransactions(address, options).then(data => { assert.strictEqual(data.length, 0); - done(error); }); }); - it('getTransactions - gap', function(done) { + it('getTransactions - gap', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 2, maxLedgerVersion: 348858000 }; - this.api.getTransactions(address, options, (error) => { + return this.api.getTransactions(address, options).then(() => { + assert(false, 'Should throw MissingLedgerHistoryError'); + }).catch(error => { assert(error instanceof this.api.errors.MissingLedgerHistoryError); - done(); }); }); - it('getTransactions - tx not found', function(done) { + it('getTransactions - tx not found', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 2, start: hashes.NOTFOUND_TRANSACTION_HASH, counterparty: address }; - this.api.getTransactions(address, options, (error) => { + return this.api.getTransactions(address, options).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); - done(); }); }); - it('getTransactions - filters', function(done) { + it('getTransactions - filters', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 10, excludeFailures: true, counterparty: addresses.ISSUER }; - this.api.getTransactions(address, options, (error, data) => { + return this.api.getTransactions(address, options).then(data => { assert.strictEqual(data.length, 10); assert(_.every(data, t => t.type === 'payment' || t.type === 'order')); assert(_.every(data, t => t.outcome.result === 'tesSUCCESS')); - done(); }); }); - it('getTransactions - filters for incoming', function(done) { + it('getTransactions - filters for incoming', function() { const options = {types: ['payment', 'order'], initiated: false, limit: 10, excludeFailures: true, counterparty: addresses.ISSUER }; - this.api.getTransactions(address, options, (error, data) => { + return this.api.getTransactions(address, options).then(data => { assert.strictEqual(data.length, 10); assert(_.every(data, t => t.type === 'payment' || t.type === 'order')); assert(_.every(data, t => t.outcome.result === 'tesSUCCESS')); - done(); }); }); // this is the case where core.RippleError just falls // through the api to the user - it('getTransactions - error', function(done) { + it('getTransactions - error', function() { const options = {types: ['payment', 'order'], initiated: true, limit: 13}; - this.api.getTransactions(address, options, (error) => { + return this.api.getTransactions(address, options).then(() => { + assert(false, 'Should throw RippleError'); + }).catch(error => { assert(error instanceof RippleError); - done(); }); }); // TODO: this doesn't test much, just that it doesn't crash - it('getTransactions with start option', function(done) { + it('getTransactions with start option', function() { const options = { start: hashes.VALID_TRANSACTION_HASH, earliestFirst: false, limit: 2 }; - this.api.getTransactions(address, options, - _.partial(checkResult, responses.getTransactions, - 'getTransactions', done)); + return this.api.getTransactions(address, options).then( + _.partial(checkResult, responses.getTransactions, 'getTransactions')); }); - it('getTrustlines', function(done) { + it('getTrustlines', function() { const options = {currency: 'USD'}; - this.api.getTrustlines(address, options, - _.partial(checkResult, responses.getTrustlines, 'getTrustlines', - done)); + return this.api.getTrustlines(address, options).then( + _.partial(checkResult, responses.getTrustlines, 'getTrustlines')); }); it('generateWallet', function() { @@ -418,29 +415,28 @@ describe('RippleAPI', function() { }); }); - it('getSettings', function(done) { - this.api.getSettings(address, {}, - _.partial(checkResult, responses.getSettings, 'getSettings', done)); + it('getSettings', function() { + return this.api.getSettings(address).then( + _.partial(checkResult, responses.getSettings, 'getSettings')); }); - it('getAccountInfo', function(done) { - this.api.getAccountInfo(address, {}, - _.partial(checkResult, responses.getAccountInfo, 'getAccountInfo', - done)); + it('getAccountInfo', function() { + return this.api.getAccountInfo(address).then( + _.partial(checkResult, responses.getAccountInfo, 'getAccountInfo')); }); - it('getOrders', function(done) { - this.api.getOrders(address, {}, - _.partial(checkResult, responses.getOrders, 'getOrders', done)); + it('getOrders', function() { + return this.api.getOrders(address).then( + _.partial(checkResult, responses.getOrders, 'getOrders')); }); - it('getOrderbook', function(done) { - this.api.getOrderbook(address, orderbook, {}, - _.partial(checkResult, responses.getOrderbook, 'getOrderbook', done)); + it('getOrderbook', function() { + return this.api.getOrderbook(address, orderbook).then( + _.partial(checkResult, responses.getOrderbook, 'getOrderbook')); }); - it('getOrderbook - sorted so that best deals come first', function(done) { - this.api.getOrderbook(address, orderbook, {}, (error, data) => { + it('getOrderbook - sorted so that best deals come first', function() { + return this.api.getOrderbook(address, orderbook).then(data => { const bidRates = data.bids.map(bid => bid.properties.makerExchangeRate); const askRates = data.asks.map(ask => ask.properties.makerExchangeRate); // makerExchangeRate = quality = takerPays.value/takerGets.value @@ -448,12 +444,11 @@ describe('RippleAPI', function() { // bids and asks should be sorted so that the best deals come first assert.deepEqual(_.sortBy(bidRates, x => Number(x)), bidRates); assert.deepEqual(_.sortBy(askRates, x => Number(x)), askRates); - done(); }); }); - it('getOrderbook - currency & counterparty are correct', function(done) { - this.api.getOrderbook(address, orderbook, {}, (error, data) => { + it('getOrderbook - currency & counterparty are correct', function() { + return this.api.getOrderbook(address, orderbook).then(data => { const orders = _.flatten([data.bids, data.asks]); _.forEach(orders, order => { const quantity = order.specification.quantity; @@ -464,30 +459,28 @@ describe('RippleAPI', function() { assert.strictEqual(totalPrice.currency, counter.currency); assert.strictEqual(totalPrice.counterparty, counter.counterparty); }); - done(); }); }); - it('getOrderbook - direction is correct for bids and asks', function(done) { - this.api.getOrderbook(address, orderbook, {}, (error, data) => { + it('getOrderbook - direction is correct for bids and asks', function() { + return this.api.getOrderbook(address, orderbook).then(data => { assert(_.every(data.bids, bid => bid.specification.direction === 'buy')); - assert( - _.every(data.asks, ask => ask.specification.direction === 'sell')); - done(); + assert(_.every(data.asks, ask => ask.specification.direction === 'sell')); }); }); - it('getServerInfo', function(done) { - this.api.getServerInfo( - _.partial(checkResult, responses.getServerInfo, 'getServerInfo', done)); + it('getServerInfo', function() { + return this.api.getServerInfo().then( + _.partial(checkResult, responses.getServerInfo, 'getServerInfo')); }); - it('getServerInfo - error', function(done) { + it('getServerInfo - error', function() { this.mockRippled.returnErrorOnServerInfo = true; - this.api.getServerInfo((error) => { + return this.api.getServerInfo().then(() => { + assert(false, 'Should throw NetworkError'); + }).catch(error => { assert(error instanceof this.api.errors.NetworkError); assert(error.message.indexOf('too much load') !== -1); - done(); }); }); @@ -495,58 +488,62 @@ describe('RippleAPI', function() { assert.strictEqual(this.api.getFee(), '0.000012'); }); - it('disconnect & isConnected', function(done) { + it('disconnect & isConnected', function() { assert.strictEqual(this.api.isConnected(), true); - this.api.disconnect(() => { + return this.api.disconnect().then(() => { assert.strictEqual(this.api.isConnected(), false); - done(); }); }); - it('getPaths', function(done) { - this.api.getPaths(requests.getPaths.normal, - _.partial(checkResult, responses.getPaths.XrpToUsd, 'getPaths', done)); + it('getPaths', function() { + return this.api.getPaths(requests.getPaths.normal).then( + _.partial(checkResult, responses.getPaths.XrpToUsd, 'getPaths')); }); // @TODO // need decide what to do with currencies/XRP: // if add 'XRP' in currencies, then there will be exception in // xrpToDrops function (called from toRippledAmount) - it('getPaths USD 2 USD', function(done) { - this.api.getPaths(requests.getPaths.UsdToUsd, - _.partial(checkResult, responses.getPaths.UsdToUsd, 'getPaths', done)); + it('getPaths USD 2 USD', function() { + return this.api.getPaths(requests.getPaths.UsdToUsd).then( + _.partial(checkResult, responses.getPaths.UsdToUsd, 'getPaths')); }); - it('getPaths XRP 2 XRP', function(done) { - this.api.getPaths(requests.getPaths.XrpToXrp, - _.partial(checkResult, responses.getPaths.XrpToXrp, 'getPaths', done)); + it('getPaths XRP 2 XRP', function() { + return this.api.getPaths(requests.getPaths.XrpToXrp).then( + _.partial(checkResult, responses.getPaths.XrpToXrp, 'getPaths')); }); - it('getPaths - XRP 2 XRP - not enough', function(done) { - this.api.getPaths(requests.getPaths.XrpToXrpNotEnough, (error) => { + it('getPaths - XRP 2 XRP - not enough', function() { + return this.api.getPaths(requests.getPaths.XrpToXrpNotEnough).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); - done(); }); }); - it('getPaths - does not accept currency', function(done) { - this.api.getPaths(requests.getPaths.NotAcceptCurrency, (error) => { + it('getPaths - does not accept currency', function() { + return this.api.getPaths(requests.getPaths.NotAcceptCurrency).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); - done(); }); }); - it('getPaths - no paths', function(done) { - this.api.getPaths(requests.getPaths.NoPaths, (error) => { + it('getPaths - no paths', function() { + return this.api.getPaths(requests.getPaths.NoPaths).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); - done(); }); }); - it('getPaths - no paths with source currencies', function(done) { - this.api.getPaths(requests.getPaths.NoPathsWithCurrencies, (error) => { + it('getPaths - no paths with source currencies', function() { + const pathfind = requests.getPaths.NoPathsWithCurrencies; + return this.api.getPaths(pathfind).then(() => { + assert(false, 'Should throw NotFoundError'); + }).catch(error => { assert(error instanceof this.api.errors.NotFoundError); - done(); }); }); @@ -740,7 +737,7 @@ describe('RippleAPI', function() { }); describe('RippleAPI - offline', function() { - it('prepareSettings and sign', function(done) { + it('prepareSettings and sign', function() { const api = new RippleAPI(); const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'; const settings = requests.prepareSettings; @@ -749,15 +746,10 @@ describe('RippleAPI - offline', function() { maxLedgerVersion: 8820051, fee: '0.000012' }; - api.prepareSettings(address, settings, instructions, (error, txJSON) => { - if (error) { - done(error); - return; - } + return api.prepareSettings(address, settings, instructions).then(txJSON => { assert.deepEqual(txJSON, responses.prepareSettings.flags); withDeterministicPRNG(() => { assert.deepEqual(api.sign(txJSON, secret), responses.sign); - done(); }); }); }); diff --git a/test/setup-api.js b/test/setup-api.js index dc7d661e..33371eb3 100644 --- a/test/setup-api.js +++ b/test/setup-api.js @@ -24,10 +24,10 @@ function getFreePort(callback) { function setupMockRippledConnection(testcase, port, done) { testcase.mockRippled = createMockRippled(port); testcase.api = new RippleAPI({servers: ['ws://localhost:' + port]}); - testcase.api.connect(() => { + testcase.api.connect().then(() => { testcase.api.remote.getServer().once('ledger_closed', () => done()); testcase.api.remote.getServer().emit('message', ledgerClosed); - }); + }).catch(done); } function setup(done) { @@ -40,10 +40,10 @@ function setup(done) { } function teardown(done) { - this.api.remote.disconnect(() => { + this.api.disconnect().then(() => { this.mockRippled.close(); setImmediate(done); - }); + }).catch(done); } module.exports = {