Category Archives: Uncategorized

Adding Jest and Enzyme and creating snapshot tests

branch-name:  
Click To Copy

 

In this tutorial we will learn how to install Jest and Enzyme, and create Snaphot tests.

If you are not familiar with these tools please read the links first since we will focus mainly on installing and using the tools.

The basic idea is that we are going to create a test cases, that will render the component, and create a snapshot of it. Next time when we run the test we could compare with the snapshot, making sure that either the component is not changed, or it renders as expected.

Setting up Jest and Enzyme.

We will need some extra packages in order to make Jest work with Enzyme.

Installing the packages.

  • enzyme – the actual enzyme testing utility.
  • enzyme-adapter-react-16 – the react adapter for enzyme. There are different adapters for different React versions, and since we are using react 16 we will install this version. A full list of adapter packages could be found here
  • enzyme-to-json – a serializer for the components.
yarn add jest enzyme enzyme-adapter-react-16 enzyme-to-json --dev

In addition we have to also install:

yarn add babel-jest --dev

  • babel-jest – allows Jest to use babel to transpile JS.

Before using Enzyme we have to configure it first. Create file with the following contents:

src/setupTests.js

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });

This tells Enzyme, to run with React using the adaptor we just installed. Make sure this file is included before using Enzyme. Open package.json and add the following config:

./package.json

...
  },
  "jest": {
    "setupFiles": [
      "./src/setupTests.js"
    ]
  },
...

Now we are almost ready to write our first test. Header component is perfect candidate since it is not connected to the redux store.

Create new file in the ./src/components/Header folder and let’s

Add a Snapshot Test

./src/components/Header/index.test.js

import React from 'react';
import { shallow } from 'enzyme';
import Header from './index';
import toJson from 'enzyme-to-json';

describe('Testing Header component', () => {
    it('renders as expected!!!', () => {
      const wrapper = shallow(
        <Header title="Title test" />
      );
     expect(toJson(wrapper)).toMatchSnapshot();
   });
});

 unfortunately if we do yarn test it will fail with error code, since Jest doesn’t know how to deal with anything different than Java Script.
But there is an easy fix: we could map CSS to a JS file that Jest understands. Create empty file in

./src/__mocks__/styleMock.js


and set up Jest to use the mapping:

./package.json

...
  "jest": {
    "setupFiles": [
      "./src/setupTests.js"
    ],
    "moduleNameMapper": {
      "\\.(css|less|scss)$": "<rootDir>/src/__mocks__/styleMock.js"
    }    
  },
...

Now let’s run yarn test and we should see something like this:

