diff --git a/package.json b/package.json index 5f04cee..0dc1aae 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "eslint-plugin-no-class": "^0.1.0", "history": "^1.17.0", "mocha": "^2.4.5", + "rx": "^4.0.7", "testem": "^0.9.11" }, "dependencies": { diff --git a/src/index.js b/src/index.js index 4e6d768..61f8ac0 100644 --- a/src/index.js +++ b/src/index.js @@ -1,2 +1,3 @@ export {makeRouterDriver} from './makeRouterDriver' -export {supportsHistory} from './util' +export {supportsHistory, createLocation} from './util' +export {createServerHistory} from './serverHistory' diff --git a/src/pathFilter.js b/src/pathFilter.js index 38d06ae..38304d9 100644 --- a/src/pathFilter.js +++ b/src/pathFilter.js @@ -2,7 +2,7 @@ import {createAPI} from './api' import {splitPath} from './util' function isStrictlyInScope(namespace, path) { - const pathParts = path.split('/').filter(x => x.length > 0) + const pathParts = splitPath(path) return namespace.every((v, i) => { return pathParts[i] === v }) diff --git a/src/serverHistory.js b/src/serverHistory.js new file mode 100644 index 0000000..96a9b2f --- /dev/null +++ b/src/serverHistory.js @@ -0,0 +1,29 @@ +import {createLocation} from './util' + +function ServerHistory() { + this.listeners = [] +} + +ServerHistory.prototype.listen = function listen(listener) { + this.listeners.push(listener) +} + +ServerHistory.prototype.push = function push(location) { + const listeners = this.listeners + if (!listeners || listeners.length === 0) { + throw new Error('There is no active listener') + } + listeners.forEach(l => l(createLocation(location))) +} + +ServerHistory.prototype.createHref = function createHref(path) { + return path +} + +ServerHistory.prototype.createLocation = createLocation + +function createServerHistory() { + return new ServerHistory() +} + +export {createServerHistory} diff --git a/src/util.js b/src/util.js index 5a326f9..fbe24e3 100644 --- a/src/util.js +++ b/src/util.js @@ -12,6 +12,8 @@ function supportsHistory() { if (typeof window !== `undefined`) { return window.history && `pushState` in window.history + } else { + return false } } @@ -35,4 +37,26 @@ function makeCreateHref(namespace, createHref) { } } -export {supportsHistory, splitPath, filterPath, makeCreateHref} +const locationDefaults = { + pathname: '/', + action: 'POP', + hash: '', + search: '', + state: null, + key: null, +} + +function createLocation(location = locationDefaults) { + if (typeof location === 'string') { + return Object.assign(locationDefaults, {pathname: location}) + } + return Object.assign(locationDefaults, location) +} + +export { + supportsHistory, + splitPath, + filterPath, + makeCreateHref, + createLocation, +} diff --git a/test/helper/mockHistory.js b/test/helper/mockHistory.js deleted file mode 100644 index 2d5a0ce..0000000 --- a/test/helper/mockHistory.js +++ /dev/null @@ -1,14 +0,0 @@ -import {createLocation} from 'history' - -function createMockHistory(paths = [], timeout = 1) { - return { - createHref: path => path, - listen: listener => { - setTimeout(() => { - paths.forEach(p => listener(createLocation(p))) - }, timeout) - }, - } -} - -export {createMockHistory} diff --git a/test/index.js b/test/index.js index 96e7822..7a483f7 100644 --- a/test/index.js +++ b/test/index.js @@ -1,8 +1,7 @@ /* eslint max-nested-callbacks: 0 */ import {describe, it} from 'mocha' import assert from 'assert' -import {createMockHistory} from './helper/mockHistory' -import {makeRouterDriver} from '../src' +import {makeRouterDriver, createServerHistory} from '../src' describe('Cyclic Router', () => { describe('makeRouterDriver', () => { @@ -14,7 +13,7 @@ describe('Cyclic Router', () => { it('should accept any object with a listen() method', () => { assert.doesNotThrow(() => { - makeRouterDriver(createMockHistory()) + makeRouterDriver(createServerHistory()) }) }) @@ -22,7 +21,7 @@ describe('Cyclic Router', () => { it('should return an object with `path` `define` `observable` ' + '`createHref` and `dispose`', () => { - const router = makeRouterDriver(createMockHistory())() + const router = makeRouterDriver(createServerHistory())() assert.notStrictEqual(router.path, null) assert.strictEqual(typeof router.path, 'function') assert.notStrictEqual(router.define, null) @@ -42,7 +41,7 @@ describe('Cyclic Router', () => { it('should return an object with `path` `define` `observable` ' + '`createHref` and `dispose`', () => { - const router = makeRouterDriver(createMockHistory())().path('/') + const router = makeRouterDriver(createServerHistory())().path('/') assert.notStrictEqual(router.path, null) assert.strictEqual(typeof router.path, 'function') assert.notStrictEqual(router.define, null) @@ -61,7 +60,7 @@ describe('Cyclic Router', () => { '/somewhere/else', '/path/that/is/correct', ] - const history = createMockHistory(routes) + const history = createServerHistory(routes) const router = makeRouterDriver(history)().path('/path') router.observable.subscribe((location) => { @@ -77,7 +76,7 @@ describe('Cyclic Router', () => { '/some/really/really/deeply/nested/incorrect/route', ] - const history = createMockHistory(routes) + const history = createServerHistory(routes) const router = makeRouterDriver(history)() .path('/some').path('/really').path('/really').path('/deeply') .path('/nested').path('/route').path('/that') @@ -95,7 +94,7 @@ describe('Cyclic Router', () => { '/some/really/really/deeply/nested/incorrect/route', ] - const history = createMockHistory(routes) + const history = createServerHistory(routes) const router = makeRouterDriver(history)() .path('/some').path('/really').path('/really').path('/deeply') .path('/nested').path('/route').path('/that') @@ -116,7 +115,7 @@ describe('Cyclic Router', () => { '/some/really/really/deeply/nested/incorrect/route', ] - const history = createMockHistory(routes) + const history = createServerHistory(routes) const router = makeRouterDriver(history)() .path('/some').path('/really').path('/really').path('/deeply') .path('/nested').path('/route').path('/that') @@ -131,7 +130,7 @@ describe('Cyclic Router', () => { it('should return an object with `path$` `value$` `fullPath$` ' + '`createHref` and `dispose`', () => { - const router = makeRouterDriver(createMockHistory())().define({}) + const router = makeRouterDriver(createServerHistory())().define({}) assert.notStrictEqual(router.path$, null) assert.strictEqual(typeof router.path$, 'object') assert.strictEqual(typeof router.path$.subscribe, 'function') @@ -157,7 +156,7 @@ describe('Cyclic Router', () => { const routes = [ '/some/route', ] - const history = createMockHistory(routes) + const history = createServerHistory() const {path$, value$, fullPath$} = makeRouterDriver(history)().define(defintion) @@ -173,6 +172,8 @@ describe('Cyclic Router', () => { assert.strictEqual(fullPath, '/some/route') setTimeout(done, 10) }) + + routes.forEach(r => history.push(r)) }) it('should respect prior filtering by path()', done => { @@ -187,7 +188,7 @@ describe('Cyclic Router', () => { '/some/nested/correct/route', '/wrong/route', ] - const history = createMockHistory(routes) + const history = createServerHistory() const {path$, value$, fullPath$} = makeRouterDriver(history)() .path('/some').path('/nested').define(defintion) @@ -203,6 +204,8 @@ describe('Cyclic Router', () => { assert.strictEqual(fullPath, '/some/nested/correct/route') setTimeout(done, 10) }) + + routes.forEach(r => history.push(r)) }) it('should match a default route if one is not found', done => { @@ -218,7 +221,7 @@ describe('Cyclic Router', () => { '/some/nested/incorrect/route', '/wrong/route', ] - const history = createMockHistory(routes) + const history = createServerHistory() const {path$, value$, fullPath$} = makeRouterDriver(history)() .path('/some').path('/nested').define(defintion) @@ -234,6 +237,8 @@ describe('Cyclic Router', () => { assert.strictEqual(fullPath, '/some/nested/incorrect/route') setTimeout(done, 10) }) + + routes.forEach(r => history.push(r)) }) it('should create a proper href using createHref()', done => { @@ -250,7 +255,7 @@ describe('Cyclic Router', () => { '/wrong/route', ] - const history = createMockHistory(routes) + const history = createServerHistory() const {fullPath$, createHref} = makeRouterDriver(history)() .path('/some').path('/nested').define(defintion) @@ -259,6 +264,8 @@ describe('Cyclic Router', () => { assert.strictEqual(createHref('/correct/route'), pathname) setTimeout(done, 5) }) + + routes.forEach(r => history.push(r)) }) it('should match partials', done => { @@ -275,7 +282,7 @@ describe('Cyclic Router', () => { '/wrong/route', ] - const history = createMockHistory(routes) + const history = createServerHistory() const {path$, fullPath$} = makeRouterDriver(history)() .path('/some').path('/nested').define(defintion) @@ -287,6 +294,8 @@ describe('Cyclic Router', () => { assert.strictEqual(pathname, '/some/nested/correct/route/partial') setTimeout(done, 5) }) + + routes.forEach(r => history.push(r)) }) it('should not work after being disposed', done => { @@ -303,12 +312,13 @@ describe('Cyclic Router', () => { '/wrong/route', ] - const history = createMockHistory(routes) + const history = createServerHistory() const {fullPath$, dispose} = makeRouterDriver(history)() .path('/some').path('/nested').define(defintion) dispose() fullPath$.subscribe(done.fail) + routes.forEach(r => history.push(r)) setTimeout(done, 10) }) })