initial codebase
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# Introduction to Angular and modern design patterns
|
||||
|
||||
[Angular](https://angular.io) (aka Angular 2, 4, 5, 6...) is a new framework completely rewritten from the ground up,
|
||||
replacing the now well-known [AngularJS](https://angularjs.org) framework (aka Angular 1.x).
|
||||
|
||||
More that just a framework, Angular should now be considered as a whole *platform* which comes with a complete set of
|
||||
tools, like its own [CLI](https://github.com/angular/angular-cli), [debug utilities](https://augury.angular.io) or
|
||||
[performance tools](https://github.com/angular/angular/tree/master/packages/benchpress).
|
||||
|
||||
Angular has been around for some time now, but I still get the feeling that it’s not getting the love it deserved,
|
||||
probably because of other players in the field like React or VueJS. While the simplicity behind these frameworks can
|
||||
definitely be attractive, they lack in my opinion what is essential when making big, enterprise-grade apps: a solid
|
||||
frame to lead both experienced developers and beginners in the same direction and a rational convergence of tools,
|
||||
patterns and documentation. Yes, the Angular learning curve may seems a little steep, but it’s definitely worth it.
|
||||
|
||||
## Getting started
|
||||
|
||||
#### Newcomer
|
||||
|
||||
If you're new to Angular you may feel overwhelmed by the quantity of new concepts to apprehend, so before digging
|
||||
into this project you may want to start with [this progressive tutorial](https://angular.io/tutorial) that will guide
|
||||
you step by step into building a complete Angular application.
|
||||
|
||||
#### AngularJS veteran
|
||||
|
||||
If you come from AngularJS and want to dig straight in the new version, you may want to take a look at the
|
||||
[AngularJS vs 2 quick reference](https://angular.io/guide/ajs-quick-reference).
|
||||
|
||||
#### Cheatsheet
|
||||
|
||||
Until you know the full Angular API by heart, you may want to keep this
|
||||
[cheatsheet](https://angular.io/guide/cheatsheet) that resumes the syntax and features on a single page at hand.
|
||||
|
||||
## Style guide
|
||||
|
||||
This project follows the standard [Angular style guide](https://angular.io/guide/styleguide).
|
||||
|
||||
More that just coding rules, this style guide also gives advices and best practices for a good application architecture
|
||||
and is an **essential reading** for starters. Reading deeper, you can even find many explanations for some design
|
||||
choices of the framework.
|
||||
|
||||
## Going deeper
|
||||
|
||||
Even though they are not mandatory, Angular was designed for the use of design patterns you may not be accustomed to,
|
||||
like [reactive programming](#reactive-programming), [unidirectional data flow](#unidirectional-data-flow) and
|
||||
[centralized state management](#centralized-state-management).
|
||||
|
||||
These concepts are difficult to resume in a few words, and despite being tightly related to each other they concern
|
||||
specific parts of an application flow, each being quite deep to learn on its own.
|
||||
|
||||
You will essentially find here a list of good starting points to learn more on these subjects.
|
||||
|
||||
#### Reactive programming
|
||||
|
||||
You may not be aware of it, but Angular is now a *reactive system* by design.
|
||||
Although you are not forced to use reactive programming patterns, they make the core of the framework and it is
|
||||
definitely recommended to learn them if you want to leverage the best of Angular.
|
||||
|
||||
Angular uses [RxJS](http://reactivex.io/rxjs/) to implement the *Observable* pattern.
|
||||
|
||||
> An *Observable* is a stream of asynchronous events that can be processed with array-like operators.
|
||||
|
||||
##### From promises to observables
|
||||
|
||||
While AngularJS used to rely heavily on [*Promises*](https://docs.angularjs.org/api/ng/service/$q) to handle
|
||||
asynchronous events, *Observables* are now used instead in Angular. Even though in specific cases like for HTTP
|
||||
requests, an *Observable* can be converted into a *Promise*, it is recommended to embrace the new paradigm as it can a
|
||||
lot more than *Promises*, with way less code. This transition is also explained in the
|
||||
[Angular tutorial](https://angular.io/tutorial/toh-pt6#!%23observables).
|
||||
Once you have made the switch, you will never look back again.
|
||||
|
||||
##### Learning references
|
||||
|
||||
- [What is reactive programming?](http://paulstovell.com/blog/reactive-programming), explained nicely through a simple
|
||||
imaged story *(5 min)*
|
||||
|
||||
- [The introduction to reactive programming you've been missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754),
|
||||
the title says it all *(30 min)*
|
||||
|
||||
- [Functional reactive programming for Angular 2 developers](http://blog.angular-university.io/functional-reactive-programming-for-angular-2-developers-rxjs-and-observables/),
|
||||
see the functional reactive programming principles in practice with Angular *(15 min)*
|
||||
|
||||
- [RxMarbles](http://rxmarbles.com), a graphical representation of Rx operators that greatly help to understand their
|
||||
usage
|
||||
|
||||
#### Unidirectional data flow
|
||||
|
||||
In opposition with AngularJS where one of its selling points was two-way data binding which ended up causing a lot of
|
||||
major headaches for complex applications, Angular now enforces unidirectional data flow.
|
||||
|
||||
What does it means? Said with other words, it means that change detection cannot cause cycles, which was one of
|
||||
AngularJS problematic points. It also helps to maintain simpler and more predictable data flows in applications, along
|
||||
with substantial performance improvements.
|
||||
|
||||
**Wait, then why the Angular documentation have mention of a
|
||||
[two-way binding syntax](https://angular.io/guide/template-syntax#binding-syntax-an-overview)?**
|
||||
|
||||
If you look closely, the new two-way binding syntax is just syntactic sugar to combine two *one-way* bindings (a
|
||||
*property* and *event* binding), keeping the data flow unidirectional.
|
||||
|
||||
This change is really important, as it was often the cause of performance issues with AngularJS, and it one of the
|
||||
pillars enabling better performance in new Angular apps.
|
||||
|
||||
While Angular tries to stay *pattern-agnostic* and can be used with conventional MV* patterns, it was designed with
|
||||
reactive programming in mind and really shines when used with reactive data flow patterns like
|
||||
[redux](http://redux.js.org/docs/basics/DataFlow.html),
|
||||
[Flux](https://facebook.github.io/flux/docs/in-depth-overview.html#content) or
|
||||
[MVI](http://futurice.com/blog/reactive-mvc-and-the-virtual-dom).
|
||||
|
||||
#### Centralized state management
|
||||
|
||||
As applications grow in size, keeping track of the all its individual components state and data flows can become
|
||||
tedious, and tend to be difficult to manage and debug.
|
||||
|
||||
The main goal of using a centralized state management is to make state changes *predictable* by imposing certain
|
||||
restrictions on how and when updates can happen, using *unidirectional data flow*.
|
||||
|
||||
This approach was first made popular with React with introduction of the
|
||||
[Flux](https://facebook.github.io/flux/docs/in-depth-overview.html#content) architecture. Many libraries emerged then
|
||||
trying to adapt and refine the original concept, and one of these gained massive popularity by providing a simpler,
|
||||
elegant alternative: [Redux](http://redux.js.org/docs/basics/DataFlow.html).
|
||||
|
||||
Redux is at the same time a library (with the big *R*) and a design pattern (with the little *r*), the latter being
|
||||
framework-agnostic and working very well with Angular.
|
||||
|
||||
The *redux* design pattern is based on these [3 principles](http://redux.js.org/docs/introduction/ThreePrinciples.html):
|
||||
|
||||
- The application state is a *single immutable* data structure
|
||||
- A state change is triggered by an *action*, an object describing what happened
|
||||
- Pure functions called *reducers* take the previous state and the next action to compute the new state
|
||||
|
||||
The core concepts behind these principles are nicely explained in
|
||||
[this example](http://redux.js.org/docs/introduction/CoreConcepts.html) *(3 min)*.
|
||||
|
||||
##### Which library to use?
|
||||
|
||||
You can make Angular work with any state management library you like, but your best bet would be to use
|
||||
[@ngrx/store](https://github.com/ngrx/store). It works the same as the popular [Redux](http://redux.js.org) library,
|
||||
but with a tight integration with Angular and [RxJS](http://reactivex.io/rxjs/), with some nice additional developer
|
||||
utilities.
|
||||
|
||||
Here are some resources to get started:
|
||||
|
||||
- [Build a better Angular 2 application with redux and ngrx](http://onehungrymind.com/build-better-angular-2-application-redux-ngrx/),
|
||||
a nice tutorial for @ngrx/store *(30 min)*
|
||||
|
||||
- [Comprehensive introduction to @ngrx/store](https://gist.github.com/btroncone/a6e4347326749f938510), an in-depth
|
||||
walkthrough to this library usage in Angular *(60 min)*
|
||||
|
||||
##### When to use it?
|
||||
|
||||
You may have noticed that the starter template does not include a centralized state management system out of the box.
|
||||
Why is that? Well, while there is many benefits from using this pattern, the choice is ultimately up to your team and
|
||||
what you want to achieve with your app.
|
||||
|
||||
Keep in mind that using a single centralized state for your app introduces a new layer a complexity
|
||||
[that might not be needed](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367), depending of your
|
||||
goal.
|
||||
|
||||
## Optimizing performance
|
||||
|
||||
While the new Angular version resolves by design most of the performance issues that could be experienced with
|
||||
AngularJS, there is always room for improvements. Just keep in mind that delivering an app with good performance is
|
||||
often a matter of common sense and sane development practices.
|
||||
|
||||
Here is [a list of key points](https://github.com/mgechev/angular-performance-checklist) to check for in your app to
|
||||
make sure you deliver the best experience to your customers.
|
||||
|
||||
After going through the checklist, make sure to also run an audit of your page through
|
||||
[**Lighthouse**](https://developers.google.com/web/tools/lighthouse/), the latest Google tool that gives you meaningful
|
||||
insight about your app performance, accessibility, mobile compatibility and more.
|
||||
@@ -0,0 +1,90 @@
|
||||
# End-to-end tests coding guide
|
||||
|
||||
End-to-end (E2E for short) tests are meant to test the behavior of your application, from start to finish.
|
||||
|
||||
While unit tests are the first choice for catching bugs and regression on individual components, it is a good idea to
|
||||
complement them with test cases covering the integration between the individual components, hence the need for E2E
|
||||
tests.
|
||||
|
||||
These tests use [Protractor](https://github.com/angular/protractor), which is a framework built for Angular on top of
|
||||
[Selenium](https://github.com/SeleniumHQ/selenium) to control browsers and simulate user inputs.
|
||||
[Jasmine](http://jasmine.github.io) is used as the base test framework.
|
||||
|
||||
## Good practices
|
||||
|
||||
- Avoid whenever possible inter-dependencies between your E2E tests
|
||||
- Run E2E tests on your continuous integration server against different browsers
|
||||
- If you use an Agile methodology, cover each user story acceptance factors with an E2E test
|
||||
|
||||
## Page objects
|
||||
|
||||
E2E tests should follow the *[Page Object](https://github.com/SeleniumHQ/selenium/wiki/PageObjects)* pattern.
|
||||
|
||||
#### What is a page object?
|
||||
|
||||
A page object:
|
||||
|
||||
- Models the objects on a page under test:
|
||||
* *Properties* wrap page elements
|
||||
* *Methods* wrap code that interacts with the page elements
|
||||
- Simplifies the test scripts
|
||||
- Reduces the amount of duplicated code
|
||||
|
||||
If the UI changes, the fix only needs to be applied in one place.
|
||||
|
||||
#### How to define a page object
|
||||
|
||||
```typescript
|
||||
// login.po.ts
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
export class LoginPage {
|
||||
emailInput = element(by.css('input[name=^"email"]'));
|
||||
passwordInput = element(by.css('input[name=^"password"]'));
|
||||
loginButton = element(by.css('button[(click)^="login"]'));
|
||||
registerButton = element(by.css('button[(click)^="register"]'));
|
||||
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getGreetingText() {
|
||||
return element(by.css('.greeting')).getText();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### How to use a page object
|
||||
|
||||
```typescript
|
||||
// login.e2e-spec.ts
|
||||
import { LoginPage } from './login.po';
|
||||
|
||||
describe('Login', () => {
|
||||
let page: LoginPage ;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new LoginPage();
|
||||
page.navigateTo();
|
||||
});
|
||||
|
||||
it('should navigate to the register page when the register button is clicked', () => {
|
||||
page.registerButton.click();
|
||||
|
||||
expect(browser.getCurrentUrl()).toContain('/register');
|
||||
});
|
||||
|
||||
it('should allow a user to log in', () => {
|
||||
page.emailInput.sendKeys('test@mail.com');
|
||||
page.passwordInput.sendKeys('abc123');
|
||||
page.loginButton.click();
|
||||
|
||||
expect(page.getGreetingText()).toContain('Welcome, Test User');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
Parts of this guide were freely inspired by this
|
||||
[presentation](https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ).
|
||||
@@ -0,0 +1,40 @@
|
||||
# HTML coding guide
|
||||
|
||||
## Naming conventions
|
||||
|
||||
- Everything should be named in `kebab-case` (lowercase words separated with a `-`): tags, attributes, IDs, etc,
|
||||
**except for everything bound to Angular** such variables, directives or events which should be in `camelCase`
|
||||
- File names should always be in `kebab-case`
|
||||
|
||||
## Coding rules
|
||||
|
||||
- Use HTML5 doctype: `<!doctype html>`
|
||||
- Use HTML [semantic elements](https://developer.mozilla.org/docs/Web/HTML/Sections_and_Outlines_of_an_HTML5_document)
|
||||
- Use double quotes `"` around attribute values in tags
|
||||
- Use a new line for every block, list, or table element, and indent every such child element
|
||||
- Clearly Separate structure (HTML) from presentation (CSS) from behavior (JavaScript):
|
||||
* Never use inline CSS or JavaScript
|
||||
* Keep any logic out of the HTML
|
||||
- `type` attribute for stylesheets and script tags should be omitted
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
- **Block**-type tags cannot be nested inside **inline**-type tags: a `<div>` tag cannot be nested in a `<span>`.
|
||||
This rule also applies regarding the `display` value of an element.
|
||||
- HTML is **not** XML: empty tags cannot be self-closing and will result in improper results
|
||||
* `<div/>` will be interpreted as a simple `<div>` without closing tag!
|
||||
* The only tags that allows self-closing are the one that does not require a closing tag in first place:
|
||||
these are the void elements that do not not accept content `<br>`, `<hr>`, `<img>`, `<input>`, `<meta>`, `<link>`
|
||||
(and others).
|
||||
|
||||
## Templates
|
||||
|
||||
In accordance with the [Angular style guide](https://angular.io/guide/styleguide), HTML templates should be extracted in
|
||||
separate files, when more than 3 lines.
|
||||
|
||||
Only use inline templates sparingly in very simple components with less than 3 lines of HTML.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Coding rules enforcement and basic sanity checks are done in this project by [HTMLHint](http://htmlhint.com).
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# Sass coding guide
|
||||
|
||||
[Sass](http://sass-lang.com) is a superset of CSS, which brings a lot of developer candy to help scaling CSS in large
|
||||
projects and keeping it maintainable.
|
||||
|
||||
The main benefits of using Sass over plain CSS are *variables*, *nesting* and *mixins*, see the
|
||||
[basics guide](http://sass-lang.com/guide) for more details.
|
||||
|
||||
> Note that this project use the newer, CSS-compatible **SCSS** syntax over the old
|
||||
[indented syntax](http://sass-lang.com/documentation/file.INDENTED_SYNTAX.html).
|
||||
|
||||
## Naming conventions
|
||||
|
||||
- In the CSS world, everything should be named in `kebab-case` (lowercase words separated with a `-`).
|
||||
- File names should always be in `kebab-case`
|
||||
|
||||
## Coding rules
|
||||
|
||||
- Use single quotes `'` for strings
|
||||
- Use this general nesting hierarchy when constructing your styles:
|
||||
```scss
|
||||
// The base component class acts as the namespace, to avoid naming and style collisions
|
||||
.my-component {
|
||||
// Put here all component elements (flat)
|
||||
.my-element {
|
||||
// Use a third-level only for modifiers and state variations
|
||||
&.active { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
Note that with
|
||||
[Angular view encapsulation](https://angular.io/docs/ts/latest/guide/component-styles.html#!#view-encapsulation),
|
||||
the first "namespace" level of nesting is not necessary as Angular takes care of the scoping for avoid collisions.
|
||||
|
||||
> As a side note, we are aware of the [BEM naming approach](https://en.bem.info/tools/bem/bem-naming/), but we found
|
||||
it impractical for large projects. The nesting approach has drawbacks such as increased specificity, but it helps
|
||||
keeping everything nicely organized, and more importantly, *scoped*.
|
||||
|
||||
|
||||
Also keep in mind this general rules:
|
||||
- Always use **class selectors**, never use ID selectors and avoid element selectors whenever possible
|
||||
- No more than **3 levels** of nesting
|
||||
- No more than **3 qualifiers**
|
||||
|
||||
## Best practices
|
||||
|
||||
- Use object-oriented CSS (OOCSS):
|
||||
* Factorize common code in base class, and extend it, for example:
|
||||
```scss
|
||||
// Base button class
|
||||
.btn { ... }
|
||||
|
||||
// Color variation
|
||||
.btn-warning { ... }
|
||||
|
||||
// Size variation
|
||||
.btn-small { ... }
|
||||
```
|
||||
* Try to name class by semantic, not style nor function for better reusability:
|
||||
Use `.btn-warning`, not `btn-orange` nor `btn-cancel`
|
||||
* Avoid undoing style, refactor using common base classes and extensions
|
||||
|
||||
- Keep your style scoped
|
||||
* Clearly separate **global** (think *framework*) and **components** style
|
||||
* Global style should only go in `src/theme/`, never in components
|
||||
* Avoid style interactions between components, if some style may need to be shared, refactor it as a framework
|
||||
component in put it in your global theme.
|
||||
* Avoid using wider selectors than needed: always use classes if you can!
|
||||
|
||||
- Avoid rules multiplication
|
||||
* The less CSS the better, factorize rules whenever it's possible
|
||||
* CSS is code, and like any code frequent refactoring is healthy
|
||||
|
||||
- When ugly hacks cannot be avoided, create an explicit `src/hacks.scss` file and put it in:
|
||||
* These ugly hacks should only be **temporary**
|
||||
* Each hack should be documented with the author name, the problem and hack reason
|
||||
* Limit this file to a reasonable length (~100 lines) and refactor hacks with proper solutions when the limit is
|
||||
reached.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Never use the `!important` keyword. Ever.
|
||||
- Never use **inline** style in html, even *just for debugging* (because we **KNOW** it will end up in your commit)
|
||||
|
||||
## Browser compatibility
|
||||
|
||||
You should never use browser-specific prefixes in your code, as [autoprefixer](https://github.com/postcss/autoprefixer)
|
||||
takes care of that part for you during the build process.
|
||||
You just need to declare which browsers you target in the [`browserslist`](https://github.com/ai/browserslist) file.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Coding rules are enforced in this project with [stylelint](https://stylelint.io).
|
||||
This tool also checks the compatibility of the rules used against the browsers you are targeting (specified in the
|
||||
[`browserslist`](https://github.com/ai/browserslist) file), via [doiuse](https://github.com/anandthakker/doiuse).
|
||||
@@ -0,0 +1,63 @@
|
||||
# TypeScript coding guide
|
||||
|
||||
[TypeScript](http://www.typescriptlang.org) is a superset of JavaScript that greatly helps building large web
|
||||
applications.
|
||||
|
||||
Coding conventions and best practices comes from the
|
||||
[TypeScript guidelines](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines), and are also detailed in the
|
||||
[TypeScript Deep Dive Style Guide](https://basarat.gitbooks.io/typescript/content/docs/styleguide/styleguide.html).
|
||||
In addition, this project also follows the general [Angular style guide](https://angular.io/guide/styleguide).
|
||||
|
||||
## Naming conventions
|
||||
|
||||
- Use `PascalCase` for types, classes, interfaces, constants and enum values.
|
||||
- Use `camelCase` for variables, properties and functions
|
||||
- Avoid prefixing interfaces with a capital `I`, see [Angular style guide](https://angular.io/guide/styleguide#!#03-03)
|
||||
- Do not use `_` as a prefix for private properties. An exception can be made for backing fields like this:
|
||||
```typescript
|
||||
private _foo: string;
|
||||
get foo() { return this._foo; } // foo is read-only to consumers
|
||||
```
|
||||
|
||||
## Ordering
|
||||
|
||||
- Within a file, type definitions should come first
|
||||
- Within a class, these priorities should be respected:
|
||||
* Properties comes before functions
|
||||
* Static symbols comes before instance symbols
|
||||
* Public symbols comes before private symbols
|
||||
|
||||
## Coding rules
|
||||
|
||||
- Use single quotes `'` for strings
|
||||
- Always use strict equality checks: `===` and `!==` instead of `==` or `!=` to avoid comparison pitfalls (see
|
||||
[JavaScript equality table](https://dorey.github.io/JavaScript-Equality-Table/)).
|
||||
The only accepted usage for `==` is when you want to check a value against `null` or `undefined`.
|
||||
- Use `[]` instead of `Array` constructor
|
||||
- Use `{}` instead of `Object` constructor
|
||||
- Always specify types for function parameters and returns (if applicable)
|
||||
- Do not export types/functions unless you need to share it across multiple components
|
||||
- Do not introduce new types/values to the global namespace
|
||||
- Use arrow functions over anonymous function expressions
|
||||
- Only surround arrow function parameters when necessary.
|
||||
For example, `(x) => x + x` is wrong but the following are correct:
|
||||
* `x => x + x`
|
||||
* `(x, y) => x + y`
|
||||
* `<T>(x: T, y: T) => x === y`
|
||||
|
||||
## Definitions
|
||||
|
||||
In order to infer types from JavaScript modules, TypeScript language supports external type definitions. They are
|
||||
located in the `node_modules/@types` folder.
|
||||
|
||||
To manage type definitions, use standard `npm install|update|remove` commands.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Coding rules are enforced in this project via [TSLint](https://github.com/palantir/tslint).
|
||||
Angular-specific rules are also enforced via the [Codelyzer](https://github.com/mgechev/codelyzer) rule extensions.
|
||||
|
||||
## Learn more
|
||||
|
||||
The read of [TypeScript Deep Dive](https://basarat.gitbooks.io/typescript) is recommended, this is a very good
|
||||
reference book for TypeScript (and also open-source).
|
||||
@@ -0,0 +1,46 @@
|
||||
# Unit tests coding guide
|
||||
|
||||
The main objective of unit tests is to detect regressions and to help you design software components. A suite of
|
||||
*good* unit tests can be *immensely* valuable for your project and makes it easier to refactor and expand your code.
|
||||
But keep in mind that a suite of *bad* unit tests can also be *immensely* painful, and hurt your development by
|
||||
inhibiting your ability to refactor or alter your code in any way.
|
||||
|
||||
## What to test?
|
||||
|
||||
Everything! But if you need priorities, at least all business logic code must be tested: services, helpers, models...
|
||||
Shared directives/components should also be covered by unit tests, if you do not have the time to test every single
|
||||
component.
|
||||
|
||||
Keep in mind that component unit tests should not overlap with [end-to-end tests](e2e-tests.md): while unit the tests
|
||||
cover the isolated behavior of the component bindings and methods, the end-to-end tests in opposition should cover the
|
||||
integration and interactions with other app components based on real use cases scenarios.
|
||||
|
||||
## Good practices
|
||||
|
||||
- Name your tests cleanly and consistently
|
||||
- Do not only test nominal cases, the most important tests are the one covering the edge cases
|
||||
- Each test should be independent to all the others
|
||||
- Avoid unnecessary assertions: it's counter-productive to assert anything covered by another test, it just increase
|
||||
pointless failures and maintenance workload
|
||||
- Test only one code unit at a time: if you cannot do this, it means you have an architecture problem in your app
|
||||
- Mock out all external dependencies and state: if there is too much to mock, it is often a sign that maybe you
|
||||
should split your tested module into several more independent modules
|
||||
- Clearly separate or identify these 3 stages of each unit test (the *3A*): *arrange*, *act* and *assert*
|
||||
- When you fix a bug, add a test case for it to prevent regression
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Sometimes your architecture might mean your code modify static variables during unit tests. Avoid this if you can,
|
||||
but if you can't, at least make sure each test resets the relevant statics before and after your tests.
|
||||
- Don’t unit-test configuration settings
|
||||
- Improving test coverage is good, but having meaningful tests is better: start with the latter first, and **only after
|
||||
essential features of your code unit are tested**, your can think of improving the coverage.
|
||||
|
||||
## Unit testing with Angular
|
||||
|
||||
A good starting point for learning is the official
|
||||
[testing guide](https://angular.io/docs/ts/latest/guide/testing.html).
|
||||
|
||||
But as you will most likely want to go bit further in real world apps, these
|
||||
[example test snippets](https://gist.github.com/wkwiatek/e8a4a9d92abc4739f04f5abddd3de8a7) are also very helpful to
|
||||
learn how to cover most common testing use cases.
|
||||
Reference in New Issue
Block a user