clean code
- small functions - 10 lines max
- proper naming
- single responsibility
jasmine - test framework
karma - test runner
pure unit test - test the class only using component variable
integration test - when testing the class along with its template
AAA - arrange, act, assert
set up - beforeEach fn
tear down - afterEach fn
==================== Forms ====================
TD forms
Import FormsModule
form control - add ngModel and name attribute
general info about forms:
dirty - the value of a control is changed
pristine - the opposite of dirty
touched - only clicked on it
Reactive Forms
Import ReactiveFormsModule
to connect the form from the view with the property from the class: [formGroup]="signUpForm"
to connect form control from the view with property from the class: formControlName="username"
to collect info from the form:
<form (ngSubmit)="onSubmit()"
==================== Unit Tests - Patterns ====================
suitable for testing:
state forms events(output properties) services(spyOn and stubs)
==================== Integration Tests - Patterns ====================
suitable for testing:
templates navigation directives async operations
TestBed - creates dynamic module in which you: declare provide import etc.
beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [TodosComponent], providers: [TodosService] }).compileComponents(); }));
async is used because compileComponents is compiling files, so working with the file system, thus asyc operations
if using webpack there is no need to call compileComponents
you can use:
TestBed.configureTestingModule({ declarations: [TodosComponent], providers: [TodosService] })
and one single beforeEach for the setup
fixture - wrapper around the instance of the class you're testing component = fixture.componentInstance fixture.nativeElement - HTML element which is the root DOM element of the view fixture.debugElement - wrapper around nativeElement you can run change detection manually by using fixture you can get the injected dependencies by using fixture
test case - check the text inside element let de = fixure.debugElement.query(By.css(".vote-count")); let el: HTMLElement = de.nativeElement // innerText exists on the native element so intellisense will work
By has another method, By.directive(yourCustomDirective), for example By.directive(VoterComponent) // VoterComponent is a custom directive
make sure to run fixture.detectChanges() if you are upating the state
trigger events in the view let de = fixure.debugElement.query(By.css(".vote-count")); de.triggerEventHandler('click', null)
get a reference to a dependency TestBed.get(TodoService) or fixture.debugElement.injector.get(TodoService)
fixture.detectChanges and spyOn make sure fixture.detectChanges() is invoked after the fake call to the method of a dependency // you most likely need to remove fixture.detectChanges() from the setup
Stubs
for example you need to stub the Router or ActivatedRoute
create dummy class which contains the methods are used in the component's class
class RouterStub { navigate(params) {} }
and then provide it in the spec file:
providers: [{provide: Router, useClass: RouterStub}]
RouterTestingModule Sets up the router to be used for testing.
Testing and promises
one approach is to wrap all in a fakeAsync fn
and just before the asserions invoke tick
another approach is to wrap with async fn
and the call fixture.whenStable().then(() => { // assertions go here })
==================== General - Angular ====================
formControlName="username" // username is STRING
[formGroup]="signUpForm" // signUpForm is PROPERTY OF A CLASS