Showing posts with label service. Show all posts
Showing posts with label service. Show all posts

1/18/17

Unit Tests In Angular2 - part 3 (Component That Uses Service)

In previous post we've learned how to test the angular2 component.
That was very nice and we have a lot of fun, but everybody knows that in real life many components may use services to bring data from server.
Lets demonstrate it on our user component:
Lets make it to display friends list of this user:



@Component({
  selector: 'my-app',
  template: `<span>name: <strong>Victor Savkin</strong></span>
   <hr/>
   <strong>Friends:</strong>
   <ul>
     <li *ngFor="let friend of friends">
       {{friend}}
     </li>
   </ul>`
})
export class App {
   
    public friends:string[]=[]
    constructor(private usersService:UsersService) {
    }
    ngOnInit(): void {
       this.usersService.getUsers().subscribe(
         users => {
           this.friends=users;
         },
         error=>console.log(error) 
       );
    }
}


And the code of UsersSerivice:

import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class UsersService {
  constructor(private http:Http) { }
  
  getUsers(){
    return this.http.get('api/users.json')
      .map(response => response.json());
  }
}


So How To Test This Thing?

Lets say we want to test that request populates the "friends" section with friends names.
Since it is bad practice to make real http request for testing purposes - we need to create a mock of UsersService:


import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
  
  class MockUsersService {
    public get() {return  Observable.of(['John', 'Steve']);}
  }

Once we have the mock of UsersService -lets inject it into the module instead of usersService:

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [UserComponent], 
      providers:[// <--HERE IS THE MAGIC!!!
       { provide: UsersService, useClass: MockUsersService}
      ],
      imports: [ HttpModule,BrowserModule ]
    })
    .compileComponents();
  }));

Great, inst it?
Now we can test the component and see if friends are displayed as planned:

  beforeEach(() => {
    fixture = TestBed.createComponent(UserComponent);
    comp = fixture.componentInstance;
    comp.user = new UserModel('Vasia','Kozlov')
    de = fixture.debugElement.query(By.css('span'));
    element = fixture.nativeElement;// to access DOM element
  });

  it('should have list of friends displayed inside UL',  async(() => {
    fixture.detectChanges();
    fixture.whenStable().then(() => { 
      expect(element.querySelector('li:first-child').innerText).toBe('John');
      expect(element.querySelector('li:last-child').innerText).toBe('Steve');
    })
  }));

you can see the full code on this plunker

2/23/16

Using Angular2 Services

Remember we created flot component in previous posts?
Lets have a quick look on the code now:


export class App {  
  constructor() {
    ...
    //Look here - dont you feel something here is uuuugggglllyyyy?
    this.dataset = [{label: "line1",color:"blue",data:[
    [1, 130],
    [2, 40],
    [3, 80],
    [4, 160],
    [5, 159],
    [6, 370],
    [7, 330],
    [8, 350],
    [9, 370],
    [10, 400],
    [11, 330],
    [12, 350]
]}];
  }
}

The way dataset property sat - is perfect example of hardcoding, and everybody knows that hardcoding is bad.
Since we dont have real server to get data from yet, at least lets move the data-getting logic to some different module, in other words -

Lets Create A Service


export var FlotEntries: Array[] = [
    [1, 130],
    [2, 40],
    [3, 80],
    [4, 160],
    [5, 159],
    [6, 370],
    [7, 330],
    [8, 350],
    [9, 370],
    [10, 400],
    [11, 330],
    [12, 350]
];

//@Injectable()
export class FlotService {
  getFlotEntries() {
    return FlotEntries;
  }
}

This service doing only one thing - getting data for a plot chart.

Lets Use Our Service

Last thing that left - is to teach our main component how to use the service:
Note: Dont forget to list the service inside "poviders" property


//our root app component
import {Component} from 'angular2/core'
import {FlotCmp} from './flot';
import {FlotService} from './FlotService';

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
      <flot  [options]="splineOptions" [dataset]="dataset" height="250px" width="100%"></flot>
    </div>
  `,
  directives: [FlotCmp],
  providers: [FlotService]//important!!!
})
export class App {
  
  constructor(private _flotService:FlotService) {
    this.name = 'Angular2'
    this.splineOptions: any = {
            series: {
                lines: { show: true },
                points: {
                    radius: 3,
                    show: true
                }
            }
    };
    this.dataset = [{label: "line1",color:"blue",data:this._flotService.getFlotEntries()]}];
  }
}


Looks better isn't it?
plunkr
Thats it, now you know how to create angular2 service.
Hope you have fun reading

Getting started with docker

It is very simple to get started usig docker. All you need to do-is download the docker desktop for your system Once you get docker syste...