yarn test
yarn run v1.12.3
$ jest
 PASS  src/components/Header/index.test.js
  Testing Home component
    ✓ renders as expected!!! (15ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        2.194s
Ran all test suites.
✨  Done in 3.05s.

Perfect ! Our first snapshot test is done.

Testing renderer component

src/components/Home/renderer.test.js

import React from 'react';
import { shallow, mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import Component from './renderer';

describe('Testing Home component', () => {
    it('renders as expected!!!', () => {
      const wrapper = shallow(<Component styles={{}} title="MyTest" />);

     expect(toJson(wrapper)).toMatchSnapshot();
     expect(wrapper.contains(<div>MyTest</div>)).toBe(true);
   });
});

Also we added expect(wrapper.contains(<div>MyTest</div>)).toBe(true); which looks for certain things into the component.

Testing Redux connected component.

./src/components/About/index.test.js

import React from 'react';
import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import { Provider } from 'react-redux';
import reducers from '../../reducers';
import { createStore} from 'redux';
import About from './index.js';

const store = createStore(reducers, {});
let wrapper;
describe('Testing About component', () => {

  beforeEach(() => {
    // Runs a function before each of the tests in this file runs
    wrapper = mount(
      <Provider store={store}>
        <About userName="Toni" />
      </Provider>
    );
  });

  it('renders as expected', () => {
   expect(toJson(wrapper)).toMatchSnapshot();
  });

  it('expect to have state.userName set to John', () => {   
   wrapper.setState({userName: "John"});
   expect(wrapper.state('userName')).toEqual("John");
  });  
});

since we wrapped MyComponent with Provider component, we have to mount the component that will render it in full instead of doing shallow rendering (like in the previous example). Otherwise shallow will render only the Provider component.

Now the two tests could be executed together yarn test

 PASS  src/components/About/index.test.js
  Testing About component
    ✓ renders as expected (56ms)
    ✓ expect to have state.userName set to John (14ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   1 passed, 1 total
Time:        3.102s
Ran all test suites matching /.\/node_modules\/jest\/bin\/jest.js|src\/components\/About\/index.test.js/i.

Adding more tests.

./src/components/Greetings/renderer.test.js

import React from 'react';
import { mount } from 'enzyme';
import toJson from 'enzyme-to-json';
import reducers from '../../reducers';
import { createStore} from 'redux';
import Component from './renderer';

const store = createStore(reducers, {});
let wrapper;
describe('Testing Greetings component', () => {

  beforeEach(() => {
    wrapper = mount(
        <Component styles={{}} store={store} />
    );
  });

  it('renders as expected', () => {
    // to snapshot test
    expect(toJson(wrapper)).toMatchSnapshot();
  });

  it('textbox does not exist', () => {  
    expect(wrapper.find('input').exists()).toBe(false);
  });

  it('textbox exists after h2 click', () => {  
    // simulate click on the h2 tag trigering props change and visualizing the input text box
    wrapper.find('h2').simulate('click');
    expect(wrapper.find('input').exists()).toBe(true);
  });    

  it('textbox values change properly', () => {    
    // text box value tests
    expect(wrapper.find('input').props().value).toBe('No Name');
    wrapper.find('input').props().value = 'test';
    expect(wrapper.find('input').props().value).toBe('test');
  });    

});
  • beforeEach – Runs a function before each of the tests in this file runs. If the function returns a promise or is a generator, Jest waits for that promise to resolve before running the test.
  • here is another way of passing the store directly to the component.
branch-name:  
Click To Copy

Adding Middleware to log requested IPs

Middleware is a good way to pre-process the request before handing it out to GraphQL.
We could add authentication that could check the auth token in the header or middleware that will log the request IPs. Let’s do the second one.

Adding middleware could be done the same way as we are doing it in Express app. Add the highlighted lines, and let’s see what they do.

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
var dogs = require('./src/models/mock_data/dogs.js');
// Construct a schema, using GraphQL schema language
var schema = buildSchema(`
  type Mutation {
    setNewDog(id: String, breed: String, displayImage: String): String
  }  
  type dog {
    id: String,
    breed: String,
    displayImage: String
  }
  type dogsCatalog {
    getDogByBreed(breed: String): dog
  }
  type Query {
    queryDogs: dogsCatalog
  }  
`);
class dogsCatalog {
  
  getDogByBreed({breed}) {
    var result = dogs.find(function(dog){
      return breed == dog.breed ? dog : null;
    });
    return result;
  }
}
// The root provides a resolver function for each API endpoint
var root = {
  queryDogs: () => {
    return new dogsCatalog();
  },
  setNewDog: ({id, breed, displayImage}) => {
    var result = dogs.find(function(dog){
      return breed == dog.breed ? dog : null;
    });
    if(result != null) {
      return 'dog already exists!';
    }
    dogs.push({
      "breed": breed,
      "displayImage": displayImage,
      "id": id      
    });
    return 'dog added successfully !';
  }
};

// Logger middleware
var logger = function(req, res, next) {
  console.log("GOT REQUEST >", req.ip);
  next(); // Passing the request to the next handler in the stack.
}

var app = express();
app.use(logger);
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(4001);
console.log('Running a GraphQL API server at localhost:4000/graphql');

 

 what we just did:
– we created the middleware object to log every request ip (lines 52-56)
– in the middleware we added the next() function to proceed to the next middleware none we are done with the request processing.
– we told Express to use our new middleware app.use(logger);

And as simple as that we created our own logging class.

Mutations and input types

 

Let’s scrap our user greeting and make really useful schema, that will show up a dog breed catalog. We are going to use it in another tutorial to create a React component to display the dog catalog.

Set up mock data.

Create a file under ./src/modules/mock_data that will serve as our data provider. Let’s add a couple of dog breeds there.

./src/modules/mock_data/dogs.js

module.exports = [
  {
    "breed": "affenpinscher",
    "displayImage": "https://images.dog.ceo/breeds/affenpinscher/n02110627_10225.jpg",
    "id": "Z1fdFgU"
  },
  {
    "breed": "african",
    "displayImage": "https://images.dog.ceo/breeds/african/n02116738_2515.jpg",
    "id": "Z1gPiBt"
  },
  {
    "breed": "airedale",
    "displayImage": "https://images.dog.ceo/breeds/airedale/n02096051_6335.jpg",
    "id": "ZNDtCU"
  },
  {
    "breed": "akita",
    "displayImage": "https://images.dog.ceo/breeds/akita/Japaneseakita.jpg",
    "id": "6HalQ"
  },
  {
    "breed": "appenzeller",
    "displayImage": "https://images.dog.ceo/breeds/appenzeller/n02107908_3311.jpg",
    "id": "Z1tlucN"
  },
  {
    "breed": "basenji",
    "displayImage": "https://images.dog.ceo/breeds/basenji/n02110806_3415.jpg",
    "id": "Zo1k5y"
  }  
];

Writing a query to fetch the mock data.

Let’s first write a query to fetch dog’s details based on the breed.

Based on the JSON data above, dog’s schema would look like this:

...
  type dog {
    id: String,
    breed: String,
    displayImage: String
  }
  type dogsCatalog {
    getDogByBreed(breed: String): dog
  }
  type Query {
    queryDogs: dogsCatalog
  } 
...

We created a dogCatalog query (line 7) that accepts the dog breed, and returns a dog type declared in the beginning of the sniped above.

Then the resolver would look like this:

...
class dogsCatalog {
  
  getDogByBreed({breed}) {
    var result = dogs.find(function(dog){
      return breed == dog.breed ? dog : null;
    });
    return result;
  }
}
...

 

Write the mutation.

The mutations are used to modify data. In GraphQL they are similar as queries and could be written in a similar way.

The basic idea.

...
  type Mutation {
    setNewDog(id: String, breed: String, displayImage: String): String
  }  
...

here, we defined mutation named setNewDog which simply takes a few parameters (id, breed and displayImage) and returns the status message.

The resolver will look like this:

...
  setNewDog: ({id, breed, displayImage}) => {
    var result = dogs.find(function(dog){
      return breed == dog.breed ? dog : null;
    });
    if(result != null) {
      return 'dog allready exists!';
    }

    dogs.push({
      "breed": breed,
      "displayImage": displayImage,
      "id": id      
    });
    return 'dog added successfuly !';
  }
...

Let’s put them all together:

./src/server.js

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
var dogs = require('./src/models/mock_data/dogs.js');

// Construct a schema, using GraphQL schema language

var schema = buildSchema(`


  type Mutation {
    setNewDog(id: String, breed: String, displayImage: String): String
  }  

  type dog {
    id: String,
    breed: String,
    displayImage: String
  }

  type dogsCatalog {
    getDogByBreed(breed: String): dog
  }

  type Query {
    queryDogs: dogsCatalog
  }  
`);

class dogsCatalog {
  
  getDogByBreed({breed}) {
    var result = dogs.find(function(dog){
      return breed == dog.breed ? dog : null;
    });
    return result;
  }
}

// The root provides a resolver function for each API endpoint
var root = {
  queryDogs: () => {
    return new dogsCatalog();
  },
  setNewDog: ({id, breed, displayImage}) => {
    var result = dogs.find(function(dog){
      return breed == dog.breed ? dog : null;
    });
    if(result != null) {
      return 'dog already exists!';
    }

    dogs.push({
      "breed": breed,
      "displayImage": displayImage,
      "id": id      
    });
    return 'dog added successfully !';
  }
};

var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');

Test Using GraphQL UI

Writing a query to fetch existing data.

Now navigate to GraphQL UI http://localhost:4001/graphql and add this in the query window (up left)

query queryLabel($breed: String!) {
  queryDogs {
    getDogByBreed(breed: $breed) {
      id
      displayImage,
      breed
    }
  }
}

and this in the variables window (down left)

{
  "breed": "african"
}

hit play and the result should be this:

{
  "data": {
    "queryDogs": {
      "getDogByBreed": {
        "id": "Z1gPiBt",
        "displayImage": "https://images.dog.ceo/breeds/african/n02116738_2515.jpg",
        "breed": "african"
      }
    }
  }
}

Now change the breed in the variables window (down left) to ‘labrador’ and hit play again, and the result is null since there is no record for this breed.

Write a mutation to add a new record to data structure.

Open a new QraphQL UI tab and add the following mutation in the query window:

mutation setNewDogLabel($id: String, $breed: String, $displayImage: String) {
  setNewDog(id: $id, breed: $breed, displayImage: $displayImage)
}

and this in the variables window:

{
  "id": "Z2iEkxg",
  "breed": "labrador",
  "displayImage": "https://images.dog.ceo/breeds/labrador/n02099712_2120.jpg"
}

Hit play and if everything went well you will see the success message.

{
  "data": {
    "setNewDog": "dog added successfuly !"
  }
}

(Out of curiosity you might want to hit play one more time to see what message you will get)

Now, navigate back to the previous GraphQL UI tab and hit play again and you will see newly created record.

 

 

 

 

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
var dogs = require('./src/models/mock_data/dogs.js');

// Construct a schema, using GraphQL schema language

var schema = buildSchema(`

  input DogInput {
    id: String,
    breed: String,
    displayImage: String
  }

  type Mutation {
    setNewDog(input: DogInput): String
  }  

  type dog {
    id: String,
    breed: String,
    displayImage: String
  }

  type dogsCatalog {
    getDogByBreed(breed: String): dog
  }

  type Query {
    queryDogs: dogsCatalog
  }  
`);

class dogsCatalog {
  
  getDogByBreed({breed}) {
    var result = dogs.find(function(dog){
      return breed == dog.breed ? dog : null;
    });
    return result;
  }
}

// The root provides a resolver function for each API endpoint
var root = {
  queryDogs: () => {
    return new dogsCatalog();
  },
  setNewDog: ({input}) => {
    var result = dogs.find(function(dog){
      return input.breed == dog.breed ? dog : null;
    });
    if(result != null) {
      return 'dog allready exists!';
    }

    dogs.push({
      "breed": input.breed,
      "displayImage": input.displayImage,
      "id": input.id      
    });
    return 'dog added successfuly !';
  }
};

var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');

 

Object Types

In many cases returning a scalar values like Int or String might not be enough and we might want to return more complex data, like Objects. Let’s modify our previous example to do this.

Adding type object into GraphQL’s schema.

Objects could be defined in the schema the same way as we defined the Query (lines 4-7) and then we could modify greetingUser Query to return our new object: greeting instead of String 

...
var schema = buildSchema(`

  type greeting {
    userName: String
    userRollDice(userName: String): String
  }

  type Query {
    greetingUser(userName:String!): greeting
  }
`);
...

Once we have the new greeting type into the schema we could write the resolver, which could be a plain Java Script object object (in our case a function that returns the exposed methods):

...
var greeting = (userName) => {

  function rollDice() {
    return Math.floor(Math.random() * 6) + 1;
  }  
    
  function userRollDice(args) {
    return `User ${args.userName} rolled: ${rollDice()}`;
  }
  return  {
    userName: userName,
    userRollDice: userRollDice
  }
}
...

what we just did:
– we created a new method called greeting which exposes one string property named userName, that we are passing and one method called userRollDice which will return String which will describe (in plain text) what dice # the used rolled.
– we also added a helper method called rollDice which will return a random number.

The whole code should look like this:

./server.js

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
// Construct a schema, using GraphQL schema language

var schema = buildSchema(`

  type greeting {
    userName: String
    userRollDice(userName: String): String
  }

  type Query {
    greetingUser(userName:String!): greeting
  }
`);

var greeting = (userName) => {
  
  function rollDice() {
    return Math.floor(Math.random() * 6) + 1;
  }  
    
  function userRollDice(args) {
    return `User ${args.userName} rolled: ${rollDice()}`;
  }
  return  {
    userName: userName,
    userRollDice: userRollDice
  }
}


// The root provides a resolver function for each API endpoint
var root = {
  greetingUser: (args) => {
    return greeting(args.userName);
  }
};

var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(4001);
console.log('Running a GraphQL API server at localhost:4000/graphql');

Let’s give it a try. Using the Document explorer click on Query and you will see that there is a query named greetingUser, that expects userName string, and returns the new method greeting.

greetingUser(userNameString!): greeting

Explore the greeting and you will see that it could be queried for userName and userRollDice which also expects one string parameter.

userRollDice(userNameString): String
Having this information we are ready to construct our new query. Add the code below in GraphQL UI’s query box (up left)
query queryLabel($userName: String!) {
  greetingUser(userName: $userName){
    userName
    userRollDice(userName: $userName)
  }
}

and leave the parameter box (down left) the same for now.

{
  "userName": "Sam Smith"
}

Hitting play will produce a nice response like this:

{
  "data": {
    "greetingUser": {
      "userName": "Sam Smith",
      "userRollDice": "User Sam Smith rolled: 4"
    }
  }
}

GraphQL just returned us the greeting object that we requested.

Using ES6 features.

Let’s modify the resolver to use ES6 class syntax and also let’s add a destructors to clean up the code a bit.

./server.js

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
// Construct a schema, using GraphQL schema language

var schema = buildSchema(`

  type greeting {
    userName: String
    userRollDice(userName: String): String
  }

  type Query {
    greetingUser(userName:String!): greeting
  }
`);

class greeting {
  
  constructor(userName) {
    this.userName = userName;
  }
  
  rollDice() {
    return Math.floor(Math.random() * 6) + 1;
  }  
    
  userRollDice({userName}) {
    return `User ${userName} rolled: ${this.rollDice()}`;
  }
}


// The root provides a resolver function for each API endpoint
var root = {
  greetingUser: ({userName}) => {
    return new greeting(userName);
  }
};

var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));
app.listen(4001);
console.log('Running a GraphQL API server at localhost:4000/graphql');

 what we just did:
– we replaced the JavaScript function resolver with class having the same methods.
– in userRollDice method we replaced args.userName with the destructor {userName}
– in the root resolver we call greetingUser, passing the userName and returning new instance of greeting

Adding Redux

branch-name:  
Click To Copy

 

In the previous tutorial we showed how to build custom Redux like store, which is a great way to understand how Redux work, but if we want a production grade app, we have to do more work on our custom Redux like store, since we cheated a bit.

For example our redux store emits setState no matter if the properties are actually changed or not which is ok for a demo app but for a big app with a lot of mapStateToProps it will have performance impact, so let’s not re-invent the wheel but use the Redux store instead.

yarn add redux react-redux

Since Redux like implementation that we did in the previous tutorial is very similar to the actual Redux, there are just a few changes that we need to do in order to start using Redux.

./src/components/App/index.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import PageLayout from '../../containers/PageLayout';
import { Provider } from 'react-redux';
import { createStore} from 'redux';
import reducers from '../../reducers';

import fetch from 'unfetch';


const store = createStore(reducers, {});

export default class App extends Component {

  render() {

    const GRAPHQL_URL = 'http://localhost:4001/graphql';
    const client = new ApolloClient({
      link: new HttpLink({ uri:  GRAPHQL_URL, fetch: fetch }),
      cache: new InMemoryCache()
    });  

    return (
      <Provider store={store}>
        <ApolloProvider client={client}>
          <Router>
            <Switch>
              <Route exact path="*" component={PageLayout} />    
            </Switch>
          </Router>
        </ApolloProvider>
      </Provider>
    );
  }
}

 what we just did:
– we removed our custom store implementation:

import Store from ‘../../store’;
import Reducers from ‘../../reducers’;
import Provider from ‘../../containers/Provider’;


– and replaced it with the Redux provider and create store (line 8 and 9)
– we called the Redux createStore (line 15)
– finally we wrapped the app with the new provider passing the store (line 28)

Next step is just cleaning up the code a bit.
– We renamed the index.js reducer to ./src/reducers/useer.js so we could keep each different reducer types in separate files and we added one main reducer ./src/reducers/index.js that will combine all other reducers. (in our case ./src/reducers/useer.js for now)

./src/reducers/user.js

const CHANGE_USERNAME = 'CHANGE_USERNAME';
const TOGGLE_EDIT_MODE = 'TOGGLE_EDIT_MODE';

const initialState = {
  todos: [],
  userName: "No Name",
  editMode: false
};

  const reducer = (state = initialState, action) => {
    switch (action.type) {
      case CHANGE_USERNAME: {
        let newState = {...state};
        newState.userName = action.data;
        return newState;
      }

      case TOGGLE_EDIT_MODE: {
        let newState = {...state};
        newState.editMode = !newState.editMode;
        return newState; 
      }

      default:
        return state;
    }
  };

export default reducer;

 

./src/reducers/index.js

import { combineReducers } from 'redux';
import user from './user';

export default combineReducers({
  user
});

 

And the best part is that since our Redux like implementation was so similar to the actual Redux implementation, we have to make just two little changes:
– Replace import connect from '../../containers/Provider/connect'; with the Redux connect import { connect } from 'react-redux';
– And since we added combineReducers we have to add user property to access the users reducer.

./src/components/About/index.js ./src/components/Greetings/index.js.

import React, { Component } from 'react';
import { connect } from 'react-redux';

const styles = require('./styles.scss');

const CHANGE_USERNAME = 'CHANGE_USERNAME';
const TOGGLE_EDIT_MODE = 'TOGGLE_EDIT_MODE';

class Greetings extends Component {

  constructor(props) {
    super(props); 
  }
  

  doneEditUsername() {
    let newName = document.querySelector('#inputField').value;
    this.props.changeUserName(newName);
    this.props.toggleLogInPopup();
  }

  usernameChanged(el) {
    let newName = el.target.value;    
    this.props.changeUserName(newName);
  }

  onToggleEditMode() {
    this.props.toggleLogInPopup();
  }

  render() {
    let element = <h2 onClick={() =>{   this.onToggleEditMode()  }}>Hello:  {this.props.userName}</h2>;
    if(this.props.editMode)
      element = <h2>Type new name:<input type="text" id='inputField' value={this.props.userName} onChange={(el) => { this.usernameChanged(el);}} /><button onClick={() =>{ this.doneEditUsername() }}>done</button></h2>
    return (
      <div>
        <div className={styles.wrapper}>
          {element}
        </div>
      </div>);
  }
}

const mapStateToProps = ( storeState ) => {
  return {  
    userName: storeState.user.userName,
    editMode: storeState.user.editMode
  }
}

const mapDispatchToProps = dispatch => {
  return {
    toggleLogInPopup: () => {
      dispatch({type: TOGGLE_EDIT_MODE});
    },
    changeUserName: (userName) => {
      dispatch({type: CHANGE_USERNAME, data: userName});
    }
  }
};


export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Greetings);

 

