Skip to content

Commit

Permalink
feat#31 implement: dispatched action logs for debugging
Browse files Browse the repository at this point in the history
  • Loading branch information
qkreltms committed Jan 17, 2021
1 parent 6d790ac commit 36433ca
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 9 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ return <button onClick={onClickPlus}>add</button>;
```ts
import { createMiddleware, useActionListener } from 'react-action-listener';
// Note: you must provide config.isContext = true;
const middleware = createMiddleware({ isContext: true });
// Note: you must provide config.isContext = true
// You will able to see redux-logger style logs for dispatched action when you provide isDebugContext = true
const middleware = createMiddleware({ isContext: true, isDebugContext: true });

const [state, dispatch] = useReducer(counterReducer, initialValues);

Expand Down
17 changes: 16 additions & 1 deletion src/listenerMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AnyAction, Dispatch, Store } from 'redux';
import reactAdapter from './react/adapter';
import getUniqueHash from './utills/generateUniqueId';
import formatTime from './utills/time';

export type ListenerActionType = string | Array<string>;
export interface ListenerAction extends AnyAction {
Expand Down Expand Up @@ -56,19 +57,33 @@ export interface ListenerStore
}

interface MiddlewareConfig {
isContext: boolean;
isContext?: boolean;
isDebugContext?: boolean;
}
export interface CreateMiddleware {
(config?: MiddlewareConfig): ListenerStore;
}

const createMiddleware: CreateMiddleware = (config) => {
const actionHandler = new ActionHandler();
const timeStyles = `color: gray; font-weight: lighter;`;
const actionTitleStyles = `color: '#03A9F4'; font-weight: bold`;

const middleware: any = config?.isContext
? (action: DispatchedActionWithType) => {
Object.values(actionHandler.listeners)
.filter(({ type }) => {
if (config.isDebugContext) {
const time = formatTime(new Date());
console.group();
console.log(`${action.type} %c@`, timeStyles, time);
console.log(
'%c action ',
actionTitleStyles,
JSON.stringify(action)
);
console.groupEnd();
}
if (type === action.type) {
return true;
}
Expand Down
11 changes: 11 additions & 0 deletions src/utills/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const repeat = (str: string, times: number) =>
new Array(times + 1).join(str);

export const pad = (num: number, maxLength: number) =>
repeat('0', maxLength - num.toString().length) + num;

export default (time: Date) =>
`${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(
time.getSeconds(),
2
)}.${pad(time.getMilliseconds(), 3)}`;
89 changes: 89 additions & 0 deletions test/react/context/components/DebugCouter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { createContext, useReducer, Dispatch, useContext } from 'react';
import { AnyAction } from 'redux';
import { useActionListener } from '../../../../src';
import middleware from '../middlewares/debugMiddleware';

interface CounterState {
cnt: number;
}
interface CounterActions {
increase: () => void;
substract: () => void;
}
type CounterReducer = (state: CounterState, action: AnyAction) => CounterState;
interface CounterContextValues extends CounterState, CounterActions {}

const counterReducer = (
state: CounterState,
action: AnyAction
): CounterState => {
switch (action.type) {
case 'INCREASE':
return {
...state,
cnt: state.cnt + action.payload,
};
case 'SUB':
return {
...state,
cnt: state.cnt - action.payload,
};
default:
return state;
}
};

function increaseAction(dispatch: Dispatch<AnyAction>) {
const action = {
type: 'INCREASE',
payload: 1,
};

middleware(action);
dispatch(action);
}
function subAction(dispatch: Dispatch<AnyAction>) {
const action = {
type: 'SUB',
payload: 1,
};
middleware(action);
dispatch(action);
}
const initialValues: CounterState & CounterActions = {
cnt: 0,
increase: () => {},
substract: () => {},
};
export const CounterContext = createContext<CounterContextValues>(
initialValues
);
export function CounterProvider({ children }: { children: any }) {
const [state, dispatch] = useReducer<CounterReducer>(
counterReducer,
initialValues
);
const actions: CounterActions = {
increase: () => increaseAction(dispatch),
substract: () => subAction(dispatch),
};
return (
<CounterContext.Provider value={{ ...state, ...actions }}>
{children}
</CounterContext.Provider>
);
}

export function Counter() {
const { cnt, increase, substract } = useContext(CounterContext);
return (
<>
<button type="button" onClick={() => increase()} data-testid="cnt">
{cnt}
</button>
<button type="button" onClick={() => substract()} data-testid="sub">
sub
</button>
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { createContext, useReducer, Dispatch, useContext } from 'react';
import { AnyAction } from 'redux';
import { useActionListener } from '../../../../src';
import middleware from '../middleware';
import middleware from '../middlewares/middleware';

interface CounterState {
cnt: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { createContext, useReducer, Dispatch, useContext } from 'react';
import { AnyAction } from 'redux';
import { useActionListener } from '../../../../src';
import middleware from '../middleware';
import middleware from '../middlewares/middleware';

interface CounterState {
cnt: number;
Expand Down
30 changes: 30 additions & 0 deletions test/react/context/debugListenerMiddleware.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
import debugMiddleware from './middlewares/debugMiddleware';
import {
CounterProvider as DebugCounterProvider,
Counter as DebugCounter,
} from './components/DebugCouter';

beforeAll(() => {});
afterEach(() => {
cleanup();
debugMiddleware.cleanup();
jest.clearAllMocks();
});
afterAll(() => {});

test('Should logs are called when isDebugContext = true', () => {
const spy = jest.spyOn(console, 'log');

render(
<DebugCounterProvider>
<DebugCounter />
</DebugCounterProvider>
);
const button = screen.getByTestId('cnt');
debugMiddleware.addListener('INCREASE', (action) => {});
fireEvent.click(button);

expect(spy).toBeCalledTimes(2);
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {
Counter,
CounterWithHook,
CounterWithHookAndDispatch,
} from './context/components/MiddlewareOnReducerCounter';
import { CounterWithHookAndDispatch2 } from './context/components/MiddlewareBeforeDispatchCounter';
import middleware from './context/middleware';
} from './components/MiddlewareOnReducerCounter';
import { CounterWithHookAndDispatch2 } from './components/MiddlewareBeforeDispatchCounter';
import middleware from './middlewares/middleware';

beforeAll(() => {});
afterEach(() => {
Expand Down
5 changes: 5 additions & 0 deletions test/react/context/middlewares/debugMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createMiddleware } from '../../../../src';

// gloabl middleware
const middleware = createMiddleware({ isContext: true, isDebugContext: true });
export default middleware;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createMiddleware } from '../../../src';
import { createMiddleware } from '../../../../src';

// gloabl middleware
const middleware = createMiddleware({ isContext: true });
Expand Down

0 comments on commit 36433ca

Please sign in to comment.