How to do Unit Testing with Jest in React?

In this tutorial, we will create a new project to illustrate Test Driven Development (TDD) with React and Jest. We will create a simple model that can generate a greeting and integrate it in a Reach application. 

Part 1 – Creating the project

Let’s create a new project.

1. Create a directory C:\LabWork , open a command project.

2. Change into the LabWork directory [create the folder if required]:

cd C:\LabWork

3. Create a new React project using the following command:

npx create-react-app testing-app

4. Enter the new project:

cd testing-app

If desired, start your favorite text editor.

Part 2 – Creating our first test

In the spirit of TDD, let’s create a unit test to verify that our future model works correctly. The unit test will also serve as a specification for our model.

1. Using your preferred text editor, create the file src/Greeter.test.js

2. Enter the following code:

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

test('provides a greeting', () => {
  const greeter = new Greeter('Ada Lovelace');

  const greeting = greeter.getGreeting();

  expect(greeting).toBe('Hello, Ada Lovelace')
});

3. Save your work.

4. Run the unit test and watch it fail:

npm run test

By default, the test running executes any files in the src directory that end with ‘.test.js’

5. Leave the test running in the command prompt window.

6. Create a new file called src/Greeter.js

7. Enter the following code:

export default class Greeter {
  constructor(userName = '') {
    this.userName = userName;
  }

  getGreeting() {
    if (this.userName) {
      return `Hello, ${this.userName}`;
    } else {
      return `Hello, Anonymous`;
    }
  }

  async getGreetingAsync() {
    return this.getGreeting();
  }
}

8. Save your work.

9. Return to the command prompt. Observer that the test now passes.

(If the test fails, verify your code from step 7)

10. Let’s complete the unit test. Add the following code at the end of src/Greeter.test.js:

test('provides a default greeting', () => {
  const greeter = new Greeter();

  const greeting = greeter.getGreeting();

  expect(greeting).toBe('Hello, Anonymous')
});

test('Can generate a greeting asynchronously', async () => {
  const greeter = new Greeter('Ada Lovelace');

  const greeting = await greeter.getGreetingAsync();

  expect(greeting).toBe('Hello, Ada Lovelace');
})

11. Save the file.

12. Return to the command prompt window. Observe that now all tests are said to pass.

Part 3 – Creating the React application

In the previous part, we performed unit tests but we did not write any React code. Now, let’s add a user interface on top of our model and test it using Jest.

1. Keep the current command prompt window open.

2. Start a second command prompt.

3. Change directory to C:\LabWork\testing-app

cd C:\LabWork\testing-app

4. Start the development server by executing the following:

npm run start

The placeholder React page comes up in the default browser.

5. Create the file src/GreeterComponent.js with the following code:

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

export default class GreeterComponent extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      greeter: new Greeter(),
    }
  }

  static getDerivedStateFromProps(props, state) {
    return {
      greeter: new Greeter(props.userName)
    };
  }

  render() {
    return <div id='greet'>Message: {this.state.greeter.getGreeting()}</div>
  }
}

6. Save the file.

7. Open src/App.js and replace the placeholder code with the following:

import React from 'react'
import './App.css'
import Greeter from './GreeterComponent'

export default class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      userName: '',
    }
  }

  updateUserName = (event) => {
    this.setState({
      userName: event.target.value,
    })
  }

  clearName = (event) => {
    this.setState({
      userName: '',
    })
  }

  render() {
    return (
      <div id='app'>
        <h3>Input:</h3>
        <p>
          <label htmlFor='userName'>User Name: </label>
          <input type='text' id='userName' value={this.state.userName} onChange={this.updateUserName}/>
          <button onClick={this.clearName}>Clear</button>
        </p>
        <h3>Message:</h3>
        <Greeter userName={this.state.userName}/>
      </div>
    )
  }
}

8. Save the file.

9. Return to the default web browser, and ensure the following page comes up:

10. Test the basic behavior by entering a name and observe the message down below. Test the clear button.

11. Return to the command-prompt that is running Jest. Notice there are src/App.test.js is now failing.

We are ready to add React tests!

Part 4 – Adding React Test

In this part, we will add automated test to ensure that our application renders as expected.

1. Open src/App.test.js

2. Replace the code with the following:

import React from 'react';
import { render } from '@testing-library/react';
import App from './App';
import { fireEvent } from '@testing-library/react'

