redux-optimist
Advanced tools
Comparing version 0.0.1 to 0.0.2
173
lib/index.js
@@ -7,8 +7,7 @@ 'use strict'; | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
var BEGIN = 'BEGIN'; | ||
var COMMIT = 'COMMIT'; | ||
var REVERT = 'REVERT'; | ||
var INITIAL_OPTIMIST = {}; | ||
// Array({transactionID: string or null, beforeState: {object}, action: {object}} | ||
var INITIAL_OPTIMIST = []; | ||
@@ -20,74 +19,130 @@ module.exports = optimist; | ||
function optimist(fn) { | ||
return function (state, action) { | ||
var _ref = state || {}; | ||
function beginReducer(state, action) { | ||
var _separateState = separateState(state); | ||
var _ref$optimist = _ref.optimist; | ||
var optimist = _ref$optimist === undefined ? INITIAL_OPTIMIST : _ref$optimist; | ||
var optimist = _separateState.optimist; | ||
var innerState = _separateState.innerState; | ||
var oldState = _objectWithoutProperties(_ref, ['optimist']); | ||
optimist = optimist.concat([{ beforeState: innerState, action: action }]); | ||
innerState = fn(innerState, action); | ||
validateState(innerState, action); | ||
return _extends({ optimist: optimist }, innerState); | ||
} | ||
function commitReducer(state, action) { | ||
var _separateState2 = separateState(state); | ||
var oldOptimist = optimist; | ||
if (!state) oldState = undefined; | ||
if (action.optimist && (action.optimist.type === COMMIT || action.optimist.type === REVERT)) { | ||
var _optimist = optimist; | ||
var transaction = _optimist[action.optimist.id]; | ||
var optimist = _separateState2.optimist; | ||
var innerState = _separateState2.innerState; | ||
var transactions = _objectWithoutProperties(_optimist, [action.optimist.id]); | ||
if (!transaction) { | ||
console.error('Cannot ' + action.optimist.type + ' transaction with id "' + action.optimist.id + '" because it does not exist'); | ||
var newOptimist = [], | ||
started = false, | ||
committed = false; | ||
optimist.forEach(function (entry) { | ||
if (started) { | ||
if (entry.beforeState && matchesTransaction(entry.action, action.optimist.id)) { | ||
committed = true; | ||
newOptimist.push({ action: entry.action }); | ||
} else { | ||
newOptimist.push(entry); | ||
} | ||
} else if (entry.beforeState && !matchesTransaction(entry.action, action.optimist.id)) { | ||
started = true; | ||
newOptimist.push(entry); | ||
} else if (entry.beforeState && matchesTransaction(entry.action, action.optimist.id)) { | ||
committed = true; | ||
} | ||
optimist = transactions; | ||
if (transaction && action.optimist.type === REVERT) { | ||
(function () { | ||
var state = transaction.state; | ||
var actions = transaction.actions; | ||
}); | ||
if (!committed) { | ||
console.error('Cannot commit transaction with id "my-transaction" because it does not exist'); | ||
} | ||
optimist = newOptimist; | ||
return baseReducer(optimist, innerState, action); | ||
} | ||
function revertReducer(state, action) { | ||
var _separateState3 = separateState(state); | ||
actions.forEach(function (action) { | ||
state = fn(state, action); | ||
}); | ||
oldState = state; | ||
})(); | ||
var optimist = _separateState3.optimist; | ||
var innerState = _separateState3.innerState; | ||
var newOptimist = [], | ||
started = false, | ||
gotInitialState = false, | ||
currentState = innerState; | ||
optimist.forEach(function (entry) { | ||
if (entry.beforeState && matchesTransaction(entry.action, action.optimist.id)) { | ||
currentState = entry.beforeState; | ||
gotInitialState = true; | ||
} | ||
if (!matchesTransaction(entry.action, action.optimist.id)) { | ||
if (entry.beforeState) { | ||
started = true; | ||
} | ||
if (started) { | ||
if (gotInitialState && entry.beforeState) { | ||
newOptimist.push({ | ||
beforeState: currentState, | ||
action: entry.action | ||
}); | ||
} else { | ||
newOptimist.push(entry); | ||
} | ||
} | ||
if (gotInitialState) { | ||
currentState = fn(currentState, entry.action); | ||
validateState(innerState, action); | ||
} | ||
} | ||
}); | ||
if (!gotInitialState) { | ||
console.error('Cannot revert transaction with id "my-transaction" because it does not exist'); | ||
} | ||
if (Object.keys(optimist).length) { | ||
(function () { | ||
var newOptimist = {}; | ||
Object.keys(optimist).forEach(function (key) { | ||
newOptimist[key] = { state: optimist[key].state, actions: optimist[key].actions.concat([action]) }; | ||
}); | ||
optimist = newOptimist; | ||
})(); | ||
optimist = newOptimist; | ||
return baseReducer(optimist, currentState, action); | ||
} | ||
function baseReducer(optimist, innerState, action) { | ||
if (optimist.length) { | ||
optimist = optimist.concat([{ action: action }]); | ||
} | ||
if (action.optimist && action.optimist.type === BEGIN) { | ||
if (action.optimist.id in optimist) { | ||
console.error('Implicitly committing transaction with id "' + action.optimist.id + '" because it already exists, and you are starting' + ' it again.'); | ||
innerState = fn(innerState, action); | ||
validateState(innerState, action); | ||
return _extends({ optimist: optimist }, innerState); | ||
} | ||
return function (state, action) { | ||
if (action.optimist) { | ||
switch (action.optimist.type) { | ||
case BEGIN: | ||
return beginReducer(state, action); | ||
case COMMIT: | ||
return commitReducer(state, action); | ||
case REVERT: | ||
return revertReducer(state, action); | ||
} | ||
if (!state) { | ||
console.error('You should never begin an optimistic transaction before initializing your store.' + ' You would have nothing to revert to!'); | ||
} | ||
optimist = _extends({}, optimist, _defineProperty({}, action.optimist.id, { state: oldState, actions: [] })); | ||
} | ||
var newState = fn(oldState, action); | ||
if (!newState || typeof newState !== 'object' || Array.isArray(newState)) { | ||
throw new TypeError('Error while handling "' + action.type + '": Optimist requires that state is always a plain object.'); | ||
} | ||
if (oldOptimist !== optimist || !equal(newState, oldState)) return _extends({ optimist: optimist }, newState);else return state; | ||
var separated = separateState(state); | ||
return baseReducer(separated.optimist, separated.innerState, action); | ||
}; | ||
} | ||
function equal(newState, oldState) { | ||
if (newState === oldState) return true; | ||
if (!(newState && oldState)) return false; | ||
for (var key in newState) { | ||
if (newState[key] !== oldState[key]) { | ||
return false; | ||
} | ||
function matchesTransaction(action, id) { | ||
return action.optimist && action.optimist.id === id; | ||
} | ||
function validateState(newState, action) { | ||
if (!newState || typeof newState !== 'object' || Array.isArray(newState)) { | ||
throw new TypeError('Error while handling "' + action.type + '": Optimist requires that state is always a plain object.'); | ||
} | ||
for (var key in oldState) { | ||
if (newState[key] !== oldState[key]) { | ||
return false; | ||
} | ||
} | ||
function separateState(state) { | ||
if (!state) { | ||
return { optimist: INITIAL_OPTIMIST, innerState: state }; | ||
} else { | ||
var _state$optimist = state.optimist; | ||
var _optimist = _state$optimist === undefined ? INITIAL_OPTIMIST : _state$optimist; | ||
var innerState = _objectWithoutProperties(state, ['optimist']); | ||
return { optimist: _optimist, innerState: innerState }; | ||
} | ||
return true; | ||
} |
{ | ||
"name": "redux-optimist", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"description": "Optimistically apply actions that can be later commited or reverted.", | ||
@@ -9,2 +9,5 @@ "keywords": [], | ||
"babel": "^5.8.23", | ||
"babel-istanbul": "^0.3.20", | ||
"chalk": "^1.1.1", | ||
"diff": "^2.1.2", | ||
"testit": "^2.0.2" | ||
@@ -15,3 +18,4 @@ }, | ||
"build": "babel src --out-dir lib", | ||
"test": "babel-node test/index.js" | ||
"test": "babel-node test/index.js", | ||
"coverage": "babel-node node_modules/.bin/babel-istanbul cover test/index.js" | ||
}, | ||
@@ -18,0 +22,0 @@ "repository": { |
@@ -5,4 +5,18 @@ 'use strict'; | ||
import test from 'testit'; | ||
import {diffLines} from 'diff'; | ||
import chalk from 'chalk'; | ||
import optimist from '../src'; | ||
function deepEqual(expected, actual) { | ||
expected = JSON.stringify(expected, null, ' '); | ||
actual = JSON.stringify(actual, null, ' '); | ||
if (expected !== actual) { | ||
var diff = diffLines(actual, expected); | ||
var err = ''; | ||
diff.forEach(function (chunk) { | ||
err += chunk.added ? chalk.red(chunk.value) : chunk.removed ? chalk.green(chunk.value) : chunk.value; | ||
}); | ||
throw err; | ||
} | ||
} | ||
function getWarnings(fn) { | ||
@@ -17,42 +31,16 @@ var warnings = []; | ||
test('with a non-object return type it throws', () => { | ||
try { | ||
optimist(function () { })(undefined, {type: 'foo'}); | ||
} catch (ex) { | ||
assert(ex instanceof TypeError); | ||
assert(ex.message === 'Error while handling "foo": Optimist requires that state is always a plain object.'); | ||
return; | ||
} | ||
throw new Error('Optimist should have thrown an exception'); | ||
}); | ||
test('with an object it mixes in the initial state', () => { | ||
let action = {type: 'foo'}; | ||
let res = optimist(function (state, a) { | ||
assert(state === undefined); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})(undefined, action); | ||
assert.deepEqual(res, {optimist: {}, lastAction: action}); | ||
}); | ||
test('when you attempt to commit a non-existent transaction it warns', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-transaction'}}; | ||
let res; | ||
let warnings = getWarnings(() => { | ||
res = optimist(function (state, a) { | ||
assert(state === undefined); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})(undefined, action); | ||
test('errors and warnings', () => { | ||
test('with a non-object return type it throws', () => { | ||
try { | ||
optimist(function () { })(undefined, {type: 'foo'}); | ||
} catch (ex) { | ||
assert(ex instanceof TypeError); | ||
assert(ex.message === 'Error while handling "foo": Optimist requires that state is always a plain object.'); | ||
return; | ||
} | ||
throw new Error('Optimist should have thrown an exception'); | ||
}); | ||
assert.deepEqual( | ||
warnings, | ||
['Cannot COMMIT transaction with id "my-transaction" because it does not exist'] | ||
); | ||
assert.deepEqual(res, {optimist: {}, lastAction: action}); | ||
}); | ||
test('when you attempt to revert a non-existent transaction it warns', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-transaction'}}; | ||
let res; | ||
let warnings = getWarnings(() => { | ||
res = optimist(function (state, a) { | ||
test('with an object it mixes in the initial state', () => { | ||
let action = {type: 'foo'}; | ||
let res = optimist(function (state, a) { | ||
assert(state === undefined); | ||
@@ -62,128 +50,220 @@ assert(a === action); | ||
})(undefined, action); | ||
assert.deepEqual(res, {optimist: [], lastAction: action}); | ||
}); | ||
assert.deepEqual( | ||
warnings, | ||
['Cannot REVERT transaction with id "my-transaction" because it does not exist'] | ||
); | ||
assert.deepEqual(res, {optimist: {}, lastAction: action}); | ||
test('when you attempt to commit a non-existent transaction it warns', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-transaction'}}; | ||
let res; | ||
let warnings = getWarnings(() => { | ||
res = optimist(function (state, a) { | ||
assert(state === undefined); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})(undefined, action); | ||
}); | ||
assert.deepEqual( | ||
warnings, | ||
['Cannot commit transaction with id "my-transaction" because it does not exist'] | ||
); | ||
assert.deepEqual(res, {optimist: {}, lastAction: action}); | ||
}); | ||
test('when you attempt to revert a non-existent transaction it warns', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-transaction'}}; | ||
let res; | ||
let warnings = getWarnings(() => { | ||
res = optimist(function (state, a) { | ||
assert(state === undefined); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})(undefined, action); | ||
}); | ||
assert.deepEqual( | ||
warnings, | ||
['Cannot revert transaction with id "my-transaction" because it does not exist'] | ||
); | ||
assert.deepEqual(res, {optimist: {}, lastAction: action}); | ||
}); | ||
}); | ||
test('beginning a transaction', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}; | ||
let res = optimist(function (state, a) { | ||
assert.deepEqual(state, {initial: 'state'}); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})({initial: 'state'}, action); | ||
assert.deepEqual( | ||
res, | ||
{ | ||
optimist: { | ||
'my-transaction': { state: {initial: 'state'}, actions: [] } | ||
basic('beginning a transaction', { | ||
reducer: (state, a) => ({lastAction: a}), | ||
before: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}, | ||
after: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
} | ||
], | ||
lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
} | ||
}); | ||
basic('within a transaction', { | ||
reducer: (state, a) => ({lastAction: a}), | ||
before: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
} | ||
], | ||
lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
action: {type: 'foo'}, | ||
after: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
lastAction: action | ||
} | ||
); | ||
{action: {type: 'foo'}} | ||
], | ||
lastAction: {type: 'foo'} | ||
} | ||
}); | ||
test('within a transaction', () => { | ||
let action = {type: 'foo'}; | ||
let initialState = { | ||
optimist: { | ||
'my-transaction': { state: {initial: 'state'}, actions: [] } | ||
}, | ||
lastAction: {type: 'bar'} | ||
}; | ||
let res = optimist(function (state, a) { | ||
assert.deepEqual(state, {lastAction: {type: 'bar'}}); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})(initialState, action); | ||
assert.deepEqual( | ||
res, | ||
{ | ||
optimist: { | ||
'my-transaction': { state: {initial: 'state'}, actions: [action] } | ||
basic('nest a transaction', { | ||
reducer: (state, a) => ({lastAction: a}), | ||
before: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
} | ||
], | ||
lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}}, | ||
after: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
lastAction: action | ||
} | ||
); | ||
{ | ||
beforeState: {lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
], | ||
lastAction: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
} | ||
}); | ||
test('revert a transaction', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-transaction'}}; | ||
let initialState = { | ||
optimist: { | ||
'my-transaction': { state: {initial: 'state'}, actions: [] } | ||
}, | ||
lastAction: {type: 'bar'} | ||
}; | ||
let res = optimist(function (state, a) { | ||
assert.deepEqual(state, {initial: 'state'}); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})(initialState, action); | ||
assert.deepEqual( | ||
res, | ||
{ | ||
optimist: {}, | ||
lastAction: action | ||
} | ||
); | ||
basic('revert a transaction', { | ||
reducer: (state, a) => ({lastAction: a}), | ||
before: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
{ | ||
beforeState: {lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
], | ||
lastAction: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
action: {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-transaction'}}, | ||
after: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
{ | ||
action: {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-transaction'}}, | ||
} | ||
], | ||
lastAction: {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-transaction'}}, | ||
} | ||
}); | ||
test('revert a transaction with intermediate actions', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-transaction'}}; | ||
let initialState = { | ||
optimist: { | ||
'my-transaction': { state: {initial: 'state'}, actions: [{type: 'bar'}] } | ||
}, | ||
lastAction: {type: 'bar'} | ||
}; | ||
var call = 0; | ||
let res = optimist(function (state, a) { | ||
call++; | ||
if (call === 1) { | ||
assert.deepEqual(state, {initial: 'state'}); | ||
assert.deepEqual(a, {type: 'bar'}); | ||
} | ||
if (call === 2) { | ||
assert.deepEqual(state, {lastAction: {type: 'bar'}}); | ||
assert.deepEqual(a, action); | ||
} | ||
if (call > 2) { | ||
throw new Error('Expected only 2 calls'); | ||
} | ||
return {lastAction: a}; | ||
})(initialState, action); | ||
assert.deepEqual( | ||
res, | ||
{ | ||
optimist: {}, | ||
lastAction: action | ||
} | ||
); | ||
basic('revert other transaction', { | ||
reducer: (state, a) => ({lastAction: a}), | ||
before: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
{ | ||
beforeState: {lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
], | ||
lastAction: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
action: {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-other-transaction'}}, | ||
after: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
{ | ||
action: {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-other-transaction'}}, | ||
} | ||
], | ||
lastAction: {type: 'foo', optimist: {type: optimist.REVERT, id: 'my-other-transaction'}}, | ||
} | ||
}); | ||
test('commit a transaction', () => { | ||
let action = {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-transaction'}}; | ||
let initialState = { | ||
optimist: { | ||
'my-transaction': { state: {initial: 'state'}, actions: [] } | ||
}, | ||
lastAction: {type: 'bar'} | ||
}; | ||
let res = optimist(function (state, a) { | ||
assert.deepEqual(state, {lastAction: {type: 'bar'}}); | ||
assert(a === action); | ||
return {lastAction: a}; | ||
})(initialState, action); | ||
assert.deepEqual( | ||
res, | ||
{ | ||
optimist: {}, | ||
lastAction: action | ||
} | ||
); | ||
basic('commit a transaction', { | ||
reducer: (state, a) => ({lastAction: a}), | ||
before: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
{ | ||
beforeState: {lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
], | ||
lastAction: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
action: {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-transaction'}}, | ||
after: { | ||
optimist: [ | ||
{ | ||
beforeState: {lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
{ | ||
action: {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-transaction'}}, | ||
} | ||
], | ||
lastAction: {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-transaction'}}, | ||
} | ||
}); | ||
basic('commit other transaction', { | ||
reducer: (state, a) => ({lastAction: a}), | ||
before: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
{ | ||
beforeState: {lastAction: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}}}, | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
], | ||
lastAction: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
action: {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-other-transaction'}}, | ||
after: { | ||
optimist: [ | ||
{ | ||
beforeState: {initial: 'state'}, | ||
action: {type: 'foo', optimist: {type: optimist.BEGIN, id: 'my-transaction'}} | ||
}, | ||
{ | ||
action: {type: 'bar', optimist: {type: optimist.BEGIN, id: 'my-other-transaction'}} | ||
}, | ||
{ | ||
action: {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-other-transaction'}}, | ||
} | ||
], | ||
lastAction: {type: 'foo', optimist: {type: optimist.COMMIT, id: 'my-other-transaction'}}, | ||
} | ||
}); | ||
@@ -246,3 +326,86 @@ | ||
}); | ||
assert.deepEqual(state, {optimist: {}, value: 4}); | ||
deepEqual(state, {optimist: [], value: 4}); | ||
}); | ||
test('real world example 2', () => { | ||
function originalReducer(state = {value: 0}, action) { | ||
switch (action.type) { | ||
case 'SET': | ||
return {value: action.value}; | ||
case 'INCREMENT': | ||
return {value: state.value + 1}; | ||
case 'INCREMENT_IF_EVEN': | ||
return state.value % 2 === 0 ? {value: state.value + 1} : state; | ||
default: | ||
return state; | ||
} | ||
} | ||
let reducer = optimist(originalReducer); | ||
let actionCreators = { | ||
set(value, transactionID) { | ||
return { | ||
type: 'SET', | ||
value: value, | ||
optimist: transactionID ? {id: transactionID} : undefined | ||
}; | ||
}, | ||
increment(transactionID) { | ||
return { | ||
type: 'INCREMENT', | ||
optimist: transactionID ? {id: transactionID} : undefined | ||
}; | ||
}, | ||
incrementIfEven(transactionID) { | ||
return { | ||
type: 'INCREMENT_IF_EVEN', | ||
optimist: transactionID ? {id: transactionID} : undefined | ||
}; | ||
}, | ||
begin(transactionID) { | ||
return {type: 'BEGIN', optimist: {type: optimist.BEGIN, id: transactionID}}; | ||
}, | ||
commit(transactionID) { | ||
return {type: 'COMMIT', optimist: {type: optimist.COMMIT, id: transactionID}}; | ||
}, | ||
revert(transactionID) { | ||
return {type: 'REVERT', optimist: {type: optimist.REVERT, id: transactionID}}; | ||
}, | ||
}; | ||
let actions = [ | ||
{action: {type: '@@init'}, value: 0}, | ||
{action: actionCreators.set(2), value: 2}, | ||
{action: actionCreators.begin('start-at-1'), value: 2}, | ||
{action: actionCreators.set(1, 'start-at-1'), value: 1}, | ||
{action: actionCreators.incrementIfEven(), value: 1}, | ||
{action: actionCreators.increment('start-at-1'), value: 2}, | ||
{action: actionCreators.begin('inc'), value: 2}, | ||
{action: actionCreators.increment('inc'), value: 3}, | ||
{action: actionCreators.commit('inc'), value: 3}, | ||
{action: actionCreators.revert('start-at-1'), value: 4}, | ||
]; | ||
let state; | ||
actions.forEach(({action, value}) => { | ||
state = reducer(state, action); | ||
assert(state.value === value); | ||
}); | ||
assert.deepEqual(state, {optimist: [], value: 4}); | ||
}); | ||
function basic(name, {reducer, before, action, after}) { | ||
test(name, () => { | ||
let res = optimist(function (state, a) { | ||
/* | ||
if (before) { | ||
let {optimist, ...filteredBefore} = before; | ||
assert.deepEqual(state, filteredBefore); | ||
} else { | ||
assert(state === before); | ||
} | ||
assert(a === action, 'action should be passed through to reducer'); | ||
*/ | ||
return reducer(state, a); | ||
})(before, action); | ||
deepEqual(res, after); | ||
}); | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
89402
19
911
5
1