./src/components/About/index.js ./src/components/About/index.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

const CHANGE_USERNAME = 'CHANGE_USERNAME';
class About extends Component {
  constructor(props) {
    super(props);
    this.state = {
      userName: this.props.userName,
    };    
  }
  handleChange() {
    const userName = document.querySelector('input[name=username]').value;
    this.setState( { userName: userName } );
    this.props.onEdit(userName);
  }
  render() {
    return (
      <div>
        <p>This is <input type="text" name="username" value={this.state.userName} onChange={() => { this.handleChange()}} /></p>
      </div>
    );
  }
}
//export default About;
const mapStateToProps = storeState => ({
  userName: storeState.user.userName
}
);
const mapDispatchToProps = dispatch => ({
  onEdit: (userName) => dispatch({
    type: CHANGE_USERNAME,
    data: userName
  })
});
const AboutContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(About);
export default AboutContainer;

 

And delete ./src/containers/Provider folder.

And now all custom Redux like implementation was replaced wit the actual Redux store. Give it a try and everything shoul;d work like before but using the actual Redux store.

 

branch-name:  
Click To Copy

 

Max Consecutive Ones

[tabby title=”Task”]

Given a binary array, find the maximum number of consecutive 1s in this array.

Example 1:

Input: [1,1,0,1,1,1]
Output: 3
Explanation: The first two digits or the last three digits are consecutive 1s.
    The maximum number of consecutive 1s is 3.

