Content:
1. Introduction
   - Virtual DOM
   - Support among browsers
2. Node.js and Node Package Manager
   - Node
   - NPM
   - New NPM project
   - Starting project
   - Installing a package locally
   - installing a package globally
   - Installing specific version of package
   - Configuration
3. Visual Studio
   - Visual Studio Code
   - Visual Studio Code Extensions
   - Node.js tools for Visual Studio
4. Webpack
   - Installation
   - Configuration and new project
   - Running
   - Creating bundle.js for deployment
   - Creating packages
5. React
   - Resources
   - Hello World
   - Hello World with Node.js
6. JSX
7. Build a react component
   - ES6
   - Prebuild components
8. Managing state
9. Routing
   - Simple routing
   - Router
10. Display a list
11. PropTypes
12. Redux
   - Store
   - Actions (events)
   - Reducers (event handlers)
   - Enrich page
   - Responding to events
13. MobX
   - Installation
   - Refreshing data
14. TypeScript
   - Resources
   - The idea
   - Installing
   - Compiling and running in Visual Studio
   - TypScript in Node.js
   - Debugging
15. Using external libraries with TypeScript
   - jQuery
   - React
16. Typescript - Advanced features
17. Testing
   - Test runner - Mocha
   - Test setup/tear down
   - Custom test suite
   - Setup environment
   - Simple Test
   - Running test upon save
   - Assertion library - Expect
   - Assertion library - Chai
   - Mocking (with expect)
   - Assertion library comparison
   - Testing React Code (React Utils)
   - Testing React Code (React Utils + Enzyme)
   - Adding TypeScript support1
   - JEST test framework



1. Introduction

Note: This is a draft, work in progress. Please report inaccuracies.

React is a JavaScript framework for building responsive (single page) applications.

React web

React web - Tic-tac-toe game

Code pen to play with React

Why React.js?

node.js tutorial on guru99.com

Virtual DOM

React maintains Virtual DOM, shadow of current DOM. Developers updates the Virtual DOM and React finds the most efficient way to update the real DOM.

Support among browsers

Not all JavaScript featurss are equally supported among Internet browsers. You can differences in Compatibility matrix

2. Node.js and Node Package Manager

To instal Node.js and NPM, download Node.js installer from Node.js site and run it.
Node.js tutorial at w3resource

Node

Node is JavaScript execution engine

Having index.js

JavaScript
console.log('Hello from Basics');
Then

CMD
node index.js
will write "Hello from Basics" to console output

NPM

NPM - Node Package Manager supports JavaScript batch execution and manages external libraries

New NPM project

CMD
npm init
This will create package.json project file (similar to .csproj in C#)

JavaScript
{
  "name": "tutorial",
  "version": "1.0.0",
  "description": "tutorial",
  "scripts": {
    "start": "node src/index.js"
  },
  "author": "Zbynek",
}

Starting project

By executing

CMD
npm start
NPM will look in package.json for scripts/start

JavaScript
  "scripts": {
    "start": "node server.js",
  }
and start "node server.js" in in the example above

Installing a package locally

NPM can download external binaries described in "dependencies" or "devDependencies" section in package.json

CMD
npm install <package> 
will create local folder node_modules\<package> and add will dependency to package.json

JavaScript
  "dependencies": {
    "jquery": "2.2.3",
    "node_module": "0.0.0"
  },
  "devDependencies": {
    "mocha": "2.4.5"
  }

CMD
npm install
will read the list of dependencies from package.json and check if they are already downloaded

Note: if an error "cannot rename file" coccurs, close all apps that can lock projects folders (especially Free Commander or browser). Worst case, restart computer.

installing a package globally

CMD
npm install -g <package> 
will copy the package to C:\Users\<user>\AppData\Roaming\npm\<package>
Downloaded packages are held in npm cache under C:\Users\<user>\AppData\Roaming\npm-cache

Installing specific version of package

CMD
npm install myPackage@1.0.1

Configuration

Edit config

CMD
npm config edit
Config file is stored as C:\windows\<user>\.npmrc

List config

CMD
npm config ls -l

3. Visual Studio

Visual Studio Code

Visual Studio Code is a lightweight free editor for Windows, Mac and Unix that supports working with node.js projects.

Visual Studio Code Extensions

Useful extensions:
Debugger for Chrome
Code coverage Code coverage - github

Read here how to write Create custom extensions

Node.js tools for Visual Studio

Nodejs tools for Visual Studio helps to develop Node.js apps in full Visual Studio.

4. Webpack

Webpack - gettting started

Helps with:
- bundling all .js files into one .js file - runs as dev server (with the bundled .js file in memory)

Installation

Use NPM to install webpack

CMD
npm install -g webpack

Configuration and new project

Extend package.json

JSON
    
{
  "name": "basics1",
  "description": "Run simple script with webpack",
  "scripts": {
    "start": "node devServer.js"
  },
  "dependencies": {
    "jquery": "2.2.3"
  },

  "devDependencies": {
    "extract-text-webpack-plugin": "^1.0.1",
    "transfer-webpack-plugin": "^0.1.4",
    "webpack": "^1.13.3",
    "webpack": "1.13.0",
    "webpack-dev-server": "^1.16.2",	
    "write-file-webpack-plugin": "^3.4.2"
   }
   
}
Create webpack.config.dev.js in root of your project

JSON
    
var webpack = require('webpack');
var TransferWebpackPlugin = require('transfer-webpack-plugin');
var WriteFilePlugin = require('write-file-webpack-plugin');

module.exports = {
    entry: [
        'webpack-dev-server/client?http://localhost:3000',
        './index.js'
    ],
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist",
        publicPath: '/'
    },

    resolve: {
        extensions: ["", ".js"]
    }
};
Create devserver.js in root of your project

