Repository: ViacomInc/data-point (js)

Issue:
ability to inspect a request before making the call
New feature that would allow the developer to inspect a request before being sent

```js
dataPoint.addEntities({
  'request:<entityId>': {
    params: {
      inspect: Boolean|Function
    }
  }
})
```

If `params.inspect` is `true` it will output the entity's information to the console.

If `params.inspect` is a `function`, you may execute custom debugging code to be executed before the actual request gets made. The function receives the current accumulator value as its only parameter.
 

Pull request description:
feat(entity-request): ability to inspect a request before making the call
closes #25

Patch:
diff --git a/README.md b/README.md
index 1791b84..e1d7b94 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,7 @@ npm install --save data-point
     - [Control](#control-entity)
     - [Schema](#schema-entity)
   - [Entity ComposeReducer](#entity-compose-reducer)
+  - [Inspecting Entities](#inspecting-entities)
   - [Extending Entities](#extending-entities)
 - [dataPoint.use](#api-data-point-use)
 - [dataPoint.addValue](#api-data-point-add-value)
@@ -1419,6 +1420,29 @@ Example at: [examples/entity-request-before-request.js](examples/entity-request-
 
 For more examples of request entities, see the [Examples](examples), the unit tests: [Request Definitions](test/definitions/sources.js), and [Integration Examples](test/definitions/integrations.js)
 
+### <a name="request-inspect">Inspecting Request</a>
+
+You may inspect a Request entity through the `params.inspect` property.
+
+**note:** At the moment this feature is only available on Request entity, PRs are welcome.
+
+**SYNOPSIS**
+
+```js
+dataPoint.addEntities({
+  'request:<entityId>': {
+    params: {
+      inspect: Boolean|Function
+    }
+  }
+})
+```
+
+If `params.inspect` is `true` it will output the entity's information to the console.
+
+If `params.inspect` is a `function`, you may execute custom debugging code to be executed before the actual request gets made. The function receives the current accumulator value as its only parameter.
+
+
 #### <a name="hash-entity">Hash Entity</a>
 
 A Hash entity transforms a _Hash_ like data structure. It enables you to manipulate the keys within a Hash. 
diff --git a/lib/entity-types/entity-request/reducer.js b/lib/entity-types/entity-request/reducer.js
index f5bec32..7c7ceaf 100644
--- a/lib/entity-types/entity-request/reducer.js
+++ b/lib/entity-types/entity-request/reducer.js
@@ -72,6 +72,16 @@ function resolveOptions (acc, resolveTransform) {
 
 module.exports.resolveOptions = resolveOptions
 
+function inspect (acc, options) {
+  if (acc.params && acc.params.inspect) {
+    utils.inspect(acc, {
+      options,
+      value: acc.value
+    })
+  }
+}
+module.exports.inspect = inspect
+
 function resolveBeforeRequest (acc, resolveTransform) {
   const entity = acc.reducer.spec
 
@@ -87,14 +97,16 @@ function resolveBeforeRequest (acc, resolveTransform) {
   }
 
   const beforeRequestAcc = utils.set(acc, 'value', options)
-  return resolveTransform(beforeRequestAcc, entity.beforeRequest)
+  return resolveTransform(beforeRequestAcc, entity.beforeRequest).then(result =>
+    utils.set(acc, 'options', result.value)
+  )
 }
 
 module.exports.resolveBeforeRequest = resolveBeforeRequest
 
 function resolveRequest (acc, resolveTransform) {
-  const options = acc.value
-  return rp(options).then(result => utils.set(acc, 'value', result))
+  inspect(acc)
+  return rp(acc.options).then(result => utils.set(acc, 'value', result))
 }
 
 module.exports.resolveRequest = resolveRequest
diff --git a/lib/utils/index.js b/lib/utils/index.js
index dff32e3..728365c 100644
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -1,5 +1,7 @@
 'use strict'
 
+const _ = require('lodash')
+
 /**
  * sets key to value of a copy of target. target stays untouched, if key is
  * an object, then the key will be taken as an object and merged with target
@@ -40,3 +42,20 @@ function typeOf (value) {
     .toLowerCase()
 }
 module.exports.typeOf = typeOf
+
+function inspect (acc, data) {
+  const log = []
+  log.push('\n\x1b[33minspect\x1b[0m:', _.get(acc, 'reducer.spec.id'))
+  for (let key in data) {
+    const value = data[key]
+    log.push(`\n${key}:`, _.attempt(JSON.stringify, value, null, 2))
+  }
+
+  console.info.apply(null, log)
+
+  if (typeof acc.params.inspect === 'function') {
+    console.info('\ncustom:')
+    _.attempt(acc.params.inspect, acc)
+  }
+}
+module.exports.inspect = inspect


Test patch:
diff --git a/lib/entity-types/entity-request/reducer.test.js b/lib/entity-types/entity-request/reducer.test.js
index fdc1871..34562e6 100644
--- a/lib/entity-types/entity-request/reducer.test.js
+++ b/lib/entity-types/entity-request/reducer.test.js
@@ -182,7 +182,7 @@ describe('resolveRequest', () => {
       })
 
     const acc = {
-      value: {
+      options: {
         json: true,
         url: 'http://remote.test/source1'
       }
@@ -196,6 +196,39 @@ describe('resolveRequest', () => {
   })
 })
 
+describe('inspect', () => {
+  let consoleInfo
+  function getAcc () {
+    const acc = {}
+    _.set(acc, 'reducer.spec.id', 'test:test')
+    _.set(acc, 'params.inspect', true)
+    return acc
+  }
+  beforeAll(() => {
+    consoleInfo = console.info
+  })
+  afterEach(() => {
+    console.info = consoleInfo
+  })
+  test('It should not execute utils.inspect', () => {
+    console.info = jest.fn()
+    const acc = getAcc()
+    acc.params.inspect = undefined
+    Reducer.inspect(acc)
+    expect(console.info).not.toBeCalled()
+  })
+  test('It should not execute utils.inspect', () => {
+    console.info = jest.fn()
+    Reducer.inspect(getAcc())
+    expect(console.info.mock.calls[0]).toContain('test:test')
+  })
+  test('It should output options', () => {
+    console.info = jest.fn()
+    Reducer.inspect(getAcc(), { options: 1 })
+    expect(console.info.mock.calls[0]).toContain('\noptions:')
+  })
+})
+
 describe('resolve', () => {
   test('simplest json call', () => {
     nock('http://remote.test')
diff --git a/lib/utils/utils.test.js b/lib/utils/utils.test.js
index e6654b7..6da2b80 100644
--- a/lib/utils/utils.test.js
+++ b/lib/utils/utils.test.js
@@ -1,6 +1,7 @@
 /* eslint-env jest */
 'use strict'
 
+const _ = require('lodash')
 const utils = require('./index')
 
 describe('utils.set', () => {
@@ -64,3 +65,38 @@ describe('typeOf', () => {
     expect(utils.typeOf(() => 1)).toEqual('function')
   })
 })
+
+describe('inspect', () => {
+  let consoleInfo
+  function getAcc () {
+    const acc = {}
+    _.set(acc, 'reducer.spec.id', 'test:test')
+    _.set(acc, 'params.inspect', true)
+    return acc
+  }
+  beforeAll(() => {
+    consoleInfo = console.info
+  })
+  afterEach(() => {
+    console.info = consoleInfo
+  })
+  test('It should log entityId', () => {
+    console.info = jest.fn()
+    utils.inspect(getAcc())
+    expect(console.info.mock.calls[0]).toContain('test:test')
+  })
+  test('It should log data', () => {
+    console.info = jest.fn()
+    utils.inspect(getAcc(), { foo: 'bar' })
+    expect(console.info.mock.calls[0]).toContain('\nfoo:')
+    expect(console.info.mock.calls[0]).toContain('"bar"')
+  })
+  test('It should execute custom inspect if function', () => {
+    console.info = jest.fn()
+    const acc = getAcc()
+    acc.params.inspect = () => console.info('baz')
+    utils.inspect(acc)
+    expect(console.info.mock.calls[1]).toContain('\ncustom:')
+    expect(console.info.mock.calls[2]).toContain('baz')
+  })
+})