Skip to content

Commit

Permalink
Merge pull request #61 from storybooks/use-podda
Browse files Browse the repository at this point in the history
Use podda instead of Redux
  • Loading branch information
arunoda authored Nov 16, 2016
2 parents 29d573a + 3b3c8c7 commit 75073ec
Show file tree
Hide file tree
Showing 40 changed files with 681 additions and 872 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"keycode": "^2.1.1",
"lodash.pick": "^4.2.1",
"mantra-core": "^1.7.0",
"podda": "^1.2.1",
"qs": "^6.2.0",
"react-fuzzy": "^0.3.3",
"react-inspector": "^1.1.0",
Expand Down
4 changes: 2 additions & 2 deletions src/context.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function (reduxStore, domNode, provider) {
export default function (clientStore, domNode, provider) {
return {
reduxStore,
clientStore,
domNode,
provider,
};
Expand Down
19 changes: 10 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createStore, combineReducers } from 'redux';
import { createApp } from 'mantra-core';
import Podda from 'podda';

import buildContext from './context.js';
import shortcutsModule from './modules/shortcuts';
Expand All @@ -22,16 +22,17 @@ export default function (domNode, provider) {
throw new Error('provider is not extended from the base Provider');
}

const reducer = combineReducers({
...shortcutsModule.reducers,
...apiModule.reducers,
...uiModule.reducers,
const defaultState = {
...shortcutsModule.defaultState,
...apiModule.defaultState,
...uiModule.defaultState,
};
const clientStore = new Podda(defaultState);
clientStore.registerAPI('toggle', (store, key) => {
return store.set(key, !store.get(key));
});

const devTools = window.devToolsExtension && window.devToolsExtension();
const reduxStore = createStore(reducer, devTools);

const context = buildContext(reduxStore, domNode, provider);
const context = buildContext(clientStore, domNode, provider);
const app = createApp(context);

app.loadModule(shortcutsModule);
Expand Down
255 changes: 201 additions & 54 deletions src/modules/api/actions/__tests__/api.js
Original file line number Diff line number Diff line change
@@ -1,90 +1,237 @@
import actions from '../api';
import { expect } from 'chai';
import sinon from 'sinon';
import { types } from '../';
const { describe, it } = global;

class MockClientStore {
update(cb) {
this.updateCallback = cb;
}
}

const stories = [
{ kind: 'abc', stories: ['a', 'b', 'c'] },
{ kind: 'bbc', stories: ['x', 'y', 'z'] },
];

describe('manager.api.actions.api', () => {
describe('setStories', () => {
it('should dispatch related redux action', () => {
const reduxStore = {
dispatch: sinon.stub(),
};
const stories = [{ kind: 'aa', stories: [] }];
describe('no selected story', () => {
it('should set stories and select the first story', () => {
const clientStore = new MockClientStore();
actions.setStories({ clientStore }, stories);

const newState = clientStore.updateCallback({});
expect(newState).to.deep.equal({
stories,
selectedKind: 'abc',
selectedStory: 'a',
});
});
});

describe('has a selected story', () => {
it('should set stories and select the existing story', () => {
const clientStore = new MockClientStore();
actions.setStories({ clientStore }, stories);

const state = {
selectedKind: 'abc',
selectedStory: 'c',
};
const newState = clientStore.updateCallback(state);
expect(newState).to.deep.equal({
stories,
selectedKind: 'abc',
selectedStory: 'c',
});
});
});

describe('has a selected story, but it\'s story isn\'t in new stories', () => {
it('should set stories and select the first story of the selected kind', () => {
const clientStore = new MockClientStore();
actions.setStories({ clientStore }, stories);

actions.setStories({ reduxStore }, stories);
const action = reduxStore.dispatch.args[0][0];
expect(action).to.deep.equal({
type: types.SET_STORIES,
stories,
const state = {
selectedKind: 'bbc',
selectedStory: 'k',
};
const newState = clientStore.updateCallback(state);
expect(newState).to.deep.equal({
stories,
selectedKind: 'bbc',
selectedStory: 'x',
});
});
});

describe('has a selected story, but it\'s kind isn\'t in new stories', () => {
it('should set stories and select the first story', () => {
const clientStore = new MockClientStore();
actions.setStories({ clientStore }, stories);

const state = {
selectedKind: 'kky',
selectedStory: 'c',
};
const newState = clientStore.updateCallback(state);
expect(newState).to.deep.equal({
stories,
selectedKind: 'abc',
selectedStory: 'a',
});
});
});
});

describe('selectStory', () => {
it('should dispatch related redux action', () => {
const reduxStore = {
dispatch: sinon.stub(),
};
const kind = 'kkkind';
const story = 'ssstory';

actions.selectStory({ reduxStore }, kind, story);
const action = reduxStore.dispatch.args[0][0];
expect(action).to.deep.equal({
type: types.SELECT_STORY,
kind,
story,
describe('with both kind and story', () => {
it('should select the correct story', () => {
const clientStore = new MockClientStore();
actions.selectStory({ clientStore }, 'bbc', 'y');

const state = {
stories,
selectedKind: 'abc',
selectedStory: 'c',
};
const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
selectedKind: 'bbc',
selectedStory: 'y',
});
});
});

describe('with just the kind', () => {
it('should select the first of the kind', () => {
const clientStore = new MockClientStore();
actions.selectStory({ clientStore }, 'bbc');

const state = {
stories,
selectedKind: 'abc',
selectedStory: 'c',
};
const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
selectedKind: 'bbc',
selectedStory: 'x',
});
});
});
});

describe('jumpToStory', () => {
it('should dispatch related redux action', () => {
const reduxStore = {
dispatch: sinon.stub(),
};
const direction = -1;
describe('has enough stories', () => {
it('should select the next story', () => {
const clientStore = new MockClientStore();
actions.jumpToStory({ clientStore }, 1);

const state = {
stories,
selectedKind: 'abc',
selectedStory: 'c',
};
const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
selectedKind: 'bbc',
selectedStory: 'x',
});
});

actions.jumpToStory({ reduxStore }, direction);
const action = reduxStore.dispatch.args[0][0];
expect(action).to.deep.equal({
type: types.JUMP_TO_STORY,
direction,
it('should select the prev story', () => {
const clientStore = new MockClientStore();
actions.jumpToStory({ clientStore }, -1);

const state = {
stories,
selectedKind: 'abc',
selectedStory: 'c',
};
const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
selectedKind: 'abc',
selectedStory: 'b',
});
});
});

describe('has not enough stories', () => {
it('should select the current story', () => {
const clientStore = new MockClientStore();
actions.jumpToStory({ clientStore }, 1);

const state = {
stories,
selectedKind: 'bbc',
selectedStory: 'z',
};
const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
selectedKind: 'bbc',
selectedStory: 'z',
});
});
});
});

describe('setOptions', () => {
it('should dispatch related redux action', () => {
const reduxStore = {
dispatch: sinon.stub(),
it('should update options', () => {
const clientStore = new MockClientStore();
actions.setOptions({ clientStore }, { abc: 10 });

const state = {
uiOptions: { bbc: 50, abc: 40 },
};
const options = {};

actions.setOptions({ reduxStore }, options);
const a = reduxStore.dispatch.args[0][0];
expect(a).to.deep.equal({
type: types.SET_OPTIONS,
options,
const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
uiOptions: { bbc: 50, abc: 10 },
});
});

it('should only update options for the key already defined', () => {
const clientStore = new MockClientStore();
actions.setOptions({ clientStore }, { abc: 10, notGoingToState: 20 });

const state = {
uiOptions: { bbc: 50, abc: 40 },
};

const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
uiOptions: { bbc: 50, abc: 10 },
});
});
});

describe('setQueryParams', () => {
it('should dispatch related redux action', () => {
const reduxStore = {
dispatch: sinon.stub(),
it('shodul update query params', () => {
const clientStore = new MockClientStore();
actions.setQueryParams({ clientStore }, { abc: 'aaa', cnn: 'ccc' });

const state = {
customQueryParams: { bbc: 'bbb', abc: 'sshd' },
};
const customQueryParams = {
foo: 'bar',

const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
customQueryParams: { bbc: 'bbb', abc: 'aaa', cnn: 'ccc' },
});
});

it('should delete the param if it\'s null', () => {
const clientStore = new MockClientStore();
actions.setQueryParams({ clientStore }, { abc: null, bbc: 'ccc' });

const state = {
customQueryParams: { bbc: 'bbb', abc: 'sshd' },
};

actions.setQueryParams({ reduxStore }, customQueryParams);
const a = reduxStore.dispatch.args[0][0];
expect(a).to.deep.equal({
type: types.SET_QUERY_PARAMS,
customQueryParams,
const stateUpdates = clientStore.updateCallback(state);
expect(stateUpdates).to.deep.equal({
customQueryParams: { bbc: 'ccc' },
});
});
});
Expand Down
Loading

0 comments on commit 75073ec

Please sign in to comment.