예제 #1
0
	def test_does_not_have_referential_equality_if_one_reducer_changes_something(self):
		def child_1(state=None, action=None):
			if state is None:
				state = {}
			return state
		
		def child_2(state=None, action=None):
			if action is None:
				action = {}
			if state is None:
				state = { 'count': 0 }
			if action.get('type') == 'increment':
				return { 'count': state['count'] + 1}
			return state
		
		def child_3(state=None, action=None):
			if state is None:
				state = {}
			return state
		
		reducer = combine_reducers({
			'child_1': child_1,
			'child_2': child_2,
			'child_3': child_3
		})
		
		initial_state = reducer(None)
		self.assertNotEqual(reducer(initial_state, { 'type': 'increment' }), initial_state)
예제 #2
0
    def test_handles_nested_dispatches_gracefully(self):
        def foo(state, action={}):
            if state is None:
                state = 0
            if action.get('type') == 'foo':
                return 1
            return state

        def bar(state, action={}):
            if state is None:
                state = 0
            if action.get('type') == 'bar':
                return 2
            else:
                return state

        store = create_store(combine_reducers({'foo': foo, 'bar': bar}))

        def kinda_component_did_update():
            state = store['get_state']()
            if state.get('bar') == 0:
                store['dispatch']({'type': 'bar'})

        store['subscribe'](kinda_component_did_update)
        store['dispatch']({'type': 'foo'})

        self.assertEqual(store['get_state'](), {'foo': 1, 'bar': 2})
예제 #3
0
	def test_handles_nested_dispatches_gracefully(self):
		def foo(state, action={}):
			if state is None:
				state = 0
			if action.get('type') == 'foo':
				return 1
			return state
		
		def bar(state, action={}):
			if state is None:
				state = 0
			if action.get('type') == 'bar':
				return 2
			else:
				return state
		
		store = create_store(combine_reducers({ 'foo': foo, 'bar': bar }))
		def kinda_component_did_update():
			state = store['get_state']()
			if state.get('bar') == 0:
				store['dispatch']({ 'type': 'bar' })
		store['subscribe'](kinda_component_did_update)
		store['dispatch']({ 'type': 'foo' })
		
		self.assertEqual(store['get_state'](), {
			'foo': 1,
			'bar': 2
		})
예제 #4
0
	def test_throws_if_reducer_returns_undefined_handling_an_action(self):
		def counter(state=None, action=None):
			state = 0 if state is None else state
			action = {} if action is None else action
			if action.get('type') == 'increment':
				return state + 1
			if action.get('type') == 'decrement':
				return state - 1
			if action.get('type') in ['decrement', 'whatever', None]:
				return None
			return state
		
		reducer = combine_reducers({ 'counter': counter })
		
		with self.assertRaises(Exception) as e:
			reducer({ 'counter': 0}, { 'type': 'whatever' })
		e = str(e.exception)
		self.assertTrue('"whatever"' in e and "counter" in e)
		
		with self.assertRaises(Exception) as e:
			reducer({ 'counter': 0 }, None)
		e = str(e.exception)
		self.assertTrue('"counter"' in e and 'an action' in e)
		
		with self.assertRaises(Exception) as e:
			reducer({ 'counter': 0 }, {})
		e = str(e.exception)
		self.assertTrue('"counter"' in e and 'an action' in e)
예제 #5
0
    def test_exposes_public_API(self):
        store = create_store(combine_reducers(reducers))
        methods = store.keys()

        self.assertEqual(len(methods), 4)
        self.assertTrue('subscribe' in methods)
        self.assertTrue('dispatch' in methods)
        self.assertTrue('get_state' in methods)
        self.assertTrue('replace_reducer' in methods)
예제 #6
0
	def test_exposes_public_API(self):
		store = create_store(combine_reducers(reducers))
		methods = store.keys()
		
		self.assertEqual(len(methods), 4)
		self.assertTrue('subscribe' in methods)
		self.assertTrue('dispatch' in methods)
		self.assertTrue('get_state' in methods)
		self.assertTrue('replace_reducer' in methods)
예제 #7
0
	def test_ignores_all_props_which_are_not_functions(self):
		reducer = combine_reducers({
			'fake': True,
			'broken': 'string',
			'another': { 'nested': 'object' },
			'stack': lambda state, action: state if state is not None else []
		})
		
		self.assertEqual(list(reducer({}, { 'type': 'push' }).keys()), [ 'stack' ])
예제 #8
0
	def test_catches_error_thrown_in_reducer_when_initializing_and_re_throw(self):
		def throwing_reducer(state=None, action=None):
			raise Exception('Error in reducer')
		reducer = combine_reducers({
			'throwing_reducer': throwing_reducer
		})
		
		with self.assertRaises(Exception) as e:
			reducer({})
		self.assertTrue('Error in reducer' in str(e.exception))
예제 #9
0
	def test_throws_error_on_first_call_if_reducer_returns_undefined_initializing(self):
		def counter(state=None, action=None):
			if action.get('type') == 'increment':
				return state + 1
			if action.get('type') == 'decrement':
				return state - 1
			return state
		
		reducer = combine_reducers({ 'counter': counter })
		with self.assertRaises(Exception) as e:
			reducer({})
		e = str(e.exception)
		self.assertTrue('"counter"' in e and 'initialization' in e)
