Skip to content

Instantly share code, notes, and snippets.

@NaomiKC92
Created January 14, 2020 17:37
Show Gist options
  • Save NaomiKC92/3094e2ac0ed5aa1fcdd620d1c50f8d82 to your computer and use it in GitHub Desktop.
Save NaomiKC92/3094e2ac0ed5aa1fcdd620d1c50f8d82 to your computer and use it in GitHub Desktop.

Edited and formatted by ericwm76
Eric's gist https://gist.github.com/ericwm76/e1204fc03f14af4429add8225ff55f71

Creating a React App

  1. In the terminal run: npx create-react-app NAME-OF-APP
  2. Cd into the new directory: cd NAME-OF-APP
  3. Run: npm install.
  4. You can run npm start to see if the app was set up correctly.

Setup Redux

  1. 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
  1. 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 const store = createStore(rootReducer, composeWithDevTools());
ReactDOM.render(
  <Provider store={store} >
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>, 
  document.getElementById('root')
);

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)


ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
  1. In actions/index.js
  1. 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

  1. npm i redux-thunk -S

Setup Backend

  1. Clone repo, not nested in project directory
  2. Globally install nodemon. Runs the server.
  3. npm install nodemon -g
  4. cd into repo
  5. Run npm install
  6. Run npm start
  7. Use Postman to checkout the data

Setting Up Testing

  1. Install Enzyme: npm i enzyme -D
  2. Install Enzyme Adapter: npm install enzyme-adapter-react-16 -D
  3. Inside of /src create setupTests.js: touch src/setupTests.js
  4. 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() });
  1. For snapshot testing, install Enzyme Wrappers: npm install enzyme-to-json -D
  2. Add serializer to package.json:
  "jest": {
    "snapshotSerializers": [
      "enzyme-to-json/serializer"
    ]
  }

Don't forget the comma!

  1. 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.
  2. Include the following lines as headers for all test files:
import React from 'react';
import { shallow } from 'enzyme';
import ClassName from './ClassName';

Check Testing Coverage

npm test -- --coverage --watchAll=false

Setting Up ESLint

  1. ESLint is already built in with create-react-app. Installing another eslint will likely break things.
  2. Add a script called "lint": "eslint src/" in your package.json (in the scripts object)
  3. In your terminal, run: npm run lint
  4. Turing Mod3 Linter

Install SCSS/Sass

  1. Run: npm install node-sass --save
  2. Add variable file: touch src/variables.scss
  3. Change all .css file extentions to .scss
  • index.css App.css => index.scss App.scss
  1. Remeber to update the file paths anywhere the style files are being imported
  2. Add: @import './src/variables.scss'; To any .scss files you want to uses variables
  3. Format for creating variables: $var-name: var-value;

propTypes

npm install prop-types -S 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
}

Router

  1. npm i react-router-dom -S
  2. In index.js
import { BrowserRouter } from 'react-router-dom'

const router = (
  <BrowserRouter>
    <App />
  </BrowserRouter>
)

ReactDOM.render(router, document.getElementById('root'));
  1. Import what is needed in components import { Route, NavLink, Link, Redirect, Switch} from 'react-router-dom'

TESTING

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')

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()
  • If imported as a seperate funtion:

    • test the function in the file where it lives on it's own (unit test)
    • where it is imported, use a jest.fn() to create where the method is called and what it is called with
  • Method passed as props:

    • pass function into components shallow copy as a prop
    • pass in a jest.fn()
    • ex: if the props is 'upDateRqatings' : const mockUpdateRatings = jest.fn() then...
  • Method on a class component: wrapper.instance().methodName = jest.fn() (when you want to track if it's invoked)

Network Requests

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)
    });

Top of page:

  • import React, { Component } from 'react';
  • import RecipieContainer from './RecipieContainer.js'
  • import './App.css';

Testing async:

  • Move fetches into their own file Discuss why Import fetches into the React component they originally belonged in Make sure component tests still pass Test each fetch in isolation Learn how to figure out what needs to be tested Test the asynchronous functions of the component Learn to mock a file Learn what to mock and what to test
describe('fetchMovies', () => {
    let mockResponse = {
      "movies": [
        {
          id: 1, 
          title: "Movie Title", 
          poster_path: "someURL", 
          backdrop_path: "someURL",
          release_date: "2019-12-04", 
          overview: "Some overview", 
          average_rating: 6 
        }
      ]
    }

    beforeEach(() => {
      window.fetch = jest.fn().mockImplementation(() => {
        return Promise.resolve({
          ok: true,
          json: () => Promise.resolve(mockResponse)
        })
      })
    })

    it('should call fetch with the correct URL', () => {
      fetchMovies()

      expect(window.fetch).toHaveBeenCalledWith('https://rancid-tomatillos.herokuapp.com/api/v1/movies')
    })

    it('should return an array of movies', () => {
      expect(fetchMovies()).resolves.toEqual(mockResponse)
    })
    
    it('should throw an error if fetch fails', () => {
      window.fetch = jest.fn().mockImplementation(()=> {
        return Promise.resolve({
          ok: false
        })
      })

      expect(fetchMovies()).rejects.toEqual(Error('Error fetching movies'))
    }) 

    it('should return an error if promise rejects', () => {
      window.fetch = jest.fn().mockImplementation(() => {
        return Promise.reject(Error('fetch failed'))
      })

      expect(fetchMovies()).rejects.toEqual(Error('fetch failed'))
    })
  })

Input:

  • name = 'name', value={this.state.value}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment