index.test.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { describe, expect, it } from 'vitest'
  2. import Redux from 'redux'
  3. import { ReduxStore, reducer } from './index.js'
  4. describe('ReduxStore', () => {
  5. function createStore (reducers = {}) {
  6. const combinedReducers = Redux.combineReducers({ ...reducers, uppy: reducer })
  7. return Redux.createStore(combinedReducers)
  8. }
  9. it('can be created with named or default import', () => {
  10. const r = createStore()
  11. let store = new ReduxStore({ store: r })
  12. expect(typeof store).toBe('object')
  13. store = new ReduxStore({ store: r })
  14. expect(typeof store).toBe('object')
  15. })
  16. it('merges in state using `setState`', () => {
  17. const r = createStore()
  18. const store = new ReduxStore({ store: r })
  19. expect(store.getState()).toEqual({})
  20. store.setState({
  21. a: 1,
  22. b: 2,
  23. })
  24. expect(store.getState()).toEqual({ a: 1, b: 2 })
  25. store.setState({ b: 3 })
  26. expect(store.getState()).toEqual({ a: 1, b: 3 })
  27. })
  28. it('notifies subscriptions when state changes', () => {
  29. let expected = []
  30. let calls = 0
  31. function listener (prevState, nextState, patch) {
  32. calls++
  33. expect([prevState, nextState, patch]).toEqual(expected)
  34. }
  35. const r = createStore()
  36. const store = new ReduxStore({ store: r })
  37. store.subscribe(listener)
  38. expected = [{}, { a: 1, b: 2 }, { a: 1, b: 2 }]
  39. store.setState({
  40. a: 1,
  41. b: 2,
  42. })
  43. expected = [{ a: 1, b: 2 }, { a: 1, b: 3 }, { b: 3 }]
  44. store.setState({ b: 3 })
  45. expect(calls).toBe(2)
  46. })
  47. it('fires `subscribe` if state is modified externally (eg redux devtools)', () => {
  48. const combinedReducers = Redux.combineReducers({ uppy: reducer })
  49. const r = Redux.createStore((state, action) => {
  50. // Add a `SET` action that can change Uppy state without going through the Uppy reducer or action creator.
  51. // Emulates Redux Devtools.
  52. if (action.type === 'SET') return action.payload
  53. return combinedReducers(state, action)
  54. })
  55. let expected = []
  56. let calls = 0
  57. function listener (prevState, nextState, patch) {
  58. calls++
  59. expect([prevState, nextState, patch]).toEqual(expected)
  60. }
  61. const store = new ReduxStore({ store: r })
  62. store.subscribe(listener)
  63. expected = [{}, { a: 1 }, { a: 1 }]
  64. store.setState({ a: 1 })
  65. expected = [{ a: 1 }, { b: 2 }, { b: 2 }]
  66. // redux-devtools's `JUMP_TO_STATE` is similar to this.
  67. r.dispatch({
  68. type: 'SET',
  69. payload: {
  70. uppy: {
  71. [store[Symbol.for('uppy test: get id')]()]: { b: 2 },
  72. },
  73. },
  74. })
  75. expect(calls).toBe(2)
  76. })
  77. it('can mount in a custom state key', () => {
  78. const combinedReducers = Redux.combineReducers({
  79. hello: reducer,
  80. })
  81. const r = Redux.createStore(combinedReducers)
  82. const store = new ReduxStore({
  83. store: r,
  84. id: 'world',
  85. selector: state => state.hello.world,
  86. })
  87. store.setState({ a: 1 })
  88. expect(r.getState()).toEqual({
  89. hello: {
  90. world: {
  91. a: 1,
  92. },
  93. },
  94. })
  95. })
  96. })