mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-22 09:36:43 +03:00
merge
This commit is contained in:
commit
49bb120444
|
@ -4,6 +4,12 @@ Redux DevTools
|
||||||
A live-editing time travel environment for [Redux](https://github.com/rackt/redux).
|
A live-editing time travel environment for [Redux](https://github.com/rackt/redux).
|
||||||
**[See Dan's React Europe talk demoing it!](http://youtube.com/watch?v=xsSnOQynTHs)**
|
**[See Dan's React Europe talk demoing it!](http://youtube.com/watch?v=xsSnOQynTHs)**
|
||||||
|
|
||||||
|
[![build status](https://img.shields.io/travis/gaearon/redux-devtools/master.svg?style=flat-square)](https://travis-ci.org/gaearon/redux-devtools)
|
||||||
|
[![npm version](https://img.shields.io/npm/v/redux-devtools.svg?style=flat-square)](https://www.npmjs.com/package/redux-devtools)
|
||||||
|
[![npm downloads](https://img.shields.io/npm/dm/redux-devtools.svg?style=flat-square)](https://www.npmjs.com/package/redux-devtools)
|
||||||
|
[![redux channel on slack](https://img.shields.io/badge/slack-redux@reactiflux-61DAFB.svg?style=flat-square)](http://www.reactiflux.com)
|
||||||
|
|
||||||
|
|
||||||
![](http://i.imgur.com/J4GeW0M.gif)
|
![](http://i.imgur.com/J4GeW0M.gif)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default function persistState(sessionId, stateDeserializer = null, action
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(key, JSON.stringify(store.getState()));
|
localStorage.setItem(key, JSON.stringify(store.getState()));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Could not write debug session from localStorage:', e);
|
console.warn('Could not write debug session to localStorage:', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
|
|
|
@ -14,6 +14,7 @@ function counterWithBug(state = 0, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'INCREMENT': return state + 1;
|
case 'INCREMENT': return state + 1;
|
||||||
case 'DECREMENT': return mistake - 1; // eslint-disable-line no-undef
|
case 'DECREMENT': return mistake - 1; // eslint-disable-line no-undef
|
||||||
|
case 'SET_UNDEFINED': return undefined;
|
||||||
default: return state;
|
default: return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +100,7 @@ describe('devTools', () => {
|
||||||
expect(store.getState()).toBe(1);
|
expect(store.getState()).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sweep disabled actions', () => {
|
it('should sweep disabled actions', () => {
|
||||||
// stateIndex 0 = @@INIT
|
// stateIndex 0 = @@INIT
|
||||||
store.dispatch({ type: 'INCREMENT' });
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
store.dispatch({ type: 'DECREMENT' });
|
store.dispatch({ type: 'DECREMENT' });
|
||||||
|
@ -153,13 +154,14 @@ describe('devTools', () => {
|
||||||
store.dispatch({ type: 'INCREMENT' });
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
expect(store.getState()).toBe(1);
|
expect(store.getState()).toBe(1);
|
||||||
|
|
||||||
let devStoreState = store.devToolsStore.getState();
|
let stagedActions = [...store.devToolsStore.getState().stagedActions];
|
||||||
devStoreState.committedState = 10;
|
// replace DECREMENT with INCREMENT (stagedAction[0] is @@INIT)
|
||||||
devStoreState.stagedActions[2] = { type: 'INCREMENT' };
|
stagedActions[2] = { type: 'INCREMENT' };
|
||||||
|
const committedState = 10;
|
||||||
|
|
||||||
devToolsStore.dispatch(ActionCreators.recomputeStates(
|
devToolsStore.dispatch(ActionCreators.recomputeStates(
|
||||||
devStoreState.committedState,
|
committedState,
|
||||||
devStoreState.stagedActions
|
stagedActions
|
||||||
));
|
));
|
||||||
|
|
||||||
expect(store.getState()).toBe(13);
|
expect(store.getState()).toBe(13);
|
||||||
|
@ -201,18 +203,13 @@ describe('devTools', () => {
|
||||||
spy.restore();
|
spy.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the last non-undefined state from getState', () => {
|
it('should return the last non-undefined state from getState', () => {
|
||||||
let spy = spyOn(console, 'error');
|
let storeWithBug = devTools()(createStore)(counterWithBug);
|
||||||
|
storeWithBug.dispatch({ type: 'INCREMENT' });
|
||||||
|
storeWithBug.dispatch({ type: 'INCREMENT' });
|
||||||
|
expect(storeWithBug.getState()).toBe(2);
|
||||||
|
|
||||||
store.dispatch({ type: 'INCREMENT' });
|
storeWithBug.dispatch({ type: 'SET_UNDEFINED' });
|
||||||
store.dispatch({ type: 'DECREMENT' });
|
expect(storeWithBug.getState()).toBe(2);
|
||||||
store.dispatch({ type: 'INCREMENT' });
|
|
||||||
store.dispatch({ type: 'INCREMENT' });
|
|
||||||
expect(store.getState()).toBe(2);
|
|
||||||
|
|
||||||
store.replaceReducer(counterWithBug);
|
|
||||||
expect(store.getState()).toBe(1);
|
|
||||||
|
|
||||||
spy.restore();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
123
test/persistState.spec.js
Normal file
123
test/persistState.spec.js
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
import expect from 'expect';
|
||||||
|
import devTools from '../src/devTools';
|
||||||
|
import persistState from '../src/persistState';
|
||||||
|
import { compose, createStore } from 'redux';
|
||||||
|
|
||||||
|
describe('persistState', () => {
|
||||||
|
let savedLocalStorage = global.localStorage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
global.localStorage = {
|
||||||
|
store: {},
|
||||||
|
getItem(key) {
|
||||||
|
return this.store[key] || null;
|
||||||
|
},
|
||||||
|
setItem(key, value) {
|
||||||
|
this.store[key] = value;
|
||||||
|
},
|
||||||
|
removeItem(key) {
|
||||||
|
delete this.store[key];
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
this.store = {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
global.localStorage = savedLocalStorage;
|
||||||
|
});
|
||||||
|
|
||||||
|
const reducer = (state = 0, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'INCREMENT':
|
||||||
|
return state + 1;
|
||||||
|
case 'DECREMENT':
|
||||||
|
return state - 1;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should persist state', () => {
|
||||||
|
const finalCreateStore = compose(devTools(), persistState('id'))(createStore);
|
||||||
|
const store = finalCreateStore(reducer);
|
||||||
|
expect(store.getState()).toBe(0);
|
||||||
|
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
expect(store.getState()).toBe(2);
|
||||||
|
|
||||||
|
const store2 = finalCreateStore(reducer);
|
||||||
|
expect(store2.getState()).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not persist state if no session id', () => {
|
||||||
|
const finalCreateStore = compose(devTools(), persistState())(createStore);
|
||||||
|
const store = finalCreateStore(reducer);
|
||||||
|
expect(store.getState()).toBe(0);
|
||||||
|
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
expect(store.getState()).toBe(2);
|
||||||
|
|
||||||
|
const store2 = finalCreateStore(reducer);
|
||||||
|
expect(store2.getState()).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run with a custom state deserializer', () => {
|
||||||
|
const oneLess = state => state === undefined ? -1 : state - 1;
|
||||||
|
const finalCreateStore = compose(devTools(), persistState('id', oneLess))(createStore);
|
||||||
|
const store = finalCreateStore(reducer);
|
||||||
|
expect(store.getState()).toBe(0);
|
||||||
|
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
expect(store.getState()).toBe(2);
|
||||||
|
|
||||||
|
const store2 = finalCreateStore(reducer);
|
||||||
|
expect(store2.getState()).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run with a custom action deserializer', () => {
|
||||||
|
const incToDec = action => action.type === 'INCREMENT' ? { type: 'DECREMENT' } : action;
|
||||||
|
const finalCreateStore = compose(devTools(), persistState('id', null, incToDec))(createStore);
|
||||||
|
const store = finalCreateStore(reducer);
|
||||||
|
expect(store.getState()).toBe(0);
|
||||||
|
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
expect(store.getState()).toBe(2);
|
||||||
|
|
||||||
|
const store2 = finalCreateStore(reducer);
|
||||||
|
expect(store2.getState()).toBe(-2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should warn if read from localStorage fails', () => {
|
||||||
|
const spy = expect.spyOn(console, 'warn');
|
||||||
|
const finalCreateStore = compose(devTools(), persistState('id'))(createStore);
|
||||||
|
delete global.localStorage.getItem;
|
||||||
|
finalCreateStore(reducer);
|
||||||
|
|
||||||
|
expect(spy.calls).toContain(
|
||||||
|
/Could not read debug session from localStorage/,
|
||||||
|
(call, errMsg) => call.arguments[0].match(errMsg)
|
||||||
|
);
|
||||||
|
|
||||||
|
spy.restore();
|
||||||
|
});
|
||||||
|
it('should warn if write to localStorage fails', () => {
|
||||||
|
const spy = expect.spyOn(console, 'warn');
|
||||||
|
const finalCreateStore = compose(devTools(), persistState('id'))(createStore);
|
||||||
|
delete global.localStorage.setItem;
|
||||||
|
const store = finalCreateStore(reducer);
|
||||||
|
|
||||||
|
store.dispatch({ type: 'INCREMENT' });
|
||||||
|
expect(spy.calls).toContain(
|
||||||
|
/Could not write debug session to localStorage/,
|
||||||
|
(call, errMsg) => call.arguments[0].match(errMsg)
|
||||||
|
);
|
||||||
|
|
||||||
|
spy.restore();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user