test('renders two message elements', () => {
  const app = render(<App />);
  const inputHeadings = app.getAllByText(/message:/i);
  expect(inputHeadings.length).toBe(2);
});

3. Save the file.

4. Ensure that all unit test pass.

5. Let’s add a couple more unit test. Add the following code at the end of src/App.test.js:

test('has a GreetingComponent', () => {
  const app = render(<App />);

  const greetingComponent = app.getByText(/Anonymous/i);

  expect(greetingComponent).toBeInTheDocument();
})

test('changing the input updates the message', () => {
  const app = render(<App />);

  const input = app.getByLabelText(/user name/i);

  fireEvent.change(input, { target: { value: 'Ada Lovelace '}});

  const message1 = app.getByText(/Hello, Ada Lovelace/i);
  expect(message1).toBeInTheDocument();

  const clearButton = app.getByText(/clear/i);

  fireEvent.click(clearButton);

  const message2 = app.getByText(/Hello, Anonymous/i);
  expect(message2).toBeInTheDocument();
})

6. Save the file.

7. Ensure that all test pass.

8. Quit Jest by pressing ‘q’ at the command prompt.

9. Close all.

Part 5 – Review

In this tutorial, we created unit test to ensure our business logic and our rendering is correct. This will allow up to evolve the application with the confidence that and side-effect introduced by changes in the application can be quickly detected.

Current Trends in Infrastructure Training

Due to the popularity of Infrastructure concepts like DevOps, CI/CD, Automation, Cloud, and Containerization, here is the general industry trend seen among infrastructure over the last few years. 

Overall

 There is a general trend towards more automation and CI/CD due to the insertion of Dev Ops practices and ideas in most organizations.  Couple this with the move towards Agile and DevOps and you are seeing the infrastructure position ,whether it is titled  System Engineer, System Administrator, DevOps Engineer, Infrastructure Engineer etc, move into coding/orchestrating sophisticated self-provisioned offerings.  What does that mean?  Infrastructures are not expected to provide AWS style automated pipelines that do everything from delivering working code from source to production, but also create production systems in a similar manner. This expectations is driving a bevy of other skills sets into the Infrastructure role and expectations are super high if you are in this kind of position in terms of technical capabilities.  

Programming Languages

 You now must know a programming language not as a dabbler or hacker, but as someone who can create/build/manipulate product customer-facing software to be DevOps in 2020.   This means not just BASH shell scripting, but a full blown language like Python, Java, .Net, Go etc. Probably in that order is preferred.  you will still be required to know Bash because it is everywhere.  So there is a trend for everyone to know the companies product language (Java, Python, etc) so that can support it and troubleshoot it from an infrastructure perspective.  Bash is still king for most infrastructure teams with Python and Go in that order for most shops that are not Windows based.  For Windows-based shops it is mainly Powershell, .Net and Python.  Java is not favored in most early adopters to startups, but is still used with Enterprises and late adopters not for automation but for product support.

Automation/Orchestration tools

 In addition, you must have an orchestration tool in play in your infrastructure.   So technologies, like Jenkins, Bamboo, TravisCI, TeamCity, Gitlab and Github Actions (pending) are all emerging with Jenkins being the dominant player currently.  Jenkins is slowly losing respect though as it is not emerging tech and doesn’t have great API integration without a lot of manipulation.   The plugin community that enables integrations is not keeping things up to date as quickly as desired and thus people are looking more and more at Gitlab or Github actions or paying for Enterprise versions to cover the gap.  Most Enterprises are also locked into their current tool already through configuration investment and/or licensing. 

 Configuration Management

While this is dipping in popularity in part due to the rise of Immutable infrastructure concepts like Docker and VM Images for every provider (AMI, VMWare, etc) the configuration technologies in this space are extending like crazy to cover other areas such as cloud provisioning.  That being said Ansible is the rising star here with old holdouts like Chef, Puppet and newcomer Salt still present but seemingly losing ground. 

Infrastructure Provisioning

This is a training area tied close to the provider of infrastructure (if you are using AWS you use AWS Cloudformation, Microsoft Azure uses Azure Resources Templates, etc) but multi-cloud was the battle cry in 2019 and it will be in 2020 as well.  Since Hybrid cross-cloud is a target especially with Kubernetes there is a push to have Infrastructure Provisioners that go “across” cloud providers and data center boundaries.  The only tool that does this at present that almost every Dev Ops Engineer I know either loves or hates (no middle ground) is Hashicorp’s Terraform. Classes on this are hot right now.  There are no real cross competitive tools as of my most recent knowledge in late 2019. 