JavaScript
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config.dev');

var port=3000;

new WebpackDevServer(webpack(config), {
	publicPath: config.output.publicPath,
	// hot: true,  // enables hot reloading
	historyApiFallback: true
}).listen(port, 'localhost', function (err, result) {
	if (err) {
		console.log(err);
	}

	console.log('Listening at localhost:'+port);
});
Create index.html as starting point

HTML
<html>
<body>
  <div id="root"></div>
  <script src="bundle.js"></script> <!-- bundle.je gets created webpack (all .js in one file) -->
</body>
</html>
Create index.js as starting point

JavaScript
document.write("hello from Basics1/index.js");

Running

Open a web browser and type "localhost:3000"

Bundle.js can be seen by typing "localhost:3000/bundle.js"

Creating bundle.js for deployment

In order to create physical file on disk you need to change existing or preferably create new webpack.publish.config.json

JSON
    webpack.publish.config.json
...
module.exports = {
        entry: [
            './index.tsx'
        ],
        output: {
            filename: "bundle.js",
            path: __dirname + "/dist",
            publicPath: ''
        },
..		
the entry elements doesn ot have to have any dev-server info

Create new command in package.json to use new config

JSON
    package.json
 "scripts": {
    "package": "webpack --config webpack.publish.config.json"
	...
  },
and run

CMD
npm run package
to create bundle.js under dist

Creating packages

In order to allow reusing your packages you need to create a new package. It can be done using "gulp".

Add following to package.json

JSON
    package.json
  "scripts": {
    "build": "gulp pack",
	...
  },
   "devDependencies": {
    "gulp": "^3.9.1",
    "gulp-clean": "^0.3.2",
    "gulp-shell": "^0.5.2",
	...
  }
and run "npm install" to install gulp

Create new gulpfile.js in root

JSON
    package.json
var gulp  = require('gulp'),
    shell = require('gulp-shell'),
    clean = require('gulp-clean');
    
gulp.task('clean', function () {
    return gulp.src(['./dist'], { read: false }).pipe(clean());
});

gulp.task('compile-tsx', ['clean'], shell.task(['tsc']))

gulp.task('copy-files', ['compile-tsx'], function() {  
    return gulp.src(['src/**/!(*.tsx)', 'package.json']).pipe(gulp.dest('./dist'));
});

gulp.task('pack', ['copy-files'], shell.task(['npm pack dist/']));

gulp.task('publish', ['copy-files'], shell.task(['npm publish dist/']));
and run

CMD
npm run build
to create my-package-1.0.0.tgz in root

To consume the file from other project add the package to package.json

JSON
    package.json
  "dependencies": {
    "my-package": "1.0.0",
	...
  }
and either copy the my-package-1.0.0.tgz to the root of the project that should consume it or publish the package to repository and run "npm install" to install the package in under "node_module"

5. React

Resources

React web site

Great tutorials at tutorialspoint.com https://www.tutorialspoint.com/reactjs/

Hello World

The web page below uses React from CDN, creates root element by React functions and replaces elements in DOM

HTML
<html>
<body onload="myFunction()" />
	<h1>React.js basics</h1>
	<div id="demo" >This will be replaced by pure JavaScript</div>
	<div id="react-app" >This will be replaced by React.js</div>
	<div id="react-app1" >This will be replaced by React.js 1</div>

	<script src="https://unpkg.com/react@15/dist/react.js"></script>
	<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>

	<script>
	function myFunction() {
	  document.getElementById("demo").innerHTML = "Hello Wrold - Replaced by pure JavaScript";

	  var rootElement =
	  React.createElement('div', {}, 
		React.createElement('h1', {}, "People"),
		React.createElement('ul', {},
		  React.createElement('li', {},
			React.createElement('h2', {}, "John First"),
			React.createElement('a', {href: 'mailto:john@first.com'}, 'john@first.com')
		  ),
		  React.createElement('li', {},
			React.createElement('h2', {}, "Paul Second"),
			React.createElement('a', {href: 'mailto:paul@second.com'}, 'paul@second.com')
		  )
		)
	  )

	  ReactDOM.render(rootElement, document.getElementById('react-app'))
	  ReactDOM.render(rootElement, document.getElementById('react-app1'))
	} 
	</script>
</body>
</html>

Hello World with Node.js

In your previously setup dev environment change index.html

HTML
import * as React from 'react';
import * as ReactDOM from 'react-dom';

  var rootElement =
  React.createElement('div', {}, 
    React.createElement('h1', {}, "People"),
    React.createElement('ul', {},
      React.createElement('li', {},
        React.createElement('h2', {}, "John First"),
        React.createElement('a', {href: 'mailto:john@first.com'}, 'john@first.com')
      ),
      React.createElement('li', {},
        React.createElement('h2', {}, "Paul Second"),
        React.createElement('a', {href: 'mailto:paul@second.com'}, 'paul@second.com')
      )
    )
  )

  ReactDOM.render(rootElement, document.getElementById('root'))
and add following to package.json

JSON
    
  "dependencies": {
    ...
    "@types/react": "^0.14.47",
    "@types/react-dom": "^0.14.18",
    "@types/react-redux": "^4.4.35",
    "@types/redux-logger": "^2.6.32",
    "@types/redux-thunk": "^2.1.32",
	"react": "15.3.2",
    "react-dom": "15.3.2"
  },
  "devDependencies": {
    ...
    "react-hot-loader": "^1.3.0",
    "react-logger": "^1.1.0",
    "react-redux": "^4.4.6",
    "react-router": "^3.0.0",
    "react-thunk": "^1.0.0",
	"redux": "^3.6.0",
    "redux-logger": "^2.7.4",
    "redux-thunk": "^2.1.0",
  }
and run "nmp install" or install the lastest by "nmp install <package> --save"

6. JSX

react - jsx in depth
Babel preprocessor
JSX on typescriptlang.org
JSX aloows embedding hmlt tag into JavaScrip.

JavaScript
var AboutPage = React.createClass({
  render: funtion() {
  return (
     
	 <div>
	    <h1 color="blue">About</h1>
	    <p>Demo page</p>
	 </div>	
	 
    );
  }
});
The JSX code with nested elements above compiles to JavaScript with React

JavaScript
React.createElement("div", null,   
  React.createElement("h1", {color:"blue"}, "About" ),
  React.createElement("p", null, "Demo page"},
)  

7. Build a react component

Create about Page as a component

JavaScript
var React = require('react'); // includes React package

var AboutPage = React.createClass({
  render: function() {
  return (
     
	 <div>
	    <h1 color="blue">About</h1>
	    <p>Demo page</p>
	 </div>	
	 
    );
  }
});

module.Export = AboutPage; // makes the page available
Include that page in main page

JavaScript
var React = require('react'); 
var AboutPage = require('./components/aboutPage'); // includes AbouPage component

React.render(<AboutPage>, document.getElementById('root')); // renders AboutPage in root element
Create index.html that uses the app built above

HTML
<html>
<body>
  <div id="root"></div>
  <script src="scripts/bundle.js"></script> // gets created by gulp or webpack (all .js in one file)
</body>
</html>

ES6

Work in ES5

JavaScript
<div onClick={this.handleClick}/>
ES6 requires bind

JavaScript
<div onClick={this.handleClick.bind(this)}/>
It can be handled in class constructor

JavaScript
class People extends React.Component{
  constructor(props) {
    super(props);
    this.handleClick=this.handleClick.bind(this);
}
ES5 Stateless component (since React 1.4)

JavaScript
var ContactPage = function(props) {
    return (
	<h1> Main Street 1, Small City</h1>
	);
});
ES6 Stateless component

JavaScript
const ContactPage = (props) => {
    return (
	<h1> Main Street 1, Small City</h1>
	);
});