Note:

  • The input array will only contain 0 and 1.
  • The length of input array is a positive integer and will not exceed 10,000

[tabby title=”Solution”]

The solution:

/**
 * @param {number[]} nums
 * @return {number}
 */
var findMaxConsecutiveOnes = function(nums) {
    var count = 0;
    var last = 0;
    for(var c in nums) {
        if(nums[c])
            count ++;
        else {
            if(count > last)
                last = count;
            count = 0;
        }
    }
    return Math.max(count, last);
};

 

[tabbyending]

Plus One

[tabby title=”Task”]

Given a non-empty array of digits representing a non-negative integer, plus one to the integer.

The digits are stored such that the most significant digit is at the head of the list, and each element in the array contain a single digit.

You may assume the integer does not contain any leading zero, except the number 0 itself.

Example 1:

Input:

 [1,2,3]

Output:

 [1,2,4]

Explanation:

 The array represents the integer 123.

Example 2:

Input:

 [4,3,2,1]

Output:

 [4,3,2,2]

Explanation:

 The array represents the integer 4321.

This problem was taken from Leetcode

[tabby title=”Solution”]

The solution:

The solution is pretty straight forward. We traverse all digits in the opposite direction, and make sure that we add +1 only on the last digit (the first iteration ). Then if the digit > 9 we set up the dit to 0, and we carry on 1 to add it to the next digit, and keep going till we reach the first digit. If the first digit is 9 and cary over is not 0, we add 1 to the beginning of the array.

