Repository: vigetlabs/microcosm
Pull request #479 (2018-02-20 13:27:28)

Presenter::intercept can have multiple handlers
In order to achieve consistency with effects and domains, the
presenter intercept method can now accept an array of handlers.

efatsi: looks great 👍 
nhunzaker: Thanks guys!
codecov-io: # [Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/479?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@b136cee`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/vigetlabs/microcosm/pull/479/graphs/tree.svg?width=650&src=pr&token=AaE0FLz9sU&height=150)](https://codecov.io/gh/vigetlabs/microcosm/pull/479?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master     #479   +/-   ##
=========================================
  Coverage          ?   97.65%           
=========================================
  Files             ?       29           
  Lines             ?      681           
  Branches          ?      143           
=========================================
  Hits              ?      665           
  Misses            ?       13           
  Partials          ?        3
```


| [Impacted Files](https://codecov.io/gh/vigetlabs/microcosm/pull/479?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/microcosm-dom/src/utilities.js](https://codecov.io/gh/vigetlabs/microcosm/pull/479/diff?src=pr&el=tree#diff-cGFja2FnZXMvbWljcm9jb3NtLWRvbS9zcmMvdXRpbGl0aWVzLmpz) | `100% <100%> (ø)` | |
| [packages/microcosm-dom/src/presenter.js](https://codecov.io/gh/vigetlabs/microcosm/pull/479/diff?src=pr&el=tree#diff-cGFja2FnZXMvbWljcm9jb3NtLWRvbS9zcmMvcHJlc2VudGVyLmpz) | `100% <100%> (ø)` | |
| [packages/microcosm-dom/src/intercept.js](https://codecov.io/gh/vigetlabs/microcosm/pull/479/diff?src=pr&el=tree#diff-cGFja2FnZXMvbWljcm9jb3NtLWRvbS9zcmMvaW50ZXJjZXB0Lmpz) | `100% <100%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/479?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/479?src=pr&el=footer). Last update [b136cee...9f77ad4](https://codecov.io/gh/vigetlabs/microcosm/pull/479?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index eba602f1..ea993817 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -4,7 +4,7 @@ jobs:
   build:
     working_directory: /home/circleci/microcosm
     docker:
-      - image: circleci/node:8.0
+      - image: circleci/node:8.9
     steps:
       - checkout
       - restore_cache:
diff --git a/packages/microcosm-dom/src/intercept.js b/packages/microcosm-dom/src/intercept.js
new file mode 100644
index 00000000..89d1a4e5
--- /dev/null
+++ b/packages/microcosm-dom/src/intercept.js
@@ -0,0 +1,29 @@
+/**
+ * This module describes how the Presenter's intercept feature works
+ */
+
+import { tag } from 'microcosm'
+import { ensureArray } from './utilities'
+
+export function intercept(mediator, command, ...params) {
+  // Save a reference to the original repo. If an action is not intercepted,
+  // the original repo receives the dispatch
+  let repo = mediator.repo
+
+  // Tag the command so that intercept works correctly
+  let tagged = tag(command)
+
+  while (mediator) {
+    let registry = mediator.presenter.intercept()
+
+    if (registry.hasOwnProperty(tagged)) {
+      return ensureArray(registry[tagged]).reduce((_next, callback) => {
+        return callback.call(mediator.presenter, mediator.repo, ...params)
+      }, null)
+    }
+
+    mediator = mediator.context.parent
+  }
+
+  return repo.push(tagged, ...params)
+}
diff --git a/packages/microcosm-dom/src/presenter.js b/packages/microcosm-dom/src/presenter.js
index 758e54f8..51ba2fd7 100644
--- a/packages/microcosm-dom/src/presenter.js
+++ b/packages/microcosm-dom/src/presenter.js
@@ -1,5 +1,6 @@
-import { Microcosm, Observable, tag } from 'microcosm'
+import { Microcosm, Observable } from 'microcosm'
 import { advice, noop } from './utilities'
+import { intercept } from './intercept'
 
 export function generatePresenter(createElement, Component) {
   function renderMediator() {
@@ -15,11 +16,10 @@ export function generatePresenter(createElement, Component) {
     constructor() {
       super(...arguments)
 
-      this.send = this.send.bind(this)
       this.state = {}
 
       // Ensure key lifecycle methods are protected by first applying
-      // prototype behavior, thenany extended behavior
+      // prototype behavior, then any extended behavior
       advice(Presenter, this, 'componentWillUpdate')
       advice(Presenter, this, 'componentDidMount')
 
@@ -90,21 +90,8 @@ export function generatePresenter(createElement, Component) {
       return this.props.children || null
     }
 
-    send(intent, ...params) {
-      let mediator = this.mediator
-      let taggedIntent = tag(intent)
-
-      while (mediator) {
-        let handler = mediator.presenter.intercept()[taggedIntent]
-
-        if (handler) {
-          return handler.call(mediator.presenter, mediator.repo, ...params)
-        }
-
-        mediator = mediator.context.parent
-      }
-
-      return this.repo.push(taggedIntent, ...params)
+    get send() {
+      return intercept.bind(null, this.mediator)
     }
   }
 
diff --git a/packages/microcosm-dom/src/utilities.js b/packages/microcosm-dom/src/utilities.js
index 57475aad..31c986a6 100644
--- a/packages/microcosm-dom/src/utilities.js
+++ b/packages/microcosm-dom/src/utilities.js
@@ -35,3 +35,7 @@ const cache = {
 export function toCallbackName(status) {
   return cache[status]
 }
+
+export function ensureArray(value) {
+  return Array.isArray(value) ? value : [].concat(value)
+}


Test patch:
diff --git a/packages/microcosm-dom/test/presenter.test.js b/packages/microcosm-dom/test/presenter.test.js
index 8de41f3b..fbe5fcec 100644
--- a/packages/microcosm-dom/test/presenter.test.js
+++ b/packages/microcosm-dom/test/presenter.test.js
@@ -1066,6 +1066,27 @@ describe('intercepting actions', function() {
       </Parent>
     ).click()
   })
+
+  it('can handle multiple intercepts', function() {
+    let one = jest.fn()
+    let two = jest.fn()
+
+    class Test extends Presenter {
+      intercept() {
+        return {
+          test: [one, two]
+        }
+      }
+      render() {
+        return <ActionButton action="test" />
+      }
+    }
+
+    mount(<Test />).click()
+
+    expect(one).toHaveBeenCalled()
+    expect(two).toHaveBeenCalled()
+  })
 })
 
 describe('forks', function() {