Stateless components do not have Lifecycle methods

Prebuild components


8. Managing state

There are at least 3 options how to refresh UI when data changes (or how manage state of a web app)

Assuming there is a simple React component that renders first name from a Person class.

1. using forceUpdate
In constructor

JavaScript
render()

JavaScript
  this.Person.firstName
onClick()

JavaScript
  this.person = new Person('Paul');
  this.forceUpdate()

2. using State
In constructor

JavaScript
this.state = new Person('John');
render()

JavaScript
this.state.person.firstName
onClick()

JavaScript
var newPerson = new Person('Paul');
this.setState(newPerson);

Note: if you use an array, you cannot assign it directly to state, you have to use

JavaScript
 this.state = { "people" : people }

Note: Redux is using the same principle, just requires more code.

3. Using @observable in MobX, please refer to the MobX section

9. Routing

Simple routing

Assuming you have multiple components/pages and you need to defined mapping between page and url.
You have to display contact page is user types http://mypages.com/#contact

JavaScript
var React = require('react'); 
var AboutPage = require('./components/aboutPage'); 
var Contact = require('./components/contact'); 

var AboutPage = React.createClass({
  render: function() {
	var Page;
	
	switch (this.props.route) {
	  case 'contact' : Page = Contact; break;
	  default: Page = AboutPage;
	}

  return (
	 <div>
     <Page/>
	 </div>	
    );
  }
});

function render() {
  var myRoute = window.location.hash.substr(1);
  React.render(<App route = {myRoute} /> document.getElementById('root'));  
}

window.addEventListener('hashchange', render); // listens to URL changes and renders new content

render();  // renders page first time

Router

Router provider centralized way of handling routes. Create myRoutes.js that contains all mapping among urls and components

JavaScript
var React = require('react'); // includes React package

var myRoutes = (
     <Route name="app" path="/" handler={require('./main')}>
		 <DefaultRoute handler=={require('./components/aboutPage'}>
		 // if path is not set, name is used 
		 <Route name="people" path="allPeople" handler=={require('./components/people'}>
	 </Route>
    );
  }
});

module.Export = myRoutes; 
Update main.js to use myRoutes

JavaScript
var React = require('react'); 
var RouteHandler = require('react-router'); 
var myRoutes = require('./myRoutes');

