- simple, straightforward APIs
- works consistently, reliably and performantly in all environments
- fully accessible for users of all abilities
- internationalized for users around the world
- documentation for general use and public API
- comprehensive demos
- robust unit tests, some e2e tests
- performance is measured and tracked
- your component from the outside: how developers and users interact with your component
- your component from the inside
Huge importance: public API
- component class (analogous to the controller in Angular 1)
- much more expressive in Angular 2
- template syntax
- @ContentChildren
- @Host
Events fired by the component are also part of the public API
- given how change detection works in Angular 2, events will be used a lot more
- @Output also make it clear which events can be fired, compared with Angular 1 where any arbitrary string could be used as an event
Ensure that a maximal number of users can use the component.
First, always use the right component for the job (e.g., prefer a real button over a div with a click event)
Second, bind aria attributes. For example: <div class="cool-checkbox" role="checkbox" [attr.aria-checked]="isChecked">...</div>
Other example:
@Component({
selector: 'cool-checkbox',
host: {
'attr.role': 'checkbox',
'[attr.aria-checked]': 'isChecked'
class CoolCheckbox { ... }
}
})
Make sure to support keyboard interaction for disabled users. Angular 2 makes this very easy:
<div role="checkbox" class="zz-checkbox"
(keydown.space)="toggle()"
(keydown.u)="navigate()"
(keydown.control.enter)="submit()"
(keydown.alt.shift.escape)="superExit()"
[attr.aria-checked]="isChecked"
[attr.aria-disabled]="isDisabled"
Manage the focus correctly. For example if a popup is displayed, focus should remain in the popup even if the user hits tab multiple times:
<div tabindex="0" (focus)="myDialog.focus()"></div>
- provide those with your actual components
- expose a real API plus extra testing methods
- no real work, only tracks state
- can help hammer out the API
- makes testing more pleasant downstream
Example: CoolComponent that uses a CoolDropDown component. For testing, it might be useful to use a fake CoolDropDown:
@Component({
selector: 'cool-dropdown',
template: ''
})
class FakeCoolDropDown implements CoolDropDown{
// doesn't do much
}
Angular 2 provides a testComponentBuilder
:
testComponentBuilder
.overrideDirective(CoolComponent, FakeCoolDropDown)
.createAsync(CoolComponentTest).then();
...
- more testable
- looser coupling
Plus in Angular 2:
- scope explicitly to a component's content or view children
- can override injectable for a subset of the app
- concise, declarative syntax is better than ever
- direct DOM manipulation can get unorganized and hard to follow
- performance improvements for NG2 makes direct DOM much less necessary
- avoiding direct DOM manipulations enables
- server-side rendering
- running in a Web Worker
- can find mistakes in code statically
- better tooling
- much easier to express function APIs
- generally makes code easier to understand
Angular 2 provides the TestComponentBuilder:
beforeEach(inject([TestComponentBuilder], (tcb) => {
builder = tcb;
}));
it('should test something', (done) => {
builder.createAsync(TestApp).then(rootTestCmp => { ... });
});
- unit and e2e tests guard against behavioral regressions
- benchmark tests guard against performance regressions
Benchpress:
- framework for creation and sampling of benchmarks for real world apps
- Angular team created Benchpress for measuring the framework itself
- detailed breakdown of performance metrics
Example Benchpress test:
let runner = new benchpress.Runner(config);
it('should be fast!', (done) => {
browser.get(testUrl);
runner.sample({
id: 'important-test',
execute: () => { doStuffWeWantToMeasure(); }
});
done();
});
The output includes:
- amount of memory garbage collected
- garbage collection time
- render time
- script execution time