<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: edensongjbs</title>
    <description>The latest articles on DEV Community by edensongjbs (@edensongjbs).</description>
    <link>https://dev.to/edensongjbs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F413310%2Faacd287b-6edc-4792-85f3-c7ebe7e9f063.jpg</url>
      <title>DEV Community: edensongjbs</title>
      <link>https://dev.to/edensongjbs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edensongjbs"/>
    <language>en</language>
    <item>
      <title>Redux-Thunk Testing with Chuck Norris</title>
      <dc:creator>edensongjbs</dc:creator>
      <pubDate>Mon, 16 Nov 2020 21:58:01 +0000</pubDate>
      <link>https://dev.to/edensongjbs/redux-thunk-testing-with-chuck-norris-2mfg</link>
      <guid>https://dev.to/edensongjbs/redux-thunk-testing-with-chuck-norris-2mfg</guid>
      <description>&lt;h1&gt;
  
  
  Asynchronous Testing Techniques with Jest
&lt;/h1&gt;

&lt;p&gt;When I'm working on a personal &lt;strong&gt;React&lt;/strong&gt; project, I'm always tempted to cut to the chase and get right to coding the fun stuff: seeing my app concept come to life.  I'll try and get a quick interface up and running, verify that it's behaving as expected in the browser and call it a day.  Often times (especially with a simple project), this is fine.  There are those other times when things break unexpectedly and I'll be stuck digging back through my code in painstaking detail trying to remind myself how a particular piece of state is being updated or how a particular component is being used, all the while cursing myself for not starting out the project with a more rigorous test-driven approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test-driven development&lt;/strong&gt; (TDD) always feels like a lift in the beginning stages of a project, but it can end up saving so much time down the road.  TDD forces us to do the mental work up front.  In the context of a &lt;strong&gt;React&lt;/strong&gt; project, this means more rigorously planning the different components and their responsibilities, how these components will use state and how that state will be updated.  It lets us determine what is essential to the structure and function of our app, while abstracting away the implementation details that we can refactor as we go.  It provides us a failsafe, letting us know immediately if we modified something that's going to break our application. Beyond this, it makes collaboration and communication easier in the long-run.  Being able to successfully test an app requires that we are able to clearly understand, anticipate, codify, and communicate how the app should be working.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges of Asynchronous Testing
&lt;/h2&gt;

&lt;p&gt;For testing in &lt;strong&gt;React&lt;/strong&gt;, I've primarily been using the &lt;strong&gt;Jest&lt;/strong&gt; testing framework (which comes pre-installed in any new project created with &lt;code&gt;npx create-react-app&lt;/code&gt;).  The &lt;a href="https://jestjs.io/docs/en/getting-started"&gt;API Docs&lt;/a&gt; are well-written and the syntax (&lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;expect&lt;/code&gt;) felt quite familiar to me coming from &lt;strong&gt;Rspec&lt;/strong&gt; in the Ruby language.  Nevertheless, testing &lt;strong&gt;JavaScript&lt;/strong&gt; poses some interesting challenges, especially when it comes to handling asynchronous functions.  While there are endless examples of those in any given &lt;strong&gt;JS/React&lt;/strong&gt; project, I'm going to focus this article on how to do asynchronous testing with &lt;strong&gt;Redux-Thunk&lt;/strong&gt; action creators, something I've found particularly challenging to wrap my head around.&lt;/p&gt;

&lt;p&gt;If you're unfamiliar with &lt;strong&gt;Redux-Thunk&lt;/strong&gt;, I'd recommend checking out &lt;a href="https://www.digitalocean.com/community/tutorials/redux-redux-thunk#:~:text=Redux%20Thunk%20is%20a%20middleware,asynchronous%20operations%20have%20been%20completed."&gt;this post&lt;/a&gt;.  In short, &lt;strong&gt;Redux-Thunk&lt;/strong&gt; allows for dispatching an asynchronous action, by letting you call an action creator that returns a function (instead of a simple action object), into which the store's dispatch function is passed.  The passed dispatch function is then used to dispatch standard &lt;strong&gt;Redux&lt;/strong&gt; action objects from within the function (either synchronously or asynchronously).&lt;/p&gt;

&lt;p&gt;To help me demonstrate some &lt;strong&gt;Redux-Thunk&lt;/strong&gt; testing techniques in &lt;strong&gt;Jest&lt;/strong&gt;, I'll call upon everyone's favorite hyperbolic tough guy, Chuck Norris, to lend a hand...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1928MA7i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sm00iifupjcl7836qone.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1928MA7i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sm00iifupjcl7836qone.jpg" alt="Friendly Chuck gives a thumbs up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The App
&lt;/h2&gt;

&lt;p&gt;I've built an exceedingly simple &lt;strong&gt;React/Redux&lt;/strong&gt; app to demo our tests (you can find the GitHub repo &lt;a href="https://github.com/edensongjbs/chuck-norris-jokes"&gt;here&lt;/a&gt;).  In short, the app is a front-end for the &lt;a href="https://api.chucknorris.io/"&gt;ChuckNorris.io API&lt;/a&gt;, where the user will click a button and a random Chuck Norris &lt;br&gt;
"fact" will be displayed on the screen.  Important to our implementation is the detail that the user can only fetch up to 5 Chuck Norris "facts" before being cut off and being forced to refresh the page.  Though it's overkill in the extreme to be using &lt;strong&gt;Redux&lt;/strong&gt; for such a simple app, it seems appropriately in the spirit of Chuck Norris and certainly a good opportunity to demo testing techniques without too many complicating factors. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XFS7E78B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bsfbjzv97w1rkxfvpoda.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XFS7E78B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bsfbjzv97w1rkxfvpoda.gif" alt="App Demo Gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a step by step for following along at home:&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing Dependencies
&lt;/h2&gt;

&lt;p&gt;After creating a new react app (via &lt;code&gt;npx create-react-app chuck-norris-jokes&lt;/code&gt;), you'll need to install the following dependencies to get things set up:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install --save-dev fetch-mock&lt;/code&gt; ( to mock the API fetch request so that we can test our app in isolation )&lt;br&gt;
&lt;code&gt;npm intall --save-dev node-fetch&lt;/code&gt; ( since the tests will be using the fetch API without the browser )&lt;br&gt;
&lt;code&gt;npm install redux react-redux redux-thunk&lt;/code&gt; ( since the app uses &lt;strong&gt;Redux&lt;/strong&gt; and &lt;strong&gt;Redux-Thunk&lt;/strong&gt;)&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Up the App
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The Components
&lt;/h3&gt;