예제 #10
0
	def test_warns_if_no_reducers_passed_to_combine_reducers(self, logging):
		def foo(state=None, action=None):
			if state is None: 
				state = { 'bar': 1}
			return state
		def baz(state=None, action=None):
			if state is None:
				state = { 'qux': 3 }
			return state
		
		reducer = combine_reducers({
			'foo': foo,
			'baz': baz
		})
		reducer()
		self.assertEqual(len(logging.call_args_list), 0)
		
		reducer({ 'foo': { 'bar': 2 }})
		self.assertEqual(len(logging.call_args_list), 0)
		
		reducer({
			'foo': { 'bar': 2 },
			'baz': { 'qux': 4 }
		})
		self.assertEqual(len(logging.call_args_list), 0)
		
		create_store(reducer, { 'bar': 2 })
		m = str(logging.call_args_list[0])
		self.assertTrue(re.search(r'Unexpected key "bar".*create_store.*instead: ("foo"|"baz"), ("foo"|"baz")', m))
		
		create_store(reducer, { 'bar': 2, 'qux': 4, 'thud': 5 })
		m = str(logging.call_args_list[1])
		self.assertTrue(re.search(r'Unexpected keys ("qux"|"thud"), ("qux"|"thud").*create_store.*instead: ("foo"|"baz"), ("foo"|"baz")', m))
		
		create_store(reducer, 1)
		m = str(logging.call_args_list[2])
		self.assertTrue(re.search(r'create_store has an unexpected type of <class "int">.*keys: ("foo"|"baz"), ("foo"|"baz")', m))
		
		reducer({ 'corge': 2 })
		m = str(logging.call_args_list[3])
		self.assertTrue(re.search(r'Unexpected key "corge".*reducer.*instead: ("foo"|"baz"), ("foo"|"baz")', m))
		
		reducer({ 'rick': 2, 'morty': 4 })
		m = str(logging.call_args_list[4])
		self.assertTrue(re.search(r'Unexpected keys ("rick"|"morty"), ("rick"|"morty").*reducer.*instead: ("foo"|"baz"), ("foo"|"baz")', m))

		reducer(1)
		m = str(logging.call_args_list[5])
		self.assertTrue(re.search(r'reducer has an unexpected type of <class "int">', m))
예제 #11
0
	def test_maintains_referential_equality_if_reducers_it_combines_does(self):
		def child_1(state=None, action=None):
			state = {} if state is None else state
			return state
		def child_2(state=None, action=None):
			state = {} if state is None else state
			return state
		def child_3(state=None, action=None):
			state = {} if state is None else state
			return state
		reducer = combine_reducers({
			'child_1': child_1,
			'child_2': child_2,
			'child_3': child_3
		})
		
		initial_state = reducer(None, '@@INIT')
		self.assertEqual(reducer(initial_state, { 'type': 'FOO' }), initial_state)
예제 #12
0
	def test_only_warns_for_unexpected_keys_once(self, logging):
		def foo(state=None, action=None):
			return { 'foo': 1 }
		def bar(state=None, action=None):
			return { 'bar': 2 }
		
		self.assertEqual(len(logging.call_args_list), 0)
		reducer = combine_reducers(dict(foo=foo, bar=bar))
		state = dict(foo=1, bar=2, qux=3)
		reducer(state, {})
		reducer(state, {})
		reducer(state, {})
		reducer(state, {})
		self.assertEqual(len(logging.call_args_list), 1)
		reducer(dict(baz=5, **state), {})
		reducer(dict(baz=5, **state), {})
		reducer(dict(baz=5, **state), {})
		reducer(dict(baz=5, **state), {})
		self.assertEqual(len(logging.call_args_list), 2)		
예제 #13
0
	def test_throws_error_if_reducer_attempts_to_handle_a_private_action(self):
		def counter(state=None, action=None):
			if action is None:
				action = {}
			if state is None:
				state = 0
			if action.get('type') == 'increment':
				return state + 1
			if action.get('type') == 'decrement':
				return state - 1
			# Never do this
			if action.get('type') == ACTION_TYPES['INIT']:
				return 0
			return None
		
		reducer = combine_reducers({ 'counter': counter })
		with self.assertRaises(Exception) as e:
			reducer()
		self.assertTrue('counter' in str(e.exception) and 'private' in str(e.exception))
예제 #14
0
	def test_returns_reducer_that_maps_state_keys_to_given_reducers(self):
		def counter(state=None, action={}):
			if state is None:
				state = 0
			if action.get('type') == 'increment':
				return state + 1
			return state
		
		def stack(state=None, action={}):
			if state is None: state = []
			if action.get('type') == 'push':
				return list(state) + [action.get('value')]
			return state
		
		reducer = combine_reducers({
			'counter': counter,
			'stack': stack
		})
		s1 = reducer({}, { 'type': 'increment' })
		self.assertEqual(s1, { 'counter': 1, 'stack': []})
		s2 = reducer(s1, { 'type': 'push', 'value': 'a' })
		self.assertEqual(s2, { 'counter': 1, 'stack': [ 'a' ] })