From 67f74caa629dc25cdbe90b033be8acf13ad2d57f Mon Sep 17 00:00:00 2001
From: Jonas Snellinckx
Date: Tue, 8 Dec 2020 21:11:59 +0100
Subject: [PATCH 1/2] fix: align enhancer style with standards to wrap the
middleware
---
src/mainStateSyncEnhancer.ts | 29 ++++++++++++++++++----
src/rendererStateSyncEnhancer.ts | 41 ++++++++++++++++++++++----------
tests/counter.ts | 10 +++++++-
tests/e2e.spec.ts | 33 +++++++++++++++++++++++++
tests/e2e/main/index.ts | 17 ++++++++++---
tests/e2e/renderer/index.ts | 23 ++++++++++++++++--
tests/middleware.ts | 8 +++++++
7 files changed, 138 insertions(+), 23 deletions(-)
create mode 100644 tests/middleware.ts
diff --git a/src/mainStateSyncEnhancer.ts b/src/mainStateSyncEnhancer.ts
index 08aeb6e8..8827e87d 100644
--- a/src/mainStateSyncEnhancer.ts
+++ b/src/mainStateSyncEnhancer.ts
@@ -1,11 +1,18 @@
import { ipcMain, webContents } from 'electron'
-import { Action, applyMiddleware, Middleware, StoreCreator, StoreEnhancer } from 'redux'
+import {
+ Action,
+ compose,
+ Dispatch,
+ Middleware,
+ MiddlewareAPI,
+ StoreCreator,
+ StoreEnhancer,
+} from 'redux'
import { IPCEvents } from './constants'
import {
defaultMainOptions,
MainStateSyncEnhancerOptions,
} from './options/MainStateSyncEnhancerOptions'
-
import { preventDoubleInitialization, stopForwarding, validateAction } from './utils'
function createMiddleware(options: MainStateSyncEnhancerOptions) {
@@ -60,7 +67,21 @@ export const mainStateSyncEnhancer = (options = defaultMainOptions): StoreEnhanc
) => {
preventDoubleInitialization()
const middleware = createMiddleware(options)
- return (reducer, state) => {
- return createStore(reducer, state, applyMiddleware(middleware))
+ return (reducer, preloadedState) => {
+ const store = createStore(reducer, preloadedState)
+
+ let dispatch = store.dispatch
+
+ const middlewareAPI: MiddlewareAPI> = {
+ getState: store.getState,
+ dispatch,
+ }
+
+ dispatch = compose(middleware(middlewareAPI))(store.dispatch)
+
+ return {
+ ...store,
+ dispatch,
+ }
}
}
diff --git a/src/rendererStateSyncEnhancer.ts b/src/rendererStateSyncEnhancer.ts
index ca49331e..ccd35194 100644
--- a/src/rendererStateSyncEnhancer.ts
+++ b/src/rendererStateSyncEnhancer.ts
@@ -1,10 +1,20 @@
import { ipcRenderer } from 'electron'
-import { Action, applyMiddleware, Middleware, StoreCreator, StoreEnhancer } from 'redux'
+import {
+ Action,
+ compose,
+ Dispatch,
+ Middleware,
+ MiddlewareAPI,
+ StoreCreator,
+ StoreEnhancer,
+} from 'redux'
import { IPCEvents } from './constants'
import { fetchInitialState, fetchInitialStateAsync } from './fetchState'
import { replaceState, withStoreReplacer } from './fetchState/replaceState'
-import { defaultRendererOptions, RendererStateSyncEnhancerOptions } from './options/RendererStateSyncEnhancerOptions'
-
+import {
+ defaultRendererOptions,
+ RendererStateSyncEnhancerOptions,
+} from './options/RendererStateSyncEnhancerOptions'
import { preventDoubleInitialization, stopForwarding, validateAction } from './utils'
const createMiddleware = (options: RendererStateSyncEnhancerOptions): Middleware => (store) => {
@@ -35,11 +45,12 @@ export const rendererStateSyncEnhancer = (options = defaultRendererOptions): Sto
preventDoubleInitialization()
return (reducer, state) => {
+ const middleware = createMiddleware(options)
+
const initialState = options.lazyInit ? state : fetchInitialState(options)
const store = createStore(
options.lazyInit ? withStoreReplacer(reducer) : reducer,
- initialState,
- applyMiddleware(createMiddleware(options))
+ initialState
)
if (options.lazyInit) {
@@ -48,14 +59,18 @@ export const rendererStateSyncEnhancer = (options = defaultRendererOptions): Sto
})
}
- // TODO: this needs some ❤️
- // XXX: TypeScript is dumb. If you return the call to createStore
- // immediately it's fine, but even assigning it to a constant and returning
- // will make it freak out. We fix this with the line below the return.
- return store
+ let dispatch = store.dispatch
+
+ const middlewareAPI: MiddlewareAPI> = {
+ getState: store.getState,
+ dispatch,
+ }
+
+ dispatch = compose(middleware(middlewareAPI))(store.dispatch)
- // TODO: this needs some ❤️
- // XXX: Even though this is unreachable, it fixes the type signature????
- return (store as unknown) as any
+ return {
+ ...store,
+ dispatch,
+ }
}
}
diff --git a/tests/counter.ts b/tests/counter.ts
index 92458747..8862494c 100644
--- a/tests/counter.ts
+++ b/tests/counter.ts
@@ -8,6 +8,7 @@ const init: CounterState = {
const INCREMENT = 'INCREMENT'
const DECREMENT = 'DECREMENT'
+const SET_COUNT_MIDDLEWARE = 'SET_COUNT_MIDDLEWARE'
type IncrementAction = {
type: typeof INCREMENT
@@ -17,7 +18,12 @@ type DecrementAction = {
type: typeof DECREMENT
}
-export type Actions = IncrementAction | DecrementAction
+type SetCountMiddlewareAction = {
+ type: typeof SET_COUNT_MIDDLEWARE
+ payload: number
+}
+
+export type Actions = IncrementAction | DecrementAction | SetCountMiddlewareAction
export const reducer = (state = init, action: Actions): CounterState => {
switch (action.type) {
@@ -25,6 +31,8 @@ export const reducer = (state = init, action: Actions): CounterState => {
return { ...state, count: state.count + 1 }
case DECREMENT:
return { ...state, count: state.count - 1 }
+ case SET_COUNT_MIDDLEWARE:
+ return { ...state, count: action.payload }
default:
return state
}
diff --git a/tests/e2e.spec.ts b/tests/e2e.spec.ts
index 40a0a11f..48f218fb 100644
--- a/tests/e2e.spec.ts
+++ b/tests/e2e.spec.ts
@@ -48,4 +48,37 @@ describe('End to End Tests', () => {
// eslint-disable-next-line @typescript-eslint/await-thenable
expect(await app.browserWindow.getTitle()).toEqual('9')
})
+
+ it('should be able to increment value from main process', async () => {
+ expect(await getText('#value')).toEqual('10')
+ expect(await app.browserWindow.getTitle()).toEqual('10')
+
+ await click('#mainIncrement')
+
+ expect(await getText('#value')).toEqual('11')
+ // eslint-disable-next-line @typescript-eslint/await-thenable
+ expect(await app.browserWindow.getTitle()).toEqual('11')
+ })
+
+ it('should be able to use middleware when dispatching from renderer process', async () => {
+ expect(await getText('#value')).toEqual('10')
+ expect(await app.browserWindow.getTitle()).toEqual('10')
+
+ await click('#setCountMiddleware')
+
+ expect(await getText('#value')).toEqual('99')
+ // eslint-disable-next-line @typescript-eslint/await-thenable
+ expect(await app.browserWindow.getTitle()).toEqual('99')
+ })
+
+ it('should be able to use middleware when dispatching from main process', async () => {
+ expect(await getText('#value')).toEqual('10')
+ expect(await app.browserWindow.getTitle()).toEqual('10')
+
+ await click('#mainsetCountMiddleware')
+
+ expect(await getText('#value')).toEqual('99')
+ // eslint-disable-next-line @typescript-eslint/await-thenable
+ expect(await app.browserWindow.getTitle()).toEqual('99')
+ })
})
diff --git a/tests/e2e/main/index.ts b/tests/e2e/main/index.ts
index 2591aa2c..15911886 100644
--- a/tests/e2e/main/index.ts
+++ b/tests/e2e/main/index.ts
@@ -1,9 +1,10 @@
import path from 'path'
import url from 'url'
-import { app, BrowserWindow } from 'electron'
-import { createStore } from 'redux'
+import { app, BrowserWindow, ipcMain } from 'electron'
+import { applyMiddleware, compose, createStore } from 'redux'
import { reducer } from '../../counter'
import { mainStateSyncEnhancer } from '../../..'
+import { countMiddleware } from '../../middleware'
const isDevelopment = process.env.NODE_ENV !== 'production'
@@ -11,7 +12,9 @@ const defaultState = {
count: 10,
}
-const store = createStore(reducer, defaultState, mainStateSyncEnhancer())
+const middleware = applyMiddleware(countMiddleware)
+const enhancer = compose(middleware, mainStateSyncEnhancer())
+const store = createStore(reducer, defaultState, enhancer)
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
@@ -44,6 +47,14 @@ function createWindow() {
}
renderValue()
+ ipcMain.once('mainsetCountMiddleware', () => {
+ store.dispatch({ type: 'SET_COUNT_MIDDLEWARE', payload: 9 })
+ })
+
+ ipcMain.once('mainIncrement', () => {
+ store.dispatch({ type: 'INCREMENT' })
+ })
+
// Emitted when the window is closed.
mainWindow.on('closed', () => {
// Dereference the window object, usually you would store windows
diff --git a/tests/e2e/renderer/index.ts b/tests/e2e/renderer/index.ts
index dfe447a1..3c9a2f83 100644
--- a/tests/e2e/renderer/index.ts
+++ b/tests/e2e/renderer/index.ts
@@ -1,8 +1,13 @@
-import { createStore } from 'redux'
+import { applyMiddleware, compose, createStore } from 'redux'
import { reducer } from '../../counter'
import { rendererStateSyncEnhancer } from '../../../'
+import { countMiddleware } from '../../middleware'
+import { ipcRenderer } from 'electron'
-const store = createStore(reducer, rendererStateSyncEnhancer())
+const middleware = applyMiddleware(countMiddleware)
+const enhancer = compose(middleware, rendererStateSyncEnhancer())
+
+const store = createStore(reducer, enhancer)
function mount() {
document.getElementById('app')!.innerHTML = `
@@ -10,6 +15,10 @@ function mount() {
Clicked: 0 times
+
+
+
+
`
@@ -20,6 +29,16 @@ function mount() {
document.getElementById('decrement')!.addEventListener('click', () => {
store.dispatch({ type: 'DECREMENT' })
})
+
+ document.getElementById('setCountMiddleware')!.addEventListener('click', () => {
+ store.dispatch({ type: 'SET_COUNT_MIDDLEWARE', payload: 9 })
+ })
+ document.getElementById('mainsetCountMiddleware')!.addEventListener('click', () => {
+ ipcRenderer.send('mainsetCountMiddleware')
+ })
+ document.getElementById('mainIncrement')!.addEventListener('click', () => {
+ ipcRenderer.send('mainIncrement')
+ })
}
function renderValue() {
diff --git a/tests/middleware.ts b/tests/middleware.ts
new file mode 100644
index 00000000..934698f1
--- /dev/null
+++ b/tests/middleware.ts
@@ -0,0 +1,8 @@
+import { Middleware } from 'redux'
+
+export const countMiddleware: Middleware = () => (next) => (action) => {
+ return next({
+ ...action,
+ payload: 99,
+ })
+}
From 9dce953d23af7703caeac672bb8ba4b0ff45abf6 Mon Sep 17 00:00:00 2001
From: Jonas Snellinckx
Date: Tue, 8 Dec 2020 21:27:56 +0100
Subject: [PATCH 2/2] fix: align enhancer style with standards to wrap the
middleware
---
src/mainStateSyncEnhancer.ts | 2 +-
src/rendererStateSyncEnhancer.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mainStateSyncEnhancer.ts b/src/mainStateSyncEnhancer.ts
index 8827e87d..f175f3c5 100644
--- a/src/mainStateSyncEnhancer.ts
+++ b/src/mainStateSyncEnhancer.ts
@@ -77,7 +77,7 @@ export const mainStateSyncEnhancer = (options = defaultMainOptions): StoreEnhanc
dispatch,
}
- dispatch = compose(middleware(middlewareAPI))(store.dispatch)
+ dispatch = compose(middleware(middlewareAPI))(dispatch)
return {
...store,
diff --git a/src/rendererStateSyncEnhancer.ts b/src/rendererStateSyncEnhancer.ts
index ccd35194..0c6df751 100644
--- a/src/rendererStateSyncEnhancer.ts
+++ b/src/rendererStateSyncEnhancer.ts
@@ -66,7 +66,7 @@ export const rendererStateSyncEnhancer = (options = defaultRendererOptions): Sto
dispatch,
}
- dispatch = compose(middleware(middlewareAPI))(store.dispatch)
+ dispatch = compose(middleware(middlewareAPI))(dispatch)
return {
...store,