var App = React.createClass({
  render: function() {
  return (
	 <div>
	    <RouteHandler/>
	 </div>	
    );
  }
});
  
Router.run(myRoutes, function(Handler) {
  React.render(<handler>, document.getElementById('root'));
});
  

10. Display a list

this.props.userName - immutable - passd to child components from top level component this.state.username - data in controller view
Lifecycle:
componentWillMount - runs before initial renderning
componentDidMount  - runs after render (DOM exists)

componentWillReceiveProps - run before new properties are received. Does not run on initial render.
shouldComponentUpdate - runs before render. If returns falls, render will be ignored.

componentWillUpdate - after rendering (when new props are states changed). SetState cannot be called here
componentDidUpdate  - after componts updates propageated to the DOM

componentWillUnmount - before component is unmounted from the DOM

JavaScript
var People = React.createClass({
  
  // initial state is an empty array
  getInitialState: function() {
    return {
		people: []  
    };
  },
  
  // loads data in json format and assigns them to people
  componentWillMount: function() {
    this.setState({ people: peopleService.getPeople() });
  },
  
  render: funtion() {
      var createPersonText = function(person) {
		return (
          // id is necessary for the framework
		  <li key={author.id}>{person.firstName} {person.lastName}</li>
		);
	  }
  
	  return (
		 <div>
		 <ul>
			{this.state.people.map(createPersonText, this)}
		 </ul>
		 </div>
		);
  }
});

module.exports = People;

11. PropTypes

PropTypes help to validate if required parameters or/and types were passed to the component.
React.PropTypes.object.isRequired
React.PropTypes.func.isRequired

React.PropTypes.bool
React.PropTypes.number
React.PropTypes.string
React.PropTypes.array
React.PropTypes.func
Do not run in minified version!

