Repository: vigetlabs/microcosm
Pull request #387 (2017-08-08 21:00:57)

Test registration in terms of public API
Related to #380. I'm chipping away at only using the public API for testing. That way, we can eventually do some advanced build optimizations and still ensure the correctness of Microcosm.

codecov-io: # [Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/387?src=pr&el=h1) Report
> Merging [#387](https://codecov.io/gh/vigetlabs/microcosm/pull/387?src=pr&el=desc) into [master](https://codecov.io/gh/vigetlabs/microcosm/commit/e530f41114ae3bebf958548602207d465e4f803d?src=pr&el=desc) will **decrease** coverage by `0.22%`.
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff             @@
##           master     #387      +/-   ##
==========================================
- Coverage     100%   99.77%   -0.23%     
==========================================
  Files          25       25              
  Lines         876      878       +2     
==========================================
  Hits          876      876              
- Misses          0        2       +2
```


| [Impacted Files](https://codecov.io/gh/vigetlabs/microcosm/pull/387?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/history.js](https://codecov.io/gh/vigetlabs/microcosm/pull/387?src=pr&el=tree#diff-c3JjL2hpc3RvcnkuanM=) | `100% <100%> (ø)` | :arrow_up: |
| [src/lifecycle.js](https://codecov.io/gh/vigetlabs/microcosm/pull/387?src=pr&el=tree#diff-c3JjL2xpZmVjeWNsZS5qcw==) | `88.88% <0%> (-11.12%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/vigetlabs/microcosm/pull/387?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/387?src=pr&el=footer). Last update [e530f41...113f6c7](https://codecov.io/gh/vigetlabs/microcosm/pull/387?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/src/get-registration.js b/src/get-registration.js
index 30d5264c..bc04dbfa 100644
--- a/src/get-registration.js
+++ b/src/get-registration.js
@@ -1,7 +1,7 @@
 // @flow
 import { isObject } from './utils'
 
-export const ALIASES = {
+export const STATUSES = {
   inactive: 'inactive',
   open: 'open',
   update: 'loading',
@@ -19,7 +19,7 @@ export const ALIASES = {
  */
 function getRegistration(pool: Object, command: Tagged, status: Status) {
   let answer = null
-  let alias = ALIASES[status]
+  let alias = STATUSES[status]
 
   console.assert(alias, 'Invalid action status ' + status)
   console.assert(
diff --git a/src/history.js b/src/history.js
index e86b4b26..3b2a3340 100644
--- a/src/history.js
+++ b/src/history.js
@@ -206,6 +206,7 @@ class History extends Emitter {
     } else {
       // Always have a parent node, no matter what
       let birth = new Action(BIRTH, 'resolve')
+
       birth.adopt(action)
 
       this.root = action
@@ -214,9 +215,13 @@ class History extends Emitter {
     this.head = action
     this.size += 1
 
+    action.on('change', this.reconcile, this)
+
     this._emit('append', action)
 
-    action.on('change', this.reconcile, this)
+    if (status && action.command !== START) {
+      this.reconcile(action)
+    }
 
     return action
   }


Test patch:
diff --git a/test/unit/emitter.test.js b/test/unit/emitter.test.js
index 239f2f5a..3c61ca66 100644
--- a/test/unit/emitter.test.js
+++ b/test/unit/emitter.test.js
@@ -1,4 +1,4 @@
-import Emitter from '../../src/emitter'
+import { Emitter } from '../../src/microcosm'
 
 describe('Emitter', function() {
   it('adds listeners', function() {
diff --git a/test/unit/get-registration.test.js b/test/unit/get-registration.test.js
deleted file mode 100644
index f9830183..00000000
--- a/test/unit/get-registration.test.js
+++ /dev/null
@@ -1,151 +0,0 @@
-import tag from '../../src/tag'
-import getRegistration, { ALIASES } from '../../src/get-registration'
-
-const action = tag(n => n)
-
-describe('getRegistration', function() {
-  it('can use nested objects to return specific statuses', function() {
-    let success = n => n
-    let answer = getRegistration(
-      {
-        [action]: {
-          reject: success
-        }
-      },
-      action,
-      'reject'
-    )
-
-    expect(answer).toBe(success)
-  })
-
-  it('throws if given an invalid status', function() {
-    let fail = function() {
-      getRegistration({}, action, 'totally-missing')
-    }
-
-    expect(fail).toThrow('Invalid action status totally-missing')
-  })
-
-  describe('Action aliasing', function() {
-    for (let status in ALIASES) {
-      let alias = ALIASES[status]
-
-      it(`can inspect the ${status} status`, function() {
-        let success = n => n
-        let answer = getRegistration(
-          {
-            [action]: {
-              [status]: success
-            }
-          },
-          action,
-          ALIASES[status]
-        )
-
-        expect(answer).toBe(success)
-      })
-
-      it(`can register the ${alias} alias`, function() {
-        let success = n => n
-        let answer = getRegistration(
-          {
-            [action]: {
-              [alias]: success
-            }
-          },
-          action,
-          status
-        )
-
-        expect(answer).toBe(success)
-      })
-    }
-  })
-
-  describe('Errors', function() {
-    describe('Flat registrations', function() {
-      it('throws when a registration is undefined', function() {
-        expect(function() {
-          getRegistration(
-            {
-              [action]: undefined
-            },
-            action,
-            'resolve'
-          )
-        }).toThrow(
-          'action key within a registration is undefined. Is it being referenced correctly?'
-        )
-      })
-
-      it('uses the command name when it can', function() {
-        let getUser = tag(function getUser() {})
-
-        expect(function() {
-          getRegistration(
-            {
-              [getUser]: undefined
-            },
-            getUser,
-            'resolve'
-          )
-        }).toThrow(
-          'getUser key within a registration is undefined. Is it being referenced correctly?'
-        )
-      })
-    })
-
-    describe('Nested registrations', function() {
-      it('throws when a nested status registration is undefined', function() {
-        expect(function() {
-          getRegistration(
-            {
-              [action]: {
-                reject: undefined
-              }
-            },
-            action,
-            'reject'
-          )
-        }).toThrow(
-          'The "reject" key within a nested registration for an action is undefined. Is it being referenced correctly?'
-        )
-      })
-
-      it('throws when a nested alias registration is undefined', function() {
-        expect(function() {
-          getRegistration(
-            {
-              [action]: {
-                error: undefined
-              }
-            },
-            action,
-            'reject'
-          )
-        }).toThrow(
-          'The "error" key within a nested registration for an action is undefined. Is it being referenced correctly?'
-        )
-      })
-
-      it('uses the action name when it can', function() {
-        let getUser = tag(function getUser() {})
-
-        expect(function() {
-          getRegistration(
-            {
-              [getUser]: {
-                error: undefined
-              }
-            },
-            getUser,
-            'reject'
-          )
-        }).toThrow(
-          'The "error" key within a nested registration for getUser is undefined. Is it being referenced correctly?'
-        )
-      })
-    })
-  })
-})
diff --git a/test/unit/microcosm/lifecycle.test.js b/test/unit/microcosm/lifecycle.test.js
deleted file mode 100644
index c8244c75..00000000
--- a/test/unit/microcosm/lifecycle.test.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import Microcosm from '../../../src/microcosm'
-
-import { BIRTH, START } from '../../../src/lifecycle'
-
-describe('Lifecycle', function() {
-  it('$birth should never be invoked directly', function() {
-    let repo = new Microcosm()
-    let test = repo.prepare(BIRTH)
-
-    expect(test).toThrow()
-  })
-
-  it('$start should never be invoked directly', function() {
-    let repo = new Microcosm()
-    let test = repo.prepare(START)
-
-    expect(test).toThrow()
-  })
-})
diff --git a/test/unit/microcosm/register.test.js b/test/unit/microcosm/register.test.js
deleted file mode 100644
index 4c42d995..00000000
--- a/test/unit/microcosm/register.test.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import Microcosm, { update } from '../../../src/microcosm'
-
-describe('Microcosm::register', function() {
-  it('a Microcosm can register to actions', function() {
-    const ADD = 'ADD'
-
-    class Repo extends Microcosm {
-      getInitialState() {
-        return { count: 0 }
-      }
-
-      add(state, n) {
-        return update(state, 'count', value => value + n)
-      }
-
-      register() {
-        return {
-          [ADD]: this.add
-        }
-      }
-    }
-
-    let repo = new Repo()
-
-    repo.push(ADD, 2)
-    repo.push(ADD, 2)
-
-    expect(repo).toHaveState('count', 4)
-  })
-
-  describe('lifecycle hooks', function() {
-    it('does not call deserialize infinitely', function() {
-      class Repo extends Microcosm {
-        register() {
-          return {}
-        }
-      }
-
-      let repo = new Repo()
-      let spy = jest.spyOn(repo, 'deserialize')
-
-      repo.deserialize()
-
-      expect(spy).toHaveBeenCalledTimes(1)
-    })
-
-    it('does not call serialize infinitely', function() {
-      class Repo extends Microcosm {
-        register() {
-          return {}
-        }
-      }
-
-      let repo = new Repo()
-      let spy = jest.spyOn(repo, 'serialize')
-
-      repo.serialize()
-
-      expect(spy).toHaveBeenCalledTimes(1)
-    })
-
-    it('does not call getInitialState infinitely', function() {
-      class Repo extends Microcosm {
-        register() {
-          return {}
-        }
-      }
-
-      let repo = new Repo()
-      let spy = jest.spyOn(repo, 'getInitialState')
-
-      repo.getInitialState()
-
-      expect(spy).toHaveBeenCalledTimes(1)
-    })
-  })
-})
diff --git a/test/unit/registration.test.js b/test/unit/registration.test.js
new file mode 100644
index 00000000..8109c12f
--- /dev/null
+++ b/test/unit/registration.test.js
@@ -0,0 +1,104 @@
+import Microcosm from '../../src/microcosm'
+import { STATUSES } from '../../src/get-registration'
+
+const action = n => n
+
+describe('getRegistration', function() {
+  it('can use nested objects to return specific statuses', function() {
+    let handler = jest.fn()
+
+    class Repo extends Microcosm {
+      register() {
+        return {
+          [action]: {
+            reject: handler
+          }
+        }
+      }
+    }
+
+    let repo = new Repo()
+
+    repo.append(action).reject()
+
+    expect(handler).toHaveBeenCalled()
+  })
+
+  it('throws if given an invalid status', function() {
+    let repo = new Microcosm()
+
+    let fail = function() {
+      repo.append(action, 'totally-missing')
+    }
+
+    expect(fail).toThrow('Invalid action status totally-missing')
+  })
+
+  describe('Action aliasing', function() {
+    for (let status in STATUSES) {
+      if (status === 'inactive') {
+        continue
+      }
+
+      let alias = STATUSES[status]
+
+      it(`can inspect the ${status} status`, function() {
+        let handler = jest.fn()
+
+        class Repo extends Microcosm {
+          register() {
+            return {
+              [action]: {
+                [status]: handler
+              }
+            }
+          }
+        }
+
+        let repo = new Repo()
+
+        repo.append(action, status)
+
+        expect(handler).toHaveBeenCalled()
+      })
+
+      it(`can register the ${alias} alias`, function() {
+        let handler = jest.fn()
+
+        class Repo extends Microcosm {
+          register() {
+            return {
+              [action]: {
+                [alias]: handler
+              }
+            }
+          }
+        }
+
+        let repo = new Repo()
+
+        repo.append(action, status)
+
+        expect(handler).toHaveBeenCalled()
+      })
+    }
+  })
+
+  it('includes the command name in the error message when a handler is undefined', function() {
+    let getUser = n => n
+
+    class Repo extends Microcosm {
+      register() {
+        return {
+          [getUser]: undefined
+        }
+      }
+    }
+
+    let repo = new Repo()
+
+    expect(repo.prepare(getUser)).toThrow(
+      'getUser key within a registration is undefined. Is it being referenced correctly?'
+    )
+  })
+})
diff --git a/test/unit/tag.test.js b/test/unit/tag.test.js
index 4b4aa1b5..0f4140f5 100644
--- a/test/unit/tag.test.js
+++ b/test/unit/tag.test.js
@@ -1,4 +1,4 @@
-import tag from '../../src/tag'
+import { tag } from '../../src/microcosm'
 
 describe('tag', function() {
   it('includes the function name', function() {