Image Management

 Immutable infrastructure as an architecture is on the rise in most organizations coupled with cloud and containers.   As such there is really only one tool that does this well and that  is Hashicorp’s Packer. Few are offering good classes on this, but since this will generate VM and Container images that can be run across cloud providers it is gaining in popularity.  Needs a Configuration Management tool (see above) to function properly. 

Containerization and Container Orchestration 

This is an overwhelmingly popular area of technology and the emerging trend here is mainly around  Container Orchestration and not Container Run-Time technologies themselves of which Docker remains king.  Kubernetes is the Container Orchestration alpha predator and has eaten and dominated all other competitors by far.  The hype train on this is strong and many organizations are pushing for this without regards to impact or value.   As such many are looking to speed to market for their Kubernetes initiatives so IBM/Redhat Openshift, Rancher, Platform9, Pivotal are key technologies. Managed Services in the cloud like cloud provided Kubernetes like Azure Kubernetes services or Amazon’s Elastic Kubernetes Service are also included in this trend.    Trend-wise Enterprises are using IBM/Redhat Openshift while smaller companies are looking at Rancher (FOSS).  Everyone is looking at the cloud provided Kubernetes services like Amazon Elastic Kubernetes Services, but something to note is that most infrastructures are still using Virtual Machines. 

DevOps

DevOps is emerging mainly under a focus on tools while de-emphasizing its cultural and silo-breaking roots to a certain degree so any classes that focus on  metrics(prometheus, grafana, graphite, nagios, cloudwatchm datadog) are going to be popular.   Anything doing with Continuous Integration/Continuous Delivery/Continuous Deployment in almost any of the popular tool configurations (i.e. CI/CD with Jenkins, Maven, and Artifactory) is also in trend.  DevOps classes are anything that brings all the afore mentioned tools together into a cohesive delivery system are going to be amazingly popular as well. 

Cloud

Trends here depend which provider they are using, but  everyone is now chasing a cloud provider.  Either because their clients are wanting it or they see the obvious benefit of hybridizing their cloud infrastructures.  AWS is seen as the leader and thus AWS trainings are favored, but multi-cloud is the battlecry of most Enterprises who are either chasing customers or who are worried about competition on other fronts from Amazon.com.  Since AWS funds most of Amazon.com operating capital, business-wise Enterprise leaders are looking to avoid funding Amazon.com invasion into IoT, Machine Learning, Last Mile Delivery, Streaming Services etc.   That all being said, most are still looking at AWS as their dominate cloud provider but with an eye on Hybrid data center computing.  

Introduction to Angular Material

This tutorial is adapted from Web Age course Comprehensive Angular 8 Programming.

1.1  What is Material Design (MD)?

Material Design is design language developed by Google. It was released in 2014 and incorporated into the Android OS. It is also available for other platforms (Angular, Web, iOS, Flutter, …). Developers can achieve uniformity in their applications across platforms by using Material Design. It uses paper and Ink paradigm. It uses shadows and lighting to create depth and edges. It incorporates movement that reinforces choice and navigation.

Material Design Specification can be found at https://material.io/design/.

1.2  What is Angular Material (AM)?

Angular Material contains components that implement Material Design UI standards and can be used with Angular. Angular Material components are Built in and for Angular, Reactive – they work across web, mobile and desktop, Fully tested, tuned and optimized, Themeable and Accessible, Support internationalization (i18n) .Using Angular Material components speeds up development.

The main page for Angular Material can be found at https://material.angular.io/.

AM speeds up development by solving the issues listed above which allows teams to spend more time developing application-centric code as opposed to designing and creating basic components

1.3  How to Add Angular Material to a Project?

To use Angular Material it needs to be added to an existing Angular project

  • First Create an Angular Project:

    • Install NodeJS (download installer from NodeJS website)

    • Install Angular CLI: npm install -g @angular/cli@latest

    • Create Angular Project: ng new <app-name> –defaults

  • Next Install Angular Material into the Angular Project

    • Add AM to Project:: ng add @angular/material

    • Follow prompts to:

      • Choose Theme

      • Choose Y/N Setup for gesture recognition

      • Choose Y/N Setup for browser animations

For full setup instructions see the Angular Material – Getting Started page here:

https://material.angular.io/guide/getting-started

