diff --git a/src/devTools.js b/src/devTools.js index fa079486..5510c546 100644 --- a/src/devTools.js +++ b/src/devTools.js @@ -3,6 +3,7 @@ const ActionTypes = { RESET: 'RESET', ROLLBACK: 'ROLLBACK', COMMIT: 'COMMIT', + IMPORT_STATE: 'IMPORT_STATE', SWEEP: 'SWEEP', TOGGLE_ACTION: 'TOGGLE_ACTION', JUMP_TO_STATE: 'JUMP_TO_STATE', @@ -121,6 +122,16 @@ function liftReducer(reducer, initialState) { currentStateIndex = 0; timestamps = [liftedAction.timestamp]; break; + case ActionTypes.IMPORT_STATE: + ({ + stagedActions, + skippedActions, + computedStates, + currentStateIndex, + monitorState, + timestamps + } = liftedAction.nextLiftedState); + break; case ActionTypes.ROLLBACK: stagedActions = [INIT_ACTION]; skippedActions = {}; @@ -258,6 +269,9 @@ export const ActionCreators = { commit() { return { type: ActionTypes.COMMIT, timestamp: Date.now() }; }, + importState(nextLiftedState) { + return { type: ActionTypes.IMPORT_STATE, nextLiftedState }; + }, sweep() { return { type: ActionTypes.SWEEP }; }, diff --git a/src/react/LogMonitor.js b/src/react/LogMonitor.js index c9839de5..dfa2d1f8 100644 --- a/src/react/LogMonitor.js +++ b/src/react/LogMonitor.js @@ -1,3 +1,4 @@ +/* eslint-disable no-alert */ import React, { PropTypes, findDOMNode, Component } from 'react'; import LogMonitorEntry from './LogMonitorEntry'; import LogMonitorButton from './LogMonitorButton'; @@ -118,6 +119,21 @@ export default class LogMonitor extends Component { this.props.commit(); } + handleExport() { + window.prompt('Current state\'s schema', JSON.stringify(this.props.store.getState())); + } + + handleImport() { + try { + let nextLiftedState = window.prompt('Please paste a valid action log'); + if (nextLiftedState) { + this.props.importState(JSON.parse(nextLiftedState)); + } + } catch (err) { + console.warn('There was an error parsing the new state. Please enter a valid schema.'); + } + } + handleToggleAction(index) { this.props.toggleAction(index); } @@ -184,6 +200,8 @@ export default class LogMonitor extends Component { Revert skippedActions[key])}>Sweep 1}>Commit + Import + Export
{elements} @@ -192,3 +210,4 @@ export default class LogMonitor extends Component { ); } } +/* eslint-enable no-alert */ diff --git a/test/devTools.spec.js b/test/devTools.spec.js index af47f858..7aa28ead 100644 --- a/test/devTools.spec.js +++ b/test/devTools.spec.js @@ -243,4 +243,42 @@ describe('devTools', () => { monitoredDevToolsStore.dispatch(ActionCreators.jumpToState(3)); expect(reducerCalls).toBe(4); }); + + describe('Import State', () => { + let monitoredStore; + let monitoredDevToolsStore; + let exportedState; + + beforeEach(() => { + monitoredStore = devTools()(createStore)(counter); + monitoredDevToolsStore = monitoredStore.devToolsStore; + // Set up state to export + monitoredStore.dispatch({ type: 'INCREMENT' }); + monitoredStore.dispatch({ type: 'INCREMENT' }); + monitoredStore.dispatch({ type: 'INCREMENT' }); + + exportedState = monitoredDevToolsStore.getState(); + }); + + it('should replay all the steps when a state is imported', () => { + let importMonitoredStore = devTools()(createStore)(counter); + let importMonitoredDevToolsStore = importMonitoredStore.devToolsStore; + // Import exported state + importMonitoredDevToolsStore.dispatch(ActionCreators.importState(exportedState)); + expect(importMonitoredDevToolsStore.getState()).toEqual(exportedState); + }); + + it('should replace the existing action log with the one imported', () => { + let importMonitoredStore = devTools()(createStore)(counter); + let importMonitoredDevToolsStore = importMonitoredStore.devToolsStore; + + importMonitoredStore.dispatch({ type: 'DECREMENT' }); + importMonitoredStore.dispatch({ type: 'DECREMENT' }); + + // Import exported state + importMonitoredDevToolsStore.dispatch(ActionCreators.importState(exportedState)); + + expect(importMonitoredDevToolsStore.getState()).toEqual(exportedState); + }); + }); });