diff --git a/README.md b/README.md index 37258d2..c4516d1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,114 @@ -[![Maintainability](https://api.codeclimate.com/v1/badges/ff33b4540148afef4035/maintainability)](https://codeclimate.com/github/eth0lo/juru/maintainability) -[![Test Coverage](https://api.codeclimate.com/v1/badges/ff33b4540148afef4035/test_coverage)](https://codeclimate.com/github/eth0lo/juru/test_coverage) +

+ Juru +

+ +

+ + + + + + + + + + + Standard - JavaScript Style Guide + +

+ +Juru can be used to give visibility of side-effects (i.e. asynchronous data fetching, storing data) that happens during the application runtime; making the application easier to test, and better at handling failures. + +For instance, if a module performs a HTTP remote identity provider or fetches information from your local DB, you can test that module in isolation. + +**Table of Contents** + +- [How does it work?](#how-does-it-work) +- [Install](#install) +- [Usage](#usage) +- [Alternatives](#alternatives) + +## How does it work? + +It works by leveraging the [iterable protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol) to expose side-effects descriptors of your application. + +## Install + +```sh +$ npm install --save juru +``` + +## Usage + +```js +// main module +const co = require('juru') +const { all, call } = require('juru/effects') + +const enhancedUser = function * (externalId) { + const [remoteUser, userPurchases] = yield all( + call(externalService, 'findUser', externalId), + call(insternalStorage, 'findUserByExternalId', externalId) + ) + + return userPresenter(remoteUser, userPurchases) +} +exports = module.exports = co(enhancedUser) +exports.generator = enhancedUser + +const externalService = { + findUser: async (id) => ({ id: 'remote-service-id', name: 'Jhon Doe' }) +} +exports.externalService = externalService + +const insternalStorage = { + findUserByExternalId: async (id) => ({ id: 'local-id', externalId: 'remote-service-id', purchases: [] }) +} +exports.insternalStorage = insternalStorage + +const userPresenter = (user, userPurchases) => ({ ...user, purchases: userPurchases.purchases }) +exports.userPresenter = userPresenter +``` + +```js +// test file +const test = require('tape') +const { all, call } = require('juru/effects') + +const { externalService, generator, insternalStorage } = require('./enhanced_user') + +test('should request user information both locally and remotely', (assert) => { + const externalIdMock = 'remote-service-id' + const enhancedUser = generator(externalIdMock) + + const { value: requestsDescriptor } = enhancedUser.next() + + assert.deepEqual(requestsDescriptor, all( + call(externalService, 'findUser', externalIdMock) + call(insternalStorage, 'findUserByExternalId', externalIdMock) + )) + + assert.end() +}) + +test('should return the user with all his/her purchases', (assert) => { + const externalIdMock = 'remote-service-id' + const remoteUserMock = { id: 'remote-service-id', name: 'Jhon Doe' } + const storageUserMock = { id: 'local-id', externalId: 'remote-service-id', purchases: [] } + + const enhancedUser = generator(externalIdMock) + enhancedUser.next() + + const { value: result } = enhancedUser.next([remoteUserMock, storageUserMock]) + assert.equal(result.id, remoteUserMock.id) + assert.equal(result.purchases, storageUserMock.purchases) + + assert.end() +}) +``` + +## Alternatives + +- Proxyquire +- Rewire +- Sinon