The –defaults flag on the ‘ng new’ command creates an Angular project without routing support and with plain CSS for styling. If desired you can set these differently by leaving off –defaults and following prompts or you can add parameters to the command as follows:

ng new <app-name> --routing true --style [scss|less|sass|css]

1.4  What is Angular Default Component?

The Angular project can be started as usual using:

ng serve (or npm start)

Once up and running the app displays the following default component (app.component.ts) which does not use Angular Material:

To start development replace the contents of app.component.html with your own template code.

1.5  What is Angular Material Schematics?

Angular Material’s ‘add’ schematic lets you add Angular Material to an Angular project:

ng add @angular/material

Schematics for creating components are also available:

address-form – Creates an address form component

navigation – Creates a component pre-set with sidenav and toolbar

dashboard – Creates a component with cards in a grid layout

table – Creates a table component with sorting and pagination

tree – Creates a tree structure component

Component schematics are used like this:

ng generate @angular/material:dashboard <comp-name>

Notes

Installing one of the above components will also import any Angular Material modules required by the component.

More information on Angular Material schematics is available here:

https://material.angular.io/guide/schematics

1.6 Angular Material Modules

Angular Material consists of various Modules :MatSidenavModule – Side Navigation, MatToolbarModule – ToolBar, MatIconModule – Icons, MatListModule – Lists, MatCardModule – Cards, MatButtonModule – Buttons, MatTableModule – Tables, MatDialogModule – Dialogs, MatInputModule – Form Input Fields, MatSelectModule – Dropdown Input Field. Each module must be imported separately before it’s features can be used

1.7  How to Add Angular Material Modules to a Project?

Modules must be added to your application before you can use them. The initial install of Angular Material into your project does not install any Angular Material modules. Modules can be added in one of two ways-Modules can be added directly to the app.module.ts file, An additional module can be created just to handle importing of the Angular Material modules (e.g. material.module.ts). Using a separate module reduces clutter in the app.module.ts file. The material.module.ts file is then included in the app.module.ts file as a single import and added to the imports array.

1.8 material.module.ts File

material.module.ts file example

This file goes in the same directory as the app.module.ts file

import {NgModule} from '@angular/core';

import { MatIconModule, MatCardModule } from '@angular/material';

@NgModule({
  imports: [ MatIconModule, MatCardModule ],
  exports: [ MatIconModule, MatCardModule ]
})
export class MaterialModule {}

This example imports just a few modules. In practice you can expect to import a half dozen or more.

Notes

Keep in mind that when using one of the Angular Material component schematics it will add module imports directly to the app.module.ts file. In such a case you may want to move those imports out of the app.module.ts file and add them instead to your material.module.ts file.

1.9  How to Add material.module.ts to a Project?

material.module.ts is added to the app.module.ts file

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { MaterialModule } from './material.module'

@NgModule({
  declarations: [ AppComponent ],
  imports: [ BrowserModule, MaterialModule ],
  bootstrap: [AppComponent]
})
export class AppModule { }

1.10 Angular Material Themes

A theme is a set of colors that can be applied to Angular Material components.

  • Each Theme consist of the following palettes

Primary Palette – Most widely used colors

Accent Palette – Used for floating or interactive elements

Warm Palette – Used to denote errors

Foreground Palette – For text and icons

Background Palette – For backgrounds

1.11 How to Use Themes?

Built-in themes include DeepPurple-Amber, Indigo-Pink, Pink-BlueGrey, Purple-Green. Themes are included by adding a line like this to the styles.css file

@import '@angular/material/prebuilt-themes/deeppurple-amber.css';

Theme colors are mapped by default to some components (e.g. Toolbar). Not all components have themed colors (e.g. Card)

1.12  How to Configure Animations?

Animations include ripple effects when buttons are clicked and slide and fade in-out component transitions during navigation. Animations are enabled during the addition of Angular Material to a project when the BrowserAnimationsModule is imported and added to the imports array in the appmodule.ts file. Angular Material Animations will not run unless this module is imported.

import {BrowserAnimationsModule} 
from '@angular/platform-browser/animations';
...
@NgModule({
  declarations: [ AppComponent ],
  imports: [ BrowserModule, 
             MaterialModule, 
             BrowserAnimationsModule ],
  bootstrap: [AppComponent]
})
export class AppModule { }

1.13 Enabling Gesture Support

