Skip to content

Commit

Permalink
Support passing props to tabs=true routes
Browse files Browse the repository at this point in the history
  • Loading branch information
benstepp committed Aug 15, 2016
1 parent 0ef1f7a commit 7620ab4
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,5 @@ class Actions {
}
}

export { Actions as ActionsTest };
export default new Actions();
13 changes: 12 additions & 1 deletion src/Reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,18 @@ function inject(state, action, props, scenes) {
case ActionConst.JUMP:
assert(state.tabs, `Parent=${state.key} is not tab bar, jump action is not valid`);
ind = -1;
state.children.forEach((c, i) => { if (c.sceneKey === action.key) { ind = i; } });
state.children.forEach((child, i) => {
if (child.sceneKey === action.key) {
ind = i;

// Pass the props to the wrapped tab scene
if (props.children) delete props.children;
const key = child.children[0].sceneKey;
const wrappedScene = scenes[key];
child.children = [{ ...props, ...wrappedScene }];
}
});

assert(ind !== -1, `Cannot find route with key=${action.key} for parent=${state.key}`);

if (action.unmountScenes) {
Expand Down
139 changes: 133 additions & 6 deletions test/Actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { expect } from 'chai';

import React from 'react';

import Actions from '../src/Actions';
import * as ActionConst from '../src/ActionConst';
import { ActionsTest } from '../src/Actions';
import Scene from '../src/Scene';

let id = 0;
const guid = () => id++;
const noop = () => {};

const scenesData = (
<Scene
Expand Down Expand Up @@ -39,13 +41,11 @@ const scenesData = (
</Scene>
</Scene>);

let scenes;

describe('Actions', () => {
before(() => {
scenes = Actions.create(scenesData);
});
it('should produce needed actions', () => {
const Actions = new ActionsTest();
const scenes = Actions.create(scenesData);

// check scenes
expect(scenes.conversations.component).to.equal('Conversations');

Expand All @@ -67,4 +67,131 @@ describe('Actions', () => {
expect(latestAction.param3).equal('Hello world3');
expect(latestAction.key).equal('messaging');
});

it('throws when not providing a root scene', () => {
const Actions = new ActionsTest();
const scene = void 0;
expect(() => Actions.create(scene)).to.throw(Error, 'root scene');
});

it('throws when using a reserved method', () => {
const scene = (
<Scene key="root" component={noop}>
<Scene key="create" component={noop} />
</Scene>
);

const Actions = new ActionsTest();
expect(() => Actions.create(scene)).to.throw(Error, 'create');
});

it('throws when using an action method', () => {
const scene = (
<Scene key="root" component={noop}>
<Scene key="push" component={noop} />
</Scene>
);

const Actions = new ActionsTest();
expect(() => Actions.create(scene)).to.throw(Error, 'push');
});

it('wraps child scenes if the parent is tabs', () => {
const scene = (
<Scene key="root" component={noop}>
<Scene key="main" tabs>
<Scene key="home" component={noop} />
<Scene key="map" component={noop} />
<Scene key="myAccount" component={noop} />
</Scene>
</Scene>
);
const Actions = new ActionsTest();
const scenes = Actions.create(scene);

const tabKeys = ['home', 'map', 'myAccount'];
tabKeys.forEach(key => {
expect(scenes[key].component).to.eq(void 0);
expect(scenes[key].type).to.eq(ActionConst.JUMP);

const wrappedKey = scenes[key].children[0];
expect(scenes[wrappedKey].component).to.not.eq(void 0);
expect(scenes[wrappedKey].type).to.eq(ActionConst.PUSH);
});
});

it('provides keys to children of a scene', () => {
const scene = (
<Scene key="root" component={noop}>
<Scene key="home" component={noop} />
<Scene key="map" component={noop} />
<Scene key="myAccount" component={noop} />
</Scene>
);

const Actions = new ActionsTest();
const scenes = Actions.create(scene);

const childrenKeys = ['home', 'map', 'myAccount'];
expect(scenes.root.children).to.include.all(...childrenKeys);
});

it('substates have their base set to their parent', () => {
const scene = (
<Scene key="root" component={noop}>
<Scene key="view" type={ActionConst.REFRESH} />
<Scene key="edit" type={ActionConst.REFRESH} edit />
<Scene key="save" type={ActionConst.REFRESH} save />
</Scene>
);

const Actions = new ActionsTest();
const scenes = Actions.create(scene);

const subStates = ['view', 'edit', 'save'];
subStates.forEach(key => {
expect(scenes[key].base).to.eq('root');
expect(scenes[key].parent).to.eq(scenes.root.parent);
});
});

it('substates do not need to specify REFRESH type', () => {
const scene = (
<Scene key="root" component={noop}>
<Scene key="view" />
<Scene key="edit" edit />
<Scene key="save" save />
</Scene>
);

const Actions = new ActionsTest();
const scenes = Actions.create(scene);

const subStates = ['view', 'edit', 'save'];
subStates.forEach(key => {
expect(scenes[key].type).to.eq(ActionConst.REFRESH);
});
});

it('allows mixing of substates with children', () => {
const scene = (
<Scene key="root" component={noop}>
<Scene key="view" />
<Scene key="edit" edit />
<Scene key="save" save />
<Scene key="messaging" component={noop}>
<Scene key="conversations" component={noop} />
</Scene>
</Scene>
);

const Actions = new ActionsTest();
const scenes = Actions.create(scene);

const subStates = ['view', 'edit', 'save'];
subStates.forEach(key => {
expect(scenes[key].type).to.eq(ActionConst.REFRESH);
});
expect(scenes.messaging.type).to.eq(ActionConst.PUSH);
});
});
67 changes: 65 additions & 2 deletions test/Reducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import React from 'react';
import { expect } from 'chai';

import Scene from '../src/Scene';
import Actions from '../src/Actions';
import { ActionsTest } from '../src/Actions';
import * as ActionConst from '../src/ActionConst';

import createReducer from '../src/Reducer';
import getInitialState from '../src/State';

Expand Down Expand Up @@ -54,6 +53,7 @@ describe('createReducer', () => {
// create scenes and initialState
// For creating scenes we use external modules.
// TODO: Think about fully isolated test.
const Actions = new ActionsTest();
const scenes = Actions.create(scenesData);
const initialState = getInitialState(scenes); // TODO: write test for this.

Expand Down Expand Up @@ -109,3 +109,66 @@ describe('createReducer', () => {
expect(currentScene.param1).equal('Conversations new param');
});
});

describe('passing props from actions', () => {
it('passes props for normal scenes', () => {
const noop = () => {};
const scene = (
<Scene key="root" component={noop}>
<Scene key="hello" component={noop} initial />
<Scene key="world" component={noop} />
</Scene>
);

const Actions = new ActionsTest();
const scenes = Actions.create(scene);
const initialState = getInitialState(scenes);
const reducer = createReducer({ initialState, scenes });

let state = { ...initialState, scenes };
let current = getCurrent(state);
Actions.callback = action => {
state = reducer(state, action);
current = getCurrent(state);
};

Actions.hello({ customProp: 'Hello' });
expect(current.customProp).to.eq('Hello');
Actions.world({ customProp: 'World' });
expect(current.customProp).to.eq('World');
Actions.hello();
expect(current.customProp).to.eq(void 0);
});

it('passes props for tab scenes', () => {
const noop = () => {};
const scene = (
<Scene key="root" component={noop} tabs>
<Scene key="home" component={noop} />
<Scene key="map" component={noop} />
</Scene>
);

const Actions = new ActionsTest();
const scenes = Actions.create(scene);
const initialState = getInitialState(scenes);
const reducer = createReducer({ initialState, scenes });

let state = { ...initialState, scenes };
let current = getCurrent(state);
Actions.callback = action => {
state = reducer(state, action);
current = getCurrent(state);
};

Actions.home({ customProp: 'Home' });
expect(current.customProp).to.eq('Home');
Actions.map({ customProp: 'Map', anotherProp: 'Another' });
expect(current.customProp).to.eq('Map');
expect(current.anotherProp).to.eq('Another');

Actions.home();
expect(current.customProp).to.eq(void 0);
expect(current.anotherProp).to.eq(void 0);
});
});

0 comments on commit 7620ab4

Please sign in to comment.