let’s consider: 9 9 9

iteration 1:
9            9
9            9
9 + 1 =  0 + cary on: 1

iteration 2:
9            9
9 + 1 =  0 + cary on: 1
0            0

iteration 3:
9 + 1 = 0 + cary on: 1
0          0
0          0

finally:
1     << adding leading 1 
0
0
0

which gave up the final result: 1 0 0 0

The solution will look like this:

Java Script

/**
 * @param {number[]} digits
 * @return {number[]}
 */
var plusOne = function(digits) {
    
    var carryOn = 0;
    for(q = digits.length - 1; q!=-1; q--) {
        var digit = digits[q];
        if(q == digits.length - 1) {
            digit = digit + 1;
            if(digit == 10) {
                digit = 0;
                carryOn = 1;
            }
        }
        else {
            if(digit == 9 && carryOn) {
                digit = 0;
            }
            else {
                digit = digit + carryOn;
                carryOn = 0;
            }
        }
        digits[q] = digit;
    }
    if(carryOn > 0) 
        digits.unshift(1);
    return digits;
};

 

what we just did:
– (lines 11 – 18) happened only if this is the last digit, where we have to add 1
– (lines 18 – 20) if we have carry on value of carryOn > 0 and digit = 9 simply set digit = 0 and left carryOn to be equal to 1 for the next iteration.

