Skip to content
This repository was archived by the owner on Apr 19, 2024. It is now read-only.

Commit c2e2f1a

Browse files
authored
Merge pull request #2 from rodolfo2488/add-redux
Add redux
2 parents c684701 + 322abc7 commit c2e2f1a

File tree

17 files changed

+340
-32
lines changed

17 files changed

+340
-32
lines changed

package.json

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@
1919
"devDependencies": {
2020
"@types/enzyme": "^2.7.7",
2121
"@types/jasmine": "^2.5.47",
22+
"@types/jest": "19.2.2",
23+
"@types/react": "^15.0.21",
24+
"@types/react-addons-test-utils": "0.14.18",
25+
"@types/react-dom": "^15.5.0",
26+
"@types/react-redux": "^4.4.38",
27+
"@types/redux": "3.6.0",
28+
"@types/redux-actions": "^1.2.3",
29+
"@types/redux-logger": "^3.0.0",
2230
"awesome-typescript-loader": "^3.1.2",
2331
"cross-env": "4.0.0",
2432
"enzyme": "^2.8.0",
@@ -29,20 +37,22 @@
2937
"karma-chrome-launcher": "^2.0.0",
3038
"karma-typescript": "^3.0.0",
3139
"karma-typescript-preprocessor": "^0.3.1",
32-
"react-addons-test-utils": "^15.5.1",
40+
"react-addons-test-utils": "15.5.1",
3341
"react-hot-loader": "1.3.1",
42+
"redux-actions": "2.0.2",
3443
"source-map-loader": "^0.2.1",
3544
"stylelint-webpack-plugin": "0.7.0",
36-
"typescript": "^2.2.2",
45+
"typescript": "^2.3.0",
3746
"webpack-dev-server": "^2.4.2",
3847
"webpack-merge": "4.1.0",
3948
"write-file-webpack-plugin": "4.0.2"
4049
},
4150
"dependencies": {
42-
"@types/react": "^15.0.21",
43-
"@types/react-dom": "^0.14.23",
4451
"react": "^15.5.3",
4552
"react-dom": "^15.5.3",
53+
"react-redux": "5.0.4",
54+
"redux": "3.6.0",
55+
"redux-logger": "3.0.1",
4656
"webpack": "^2.3.3"
4757
},
4858
"jest": {

preprocessor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const tsc = require('typescript');
2-
const tsConfig = require('./tsconfig.json');
2+
const tsConfig = require('./testUtils/tsconfig.json');
33

44
module.exports = {
55
process(src, path) {

src/Hello/Hello.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as React from "react";
2+
3+
import {connect, Dispatch} from "react-redux";
4+
import {bindActionCreators} from "redux";
5+
6+
import Counter from "./containers/Counter";
7+
import {IRootState} from "../rootReducer";
8+
import actions from "./actions";
9+
10+
export interface HelloProps {
11+
counter: number,
12+
actions: typeof actions
13+
}
14+
15+
export class Hello extends React.Component<HelloProps, void> {
16+
constructor(props: HelloProps) {
17+
super(props);
18+
19+
this.increment = this.increment.bind(this);
20+
this.decrement = this.decrement.bind(this);
21+
}
22+
23+
increment() {
24+
this.props.actions.incrementAction();
25+
}
26+
27+
decrement() {
28+
this.props.actions.decrementAction();
29+
}
30+
31+
render() {
32+
return <div>
33+
<h1>Hello typescript and react!</h1>
34+
<Counter
35+
counter={this.props.counter}
36+
decrement={this.decrement}
37+
increment={this.increment}
38+
/>
39+
</div>;
40+
}
41+
}
42+
43+
export const mapStateToProps = (state: IRootState) => {
44+
return state.counters;
45+
};
46+
47+
export const mapDispatchToProps = (dispatch: Dispatch<{}>) => {
48+
return {
49+
actions: bindActionCreators(actions, dispatch)
50+
}
51+
};
52+
53+
export default connect<any, any, any>(mapStateToProps, mapDispatchToProps)(Hello)

src/Hello/__test__/actions.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {actionTypes, default as actions} from "../actions";
2+
3+
describe("incrementAction", () => {
4+
it("returns action of type increment", () => {
5+
let action = {
6+
type: actionTypes.INCREMENT.toString()
7+
};
8+
expect(actions.incrementAction()).toEqual(action);
9+
});
10+
});
11+
12+
describe("decrementAction", () => {
13+
it("returns action of type decrement", () => {
14+
let action = {
15+
type: actionTypes.DECREMENT.toString()
16+
};
17+
expect(actions.decrementAction()).toEqual(action);
18+
});
19+
});

src/Hello/__test__/hello.test.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
jest.mock("../actions");
2+
3+
import * as React from "react";
4+
import {shallow, ShallowWrapper} from "enzyme";
5+
import {Dispatch} from "react-redux";
6+
import { ActionFunction0, Action } from "redux-actions";
7+
8+
import {Hello, HelloProps, mapDispatchToProps, mapStateToProps} from "../Hello";
9+
import Counter from "../containers/Counter";
10+
import {IRootState} from "../../rootReducer";
11+
import {incrementAction, decrementAction} from "../actions";
12+
13+
14+
describe("Hello Component", () => {
15+
let helloComponent: ShallowWrapper<Hello, any>;
16+
let props: HelloProps;
17+
let increment: ActionFunction0<Action<void>>;
18+
let decrement: ActionFunction0<Action<void>>;
19+
20+
beforeEach(() => {
21+
increment = jest.fn();
22+
decrement = jest.fn();
23+
props = {
24+
counter: 2,
25+
actions: {
26+
incrementAction: increment,
27+
decrementAction: decrement
28+
}
29+
} as HelloProps;
30+
31+
helloComponent = shallow(<Hello actions={props.actions} counter={props.counter} />);
32+
});
33+
34+
it("says hello", () => {
35+
expect(helloComponent.find("h1").text()).toContain("Hello typescript and react!");
36+
});
37+
38+
describe("Counter component", () => {
39+
it("shows the counter component", () => {
40+
expect(helloComponent.find(Counter).length).toEqual(1);
41+
});
42+
43+
it("passes counter property", () => {
44+
expect(helloComponent.find(Counter).props().counter).toEqual(2);
45+
});
46+
47+
it("passes functions of increment the counter", () => {
48+
helloComponent.find(Counter).props().increment();
49+
expect(increment).toBeCalled();
50+
});
51+
52+
it("passes functions of decrement the counter", () => {
53+
helloComponent.find(Counter).props().decrement();
54+
expect(decrement).toBeCalled();
55+
});
56+
});
57+
58+
describe("mapStateToProps", () => {
59+
it("maps the counter from the state", () => {
60+
const counters: any = {
61+
counter: 1
62+
};
63+
64+
const state: IRootState = {
65+
counters: counters
66+
};
67+
68+
let props = mapStateToProps(state);
69+
70+
expect(props.counter).toBe(1);
71+
});
72+
});
73+
74+
describe("mapDispatchToProps", () => {
75+
it("maps action functions to decrement the counter", () => {
76+
decrementAction.mockReturnValue("you are going down, sorry!");
77+
let dispatch: Dispatch<{}> = jest.fn();
78+
79+
let props = mapDispatchToProps(dispatch);
80+
props.actions.decrementAction();
81+
82+
expect(decrementAction).toBeCalled();
83+
expect(dispatch).toBeCalledWith("you are going down, sorry!");
84+
});
85+
86+
it("maps action functions to increment the counter", () => {
87+
incrementAction.mockReturnValue("you are going up, congratulations!");
88+
let dispatch: Dispatch<{}> = jest.fn();
89+
90+
let props = mapDispatchToProps(dispatch);
91+
props.actions.incrementAction();
92+
93+
expect(incrementAction).toBeCalled();
94+
expect(dispatch).toBeCalledWith("you are going up, congratulations!");
95+
});
96+
});
97+
});

src/Hello/actions.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {createAction} from "redux-actions";
2+
3+
export enum actionTypes {
4+
INCREMENT,
5+
DECREMENT
6+
}
7+
8+
export const incrementAction = createAction<void>(
9+
actionTypes.INCREMENT.toString(),
10+
() => {
11+
}
12+
);
13+
14+
export const decrementAction = createAction<void>(
15+
actionTypes.DECREMENT.toString(),
16+
() => {
17+
}
18+
);
19+
20+
export default {
21+
decrementAction,
22+
incrementAction
23+
}

src/Hello/containers/Counter.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as React from 'react';
2+
import DefaultState from "../interfaces/defaultState"
3+
4+
export interface IProps extends DefaultState {
5+
increment(): void;
6+
decrement(): void;
7+
}
8+
9+
const Counter = (props: IProps) => {
10+
const { counter, increment, decrement } = props;
11+
12+
return (
13+
<div>
14+
<p>Counter: {counter}</p>
15+
<button onClick={increment} label="Increment" id="increment"/>
16+
<button onClick={decrement} label="Decrement" id="decrement"/>
17+
</div>
18+
);
19+
};
20+
21+
export default Counter;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as React from "react";
2+
import {shallow} from "enzyme";
3+
4+
import Counter from "../Counter";
5+
6+
describe("counter container", () => {
7+
let subject: any,
8+
mockIncrement: () => {},
9+
mockDecrement: () => {};
10+
beforeEach(() => {
11+
mockIncrement = jest.fn();
12+
mockDecrement = jest.fn();
13+
subject = shallow(<Counter increment={mockIncrement} decrement={mockDecrement} counter={1}/>);
14+
});
15+
16+
it("it shows the counter", () => {
17+
expect(subject.text()).toContain("1");
18+
});
19+
20+
it("clicking on the increment button call property increment", () => {
21+
subject.find("#increment").props().onClick();
22+
23+
expect(mockIncrement).toBeCalled();
24+
});
25+
26+
it("clicking on the decrement button call property decrement", () => {
27+
subject.find("#decrement").props().onClick();
28+
29+
expect(mockDecrement).toBeCalled();
30+
});
31+
});

src/Hello/interfaces/defaultState.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
interface DefaultState {
2+
readonly counter: number
3+
}
4+
5+
export default DefaultState;

src/Hello/reducer.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { handleActions, Action } from "redux-actions";
2+
import { actionTypes } from "./actions";
3+
import DefaultState from "./interfaces/defaultState";
4+
5+
const initialState: DefaultState = {
6+
counter: 0
7+
};
8+
9+
export default handleActions<DefaultState, void>({
10+
[actionTypes.INCREMENT.toString()]: (state: DefaultState, action: Action<void>): DefaultState => {
11+
return {
12+
counter: state.counter + 1
13+
};
14+
},
15+
[actionTypes.DECREMENT.toString()]: (state: DefaultState, action: Action<void>): DefaultState => {
16+
return {
17+
counter: state.counter - 1
18+
};
19+
},
20+
}, initialState);

0 commit comments

Comments
 (0)