&lt;p&gt;I've set up the &lt;code&gt;App&lt;/code&gt; component to render two components: a &lt;code&gt;FetchButton&lt;/code&gt; component, that the user will click in order to fetch the new Chuck Norris "fact" and the &lt;code&gt;Joke&lt;/code&gt; component, which will display the fact if it is successfully fetched.  The &lt;code&gt;Joke&lt;/code&gt; component is purely presentational and receives the joke passed down in props from our &lt;code&gt;App&lt;/code&gt; component.  However, the &lt;code&gt;FetchButton&lt;/code&gt; component has access to our &lt;strong&gt;Redux&lt;/strong&gt; store and will invoke our &lt;strong&gt;Redux-Thunk&lt;/strong&gt; action creator &lt;code&gt;fetchJoke&lt;/code&gt;, when the button is clicked.  &lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/App.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { connect } from 'react-redux'
import FetchButton from './FetchButton'
import Joke from './Joke'

class App extends React.Component {
  render() {
    return (
      &amp;lt;div className="App"&amp;gt;
        &amp;lt;h1&amp;gt;Get a new Chuck Norris Joke&amp;lt;/h1&amp;gt;
        {!this.props.tooMany
          ?  &amp;lt;&amp;gt;&amp;lt;FetchButton/&amp;gt;&amp;lt;Joke joke={this.props.joke}/&amp;gt;&amp;lt;/&amp;gt;
          :  &amp;lt;h3&amp;gt;That's Too Many Chuck Norris Jokes.  Please refresh!&amp;lt;/h3&amp;gt;
        }
      &amp;lt;/div&amp;gt;
    )
  }
}

const mapStateToProps = state =&amp;gt; ({tooMany: state.tooMany, joke: state.joke})