Angular Material uses the HammerJS package to support gestures. HammerJS will be installed for you if you choose Yes when asked when the angular/material schematic runs.

If you chose No you can still install it later by:

  • Installing the package

npm install --save hammerjs
    • Adding an import for it at the top of main.ts

import 'hammerjs';

Gestures supported by this package include: Pan, Pinch, Press, Rotate, Swipe and Tap.

Components that make use of gestures include: mat-slide-toggle, mat-slider, matTooltip,…

1.14 Angular Material Icons

Material Design includes open source sets of icons that can be used in applications.

Icons are displayed using the mat-icon component:

<mat-icon 
  aria-hidden="false" 
  aria-label="Example home icon"
>home</mat-icon>

The above HTML displays the ‘home’ icon.

 Many other icons exist including, alarm, bookmark, delete, done, event, face, list, print, today. Several categories of Icons are available, Action, Alert, Av, Communication, Content, Device, Editor, File, Hardware, Image, Maps, Navigation, Places, Social, Toggle.

Available icons can be found here:

https://material.io/resources/icons/?style=baseline

1.15 Angular Material Components

  • Angular Material includes the following categories of components:

    • Navigation – Containers for navigation elements

    • Layout – Containers for presenting content

    • Form Controls – Form input controls

    • Buttons & Indicators – Buttons, toggles, status &, progress indicators

    • Popups & Modals – Floating components that can be hidden or shown

    • Data Table – Table and related components

  • See here for more information about components:

https://material.angular.io/components/categories

1.16 Navigation

Angular Material provides three containers for navigational items

Menu – A floating panel of items

Sidenav – A container that slides out from the side of the screen

Toolbar – A container for title information and screen controls

  • Menu Example

<button mat-button [matMenuTriggerFor]=”menu”>Menu</button>

<mat-menu #menu=”matMenu”>

<button mat-menu-item>Item 1</button>

<button mat-menu-item>Item 2</button>

</mat-menu>

Notes

More information on navigational components can be found here:

https://material.angular.io/components/categories/nav

1.17 Layout

Angular Material supports several layout related components

List – Displays list of items

Tree – Displays hierarchical content

Card – Container for itemized content

Tabs – Displays one view out of multiple possible views

Expansion Panel – Container that can be expanded

GridList – Flexible grid based container for items

Stepper – Wizard type interface

Divider – Vertical or horizontal divider

Notes

For more information on Angular Material layouts see:

https://material.angular.io/components/categories/layout

1.18 Layout Examples

  • Basic Card

  <mat-card>Basic card</mat-card> 

  • List

<mat-list role="list">
  <mat-list-item role="listitem">Maple</mat-list-item>
  <mat-list-item role="listitem">Oak</mat-list-item>
  <mat-list-item role="listitem">Birch</mat-list-item>
</mat-list>

Notes

The official documentation includes examples of all layout types:

https://material.angular.io/components/categories/layout

For more information on cards see:
https://material.angular.io/components/card/overview

For more information on Lists see:

https://material.angular.io/components/list/overview

1.19 Form Components

Angular Material includes support for the following form input controls

Autocomplete – User types and it suggests selections

Checkbox – For boolean input

Datepicker – A directive for use with <input> fields

Input – A directive for use with <input> elements

Radio button – Supports mutually exclusive selections

Select – Drop down selector

Slider – Selects value from a range

Slide Toggle – On/Off toggle

Controls exist as either an Angular Material component (e.g. mat-slider) or as a directive used with the standard HTML input element

Notes

More information on form components can be found here:

https://material.angular.io/components/categories/forms

1.20 Example Controls

  • A Select Field

<mat-form-field>
  <mat-label>Favorite Car</mat-label>
  <mat-select>
    <mat-option *ngFor="let car of cars"
    [value]="car.value">
      {{car.viewValue}}
    </mat-option>
  </mat-select>
</mat-form-field>
  • Basic Input Field

<mat-form-field class="example-full-width">
  <input matInput placeholder="enter comment">
</mat-form-field>

Notes

For more on Angular Material form input fields see:

https://material.angular.io/components/categories/forms

1.21 Summary

  • In this tutorial, we covered:

    • Material Design

    • Angular Material

    • Adding Angular Material to a Project

    • Angular Material Schematics

    • Angular Material Modules

    • Adding Modules to a Project

    • Themes

    • Configuring Animations

    • Enabling Gesture Support

    • Icons

    • Components