Skip to content

Commit

Permalink
fix: align enhancer style with standards to wrap the middleware (#284)
Browse files Browse the repository at this point in the history
* fix: align enhancer style with standards to wrap the middleware

* fix: align enhancer style with standards to wrap the middleware
  • Loading branch information
sneljo1 committed Jan 13, 2021
1 parent aa07110 commit 9778605
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 23 deletions.
29 changes: 25 additions & 4 deletions src/mainStateSyncEnhancer.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down Expand Up @@ -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<Dispatch<any>> = {
getState: store.getState,
dispatch,
}

dispatch = compose<Dispatch>(middleware(middlewareAPI))(dispatch)

return {
...store,
dispatch,
}
}
}
41 changes: 28 additions & 13 deletions src/rendererStateSyncEnhancer.ts
Original file line number Diff line number Diff line change
@@ -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) => {
Expand Down Expand Up @@ -35,11 +45,12 @@ export const rendererStateSyncEnhancer = (options = defaultRendererOptions): Sto
preventDoubleInitialization()

return (reducer, state) => {
const middleware = createMiddleware(options)

const initialState = options.lazyInit ? state : fetchInitialState<typeof state>(options)
const store = createStore(
options.lazyInit ? withStoreReplacer(reducer) : reducer,
initialState,
applyMiddleware(createMiddleware(options))
initialState
)

if (options.lazyInit) {
Expand All @@ -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<Dispatch<any>> = {
getState: store.getState,
dispatch,
}

dispatch = compose<Dispatch>(middleware(middlewareAPI))(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,
}
}
}
10 changes: 9 additions & 1 deletion tests/counter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -17,14 +18,21 @@ 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) {
case INCREMENT:
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
}
Expand Down
33 changes: 33 additions & 0 deletions tests/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
})
})
17 changes: 14 additions & 3 deletions tests/e2e/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
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'

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.
Expand Down Expand Up @@ -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
Expand Down
23 changes: 21 additions & 2 deletions tests/e2e/renderer/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
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 = `
<p>
Clicked: <span id="value">0</span> times </br>
<button id="increment">+</button>
<button id="decrement">-</button>
<button id="setCountMiddleware">#</button>
<button id="mainsetCountMiddleware">#</button>
<button id="mainIncrement">#</button>
</p>
`

Expand All @@ -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() {
Expand Down
8 changes: 8 additions & 0 deletions tests/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Middleware } from 'redux'

export const countMiddleware: Middleware = () => (next) => (action) => {
return next({
...action,
payload: 99,
})
}

0 comments on commit 9778605

Please sign in to comment.