How to leverage the best from React ecosystem and beyond to make our daily task easier and more effective within Angular apps and in the end become the best friends ever !
Question is where to start? or how to achieve that goal.
How
To answer the question “How to leverage other ecosystems” we need to introduce and take a look at 3 categories that cover an integral part of software development:
Tools
Architecture
Libraries
As a baseline we will use “Industry standard” for booting up new Angular apps — Angular CLI
We can boot new Angular app in matter of seconds, with all “recommended/required tooling and setup”, by executing simple command:
npx @angular/cli new my-app
NOTE:* never use a -g flag when installing packages! Global things are bad for your machine/life and thanks to npx, you don't need them anyway 😃*
Let’s take a look what CLI gives us by default from perspective of our 3 defined categories:
Libraries: all @angular/* packages and RxJs
Architecture: Component driven architecture with Service layer, but no restrictions on this front ( use what you want )
Tools:
→ we’ve got webpack as a module bundler
→ Protractor/Selenium for e2e testing
→ Jasmine with Karma for unit testing
→ and last but not least, the best thing that ever happened to JavaScript — Typescript with solid static analysis extensions for adhering to proper style-guides and — TSLint and Codelyzer.
So far so good right ?!
Tools
Tooling is indeed crucial for our productivity. Let’s see what can be done on this front.
Let’s start with package manager…
Package Manager/Task Runner
Most of you are probably using npm, which was super annoying to use and slow until version 5. While npm is constantly improving, you don’t have to wait and instead you can switch to a better tool -> yarn
I’m not going to enumerate all the benefits, just a few time savers that you can leverage on daily basis.
How would you execute locally installed TypeScript from CLI with npm, or execute custom npm-script or pass additional arguments to your custom npm-script ? You’re smart and sure know how to do those, but with yarn it’s much easier. Comparison is on following image:
How are you bumping you dependencies ? Manually by hand ? Seriously ? We can do better with yarn:
Just to not be biased against npm, you can achieve the same via 3rd party package(npm-check) and npx via npx npm-check -u just sayin’...
Formatting
CLI comes with pre-configured TSLint supported by Codelyzer, which helps us lint our code and adhere to strictly set style guides within our project. TSLint takes also care of consistent spaces at various places ( functions, module imports, etc… ), empty lines, single/double quotes, semicolons/no-semicolons… But if you think that this is the right way to do formatting, you are fundamentally wrong. Anyway, Lint is for linting not for formatting !
So how can we efficiently/consistently format our codebase instead of using wrong tool for that job — yes I’m talking about you Mr. linter(TSlint) ?
Ladies and gentleman, please welcome, The humble Prettier!
Prettier
is an opinionated formatter created by Facebook and OSS community. You can read more about it on prettier website.
We can add it to our CLI very easily:
Install:
yarn add -D prettier
and define a new npm script:
{
"scripts": {
"format": "prettier {src/e2e}/**/* --write"
}
}
By executing yarn format our whole codebase is formatted in matter of seconds and it's super fast!
That’s it? Not entirely! Because TSlint contains formatting rules, which has nothing to do with linting, we need to turn off these rules… Uff looks like lot of manual work !
tslint-config-prettier
Thanks to OSS we can leverage tslint-config-prettier package, which handles everything for us!
Install:
yarn add -D tslint-config-prettier
and extend tslint.json rules with it:
{
"extends": [
"tslint-config-prettier"
],
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {...}
}
There are still issues though. CLI defines lot’s of rules within tslint.json which are overriding anything that extends our config. Again, tslint-config-prettier comes with a handy CLI tool, that detects those rules in conflict, which need to be removed:
By executing local binary:
yarn tslint-config-prettier-check ./tslint.json
We will get output like this:
I see a great PR opportunity here, to automate removal of those conflicting lint rules 😉
tslint-config-airbnb
You can also install tslint-config-airbnb to import Airbnb JavaScript Style rules
Install:
yarn add -D tslint-config-airbnb
and extend tslint.json rules with it:
{
"extends": [
"tslint-config-airbnb"
],
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {...}
}
Formatting/Linting Done!
There is room for improvement though! I don’t know about you, but I’m lazy and just the thought of manually executing former command to format/lint my code, makes me ill…
Hey Robot! Do your work!
Robots (I mean npm packages) can handle that for us. This can be achieved with following node libraries:
lint-staged 🚫💩 — Run linters/formatters on git staged files
husky 🐶 Git hooks made easy
Install:
yarn add -D lint-staged husky
Configure lint-staged:
And add commit hook via custom npm script, which will be recognised by husky and executed on particular git-hook. In our case, we want to hook into pre-commit git life cycle and execute lint-staged binary which will consume our formerly defined configuration.
npm script, which will be executed by husky, looks like following:
{
"scripts": {
"precommit": "lint-staged"
}
}
Now, every time we will commit to the repo, our staged files will be formatted and linting violations will be fixed by TSLint (if they are auto-fixable), otherwise our commit will fail !
Excellent, you will never ever have to argue with your PR reviewer about semicolons vs no-semicolons, spaces…you name it…👌.
With that said, let’s switch to more serious stuff…
Unit Testing
If you’re not testing your codebase I will find you and I will… 😄
Angular CLI comes with Karma test runner and Jasmine expectation/spy library. Those tests are run usually against browser.
Karma is indeed an old tool ( levorutionary at one point some years ago ) but let’s be honest, it’s slow, debugging test is cumbersome and it needs extensive configuration. We can look outside our Angular boundaries and we will discover the “ultimate salvation”.
Everyone please welcome, silver bullet to all our testing nightmares, Dr.Jest .
Jest
Jest is a complete testing solution, that includes both test runner and assertion/spy library and much more…
It’s super easy to setup, it’s blazingly fast and introduces a brand new type of testing — snapshot testing ( which can be leveraged with everything that is serializable — component snapshots, state snapshots, image snapshots …)
Jest integration with Angular CLI
To integrate Jest with Angular CLI, we need to install
jest
**jest-preset-angular**, which handles everything for test environment setup specific to Angular ( zones and stuff ya know ? )
yarn add -D jest jest-preset-angular
Now we need to configure jest, to consume our preset:
// jest.config.js
module.exports = {
preset: 'jest-preset-angular',
setupTestFrameworkScriptFile: '<rootDir>/src/setupJest.ts',
}
Now we can add new npm-scripts for testing:
{
"scripts": {
"test": "jest --watch",
"test:ci": "jest --runInBand",
"test:coverage": "jest --coverage"
}
}
Jest speed
I briefly mentioned, that Jest is fast. How fast ?
Why is it so fast ? Well it runs against Node and JSDOM, tests are executed in parallel and efficiently cached.
Jest snapshot testing
Jest comes with snapshot testing, you just need to use toMatchSnapshot matcher within your test expectation on component fixture:
This will save a snapshot footprint of your component in that particular moment(state) - a file physically on disk - and when something changes in the component implementation afterwards, you’ll get following failing test with detailed DIFF about what changed:
I love this !
Jest interactive mode
Jest comes with advanced watch mode — a CLI like tool with lot of perks, like filtering, running only tests that changed and various other features:
Behold — Jest interactive watch mode:
Beautiful isn’t it ?!
Other Jest features
There are moar things that comes with Jest, I will name just few:
Powerful mocking features ( ES2015 modules, assets )
Code coverage — 0CJS jest --coverage
Pluggable ( run Puppeteer with Jest )
Huge ecosystem: jest-axe ( a11y ), jest-images-snapshots
E2E Testing
End to End testing is equally or even more important than unit testing. Let’s see what we get by default with CLI.
- Protractor with Selenium
Uh?! What did you just say? SELENIUM ? Did I tell you that every time I hear “SELENIUM” I wanna fight someone… and you don’t want to fight me, trust me 👀😇
Selenium was indeed useful at some point in our development carer history, but it’s 2018 and there are much better tools out there nowadays.
Please welcome, the cure for your E2E testing sickness, Dr. TestCafe 👨⚕️
TestCafe
TestCafe is pure NodeJS, non framework specific, open source tool for all our E2E scenario needs !
It’s 100% reliable, fast, zero config solution, works cross platform, cross browser( even works on custom environments like Windows Subsystem Linux or custom browsers ). Last but not least I forgot to mention that Typescript is 1st class citizen for writing e2e scenarios, so yay for type safety within your E2E tests!
Install:
yarn add -D testcafe testcafe-live
Now we can add new npm-scripts for executin e2e tests:
On CI, we wanna run our suite against all browsers and by providing --app flag, we are telling TestCafe to boot UI for us and then execute the scenarios on it, so for those purposes we will execute yarn e2e:ci
For development we will use yarn e2e which runs e2e tests in watch mode in chrome, so after every change our tests are re-run. DX experience at it's best !
Let’s see it in action (TestCafe watch mode)!
TestCafe demo example
In following e2e scenario, we are testing creation of new pizza, and after it’s created, we delete it to clean up after ourselves.
What might not be visible from the demo is, that when you wanna delete a pizza, browser native confirm dialog is shown, TestCafe handles all of this with ease.
After initial run, we’re adding toppings to the pizza, just to showcase complex UI entities selection within our e2e test.
Whole test scenario is powered by traditional PageObject pattern with custom helpers for our particular needs.
Components Development
Angular CLI doesn’t come with anything related to developing Components in isolation or for building a Demo project with components showcased in various state. Thanks to React community we can leverage Storybook !
Storybook
Storybook is powered by React under the hood and generates whole UI catalogue of your component demos/stories. Within Angular scope, it supports much more than just components. You can write stories for Services, Modules etc…
This is how the Storybook UI looks like:
Storybook is also capable to build our stories app, so we can deploy it on server, and with that, to provide a documentation for our component consumers. You can see it deployed with various Angular stories examples here
Storybook CLI integration
To add Storybook to Angular CLI, we will leverage storybook CLI:
npx @storybook/cli@alpha getstorybook
While we are enjoying our morning quick shot of espresso, everything is setup for us. Amazing!
Then we execute
yarn storybook
and our local storybook app is ready to use!
Storybook Addons
Storybook comes also with various plugins, although framework support varies. You can learn more here
Storybook: write a story
Let’s look very quickly how to write a story for simple button component:
Storybook: Component folder structure
With storybook covered, our final component folder structure should look like this:
implementation
unit test with snapshots
external styles
story
Tooling summary
Thanks to other communities and ecosystems, we are able to leverage better exisitng tools for our Angular toolkit.
We replaced Karma/Jasmine with Jest, Protractor/Selenium with TestCafe, TSlint with Prettier for formatting and added husky with lint-staged for adhering to styleguides automatically. As a last step, we added Storybook for developing components in isolation.
You can find everything that I’ve covered in this article open sourced on my GitHub repo:
BASED ON
Use React tools for better Angular apps
article from Martin Hochel on Medium