Edited and formatted by ericwm76
Eric's gist https://gist.github.com/ericwm76/e1204fc03f14af4429add8225ff55f71
- In the terminal run:
npx create-react-app NAME-OF-APP
- Cd into the new directory:
cd NAME-OF-APP
- Run:
npm install
. - You can run
npm start
to see if the app was set up correctly.
npm i redux react-redux redux-devtools-extension -S
- redux - Allows us to have access to using Redux in our app.
- react-redux - Allows us to connect our react components to our Redux store.
- redux-devtools-extension - Useful for debugging in our devtools
- In src/index.js
import { Provider } from 'react-redux';
- a component from react-redux that wraps our App component and allows each child component to be connected to the store
import { createStore } from 'redux';
- a function from Redux that uses the rootReducer to create the store
import { composeWithDevTools } from 'redux-devtools-extension';
- a method we brought in and can pass as an argument with createStore so that we have access to our devtools and can view our store.
import { rootReducer } from './reducers';
- our combined reducers to create our store
(order matters here)
const store = createStore(rootReducer, composeWithDevTools())
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
- In actions/index.js
- In src/reducers/index.js
import { combineReducers } from 'redux';
import { todos } from './todos';
export const rootReducer = combineReducers({
todos: todos
});
**Where we define the properties that will exsits in our global store
npm i redux-thunk -S
- Clone repo, not nested in project directory
- Globally install nodemon. Runs the server.
npm install nodemon -g
- cd into repo
- Run
npm install
- Run
npm start
- Use Postman to checkout the data
- Install Enzyme:
npm i enzyme -D
- Install Enzyme Adapter:
npm install enzyme-adapter-react-16 -D
- Inside of /src create setupTests.js:
touch src/setupTests.js
- Put the following 3 lines of code in setupTests.js
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
- For snapshot testing, install Enzyme Wrappers:
npm install enzyme-to-json -D
- Add serializer to package.json:
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
}
Don't forget the comma!
- Add an extra line in App.js (just so there's a change in the file) and save. Then run
npm test
to check that the files are connected correctly. - Include the following lines as headers for all test files:
import React from 'react';
import { shallow } from 'enzyme';
import ClassName from './ClassName';
npm test -- --coverage --watchAll=false
- ESLint is already built in with create-react-app. Installing another eslint will likely break things.
- Add a script called
"lint": "eslint src/" in your package.json
(in the scripts object) - In your terminal, run:
npm run lint
- Turing Mod3 Linter
- Run:
npm install node-sass --save
- Add variable file:
touch src/variables.scss
- Change all
.css
file extentions to.scss
index.css App.css
=>index.scss App.scss
- Remeber to update the file paths anywhere the style files are being imported
- Add:
@import './src/variables.scss';
To any .scss files you want to uses variables - Format for creating variables:
$var-name: var-value;
npm install prop-types -S
In file:
import PropTypes from 'prop-types'
Component.propTypes = {
prop1: PropTypes.array.isRequired,
prop2: PropTypes.any,
prop3: PropTypes.func.isRequired,
prop4: PropTypes.bool
prop5: PropTypes.string.isRequired,
prop6: PropTypes.number
}
npm i react-router-dom -S
- In index.js
import { BrowserRouter } from 'react-router-dom'
const router = (
<BrowserRouter>
<App />
</BrowserRouter>
)
ReactDOM.render(router, document.getElementById('root'));
- Import what is needed in components
import { Route, NavLink, Link, Redirect, Switch} from 'react-router-dom'
handleChange = e => {
this.setState({ [e.target.name]: e.target.value})
}
In form:
<input
type='text'
value={this.state.title}
name='title'
onChange={this.handleChange}
/>
export const fetchMethod = () => {
return fetch('url')
.then(response => {
if (!response.ok) {
throw Error('Error Message');
}
return response.json();
})
}
In state: error: ''
After fetch (in App.js/component file):
.catch(error => this.setState({ error: error.message }));
In render()
method:
{error && <h2>{error}</h2>}
import { shallow } from 'enzyme';
wrapper = shallow (<Component prop='string' prop2={2} method={jest.fn()} />
expect(wrapper).toMatchSnapshot()
Execution
wrapper.instance().methodName('optionalArgument')
wrapper.instance().forceUpdate()
wrapper.find('button').simulate('click', optionalEvent)
wrapper.instance().setState({ prop: 'value', prop2: 'value2' })
wrapper.find('[name='thing']').simulate('change', mockThingEvent)
wrapper.find('button').at(3).simulate('click')
expect(mockWhatEverEvent).toHaveBeenCalledWith('argument/value')
const startState = {
title: 'Trisha',
description: 'She has a dog named Luna.'
}
wrapper.setState(startState);
wrapper.instance().resetInputs();
expect(wrapper.state('title')).toEqual('');
wrapper = shallow(<Form />);
const mockEvent = {target: {name: 'title', value: 'Jerry'}};
const expected = 'Jerry';
wrapper.instance().handleChange(mockEvent);
expect(wrapper.state('title')).toEqual(expected);
wrapper.instance().method2 = jest.fn();
wrapper.instance().method1(argument);
expect(wrapper.instance().method2).toHaveBeenCalled();
wrapper.find('button').simulate('click');
expect(function).toHaveBeenCalledWith(arguments);
describe('fetchMethod', () => {
let mockResponse = [
{object1},
{object2}
];
beforeEach(() => {
window.fetch = jest.fn().mockImplementation(() => {
return Promise.resolve({
ok: true,
json: () => {
return Promise.resolve(mockResponse)
}
})
})
})
it('should be provided with the correct URL', () => {
fetchMethod();
expect(window.fetch).toHaveBeenCalledWith('url')
})
it('should return an array of movies', () => {
expect(fetchMethod()).resolves.toEqual(mockResponse)
})
it('should return an error for response not ok', () => {
window.fetch = jest.fn().mockImplementation(() => {
return Promise.resolve({
ok: false
})
})
expect(fetchMethod()).rejects.toEqual(Error('Error text'))
})
})
Mock Date.now()
global.Date.now = jest.spyOn(global.Date, 'now').mockImplementation(() => 123)
Can assert that the value of Date.now() will be 123 or whatever is set as the return value.
Mock e.preventDefault() Can be passed as arugments of event in other methods
const mockEvent = { preventDefault: jest.fn() }
Mock Event
const mockThingEvent = { target: { name: 'thing', value: 'Thing value' } }
Expectation
expect(wrapper.instance().handleChange).toHaveBeenCalledWith(mockThingEvent)
expect(wrapper.state('thing')).toEqual('Thing value') or expect(wrapper.state()).toEqual(expected)
expect(wrapper.instance().method).toHaveBeenCalled()
POST
method: 'POST',
body: JSON.stringify({
id: value,
prop: value,
}),
headers: {
'Content-Type': 'application/json'
}
}
return fetch('url', options)
.then(res => {
if(!res.ok) {
throw Error('Something is not right, try again later')
}
return res.json()})
DELETE
const options = {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
return fetch(`url/${id}`, options)
.then(res => {
if(!res.ok) {
throw Error('Something is not right, try again later')
}
return getFetch();
}).catch(error => {
throw Error(error.message)
});