[tabbyending]

Valid Parentheses

[tabby title=”Task”]

Given a string containing just the characters '('')''{''}''[' and ']', determine if the input string is valid.

An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.
  2. Open brackets must be closed in the correct order.

Note that an empty string is also considered valid.

Example 1:

Input:

 "()"

Output:

 true

Example 2:

Input:

 "()[]{}"

Output:

 true

Example 3:

Input:

 "(]"

Output:

 false

Example 4:

Input:

 "([)]"

Output:

 false

Example 5:

Input:

 "{[]}"

Output:

 true

This problem was taken from Leetcode

[tabby title=”Solution”]

The solution:

Let’s look at the simplest scenario where we have only one type of brackets: ‘(‘ and ‘)’. Then all that we need to do in order to figure out if each bracket has corresponding closing bracket is to put each opening bracket into a stack, and pop one bracket when we see closing bracket.

Ideally if the brackets are “normalized” (all of the open one have corresponding closing brackets) we will end up with empty stack.

in example :

( ( ) ( ) ( ( ) ) )
1 2  3  4 5  6  7  8  9  10

so here are all 10 steps:

steps  stack
1          (
2          (  (
3         (
4         (  (
5         (
6         (  (
7         (  (  (
8         (  (
9         (
10

Immediately it becomes clear that if the string  length is not an even number, it automatically becomes invalid. So we could do this check in the very beginning (lines 9 and 10)  below.

So let’s look at the current example where we have 3 different tags: ‘{}’, ‘()’, ‘[]’

The rule for a valid string is:
open tags:
– we could have as many open tag as we want. i.e. : ({[[ ...
closing tags:
– every closing tag should match previously opened tag ([]) – valid, ([)] – invalid.

So now we know the rules, let’s write the code.

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    
    var input = s.split('');
    
    if(input.length % 2 != 0)
        return false;
    
    var stack = [];

    var tagIndex = {
        '(': 0,
        ')': 1,
        '{': 2,
        '}': 3,
        '[': 4,
        ']': 5
    };        


    for(var q=0;q < input.length; q++) {
        var symbol = input[q];
        var tagType = (tagIndex[symbol] % 2); // 0 - open, 1 - close
        if(tagType == 0) {
            stack.push(symbol);
        }
        else {
            // this is a closing tag, make sure that it follows the rules
            lastTag = stack.pop();            
            lastTagIndex = tagIndex[lastTag];
            if( tagIndex[symbol] != lastTagIndex + 1 )
                return false;
        }
    }
    
    if(stack.length > 0)
        return false;
    return true;
};

 

what we just did:
– lines 9 and 10: we check if the length of the string is odd and return false immediately if so.
– we added tagIndex object where every bracket has it’s index which will help us to identify if we have the open or closing bracket.
– If it is open bracket, we just putting it inside the stack.
– if this is a close bracket, we are using the newly created  tagIndex to figure out if this is the right closing bracket from the same type. Simply following the rule that we described above (lines 32 -35)  `if( tagIndex[symbol] != lastTagIndex + 1 )` Basically we check if the previous opening tag in the stack is of the same type of the current closing tag.

[tabbyending]

Adding dynamic page layout loaded from GraphQL

branch-name:  
Click To Copy

 

Having page layout hardcoded works fine but it doesn’t let us dynamically modify it without changing the code. What about if we store the page layout in mongoDB, then request it through GraphQL and create component that could dynamically load the page components.

Luckily for us we already have page layout set up in GraphQL which for the homepage looks like this:

module.exports = [
    {
      id: 'home',
      url: '/home',
      layout: [ 
        {
          span: 12,
          components: [
            {
              name: "Header"
            }
          ]
        },
        {
          span: 12,
          components:[
            {
              name: "Home"
            }
          ] 
        }                       
      ]
    }
  ]

It simply shows that the page layout has a header and Home component. We are going to build component that will interpret this and will render a webpage with the requested components. This way we will have the flexibility to:

  • dynamically change page layout by adding and removing components without code change
  • create new pages on the fly without code change.

And if you want to explore all other layouts you could look into GraphQL project under ./src/models/mock_data/pages

Creating PageLayout component to load our modules.

Let’s change App/index.js remove all other routes and redirect everything to the new component that we are going to create (line 21).

./src/components/App/index.js

import React, { Component } from 'react';
import PageLayout from '../../containers/PageLayout';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import styles from './styles.scss';
export default class App extends Component {
  render() {
    const GRAPHQL_URL = 'http://localhost:4001/graphql';
    const client = new ApolloClient({
      link: new HttpLink({ uri:  GRAPHQL_URL }),
      cache: new InMemoryCache()
    });  
    return (
      <div className={styles.appWrapper}>
        <ApolloProvider client={client}>
          <Router>
            <Switch>
            <Route exact path="*" component={PageLayout} />  
            </Switch>
          </Router>
        </ApolloProvider>
      </div>        
    );
  }
}

Now let’s continue with creating the component itself.

./src/containers/PageLayout/index.js

import React, { Component } from 'react';
import query from './query';
import { graphql } from 'react-apollo';

class PageLayout extends Component {

    constructor(props) {
      super(props);      
    } 
  
    render() {
        console.log(this.props.data.getPageByUrl);
        return (
        <div>
            this is my page layout!
        </div>
        );
    }
}

export default graphql(query, {
    options(props) {
      return {
        variables: {
          url: props.history.location.pathname
        },
      };
    },
  })(PageLayout);

./src/containers/PageLayout/query.js

import gql from 'graphql-tag';

const query = gql`
query getPageByUrl($url: String) 
{
  getPageByUrl(url: $url) {
    id
    url
    layout {
      span
      components {
        name
      }        
    }
  }
}
`
export default query;

and when you run the project and look at the browser console you will see the layout structure that we printed out in index.js (line 12)

This basically describes which components and in what order should be rendered for the ‘home’ page.

Hook PageLayot component to render required HTML components.

Create ComponentList sub component with the following contents:

./src/containers/PageLayout/ComponentList/index.js

import Header from '../../../components/Header';
import Home from '../../../components/Home';
import About from '../../../components/About';
import Greetings from '../../../components/Greetings';
import Gallery from '../../../containers/DogsCatalog';

export default {
  Home: Home,
  About: About,
  Greetings: Greetings
}

This component simply provide a list of all components that we are going to render in our website.

Now modify PageLayout component to add the list and render the HTML components.

./src/containers/PageLayout/index.js

import React, { Component } from 'react';
import ComponentList from './ComponentList';
import query from './query';
import { graphql } from 'react-apollo';

const styles = require('./styles.scss');

class PageLayout extends Component {

    constructor(props) {
      super(props);      
    } 
  
    render() {
      if(!this.props.data.getPageByUrl) {
        return(<p>loading ...</p>);
      }     
      
      const allLayout = this.props.data.getPageByUrl.layout.map((layoutList) => {
        const layout = layoutList.components.map((component, id , components) => {
          const componentName = component.name;        
          const ChildComponent = ComponentList[componentName];
          if(typeof ChildComponent === 'undefined') {
            return(
              <div key='{id}' className={styles.error}>Can't find {componentName} component!</div>
            );
          }
          return (
              <ChildComponent key={componentName} />
          );
        });
        return layout;
      });
      return(allLayout);
    }
}

export default graphql(query, {
    options(props) {
      return {
        variables: {
          url: props.history.location.pathname
        },
      };
    },
  })(PageLayout);

 what we just did:
– we added the ComponentList which returns all components on our website
– (Line 19) we are getting the layout for this particular url that contains all components, then we loop through all components (line 20) and create an instances for all of them.
– If the component cannot be found it will show red error message (lines 23-27)

Also add the css which will colorize the error message in red:

./src/containers/PageLayout/styles.scss

.error {
  background: red;
  color: white;
}

navigate to http://localhost:8080/home and you are probably going to see this screen:

This is actually made intentional, to demonstrate how our error handler works If it can’t find particular component.

Let’s fix this. Add the highlighted lines with the missing components.

./src/containers/PageLayout/ComponentList/index.js

import Header from '../../../components/Header';
import Home from '../../../components/Home';
import About from '../../../components/About';
import Greetings from '../../../components/Greetings';
import Gallery from '../../../containers/DogsCatalog';

export default {
  Home: Home,
  About: About,
  Greetings: Greetings,
  DogsCatalogWithRedux: DogsCatalog,
  Header: Header
}

Navigate again to http://localhost:8080/home and you should have SPA with 4 pages.

 

branch-name:  
Click To Copy

 

 

 

Adding navigation in Single Page App

The concept of Single Page App is that all modules will be dynamically rendered while user navigates the page, without reloading. Express routing which we added is providing this functionality for us, so let’s use it.

Adding navigation.

Let’s get started. Edit index.html and add the highlighted line so we will have some marker on the page that will indicate if the page reloads.

./index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Babel Webpack Boilerplate</title>
    </head>
    <body>
        <h3>SPA</h3>
        <div id="root"></div>
        <script type="text/javascript" src="dist/main-bundle.js"></script>
    </body>
</html>

 

Create header menu for navigation.

Let’s create new navigation component and call it Header component. Create new folder ./src/components/Header and add:

./src/components/Header/index.js

import React from 'react';
import { Link } from 'react-router-dom';

const styles = require('./styles.scss');

const Header = ( {title} ) => (
  <div>
    <h2>{ title }</h2>
    <div className={styles.wrapper}>
      <ul>
        <li><Link to='/'>HOME</Link></li>
        <li><Link to='/about'>ABOUT</Link></li>
        <li><Link to='/greetings'>GREETINGS</Link></li>   
        <li><Link to='/gallery'>GALLERY</Link></li>      
      </ul>
    </div>
  </div>
);

export default Header;

also add the CSS

./src/components/Header/styles.scss

.wrapper {
  
  ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    border: 1px solid #e7e7e7;
    background-color: #f3f3f3;
  }
  li {
    float: left;
  }

  li a {
    display: block;
    color: #666;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
  }

  li a:hover:not(.active) {
      background-color: #ddd;
  }

  li a.active {
      color: white;
    
  }
}

Add header menu in our components.

Home component

We added home as a first link but we actually don’t have Home component, so let’s create a simple one and add header navigation there.

create ./src/components/Home folder and add:

./src/components/Home/index.js

import React from 'react';
import Header from '../Header';

const styles = require('./styles.scss');

const Home = () => (
  <div>
    <Header />
    <div className={styles.wrapper}>This is my home section.</div>
  </div>
)

export default Home;

and the css:

./src/components/Home/styles.js

.wrapper {
  background: rgb(141, 141, 172);
  color: white;
  text-align: center;
}

About component.

do the same for About component.

./src/components/About/index.js

import React from 'react';
import Header from '../Header';

const styles = require('./styles.scss');

const About = () => (
  <div>
    <Header />
    <div className={styles.wrapper}>This is the About section.</div>
  </div>
)

export default About;

./src/components/Home/styles.scss

.wrapper {
  background: rgb(141, 141, 172);
  color: white;
  text-align: center;
}

DogsCatalog container component.

and DogsCatalog container component

./src/containers/DogsCatalog/index.js

/* eslint-disable no-debugger */

import React, { Component } from 'react';
import { graphql } from 'react-apollo';
import DogDetails from './DogDetails';
import Header from '../../components/Header';

import query from './query';

const styles = require('./styles.scss');


class DogsCatalog extends Component {

  constructor(props) {
    super(props);
    this.state = {
        breed: "labrador"
    }
  }

  handleClick(breedType) {
    this.setState({
        breed: breedType
    });
  }

  render() {  
    if(typeof this.props.data.getDogsList == 'undefined') {
      return(
        <div>Loading ... </div>
      );
    }
    return(
      <div>
        <Header />
        <div className={styles.Wrapper}>
          <p>Dogs catalog</p>
          <div className={styles.Buttons}>
            {this.props.data.getDogsList.map( (dog) => {
              return (<button key={dog.id} onClick={ () => { this.handleClick(dog.breed) } }>{dog.breed}</button>);
            })}          
          </div>
          <DogDetails breed={this.state.breed} />
        </div>
      </div>
    );
  }
}


export default graphql(query, {})(DogsCatalog);

Greetings component.

./src/components/Greetings/index.js

import React from 'react';
import Header from '../Header';

const styles = require('./styles.scss');

const Greetings = (props) => (
  <div>
    <Header />
    <div className={styles.wrapper}><h2>Hello  {props.user}</h2></div>
  </div>
)



export default Greetings;

Set up the routes.

./src/components/app.index.js

import React, { Component } from 'react';
import Greetings from '../greetings';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import About from '../about';
import Home from '../Home';
import { ApolloProvider, graphql } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import DogsCatalog from '../../containers/DogsCatalog';
import fetch from 'unfetch';

export default class App extends Component {

  render() {

    const GRAPHQL_URL = 'http://localhost:4001/graphql';
    const client = new ApolloClient({
      link: new HttpLink({ uri:  GRAPHQL_URL, fetch: fetch }),
      cache: new InMemoryCache()
    });  

    return (
      <ApolloProvider client={client}>
        <Router>
          <Switch>
            <Route exact path="/" component={Home} />    
            <Route exact path="/About" component={About} />                      
            <Route exact path="/greetings" component={Greetings} />
            <Route exact path="/gallery" component={DogsCatalog} />
          </Switch>
        </Router>
      </ApolloProvider>
    );
  }
}

Basically we told Express which component to render for each route.

Give it a try and fire up the server using your preferred config.

At this point you will have neat SPA (Single Page App) that dynamically renders the components without ever reloading the page.