JavaScript
var PeopleList = React.createClass({
    propTypes: {
		people: ReactPropTypes.array.isRequired 
   },	
   
  render: funtion() {
  ...
If people array has not been passed then browser will show a warning.

12. Redux

Redux.js.org
Dank Abramov - Twitter
Dan Abramov - You might not need redux
10 Steps tutorial in (full)VS
React-redux environment setup
Single immutable store The only way to change a state is to emit an action States are changed by pure functions (called reducers) Onedirectional data flow Flux - has mutliple stores - stores owns the logic to change the data Action Creators export function setName(name) { return [ type: SET_NAME, name: name } }

Store

let store = createStore(reducer)

store.dispatch(action)
store.subscribe(listener)
replaceReducer(nextReducer)



Immutability: changing a state means returning new object

Reasons for immutable state:
  Clarity - change can occur only in one place and it is reducer
  Performance - redux does not need to iterate over all propeties to figure out if any of them changed. If reference is different, it changed.
  Time-travel debugging


Already in JS:
Number, String, Boolean, Undefined, Null

Mutable:
Objects.Arrays, Functions

Changing a state by creating new object:
in ES6 Object.assign({}, state, {name: 'John'});  // {} empty object
ES5 - Lodash
  
Ways to enforce immutability
 redux-immutable-state-invariant
 Immutable.js

Create store Configure store configureStore.js

JavaScript
 import {createStore} from 'redux';
 import rootReducer from './myReducers';
 
 export default function configureStore(initialState) {
   return createStore(
     rootReducer,
	 initialState
 }
Instantiate store for the app in src/index.js

JavaScript
import configureStore from './store/configureStore'
import {Provider} from 'react-redux'

const store = configureStore();

render(
	<Provider store={store}>
		<Router history={browseHistory routes={routes} />
	</Provider>,
	document.getElementById('root')
);   	 

Actions (events)

Create file personActions.js

JavaScript
export function createPerson(person) {
  return { type: 'CREATE_PERSON', person};
}
if the action should be reused, definig the action as a const helps avoiding type error

JavaScript
// consts defined in an independent file
export const CREATE_PERSON  = 'CREATE_PERSON';

JavaScript
import * as types from './actiontypes';

export function createPerson(person) {
  return { type: types.CREATE_PERSON, person};
}

Reducers (event handlers)

Reducers are called by dispatch() method of store and return modified data as NEW oject

JavaScript
function myReducer(state, action) {
  switch (action.type) {
    case 'SET_NAME':
	  return (Object.assign({}, state, { name: 'John' });
	default:
       return state;	
  }
}

reducers/index.js
function arrayReducer(state =[], action) {
  switch (action.type) {
    case types.CREATE_PERSON:
	  return [...state, Object.assign({}, action.person)];
	default:
       return state;	
  }
}
Using Root reducer simplifies multi case statements

JavaScript
import {combineReducers} from 'redux';
import myReducer from './myReducerFile';

const rootReducer = combineReducers({
  myReducer : myReducer
});

export default rootReducer;
All reducers are called when an action is dispatched

containers - logic
 - are aware of Redux
 - subscribe to redux state
 - dispatch Redux actions
 - generated from react-redux

 Presentational - view
 - read data from Props 
 - invoke callbacks on props
 - written by hand

Enrich page

Assuming to have a page like this

JavaScript
import React,{PropTypes} from 'redux';

class People extends React.Component{
  constructor(props) {
		super(props, contect);
		
		this.state = {
			person:{ name:""}
		};
		
		this.OnNameChanged = this.OnNameChanged.bind(this);
		this.OnClickCreate = this.OnClickCreate.bind(this);
	}

	onNameChanged(event) {
		const person = this.state.person;
		person.name = event.target.value;
		setState({person:person});
	}
	
	onClickCreate() {
		alert('${this.state.person.name} would be created here');
	}

	render() {
	  return (
		  <div>
			<input type="text" onChange={this.onNameChanged} value{this.state.course.title} />

			<input type="submit" onClick={this.onClickCreate} value="Create" />
		  </div>
	  );
	}
}

export default PeoplePage;
If you start using Redux it will change like this:

JavaScript
import React,{PropTypes} from 'redux';

import {connect} from 'react-redux';
import * as personAction from './personActions';


class PeoplePage extends React.Component{
	constructor(props) {
	...
	}
	
	onClickCreate() {
	// props.dispatch is injected by connect(), if connect uses only 1 argument
	this.props.dispatch(personAction.createPerson(this.state.person));  
	}

	personDetail(person, index) {
	  return <div key={index}>{person.name}</div>
	}
	
	render() {
	  return (
		  <div>
		    {this.props.people.map(this.personDetail)} //map() iterates over list - this line displays list
			...
		  </div>
	  );
	}
}


function mapStateToProps(state, ownProps) {
  return {
    people: state.people  
  };
}

export default connect(mapStateToProps)(PeoplePage);
Flow:
REACT
 - user clicks "Create" button
 - personPage.js onClickCreate() calls this.props.dispatch(personAction.createPerson(this.state.person))
ACTION
 - personAction.js createPerson(aPerson) returns { type='CREATE_PERSON', person=aPerson }
 - dispatch() calls all reducers
REDUCERS
 - personReducer.js personReducer() returns  new array with the person passed addedd into the array
REACT
 - personPage.js mapStateToProps(state. ownProps) returns { people: state.people}
 - personPage.js render() draws array in this.props.people 
Simplify the code by using mapDispatchToProps()

JavaScript
import React,{PropTypes} from 'redux';
import {connect} from 'react-redux';
import * as personAction from './personActions';

class PeoplePage extends React.Component{
	constructor(props) {
	  ...
	}
	
	PeoplePage.PropTypes = {
		people: PropTypes.array.isRequired,
		createPerson: PropTypes.func.isRequired
	}

	onClickCreate() {
	  this.props.createPerson(this.state.person); 
	  // before was: this.props.dispatch(personAction.createPerson(this.state.person));  
	}

	personDetail(person, index) {
	  return <div key={index}>{person.name}</div>
	}
	
	render() {
	  return (
		  <div>
		    {this.props.people.map(this.personDetail)} //map() iterates over list - this line displays list
			...
		  </div>
	  );
	}
}

function mapStateToProps(state, ownProps) {
  return {
    people: state.people  
  };
}


function mapDispatchToProps(dispatch) { // "dispatch" gets injected by the "connect()" function
  return {
    createPerson: person => dispatch(personActions.createPerson(person))
  };
}


export default connect(mapStateToProps, mapDispatchToProps)(PeoplePage);
Simplify the code by using bindActionCreators

JavaScript
import React,{PropTypes} from 'redux';
import {connect} from 'react-redux';
import * as personAction from './personActions';
import {bindActionCreators} from 'redux';

class PeoplePage extends React.Component{
	constructor(props) {
	}
	
	PeoplePage.PropTypes = {
	  people: PropTypes.array.isRequired,
	  actions: PropTypes.object.isRequired,
	}

	onClickCreate() {
	  this.props.actions.createPerson(this.state.person);
	}

	render() {
	  return (
			...
	  );
	}
}

function mapStateToProps(state, ownProps) {
  return {
    people: state.people  
  };
}

function mapDispatchToProps(dispatch) { // "dispatch" gets injected by the "connect()" function
  return {
	  actions: bindActionCreators(courseActions, dispatch);   mapping all actions in personActions.js
	  // before was: createPerson: person => dispatch(personActions.createPerson(person));  
  };
}

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

Responding to events

If you make an async call, after the call finishes, you may need to refresh data or start another async call. You are not allowed to do it in render method: warning.js:36Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to 'componentWillMount'. You cannot do it mapStateToProps(), because it does not have dispatch() to start another call.

13. MobX

MobX provides efficient an alternative to Redux and provides efficient way how to handle state in a web application.

Installation

To install MobX run following

CMD
npm install mobx --save 
npm install mobx-react --save 
if using TypeScript, set experimentalDecorators to true

JSON
    tsconfig.json
 {
    "compilerOptions": {
        "experimentalDecorators": true
    ...

Refreshing data

JavaScript
@observer
class PersonPanel {
@observable person = new Person('John')
   ...
}
render()

JavaScript
this.Person.firstName

JavaScript
onClick() {
  this.person = new Person('Paul')
}

14. TypeScript

Resources

TypeScript web

Quick Start

Typescript in 30 minutes

The idea

TypeScript can verify types at compilation time. The person classe defined in TypeScript

TypeScript
// http://www.typescriptlang.org/docs/handbook/classes.html
export class Person {
    lastName: string;
    firstName: string;
    age: number;
    member : boolean;

    constructor(aFirstName : string) {
        this.firstName = aFirstName;
    }
};
will be compiled to JavaScript

JavaScript
var Person = (function () {
    function Person(aFirstName) {
        this.firstName = aFirstName;
    }
    return Person;
}());
exports.Person = Person;
that will be deployed to browser.

Importing code from other file

TypeScript
// import a function or a class
import {add} from './src/mylib';
import {Person} from './src/mylib';

// import all exported objects
import * as myLib from './src/mylib';

Installing

TypeScript support is available in Visual Studio 2015 and 2013 Update 2.
or
it can installed (globally) by NPM as:

CMD
npm install -g typescript

Compiling and running in Visual Studio

Create New TypeScript project from Visual Studio 2015
In VS 2015 File > Create new project > Other languages > TypeScript. Hit F5.

Compiling from command line

CMD
tsc myApp.ts
tsc.exe is usually located under C:\Program Files (x86)\Microsoft SDKs\TypeScript\1.5\ or C:\Users\<userName>\AppData\Roaming\npm\

TypeScript vs. ES6
typescript vs ecmascript-6/
es5 es2015 typescript/

TypScript in Node.js

TypeScript in Node.js (full TypeScript Tutorial)
Add following to packages.json

JSON
    
{
  "devDependencies": {
    ...
	"typescript": "2.1.1",
	"ts-loader": "^1.2.0"
  }
}
and run

CMD
npm install
Add following to webpack.config.dev.js

JSON
    
    module: {
        loaders: [
            { test: /\.ts?$/, loaders: ['ts']}  // 'ts' means use 'ts-loader'
        ],
    }
Run

CMD
tsc --init 
to create tsconfig.json. The file contains tsc options then can listed by

CMD
tsc -h
be aware that there are different sets of options for Micrososft tsc and Node.js tsc.
Update the file appropriatelly

JSON
    
{
    "compilerOptions": {
        "outDir": "./dist/",
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es5"
    },
    "include": [
        "./src/**/*",
        "./index.ts"
    ],
    "exclude": [
        "node_modules"
    ]
}
Create index.ts with some TypeScript code

TypeScript
document.getElementById("root").innerHTML = "Replaced in TypeScript - pure JavaScript still works";

class Person {
    firstName: string;
    age: number;

    constructor(firstName : string) {
        this.firstName = firstName;
    }
}

var p = new PersonF("John");

document.write("FirtsName=" + p.firstName);
run

CMD
npm start
to see the code on the website

Debugging

In order to be able to see TyleScript code instead of compiled JavaScript code in debugger you need to add source mapper.

JSON
    
package.json
    "source-map-loader": "^0.1.5"

JSON
    
tsconfig.json
    "compilerOptions": {
        "sourceMap": true,    

JSON
    
webpack.config.dev.js

   // Enable sourcemaps for debugging webpack's output.
   devtool: "source-map",

   module: {

        preLoaders: [
            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            { test: /\.js$/, loader: "source-map-loader" }
        ]
    },

15. Using external libraries with TypeScript

Using external libraries requires .ts files for those libraries.

jQuery

There are 2 ways how to get them. Download jQuery Definition for TypeScript 1:
Codeplex
Github

Add to the top of your .ts file

TypeScript
/// <reference path="jquery.d.ts" /> 
use jQuery in code

TypeScript
var el1 = document.getElementById('content1');
el1.innerHTML = $("<div>ABC</div>").html();
JavaScript 2 does not require to reference .d.ts in the code file. It uses a reference in package.json
To search if a types are available for a package go to npmjs.com or http://microsoft.github.io/TypeSearch/

If yes, then run

JSON
    
npm install --save @types/<package>
or update package.json"

TypeScript
  "devDependencies": {
    "@types/<package>": "<version>"
}
and run

JSON
    
npm install 
to download the types. The types will be downloaded under node_module\@types\<package>

React

Download react definition for TypeScript:
Rect .ts

Tutorial how to install and compile react component with NPM and Webpack
Rect and Webpack

Download by npm

CMD
npm install --save react react-dom @types/react @types/react-dom
Tutorial TODO app in react

16. Typescript - Advanced features


17. Testing

Test runner - Mocha

Mocha allows test execution in Node.js To install Mocha, update package.json:

JSON
    
package.json
{
  "devDependencies": {
    ...
    "@types/mocha": "^2.2.34",	
    "mocha": "2.4.5",
	...
  }
}
In order to run Mocha, update package.json

JSON
    
package.json
{
  "scripts": {
    "pretest": "tsc",
    "test": "mocha \"dist/**/*.test.js\"",
	...
},
The "pretest" step compiles all typescript files (based on tsconfig.js) into dist folder and the "test" steps will execute the test based on *.test.js file pattern

Let's write a test. A dummy test to start to show the basics. 1 pass, 1 fail

TypeScript
export class TestException {
    message: string;
    constructor(aMessage : string) {
        this.message = aMessage;
    }
};

describe('Dummy test demo', () => {
  
  it('should PASS', () => {
     // does nothing
  });

  it('should FAIL', () => {
      throw new TestException("My failed test message");
  });
 
});
Run the tests from command line by executing

CMD
npm test
Now something more real. Assuming there is a method add that needs to be tested

TypeScript
import * as myLib from './myLib';

describe('MyLib', () => {
  
    it('WHEN add() called THEN correct value returned', () => {
        // act
        var result = myLib.add(1, 2);

        // assert
        var expected = 3;
        if (result != expected) throw new TestException(result + " != " + expected);
    });
});

Test setup/tear down

TypeScript
export class TestException {
    message: string;
    constructor(aMessage : string) {
        this.message = aMessage;
    }
};

// Setup / Tear down
before(function(){
    console.log('      Runs one time before the first test in the file')
})
after(function(){
    console.log('      Runs one time after all tests in the file were executed')
})

beforeEach(function(){
    console.log('      Runs before each test in the file')
})
afterEach(function(){
    console.log('      Runs after each test in the file')
})


describe('Dummy test demo with setup/tear down', () => {
  
  it('should PASS', () => {
     // does nothing
  });

  it('should FAIL', () => {
      throw new TestException("My failed test message");
  });
 
});

Custom test suite

TypeScript
function makeTestSuite(name:string, tests:any) {
    describe(name, function () {
        before(function () {
            console.log("    executed before each test in the tst suite");
        });

        tests();

        after(function () {
            console.log("    executed before each test in the test suite");
        });
    });
}

makeTestSuite('Suite 1 - with setup', function(){
  it('Test 1', function(done){
      done(); 
  });
  it('Test 2', function(done){
      done();
  });
});

describe('Test Suite2 - without setup', function(){
  it('Test 3', function(done){
    done();
  });
});

Setup environment

Mocha will run testSetup.js first
and all tests under src ending *.test.js

Create testSetup.js as configuration for Mocha you can use "--reporter progress" to get just limited output (how many tests passed/failed).

JSON
    
process.env.NODE_ENV = 'test'; // disables hot reloading

require('babel-register')(); // will transpile tests so that they could be written in TypeScript

require.extensions['.css'] = function () {return null;}; // disable features the Mocha does not understand

var jsdom = require('jsdom').jsdom; // simulate browser

var exposedProperties = ['window', 'navigator', 'document']; // helps to simulate browser environment

global.window = ...
if you use TypeScript, you need to compile the ts(x) files to js and copy .css or .less files that are imported in compiled .js files

JSON
    
package.json
  "scripts": {
    "pretest": "tsc & xcopy .\\src\\*.less .\\dist\\src\\ /Y /S /D /R",
    "test": "mocha --reporter progress testSetup.js \"dist/test/**/*.test.js\"",
	...
   }

Simple Test

Create src/index.test.js
Include "expect" library that provides assert (expect) functionality.

JavaScript
// import expect from 'expect';  ES6 - requires babel
var expect = require('expect');

describe('test group', () => { 

  it('dummy test - pass', () => { 

      expect(true).toEqual(true); 

	}); 
}); 
Start tests with

CMD
npm test

Running test upon save

To run tests when you save changes update package.json

JSON
    
"scripts:"{
  "start": "npm-run-all --parallel test:watch open:src",
  "open:src": "node devServer.js",
  "test:watch": "npm run test -- --watch"
  ...
}
When multiple nodes are found(e.g. 2 buttons) Error: This method is only meant to be run on single node. 2 found instead. Testing components: export class Import in {} Video Testing Connected React Compinents 5:00-6:00

Assertion library - Expect

Github: expect

To install Expect, modify package.json

JSON
    
package.json
  "devDependencies": {
    "@types/expect": "^1.13.31",
    "expect": "1.19.0",   
	...
}

TypeScript
import * as myLib from './myLib';
import * as expect from 'expect';

describe('MyLib:', () => {

    it('WHEN add() called THEN correct value returned', () => {
        // act
        var result = myLib.add(1, 2);
        
        // assert
        expect(result).toEqual(3);
    });
});

Assertion library - Chai

Chai website

To install Expect, modify package.json

JSON
    
package.json
  "devDependencies": {
    "@types/chai": "3.4.30",
    "chai": "^3.5.0"
	...
}

TypeScript
import * as myLib from './myLib';
import * as chai from 'chai'; 


chai.should();
var expect = chai.expect;
var assert = chai.assert;

describe('MyLib:', () => {
  
    it('WHEN add() called THEN correct value returned', () => {
        // act
        var result = myLib.add(1, 2);
        
        // assert
        // Option 1
        expect(result).to.equals(3);
//      expect(result).toEqual(3);   'expect' library style

        // Option 2
        result.should.equal(3);
        // Option 3
        assert.equal(result, 3);
    });
});

Mocking (with expect)

TypeScript
import * as expect from 'expect'; 

// method to be mocked
var myService = {
  getValue: function () {} 
}

describe('MyService:', () => {

    // bypass call and return value
    it('WHEN getValue() called THEN 3 returned', () => {
        // arrange
        var spy = expect.spyOn(myService, 'getValue')
        var dice = spy.andReturn(3)

        // act
        var result = myService.getValue();

        // assert
        spy.restore()
        expect(result).toEqual(3);
    });

    // fail if not called  
    it('WHEN test runs THEN FAIL if getValue() was not called', () => {
        // arrange
        var spy = expect.spyOn(myService, 'getValue')

        // assert
        expect(spy).toHaveBeenCalled('not called')
        spy.restore()
    });
});

Assertion library comparison

Feature           Chai  Expect
should() syntax     x   
expect() syntax     x    x 
assert syntax       x   
integrated mocking       x  
extensions          ?    x  
Recommendation to use Expect because:
- It integrates mocking and stubbing functionality, which limits configuration problem issues if these were in 2 separated libraries
- It limits syntax options how to write asserts, which will lean to cleaner
- Recommended by Cory House (author of Pluralsite React-Redux course - assessed with 5 stars)

Testing React Code (React Utils)

Facebook Github: test utils To install React test utils that will allow access to React components, add following to package.json

JSON
    
package.json
{ 
  "devDependencies": {
    "react-addons-test-utils": "15.0.2", 
     ...
}
and write a test like this

TypeScript
import * as React from 'react';
import * as TestUtils from 'react-addons-test-utils';
import * as expect from 'expect'; 
import {HelloMessage} from './HelloMessage';

describe('Testing with React utils', () => {

  it('WHEN page gets rendered THEN elements are correct', () => {
    // arrange
    let renderer = TestUtils.createRenderer();
    renderer.render('<HelloMessage name="John" />');
    let output = renderer.getRenderOutput();
    
    // assert
    const h1Element = output.props.children[0];
    expect(h1Element.props.value).toBe('Hello John');
  });
  
});

Testing React Code (React Utils + Enzyme)

AirBNB Gitbu: Enzyme To install Enzyme, add following to package.json

JSON
    
package.json
{ 
  "devDependencies": {
     "@types/enzyme": "2.4.30",
	  "enzyme": "2.2.0",
	  "jsdom": "8.5.0",
      ...
}
which allows to write markup test like this

TypeScript
...
import * as Enzyme from 'enzyme';

describe('Testing with Enzyme', () => {

  it('WHEN page gets rendered THEN elements are correct', () => {
    // act
    var wrapper = Enzyme.shallow(<HelloMessage name="John" />);

	// assert
    expect(wrapper.find('h1').text()).toEqual('Counter:');
  
// if you have e.g. 2 buttons, you can finsd the first one like this
//    var incrementButton = wrapper.find('button').first();
//    expect(incrementButton.text()).toEqual('INCREMENT');  // multiple control types - use the first
//    expect(incrementButton.prop('id')).toEqual('3');  // type of the control
  });
});  

Adding TypeScript support1

TypeScript in Mocha Tutorial mocha.d.ts
/// <reference path="../mocha.d.ts" />

Expect 
https://www.npmjs.com/package/expect
https://github.com/mjackson/expect 

npm

http://stackoverflow.com/questions/26977722/how-to-run-mocha-tests-written-in-typescript
$ npm install -g ts-node
$ mocha test.ts --require ts-node/register src/**/*.spec.ts


In test code: http://stackoverflow.com/questions/35812221/typescript-default-import-failing
import * as _expect from 'expect';
const expect = _expect as any as typeof _expect.default;

babel-core
babel-preset-es2015
babel-register

add .babelrc
{
  "preset": ["es2015"]
}

"test": "mocha --compilers js:babel-register"

JEST test framework

Redux site: Writting tests (with Jest)

Jest is a test framework used by Facebook. It integrates test runner, assertion library, mocking and code coverage.
The runner syntax is the same as for Mocha, syntax for expect() is similar, but not the same.
Code coverage can be executed as "npm test -- --coverage", watch as "npm test -- --watch"
To configure Jest for project, use the package.json below.

JSON
    package.json
  "scripts": {
    "test": "jest",  
	...
	},
  "jest": {
    "transform": {
      ".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
    },
    "testRegex": "(/tests/.*|\\.(test|spec))\\.(ts|tsx|js)$",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js"
    ],
    "testResultsProcessor": "<rootDir>/node_modules/ts-jest/coverageprocessor.js",
    "moduleNameMapper": {
      "^.+\\.(css|less)$": "<rootDir>/src/tools/styleMock.js",
      "^.+\\.(gif|ttf|eot|svg)$": "<rootDir>/src/tools/fileMock.js"
    }
  },
 "devDependencies": {
    "@types/enzyme": "^2.7.1",
    "@types/jest": "^16.0.3",
    "enzyme": "^2.7.0",
    "jest": "^18.1.0",
    "jest-cli": "^18.1.0",
	"react-addons-test-utils": "15.4.2",
    "ts-jest": "^18.0.1",
	...
  }
To write a React test, you can use the sample below

TypeScript
import * as React from 'react'
import { mount, shallow } from 'enzyme'
import { MyComponent } from './MyComponent'

describe('<MyComponent />', () => {
    it('should render component', () => {
        var store = { subscribe: jest.fn(), dispatch: jest.fn(), getState: jest.fn(), errors: [] }

        var props = { headerText : 'My header', store: store }
        var wrapper = mount(<MyComponent headerText='My header' store={ store } errors={ [] } />)

        expect(wrapper.find('.header').text()).toBe(props.headerText)
    });
});
If your code imports .less file, you need update configuration

JSON
    package.json
  "jest": {
    ...
	"moduleNameMapper": {
      "^.+\\.(css|less)$": "<rootDir>/src/fakeStyle.js",
      "^.+\\.(gif|ttf|eot|svg)$": "<rootDir>/src/fakeFile.js"
    },
	...
  }

JavaScript
// test/fileMock.js
module.exports = '';

JavaScript
// test/styleMock.js
module.exports = {};