export default connect(mapStateToProps)(App)`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Reducers
&lt;/h3&gt;

&lt;p&gt;I set up our root reducer to manage 3 distinct pieces of state: &lt;code&gt;joke&lt;/code&gt; (the joke fetched from the API), &lt;code&gt;jokeCount&lt;/code&gt; (the number of jokes that have been fetched from the API since the program launched, which cannot exceed 5), and &lt;code&gt;tooMany&lt;/code&gt; (initially set to &lt;code&gt;false&lt;/code&gt;, but set to &lt;code&gt;true&lt;/code&gt; once the user attempts to fetch more jokes than allowed).&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/reducers/joke.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const joke = (state=null, action={}) =&amp;gt; {
    switch (action.type) {
        case ('SET_JOKE'):
            return action.payload
        default:
            return state
    }
}

export default joke
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from &lt;code&gt;./src/reducers/jokeCount.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const jokeCount = (state=0, action={}) =&amp;gt; {
    switch (action.type) {
        case ('INC_JOKE_COUNT'):
            return state+1
        default:
            return state
    }
}

export default jokeCount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from &lt;code&gt;./src/reducers/tooMany.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tooMany = (state=false, action={}) =&amp;gt; {
    switch (action.type) {
        case ('TOO_MANY'):
            return true
        default:
            return state
    }
}

export default tooMany
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from &lt;code&gt;./src/reducers/index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { combineReducers } from 'redux'
import joke from './joke'
import jokeCount from './jokeCount'
import tooMany from './tooMany'


export default combineReducers({
    joke, jokeCount, tooMany
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring and Connecting the Store to our App
&lt;/h3&gt;

&lt;p&gt;You can refer to the &lt;a href="https://www.npmjs.com/package/redux-thunk"&gt;Redux-Thunk API docs&lt;/a&gt; for additional details on configuring the &lt;strong&gt;Redux-Thunk&lt;/strong&gt; middleware, but make sure to export your configured store so that it can be accessed for both testing and development/production purposes.  This is how I approached my &lt;code&gt;storeFactory&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/configureStore.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createStore, applyMiddleware } from 'redux'
import ReduxThunk from 'redux-thunk'
import rootReducer from './reducers'

const storeFactory = (initialState) =&amp;gt; {
    const middleware = [ReduxThunk]
    const createStoreWithMiddleware = applyMiddleware(...middleware)(createStore)
    return createStoreWithMiddleware(rootReducer, initialState)
}

export default storeFactory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll need to pass your store to your &lt;code&gt;App&lt;/code&gt; component and also import the &lt;code&gt;storeFactory&lt;/code&gt; function into your &lt;code&gt;test.js&lt;/code&gt; file, where you will use it to create a mock store for your tests.&lt;/p&gt;

&lt;p&gt;in &lt;code&gt;./src/index.js&lt;/code&gt; (creating a store for the app)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import store from './configureStore'

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;Provider store={store()}&amp;gt;&amp;lt;App /&amp;gt;&amp;lt;/Provider&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up the Tests
&lt;/h2&gt;

&lt;p&gt;At the heart of our app's functionality, is a single asynchronous action creator called &lt;code&gt;fetchJoke&lt;/code&gt;, which returns a function into which the store's dispatch function is passed.  This function will be responsible for dispatching other actions to our reducer.  It's &lt;em&gt;very important&lt;/em&gt; for us to think through the logic of how these actions will be dispatched, as certain actions may be synchronous and others asynchronous, which will affect how we must structure our tests.&lt;/p&gt;

&lt;p&gt;Let's jump now to setting up those tests.  For the purpose of this article, we're mostly concerned with setting up tests for our &lt;code&gt;fetchJoke&lt;/code&gt; action creator.  This is technically an integration test, since it will be utilizing our reducers as well, but I decided to place it in our &lt;code&gt;./src/actions&lt;/code&gt; directory and name it accordingly since its primary purpose is to test the action creator, the main logical component of our app.&lt;/p&gt;

&lt;p&gt;Here are our test descriptions:&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/actions/index.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe('fetchJoke action creator', () =&amp;gt; {

    test('fetches a joke on the first attempt', () =&amp;gt; {

    })
    test('fetches a joke when the limit has almost been reached', () =&amp;gt; {

    })
    test('fetches a joke when the limit will be exceeded', () =&amp;gt; {

    })
    test('fetches a joke when the limit has already been exceeded', () =&amp;gt; {

    })
  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we can code out the test blocks, we need to do some preliminary setup in our &lt;code&gt;./src/actions/index.test.js&lt;/code&gt; file:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 - Create a Test Store
&lt;/h3&gt;

&lt;p&gt;Since we have already created a storeFactory function, we can just import that and use it to create a mock store for our tests.&lt;/p&gt;

&lt;p&gt;in &lt;code&gt;.src/actions/index.test.js&lt;/code&gt; (creating a mock store for our tests)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import createTestStore from '../configureStore'&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Mocking the API Call
&lt;/h3&gt;

&lt;p&gt;While our actual app relies upon fetching values from the ChuckNorris.io API, we want to test our app in isolation.  So, we'll need to sub in a mock fetch in place of the real fetch in the action creator.  We can do this purely in the test file without making any changes to our actual action creator code (ie) the app never needs to know that it's not getting a real API response).  We can do this with a useful tool call &lt;strong&gt;fetch-mock&lt;/strong&gt; (that we've already installed as a dependency).  You can configure it like this:&lt;/p&gt;

&lt;p&gt;in &lt;code&gt;./src/actions/index.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fetchMock from 'fetch-mock'
import { fetchJoke } from './'

const url = 'https://api.chucknorris.io/jokes/random'

describe('fetchJoke action creator', () =&amp;gt; {
    //Setting up our mock response
    beforeEach(() =&amp;gt; {
      fetchMock.mock(url, {
          status: 200,
          value: 'Not a real Chuck Norris joke.'
      });
    })
    // Clearing the mock response.  Returning to default fetch behavior
    afterEach(() =&amp;gt; {
      fetchMock.restore()
    })
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 - Writing out the Test Blocks
&lt;/h3&gt;

&lt;p&gt;To test each of our four conditions, we start by creating our test store and initializing it with a state to support the conditions that we're aiming to test.  Here, you can see the appropriate initial state for each of our conditions:&lt;br&gt;
from &lt;code&gt;./src/actions/index.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('fetches a joke on the first attempt', () =&amp;gt; {

      const store = createTestStore()

    })
    test('fetches a joke when the limit has almost been reached', () =&amp;gt; {

      const store = createTestStore({jokeCount:4, joke:""})

    })
    test('fetches a joke when the limit will be exceeded', () =&amp;gt; {

      const store = createTestStore({jokeCount:5, joke:""})

    })
    test('fetches a joke when the limit has already been exceeded', () =&amp;gt; {

      const store = createTestStore({tooMany:true, joke:""})

    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also write out our expectations for each of the four test cases:&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/actions/index.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('fetches a joke on the first attempt', () =&amp;gt; {

      const store = createTestStore()
      expect(newState.joke).toBe('Not a real Chuck Norris joke.')
    })
    test('fetches a joke when the limit has almost been reached', () =&amp;gt; {

      const store = createTestStore({jokeCount:4, joke:""})
      expect(newState.joke).toBe('Not a real Chuck Norris joke.')
    })
    test('fetches a joke when the limit will be exceeded', () =&amp;gt; {

      const store = createTestStore({jokeCount:5, joke:""})
      expect(newState.joke).toBe('cutting you off');
    })
    test('fetches a joke when the limit has already been exceeded', () =&amp;gt; {

      const store = createTestStore({tooMany:true, joke:""})
      expect(newState.joke).toBe('no more jokes')
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two things to note here:  &lt;/p&gt;

&lt;p&gt;Firstly, these tests are not yet ready since we haven't actually dispatched our action creator.  Unless the tests are expecting the state to be unchanged (ie) our store's initial state), these tests will fail.  &lt;/p&gt;

&lt;p&gt;Secondly, note how specific the expectation statements are for each case.  There are specific strings that will need to be returned in our reducer in order to get these tests to pass.  I wanted to make doubly sure that the logic in our action creator is behaving as expected, so I'm asking for a different joke state depending on whether the limit is being reached on this call or had already been reached on a previous call (ie) whether the &lt;code&gt;tooMany&lt;/code&gt; piece of state had already been toggled from &lt;code&gt;false&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;).  This is fussy, but I thought it was important for ensuring that we cover all our cases and our action creator is acting predictably for each condition.  &lt;/p&gt;

&lt;p&gt;Before our tests are finished, we need to determine what is happening between our store initialization and our expectation.  It's &lt;em&gt;very important&lt;/em&gt; for us to have a clear sense of how our async action creator will be working, because this will affect where we place our &lt;code&gt;expect&lt;/code&gt; statement.  In the case of our &lt;code&gt;fetchJoke&lt;/code&gt; action creator, different conditions will cause our actions to be synchronous or asynchronous.  &lt;/p&gt;

&lt;p&gt;Why &lt;em&gt;is&lt;/em&gt; this exactly?  &lt;/p&gt;

&lt;p&gt;We want our action creator to first check the &lt;code&gt;tooMany&lt;/code&gt; piece of state &lt;em&gt;before&lt;/em&gt; making a fetch request to the API.  It will first determine if the user has already reached the request limit.  We'll also want to check a case where the &lt;code&gt;jokeCount&lt;/code&gt; piece of state is at the limit, but the &lt;code&gt;tooMany&lt;/code&gt; piece of state has not yet been toggled to &lt;code&gt;true&lt;/code&gt;.  In each of these cases, we want our app to NOT send a fetch request to the API, and instead dispatch a simple action object synchronously.  However, In the event that the &lt;code&gt;jokeCount&lt;/code&gt; IS under the limit set by our app, we will make the asynchronous fetch request to the server (via the fetch API), and dispatch the simple &lt;code&gt;'SET_JOKE'&lt;/code&gt; action object only &lt;em&gt;after&lt;/em&gt; receiving a response from the server.&lt;/p&gt;

&lt;p&gt;For our synchronous cases, we can simply setup our dispatch and expectation statements normally:&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/actions/index.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('fetches a joke when the limit will be exceeded', () =&amp;gt; {

      const store = createTestStore({jokeCount:5, joke:""})

      store.dispatch(fetchJoke())
      const newState = store.getState();
      expect(newState.joke).toBe('cutting you off')
    })
    test('fetches a joke when the limit has already been exceeded', () =&amp;gt; {

      const store = createTestStore({tooMany:true, joke:""})

      store.dispatch(fetchJoke())
      const newState = store.getState();
      expect(newState.joke).toBe('no more jokes')
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, for our asynchronous cases, we must set up our test so that our dispatch returns a Promise.  We can place our &lt;code&gt;expect&lt;/code&gt; statement inside a function that we pass the chained &lt;code&gt;.then()&lt;/code&gt; function.  The &lt;code&gt;expect&lt;/code&gt; statement will run once the Promise has resolved.&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/actions/index.test.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('fetches a joke on the first attempt', () =&amp;gt; {

      const store = createTestStore();

      return store.dispatch(fetchJoke())
        .then(() =&amp;gt; {
          const newState = store.getState();
          expect(newState.joke).toBe('Not a real Chuck Norris joke.')
        })
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;:  In order for this to actually work, we &lt;em&gt;must&lt;/em&gt; make sure that we actually set up our action creator to return a promise. Otherwise, we'll run into errors. Check out the action creator code below for reference.&lt;/p&gt;

&lt;p&gt;If we make a mistake and set up the synchronous test block to run asynchronously, we'll run into the above error, where a Promise is &lt;em&gt;not&lt;/em&gt; returned from our action creator, and there is no &lt;code&gt;.then&lt;/code&gt; function to invoke.  If we do the opposite and set up our asynchronous test block to run synchronously, it will simply jump to our &lt;code&gt;expect&lt;/code&gt; statement before the asynchronous code has a chance to run and the test will (most likely) fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 - Coding Out the Action Creator
&lt;/h3&gt;

&lt;p&gt;After defining the &lt;code&gt;fetchJoke&lt;/code&gt; function, you can verify that all tests are currently failing.  It's &lt;em&gt;important&lt;/em&gt; for us to verify that the tests are failing as expected so that we don't wind up with faulty tests that can lead to us assuming our code is working properly when it isn't!&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/actions/index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const fetchJoke = () =&amp;gt; { 

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the fully coded &lt;code&gt;fetchJoke&lt;/code&gt; function for reference:&lt;/p&gt;

&lt;p&gt;from &lt;code&gt;./src/actions/index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const fetchJoke = () =&amp;gt; { 
    const max = 5 // Total number of jokes allowed per session
    const url = 'https://api.chucknorris.io/jokes/random'
    return (dispatch, getState) =&amp;gt; {
        if (!getState().tooMany) {
            if (getState().jokeCount &amp;gt;= max) {
                // Runs synchronously
                dispatch({type: 'TOO_MANY'})
                dispatch({type: 'SET_JOKE', payload: 'cutting you off'})
            }
            // Runs asynchronously
            // NOTE THAT A PROMISE IS BEING RETURNED HERE!
            else return fetch(url)
            .then( res =&amp;gt; res.json())
            .then( res =&amp;gt; {
                dispatch({type: 'INC_JOKE_COUNT'})
                dispatch({type: 'SET_JOKE', payload: res.value})
            })
        }
        else {
            // Runs synchronously
            dispatch({type: 'SET_JOKE', payload: "no more jokes"})
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I mentioned in the prior section, &lt;em&gt;please&lt;/em&gt; note when a Promise is being returned from inside the function.  Neglecting this inadvertently can lead to a world of pain, hence the ALL CAPS!&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Step - Pass those tests
&lt;/h3&gt;

&lt;p&gt;Time to type &lt;code&gt;npm test&lt;/code&gt; and look at all that glorious green!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o98tp86G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yb6pra9xvzxndys2sfrn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o98tp86G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yb6pra9xvzxndys2sfrn.png" alt="Tests Passing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources:
&lt;/h2&gt;

&lt;p&gt;There's a lot more to testing &lt;strong&gt;React&lt;/strong&gt; and &lt;strong&gt;Redux&lt;/strong&gt;, and I enthusiastically recommend checking out &lt;a href="https://www.udemy.com/share/101XEwAEAdcllbRXUC/"&gt;Bonnie Schulkin's thorough Udemy course on the topic&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;To build your own Chuck Norris adjacent application, check out:&lt;br&gt;
&lt;a href="https://api.chucknorris.io/"&gt;ChuckNorris.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;API Docs for:&lt;br&gt;
&lt;a href="https://reactjs.org/docs/getting-started.html"&gt;React&lt;/a&gt;&lt;br&gt;
&lt;a href="https://redux.js.org/api/api-reference"&gt;Redux&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/redux-thunk"&gt;Redux-Thunk&lt;/a&gt;&lt;br&gt;
&lt;a href="https://jestjs.io/docs/en/getting-started"&gt;Jest&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.wheresrhys.co.uk/fetch-mock/"&gt;fetch-mock&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, I realize this is a pretty dense read, so remember...&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4fK3D8BL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jr5p257vk67zztby43a6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4fK3D8BL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jr5p257vk67zztby43a6.jpeg" alt="If at first you don't succeed...You're not Chuck Norris"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>redux</category>
      <category>tdd</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Generating Dynamic Game Links with JWTs</title>
      <dc:creator>edensongjbs</dc:creator>
      <pubDate>Tue, 18 Aug 2020 16:49:19 +0000</pubDate>
      <link>https://dev.to/edensongjbs/generating-dynamic-game-links-with-jwts-56ed</link>
      <guid>https://dev.to/edensongjbs/generating-dynamic-game-links-with-jwts-56ed</guid>
      <description>&lt;p&gt;A few days ago, I set out with a coding partner to build a multiplayer game with React.  The game will essentially be a digital version of &lt;a href="https://www.smirkandlaughter.com/product-page/shobu"&gt;Shobu&lt;/a&gt;, the popular and simple strategy board game.  Central to the concept of our web app, a player can visit our site, generate a new game and send a link for the newly generated game to a friend.  The friends could then play as opponents, each with a separate view of the game (and able to move only their own pieces).  They could leave in the middle of a game, close their browsers, and reopen their game links from another device/browser and still have their game progress reflected.&lt;/p&gt;

&lt;p&gt;The unique game links felt like a better solution for the app than requiring players to log in.  No player information (other than a first name or alias if the user opted to type one in rather than defaulting to "Player 1" or "Player 2") would be stored in the database, and the backend model relationships provided for the player model belonging to the game model.  Thus, once the game was over and deleted from the database, so too would be the players.  In essence, each new game that a user would start would create an entirely new player instance, with a new unique game link.&lt;/p&gt;

&lt;p&gt;I'd done work on previous projects with a Rails backend and handled authentication with a pretty standard password encryption approach.  Now, I wanted to use some of those same tools, but try something new in the process that felt a little more appropriate for this type of project.  So, how to achieve this?&lt;/p&gt;

&lt;h3&gt;
  
  
  Step # 1 Setting up the Rails Backend
&lt;/h3&gt;

&lt;p&gt;We're using Rails as our backend API for this project, so I first needed to properly set up my API end points in my &lt;code&gt;routes.rb&lt;/code&gt; file and generate a controller that could make use of the parameters I would be feeding in (namely, the dynamic portion of the game urls we'd ultimately be generating).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# in ./config/routes.rb
Rails.application.routes.draw do
  get '/players' =&amp;gt; "players#index"
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rather than relying on typical RESTful routing conventions and use the &lt;code&gt;#show&lt;/code&gt; route by including the player id in the URL (ie) &lt;a href="http://domain-name.com/players/1"&gt;http://domain-name.com/players/1&lt;/a&gt;), I decided to use JSON web tokens (JWTs) to send an encoded version of the unique player id to the rails back end.  It seemed like a nice and easy way to encode the information I wanted to send and solve a couple of basic issues in the process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prevent players from accessing a game link other than their own (either accidentally or maliciously)&lt;/strong&gt;.  If we stuck with accessing the API endpoint via the player id (which are assigned by the database sequentially), a user could easily guess at other player's URLs and sign into their game link, or even arrive at somebody else's URL by mistyping or omitting part of their URL.  Using the JWT in the URL instead of an unencoded id makes it very unlikely that a user would wind up at a game that wasn't their own.  Because of the way that JWTs work (utilizing a signature at the end to validate the data, and a secret key stored on the backend), it makes it exceedingly difficult to stumble upon another valid URL by chance. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensure that the game link is unique.&lt;/strong&gt;  There are certainly plenty of other methods to generate links, but this was the easiest way that I could think of to generate a link that was certain to be unique to the player in addition to being nearly impossible to guess.  If we instead relied upon a concatenation of random words or random characters, we would either need to be comfortable with the (extremely unlikely) chance that two players would be assigned the same link, or take the extra steps to ensure that a collision never occurred (ie) potentially scanning through an entire database of used URLS each time a new link was created.  As truly unlikely as a collision would be, the larger our user base, the more likely it becomes and the more unwieldy a possible used URL lookup table would be. I have actually run into colliding URLS on services like Surge.sh, so it's definitely NOT unthinkable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is my code for encoding and decoding the JWT.  The unique JWT "url" is assigned when a new player is created (as shown in &lt;code&gt;player.rb&lt;/code&gt;, and that player can be easily retrieved from the database when the frontend sends that JWT back (as demonstrated in &lt;code&gt;players_controller.rb&lt;/code&gt;).  Please note that you will first need to include &lt;code&gt;gem "jwt"&lt;/code&gt; in your &lt;code&gt;Gemfile&lt;/code&gt; and run &lt;code&gt;bundle install&lt;/code&gt; in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# in ./app/models/player.rb
class Player &amp;lt; ApplicationRecord
    belongs_to :game
    after_create :generate_url

    def generate_url
        self.update_attributes(url: JWT.encode(self.id.to_s, "some_secret_string"))
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# in ./app/controllers/players_controller.rb
class PlayersController &amp;lt; ApplicationController
    def index
        player_id = JWT.decode(params[:jwt], "some_secret_string")[0].to_i
        player = Player.find(player_id).game
        render json: player.game
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step # 2 Setting up Client Side Routing in React
&lt;/h3&gt;

&lt;p&gt;After we get our backend successfully creating and processing the JWT as parameters in a GET request (I'd highly recommend a tool like Postman for testing the API), we can move on to our frontend.  Since we built our game as a single page application in React, I'm going to demonstrate how to do this with client side routing via React-Router.&lt;/p&gt;

&lt;p&gt;Since we handle a lot of the API calls for the game in our top App level, it seemed the path of least resistance was to define our client side routes one level higher, in &lt;code&gt;index.js&lt;/code&gt;.  We weren't envisioning multiple different looking pages in our app; just one basic page that presents slightly differently depending on whether or not there is an active game.  Our routing is handling 4 basic scenarios:&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;Basic route ('/') -&lt;/strong&gt; This route will render the page with a blank game board, and render a "Play a New Game" button.  Once the button is clicked, we'll redirect to the primary player's game link.  This route will cause our &lt;code&gt;App&lt;/code&gt; component to render without any props and thus will not trigger initial API fetch request.&lt;/p&gt;

&lt;p&gt;2) &lt;strong&gt;Valid game in progress in progress ('/gameinplay/some-indecipherable-jwt-that-decodes-to-a-valid-player-id') -&lt;/strong&gt; This route will render the page with the current board of an ongoing game.  Our router will render our &lt;code&gt;App&lt;/code&gt; element and pass in the jwt as props.  Because the jwt is present in the props, our App component will know to fetch the game details from the backend API discussed in the previous section.  The view will be slightly different depending on which of the two game's players the link belongs to.&lt;/p&gt;

&lt;p&gt;3) &lt;strong&gt;Invalid game link ('/gameinplay/any-other-string-that-is-not-a-jwt-that-decodes-to-a-valid-player-id') -&lt;/strong&gt; This will be handled by our client-side router in the same exact manner as the valid link discussed in the previous scenario, however, the fetch request will return an error (since the jwt will not evaluate to a valid player id).  We built some error handling to redirect the user to the root directory.&lt;/p&gt;

&lt;p&gt;4) &lt;strong&gt;Any other invalid URL ('/any-other-string') -&lt;/strong&gt; At the time of writing this blog entry, I haven't yet accounted for this scenario.  However, I intend this to redirect to the root directory ('/') where the user can create a new game.&lt;/p&gt;

&lt;p&gt;Note:  You'll first need to run &lt;code&gt;npm install react-router-dom&lt;/code&gt; in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// in ./index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter as Router, Route } from 'react-router-dom'

ReactDOM.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;Router&amp;gt;
        &amp;lt;div&amp;gt;
          // scenario #1, renders App with no props
          &amp;lt;Route exact path="/" render={() =&amp;gt; &amp;lt;App /&amp;gt;}/&amp;gt;
          // scenario #2 and #3, renders App and passes in the jwt as props
          &amp;lt;Route path="/gameinplay/:jwt" render={(routerProps) =&amp;gt; &amp;lt;App jwt={routerProps.match.params.jwt}/&amp;gt;}/&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/Router&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;,
  document.getElementById('root')
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// in ./App.js
import React from 'react';

const playersURL = "http://localhost:3000/players"

class App extends React.Component {

fetchOngoingGame = () =&amp;gt; {
    fetch(`${playersURL}?jwt=${this.props.jwt}`)
    .then(resp =&amp;gt; {
      if (resp.ok) { 
        return resp.json()
      }
      else {throw new Error('Not a valid game link')}
    })
    // handling scenario #2 by populating the currentGame in state
    .then(currentGame =&amp;gt; {
       this.pieces = currentGame.pieces
       this.setState({ currentGame: currentGame.game })
    })
    // handling scenario #3 with a redirect
    .catch(() =&amp;gt; {
      window.history.pushState({pathname: '/'}, "", '/')
    })
  }

  // our initial fetch runs when the App component first mounts if there are props present
  componentDidMount() {
    if (this.props.jwt)
      this.fetchOngoingGame()
    else {console.log("This will load a new game")}
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;We now have both pieces (frontend and backend API) up and running and connected.  This seems a relatively straightforward approach to user authentication when security and user data is not a concern, as in the case of our simple web game.  This is the first time I've attempted this approach, so I'd be very interested to hear some feedback from others who have attempted similar things and see how they approached the same problem.  Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>rails</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Building Ada's Rainbow Piano</title>
      <dc:creator>edensongjbs</dc:creator>
      <pubDate>Tue, 14 Jul 2020 13:26:09 +0000</pubDate>
      <link>https://dev.to/edensongjbs/building-ada-s-rainbow-piano-11bd</link>
      <guid>https://dev.to/edensongjbs/building-ada-s-rainbow-piano-11bd</guid>
      <description>&lt;h3&gt;
  
  
  Some Background
&lt;/h3&gt;

&lt;p&gt;Learning Javascript has been both gratifying and frustrating in equal measure.  There's an immediacy to it that I've found a lot of fun:  seeing my code in action and easily manipulated in the browser!  And then there's a whole bunch of stuff that left me scratching my head when my code breaks down (async, promises, scoping, callbacks, argh!!)&lt;/p&gt;

&lt;p&gt;Starting out, I wanted to mark my progress with a fun little project for my 3 year old daughter Ada (which I later went on to build into a more full featured web app &lt;a href="https://github.com/edensongjbs/adas-ear-training-frontend"&gt;Ada's Ear Training&lt;/a&gt;.  We've been working together for a while on some basic music theory and ear training.  Her main introduction to playing music has been through these color coded pat bells that she received as a Christmas gift from her great grandma:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yHIxw4_A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.uncommongoods.com/images/items/25400/25455_1_640px.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yHIxw4_A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.uncommongoods.com/images/items/25400/25455_1_640px.jpg" alt="Pat bells"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I thought it would be useful to introduce the concept of the piano keyboard using the same color coding (mapping each note in the C major scale to a specific color).  Thus, my inspiration for Ada's rainbow piano.&lt;/p&gt;

&lt;p&gt;If you're curious, below is a step by step tutorial on how I built it.  And if you'd like to see and/or try out the code yourself, here's a &lt;a href="https://github.com/edensongjbs/rainbow-piano-for-ada"&gt;link to the repository on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tone.js
&lt;/h3&gt;

&lt;p&gt;At the sonic heart of this project is the pleasantly intuitive &lt;a href="https://tonejs.github.io/"&gt;Tone.js&lt;/a&gt; interactive music framework.  It's a really powerful tool with various tone generators, oscillators, effects, and built in sampler, but for this project I really just scratched the surface of its capabilities.  I ended up just downloading the source code and including it right inside my project directory, opting to avoid the ES6 &lt;code&gt;import&lt;/code&gt; statements that were suggested in the README.&lt;/p&gt;

&lt;p&gt;It's very easy to set up a basic synthesizer instance and patch it to the computer's audio output.  I initially played around with the basic monophonic option for my initial tests, but went with a 4 voice polyphonic version for the finished code, so we can play full chords etc.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;var synth = new Tone.PolySynth(4, Tone.Synth, {&lt;br&gt;
    oscillator : {&lt;br&gt;
          type : "square"&lt;br&gt;
      }&lt;br&gt;
  }).toMaster();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I've subsequently spent some time experimenting with sounds and linking it up to some real piano samples, but I've always had a fondness for a good ol' square wave, so this seems like a good place to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  The UI Layout
&lt;/h3&gt;

&lt;p&gt;After I was comfortable playing sounds and triggering attacks and releases for specific notes, it was time to build the user interface.  Honestly, the most challenging bit about this little project wasn't the JavaScript, but the CSS styling!  I hadn't ever written a ton of CSS, and positioning elements had always seemed a mysterious art form.  This project proved to be excellent practice! (Note: For later projects using the keyboard, I decided to work with Flexbox and CSS Grid instead)&lt;/p&gt;

&lt;p&gt;I started with one large &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for the full octave &lt;em&gt;keybed&lt;/em&gt;, and created an inner &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for each separate &lt;em&gt;key&lt;/em&gt;.  I created separate classes for 'white-keys' and 'black-keys' and each &lt;em&gt;key&lt;/em&gt; got its own id corresponding to its note letter and octave (C3, C#3, D3...B3, C4).  This enabled me to make very specific CSS selections for intended coloring scheme, and provided an easy mechanism to send the corresponding note name of my &lt;code&gt;mousedown&lt;/code&gt; events in order to play the intended note.  It was important to specify that my &lt;em&gt;key&lt;/em&gt; &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;'s were given CSS styling values of &lt;code&gt;display: inline-block;&lt;/code&gt; so that they would display within the &lt;em&gt;keybed&lt;/em&gt; &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; and not jump to the next line.  The 'black-keys' class required need some additional styling: &lt;code&gt;position: absolute;&lt;/code&gt; so they could overlap the 'white-keys' and be placed explicitly (make sure to specify a &lt;code&gt;position&lt;/code&gt; attribute value for the enclosing &lt;em&gt;keybed&lt;/em&gt; &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; as well or the black keys won't move with the rest of the keyboard!). It was a bit painstaking, but I specified a &lt;code&gt;top&lt;/code&gt; and &lt;code&gt;left&lt;/code&gt; value for each separate black key &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wiring it all up
&lt;/h3&gt;

&lt;p&gt;Now that I knew enough of my way around Tone.js and had a fun and colorful UI I was basically pleased with, it was time to write my JS functions to get this thing working! I wanted to give the "user" (my 3yo) a couple options for trigger pitches: clicking on the trackpad and pressing keys on the keyboard.  I wanted each to track both the &lt;em&gt;mousedown/keydown&lt;/em&gt; events as well as the &lt;em&gt;mouseup/keyup&lt;/em&gt; events for specifying the note attack and release.  &lt;/p&gt;

&lt;p&gt;I started by adding the event listeners for the "click" to each separate &lt;em&gt;key&lt;/em&gt; &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;for (const note of allNotes) {&lt;br&gt;
    note.addEventListener('mousedown', () =&amp;gt; {&lt;br&gt;
        playNote(event.target.id)&lt;br&gt;
    })&lt;br&gt;
    note.addEventListener('mouseup', () =&amp;gt; {&lt;br&gt;
        releaseNote(event.target.id)&lt;br&gt;
    })&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As mentioned above, each event sends the id of the clicked &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element as a string parameter to the play/release functions.&lt;/p&gt;

&lt;p&gt;I had to approach the &lt;em&gt;keyup/keydown&lt;/em&gt; events slightly differently. I attached the event listener to the &lt;code&gt;document&lt;/code&gt; DOM element and sent parameters to the &lt;em&gt;play/release&lt;/em&gt; functions by way of a 'keyBindings' object that I created in order to avoid an undoubtedly ugly &lt;em&gt;if/else/switch/case&lt;/em&gt; statement. The &lt;em&gt;keys&lt;/em&gt; of the 'keyBindings' object are the characters of keys pressed and the values are the note names (matching the id of the 'key' &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;'s).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const keyBindings = {&lt;br&gt;
    "a": "C3",&lt;br&gt;
    "s": "D3",&lt;br&gt;
    "d": "E3",&lt;br&gt;
    "f": "F3",&lt;br&gt;
    "g": "G3",&lt;br&gt;
    "h": "A3",&lt;br&gt;
    "j": "B3",&lt;br&gt;
    "k": "C4",&lt;br&gt;
    "w": "C#3",&lt;br&gt;
    "e": "D#3",&lt;br&gt;
    "t": "F#3",&lt;br&gt;
    "y": "G#3",&lt;br&gt;
    "u": "A#3"&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Touches
&lt;/h3&gt;

&lt;p&gt;To provide a little visual interactivity to the rainbow piano, I decided to add some additional CSS styling to indicate when a note was currently playing.  In this case, it was just a matter of adding an additional ("playing) class to the key &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; when the note attack is triggered and removing it when the release was triggered.  Here are the updated &lt;em&gt;playNote&lt;/em&gt; and &lt;em&gt;releaseNote&lt;/em&gt; functions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;playNote = (note) =&amp;gt; {&lt;br&gt;
    synth.triggerAttack(note)&lt;br&gt;
    const noteDiv = document.querySelector(&lt;/code&gt;#${note.replace("#", '\#')}`)&lt;br&gt;
    noteDiv.classList.add('playing')&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;releaseNote = (note) =&amp;gt; {&lt;br&gt;
    synth.triggerRelease(note);&lt;br&gt;
    const noteDiv = document.querySelector(&lt;code&gt;#${note.replace("#", '\\#')}&lt;/code&gt;)&lt;br&gt;
    noteDiv.classList.remove('playing')&lt;br&gt;
}`&lt;/p&gt;

&lt;p&gt;The additional styling subtly reduces the note's opacity to provide a highlighting effect when the note is played:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;div.playing {&lt;br&gt;
    opacity: 0.7;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And that's basically it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TYbnmA-2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dehezbfhlw2b849fvd80.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TYbnmA-2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dehezbfhlw2b849fvd80.JPG" alt="James and Ada playing with the piano"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  In Closing
&lt;/h3&gt;

&lt;p&gt;The rainbow piano was definitely a fun first mini JavaScript project! Ada was pretty enthusiastic as well.  At I mentioned earlier, I did go on to build this into a a more fully featured music theory and ear training application.  I'm well aware that this is not the only "Build a JS Piano" tutorial out there, so I'll probably go back and read some of the others and see how the approaches differ.  I'm somebody who enjoys the process of figuring things out for myself and struggling through the mistakes along the way, so I was hesitant to read any of those beforehand.  Anyway, happy piano building! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/edensongjbs/adas-ear-training-frontend"&gt;The Full Ear Training App&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=EAFggwkXN5w"&gt;Video Demo For Ear Training App&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Remember the environment!</title>
      <dc:creator>edensongjbs</dc:creator>
      <pubDate>Tue, 23 Jun 2020 13:49:42 +0000</pubDate>
      <link>https://dev.to/edensongjbs/remember-the-environment-32l8</link>
      <guid>https://dev.to/edensongjbs/remember-the-environment-32l8</guid>
      <description>&lt;h2&gt;
  
  
  How ignoring my Rails environment got me into trouble
&lt;/h2&gt;

&lt;p&gt;A couple days into learning Rails, I was coming off after a frustrating week of managing tedious Sinatra syntax errors, malfunctioning gems, and inexplicably failing Capybara tests.  I kept hearing that “Rails is magic” and I was very ready to embrace some of that “magic” and offload a lot of the manual and human error prone repetition of Sinatra to a framework that does much of the heavy lifting.  However, my first experience with Rails left me wanting to pull out my beard.  In fairness to Rails, and as with most coding issues, this was an easily resolved problem if only I had known where to look.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The assignment&lt;/strong&gt;: I was given a partially built basic web application to track student enrollment, and I was tasked with building out some additional functionality and make a simple change to a table in the database, namely whether the student was currently "active" or "inactive."  I needed to add an additional table column, and I decided to do this by modifying the original CreateStudents migration to create a new, larger table from scratch, rather than creating a new migration just to create the additional column in the existing table.&lt;/p&gt;

&lt;p&gt;So I rolled back and re-migrated with the original migration file that I just modified.  After seeding my data, I verified that the new attribute was showing up in my newly created student instances.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;=&amp;gt; #&amp;lt;Student id: 1, first_name: "Daenerys", last_name: "Targaryen", active: false, created_at: "2020-06-20 21:42:23", updated_at: "2020-06-20 21:42:23"&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;...and my table schema...&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ActiveRecord::Schema.define(version: 1) do&lt;br&gt;
create_table "students", force: :cascade do |t|&lt;br&gt;
         t.string   "first_name"&lt;br&gt;
         t.string   "last_name"&lt;br&gt;
         t.boolean  "active",     default: false&lt;br&gt;
         t.datetime "created_at",                 null: false&lt;br&gt;
         t.datetime "updated_at",                 null: false&lt;br&gt;
     end&lt;br&gt;
end&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;All good!  &lt;em&gt;However&lt;/em&gt;, when I went to run my capybara tests, I was failing.  Capybara was claiming that the attribute and associated methods didn’t exist!!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ActionView::Template::Error:
   undefined method 'active' for #&amp;lt;Student:0x00007fac65ac9108&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I had literally just confirmed that it was there!  I used byebug to peer inside the test run, and to my astonishment, saw that the attribute was indeed missing from the Student instance in question... &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Student id: 1, first_name: "Daenerys", last_name: "Targaryen", created_at: "2020-06-21 00:08:53", updated_at: "2020-06-21 00:08:53"&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;So, &lt;em&gt;what was happening?&lt;/em&gt;  The answer lies in the way that Rails handles environments.&lt;/p&gt;

&lt;p&gt;I felt fairly comfortable with the concept of an &lt;em&gt;environment&lt;/em&gt; in Ruby and understood the utility of the environment.rb to help centralize all our require statements and wire up all our far flung classes and methods. I had seen references to the existence of different environments (test, development, production) within ActiveRecord and Rails, but hadn’t yet spent the time to truly understand what they are and how they work.  I knew that the Capybara tests were somehow using a different set of data than I was, but hadn’t really thought through the mechanics of how this was accomplished.  &lt;/p&gt;

&lt;p&gt;It turns out that the tests operate in the capybara “test” environment and my own data seeding, testing, and manipulation exist in the “development" &lt;em&gt;environment&lt;/em&gt;.  So, while I &lt;em&gt;had&lt;/em&gt; modified my table in the “development” environment (rails treats this as default, if &lt;code&gt;RAILS_ENV&lt;/code&gt; is not explicitly defined in the shell command), I &lt;em&gt;had not&lt;/em&gt; properly rolled back and rerun the updated migration in the “test” &lt;em&gt;environment&lt;/em&gt;.  Thus, the capybara tests were still using the old table schema.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3oz8xHMVIZURzJ6itO/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3oz8xHMVIZURzJ6itO/giphy.gif" alt="bearded guy facepalm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ActiveRecord/Rails further complicates matters since there is only a single schema.rb for the project and it does not account for discrepancies between the databases for different &lt;em&gt;environments&lt;/em&gt;, nor does it reflect the state of one environment in particular, but instead seems to update to reflect the most recent migration task.&lt;/p&gt;

&lt;p&gt;So, &lt;em&gt;what is&lt;/em&gt; the purpose of the &lt;em&gt;environment&lt;/em&gt;?  From what I've learned thus far, Rails tries to preempt our needs and define some default behaviors that would likely be useful in each stage of the project development cycle. One such aspect of this behavior is to separate the databases for each of the stages.  The "test" database is populated according to the specific tests and purged between test runs, for instance.  &lt;/p&gt;

&lt;p&gt;There are far more environment implications beyond managing the project’s database, and each environment includes is own set of configuration settings and gems.  Each of the predefined environments in Rails (you can define your own as well) is optimized for its set purpose.  The "production" environment is optimized for server speed while the "development" environment is optimized for easy modification, allowing us to make changes to our app files without having to stop and restart our server.  Pretty useful!    &lt;/p&gt;

&lt;p&gt;Some developers have shared their own approaches to using and creating some custom Rails environments, and I'll link to some of those below.  Additionally, &lt;a href="https://doc.bccnsoft.com/docs/rails-guides-3.2-en/configuring.html"&gt;Rails Guides&lt;/a&gt; provides a ton of information when it comes to configuring components within each environment.  In fact, Rails provides some very useful info about the purpose of each environment and component configuration as comments within the environment files themselves (inside the config/environments directory).  &lt;/p&gt;

&lt;p&gt;While I’m just at the beginning of my Rails journey and certainly no expert on the topic, I do want to urge you to take a minute to understand the implications of &lt;em&gt;environments&lt;/em&gt; on your databases, and not make the same mistake that I did.  It was a real headscratcher/beard-puller and I’m hoping I can help save a fellow Rails newcomer some precious debugging time on their next project.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The takeaway:&lt;/strong&gt; if you’re running tests in the “test” environment and have made any changes to your database, remember to add a &lt;code&gt;RAILS_ENV=”test”&lt;/code&gt; to your rake/rails db: commands!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://doc.bccnsoft.com/docs/rails-guides-3.2-en/configuring.html"&gt;Ruby on Rails Guides: Configuring Rails Applications&lt;/a&gt;&lt;br&gt;
&lt;a href="https://signalvnoise.com/posts/3535-beyond-the-default-rails-environments#:~:text=Rails%20ships%20with%20a%20default,branches%20on%20real%20production%20data."&gt;Beyond the default Rails environments - Signal v Noise&lt;/a&gt;&lt;br&gt;
&lt;a href="http://teotti.com/use-of-rails-environments/"&gt;Use of Ruby on Rails environments - Enrico Teotti&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nts.strzibny.name/creating-staging-environments-in-rails/#:~:text=Creating%20staging%20and%20other%20environments%20in%20Rails,a%20need%20for%20staging%20environment."&gt;Creating Staging and other environments in Rails - Josef Strzibny&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
