Skip to content

Commit

Permalink
Merge branch 'development' for 0.2.0
Browse files Browse the repository at this point in the history
- adds (some) endpoint tests
- adds endpoints:
    withdraw_from_label
    withdraw_from_address
    withdraw_from_labels
    withdraw_from_addresses
    withdraw_from_users
- make clear that license is MIT
- fix README.md file length
  • Loading branch information
patricklodder committed Aug 14, 2014
2 parents 486873d + 4815298 commit 48e42f5
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 5 deletions.
2 changes: 2 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
The MIT License (MIT)

Copyright (c) 2014 BlockIo

Permission is hereby granted, free of charge, to any person
Expand Down
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# BlockIo

This nodejs module is the official reference client for the Block.io payments API. To use this, you will need the Dogecoin, Bitcoin, or Litecoin API key(s) from <a href="https://block.io" target="_blank">Block.io</a>. Go ahead, sign up :)
This nodejs module is the official reference client for the Block.io payments
API. To use this, you will need the Dogecoin, Bitcoin, or Litecoin API key(s)
from <a href="https://block.io" target="_blank">Block.io</a>. Go ahead, sign
up :)

## Installation

Expand All @@ -24,10 +27,18 @@ block_io.get_balance(console.log);
block_io.get_my_addresses(console.log);

// print the response of a withdrawal request
block_io.withdraw({ pin: 'SECRET_PIN', from_user_ids: '1,2', to_user_id: '0', amount: '50.0' }, console.log);
block_io.withdraw(
{
pin: 'SECRET_PIN',
from_user_ids: '1,2',
to_user_id: '0',
amount: '50.0'
}, console.log);
```

For more information, see [Node.js API Docs](https://block.io/api/nodejs). This client provides a mapping for all methods listed on the Block.io API site.
For more information, see [Node.js API Docs](https://block.io/api/nodejs).
This client provides a mapping for all methods listed on the Block.io API
site.

## Contributing

Expand All @@ -36,3 +47,13 @@ For more information, see [Node.js API Docs](https://block.io/api/nodejs). This
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request

## Testing

We use [vows](http://vowsjs.org/) for unit tests. To run the tests you need to
specify BLOCK_IO_API_KEY and BLOCK_IO_ADDRESS environment variables.
**DO NOT USE PRODUCTION CREDENTIALS FOR UNIT TESTING!** Syntax:

```bash
BLOCK_IO_API_KEY="API_KEY" BLOCK_IO_PIN="SECRET_PIN" npm test
```
3 changes: 2 additions & 1 deletion lib/block_io.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ BlockIo.VALID_CALL_METHODS = [
'get_balance', 'withdraw', 'get_new_address', 'get_my_addresses',
'get_address_received', 'get_address_by_label', 'get_address_balance', 'create_user',
'get_users', 'get_user_balance', 'get_user_address', 'get_user_received', 'withdraw_from_user',
'get_current_price'
'get_current_price', 'withdraw_from_label', 'withdraw_from_address', 'withdraw_from_labels',
'withdraw_from_addresses', 'withdraw_from_users'
];

BlockIo.prototype._request = function (method, path, args, cb) {
Expand Down
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name" : "block_io",
"description" : "Block.io API wrapper for node.js",
"keywords" : [ "block.io", "block_io", "bitcoin", "litecoin", "dogecoin", "wallet" ],
"version" : "0.1.0",
"version" : "0.2.0",
"preferGlobal" : false,
"homepage" : "https://github.com/BlockIo/block_io-nodejs",
"author" : "Patrick Lodder <[email protected]> (https://github.com/patricklodder)",
Expand All @@ -20,10 +20,16 @@
"dependencies" : {
"request" : "2.36.0"
},
"devDependencies": {
"vows": "0.7.x"
},
"engines" : {
"node" : ">=0.8",
"npm" : ">=1.0.0"
},
"scripts": {
"test" : "node_modules/.bin/vows --spec test/*.js"
},
"licenses" : [ {
"type" : "MIT"
, "url" : "https://github.com/BlockIo/block_io-nodejs/raw/master/LICENSE"
Expand Down
188 changes: 188 additions & 0 deletions test/all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
var vows = require('vows');
var assert = require('assert');
var cache = require('./helpers/cache');

var BlockIo = require('../lib/block_io');

var API_KEY = process.env.BLOCK_IO_API_KEY;
var PIN = process.env.BLOCK_IO_PIN;
var FEES = {BTC: 0.0001, BTCTEST: 0.0001, DOGE: 1, DOGETEST: 1, LTC: 0.001, LTCTEST: 0.001};
var NEWLABEL = (new Date).getTime().toString(36);

if (!API_KEY || !PIN) {
console.log('ERROR: Need valid BLOCK_IO_API_KEY and BLOCK_IO_PIN environment variables!');
console.log([
' provided: BLOCK_IO_API_KEY: "', API_KEY,
'"; BLOCK_IO_PIN: "', PIN ? '[masked]' : '', '"'
].join(''));
process.exit(1);
}

var client = new BlockIo(API_KEY);

vows.describe("block.io node.js api wrapper").addBatch({
"get_balance": makeMethodCase('get_balance', {}),
"get_new_address": makeMethodCase('get_new_address', {})
}).addBatch({
"get_new_address (with label)": makeMethodCase('get_new_address', {label: NEWLABEL}, {
"must return an address": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.address);
cache('newAddress', res.data.address);
},
"must return the label": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.strictEqual(res.data.label, NEWLABEL);
}
})
}).addBatch({
"get_my_addresses": makeMethodCase('get_my_addresses', {}, {
"must specify a network": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.network);
assert.ok(FEES.hasOwnProperty(res.data.network));
cache('minFee', FEES[res.data.network]);
},
"must return an address": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isArray(res.data.addresses);
assert.isString(res.data.addresses[0].address);
assert.isString(res.data.addresses[0].label);

// cache address with sufficient balance for next tests;
var hasBalance = res.data.addresses.some(function (addr) {
if (parseFloat(addr.available_balance, 10) > (20 * cache('minFee'))) {
cache('fromAddress', addr.address);
cache('fromLabel', addr.label);
return true;
}
return false;
});

if (!hasBalance) {
console.log('ERROR: Not enough balance to continue tests!');
process.exit(1);
}
}
})
}).addBatch({
"get_address_received (by address)": makeMethodCase(
'get_address_received',
{ address: cache.lazy('fromAddress') },
{
"must return balance data": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.confirmed_received);
assert.isString(res.data.unconfirmed_received);
}
}
),
"get_address_received (by label)": makeMethodCase(
'get_address_received',
{ label: cache.lazy('fromLabel') },
{
"must return balance data": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.confirmed_received);
assert.isString(res.data.unconfirmed_received);
}
}
),
}).addBatch({
"withdraw_from_address": makeMethodCase(
'withdraw_from_address',
{
from_addresses: cache.lazy('fromAddress'),
to_label: NEWLABEL,
amount: calcWithdrawalAmount,
pin: PIN
},
makeTxAssertions()
)
}).addBatch({
"withdraw_from_label": makeMethodCase(
'withdraw_from_label',
{
from_labels: cache.lazy('fromLabel'),
payment_address: cache.lazy('newAddress'),
amount: calcWithdrawalAmount,
pin: PIN
},
makeTxAssertions()
)
}).export(module);

function makeMethodCase (method, args, customChecks) {
var testCase = {
topic: function () {

// resolve lazy cached args
var resolvedArgs = {};
Object.keys(args).forEach(function (k) {
resolvedArgs[k] = (typeof(args[k]) === 'function') ?
args[k]() : args[k];
});
client[method](resolvedArgs, this.callback);
},
"must not return an error": function (err, data) {
assert.isNull(err);
},
"must return status 'success'": function (err, data) {
assert.isObject(data);
assert.equal(data.status, 'success');
}
};

if (customChecks) Object.keys(customChecks).forEach(function (k) {
testCase[k] = customChecks[k];
});

return testCase;
}

function makeTxAssertions () {
return {
"must return a txid": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.txid);
},
"must return an amount_withdrawn": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.amount_withdrawn);
assert.ok(parseFloat(res.data.amount_withdrawn, 10) >= parseFloat(calcWithdrawalAmount(), 10));
},
"must return an amount_sent": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.txid);
assert.isString(res.data.amount_sent);
assert.ok(parseFloat(res.data.amount_sent, 10) == parseFloat(calcWithdrawalAmount(), 10));
},
"must return a network_fee": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.txid);
assert.isString(res.data.network_fee);
assert.ok(!isNaN(parseFloat(res.data.network_fee, 10)));
},
"must return a blockio_fee": function (err, res) {
assert.isObject(res);
assert.isObject(res.data);
assert.isString(res.data.txid);
assert.isString(res.data.blockio_fee);
assert.ok(!isNaN(parseFloat(res.data.blockio_fee, 10)));
}
};
}

function calcWithdrawalAmount () {
return (cache('minFee') * 3).toFixed(5);
}
9 changes: 9 additions & 0 deletions test/helpers/cache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var c = {};

var cache = module.exports = function (k, v) {
if (v) {
c[k] = v;
} else return c[k];
};

cache.lazy = function (k) { return function () { return cache(k); }};

0 comments on commit 48e42f5

Please sign in to comment.