Skip to content

Instantly share code, notes, and snippets.

@chadfurman
Last active April 3, 2017 05:37
Show Gist options
  • Save chadfurman/df1a9107c84ceaf9413fcd499a82fd71 to your computer and use it in GitHub Desktop.
Save chadfurman/df1a9107c84ceaf9413fcd499a82fd71 to your computer and use it in GitHub Desktop.
4-2-notes.md

Filtering

  • .filter(callback) is like .map(callback)
  • Client side searching: array.filter( ${string_template}.toUpperCase().indexOf(this.state.searchTerm.toUpperCase()) >= 0 ) => map output what's left

Snapshot Testing w/ Jest

  • Library from Facebook
  • Migrating from Jasmine -- Jest2 uses Jasmine2 in the back-end
  • Jest2 is better than Jest1
  • snapshot testing...
/* search.spec.js -- jest knows where to find .spec.js */
/* search.js is in the same directory as search.spec.js */

import React from 'react'
import Search from './Search'
import renderer from 'react-test-renderer'

test('Search snapshot test', ()? }
  const component = renderer.create(<Search />)
  const tree = component.toJSON()
  expect(tree).toMatchsnapshot()
})

Configuring and Running Jest

  • $ jest => Test suite failed, unexpected token import
  • We need to tell bable that, when in a testing context, please compile my modules (preset in .babelrc)
  • NODE_ENV=test jest --no-cache
  • keep snapshots in repo so everyone runs same tests

Shallow rendering with enzyme

  • If there's a bug in an included module, you don't want to break the test for the module at hand.
  • Enzyme lets you use a shallow render
  • Facebook uses enzyme, but it's not officially part of react
import { shallow } from 'enzyme'
import { shallowToJson } from 'enzyne-to-json'

test('Search snapshot test', () => {
  const component = shallow(<Search />)
  const tree = shallowToJson(component)
  expect(tree).toMatchSnapshot()
})
  • Note you can snapshot test anything that you can dump to a json structure
  • We should go back and write a test for ShowCard

Testing the number of ShowCards

import preload from '../public/data.json'

test('Search should render a ShowCard for each show', () => {
  const component = shallow(<Search />)
  expect(component.find(ShowCard).length).toEqual(preload.shows.length)
})

Testing the Search Field

test('Search should render correct amount of shows based on search', ()  => {
  const searchWord = 'house'
  const component = shallow(<Search />)
  component.find('input').simulate('change', {target: {value:searchWord}})
  const showCount = preload.shows.filter((show) => `${show.title} ${show.description}`.toUpperCase().indexOf(this.state.searchTerm.toUpperCase()) >= 0).length
  expect(component.find(ShowCard).length).toEqual(showCount)
})

Test coverage with Istanbul

  • npm run test -- --coverage
  • Already built into Jest
  • open coverage/lcov-report/index.html

URL Parameters

  • Day 2! Now we get to have more fun than just tooling
  • Branch: v2-12
  • nho.lt/react
  • We're going to add a new route -- our last one
  • details.js
import React from 'react'

const Details = react.createClass({
  render () {
    return (
      <h1>something</h1>
    )
  }
})

export default Details
  • Also:
/*in clientapp.js*/
<match pattern='/details/:id' component={Details} />
  • Note the :id is standard way of saying where route parameters are
const Details = React.createComponent({
  render () => {
    return (
      <div className='details'>
        <pre><code>
          {JSOn.stringify(this.props, null, 4)} // check out this.props.params.id ...
        </code></pre>
      </div>
    )
  }
})

Sharing the State

  • You don't want to request the same data twice
  • Pushing the sharded data upto a parent container to avoid querying it twice
/* Details.js */
import React from 'react'

const Details = () => () => {
  return ( <h1></h1> )  // a stateless functional component -- basically, just a render method
} 

//=========================================

/* ClientApp.js */
// NOTE: Now we need to pass parameters to search...

import React from 'react'
import { render } from 'react-dom'
import { Browserrouter, Match } from 'react-router'
import Landing from './Landing'
import Search from './Search'
import Details from './Details
import preload from '../public/data.json'
import '../public/normalize.css'
import '../public/style.css'

const App = React.createClass({
  render () 
    return (
      <BrowserRouter>
        <div className='app'>
          <Match exactly pattern='/' component={Landing} />
          <Match 
            pattern='/search' 
            component={(props) => <Search shows={preload.shows} {...props} />} /* <-- this here */
          />
          <Match pattern='/details:id' component={Details} />
        </div>
      </BrowserRouter>
    )
  }
})

render(<App />, document.getElementById('app')}

Updating the Search Component

  • We're really taking advantage of "black magic" shortcuts
  • Anywhere you're using JSX you have to also use React -- JSX gets transpiled to React
  • replace preload.shows with this.props.shows and removed preload from imports in Search.js
  • React Router is passing props into our componenent
          <Match 
            pattern='/search' 
            component={(props) => <Search shows={preload.shows} {...props} />} /* <-- this here */
          />
  • Note the function in component={(props) => <Search shows={preload.shows} {...props} />}
    • Here, we're getting props from BrowserRouter and using spreading {...props} to maintain them as props on the compoment
    • This lets us keep things like the id from the route (i.e. on Details page) along with the new shows prop w/ preload
  • Now we get "shows" passed into Search.js as a prop, so that's why we replace preload.shows' with 'this.props.shows' and removed preloadfromimports` in Search.js
  • Nothing changes here on the front-end, but shows are now coming in as a parameter from the router
  • We should add propTypes to our Search..
const { arrayOf, shape, string } = React.PropTypes
const Search = React.createClass({
  propTypes: {
    shows: arrayOf(shape({ /* Be descriptive because we know what the objects are and they're all this format */
      title: string,
      description: string
    }))
  },
  getInitialState() {
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment