简体   繁体   中英

How to Write test for login component for angular2 ( unit testing )

This is login.component.ts



  
 
  
  
  
    import { Component, OnInit } from '@angular/core';
    import { Router, ActivatedRoute } from '@angular/router';
    import { FormBuilder, FormGroup, Validators } from '@angular/forms';
    import { CommonModule } from  '@angular/common';


    import { LoginUser } from './loginUser.model'
    import { UserService } from './user.service';
    import { LoaderService } from '../shared/loader.service';

    import 'rxjs/add/operator/toPromise';

    @Component({
        templateUrl: './login.component.html'
    })
    export class LoginComponent implements OnInit {
        errorMessage: string;
        loginForm: FormGroup;
        loginObj = new LoginUser();

        constructor(private userService: UserService, private loaderService: LoaderService, private router: Router, fb: FormBuilder) {
            this.loginForm = fb.group({
                userName: [null, Validators.required],
                password: [null, Validators.required]
            })
            console.log(this.loginForm);
        }

    test() : void{
        console.log("This is a test");
    }
        login(loginObjValue: any): void {
            if (loginObjValue.userName == null || loginObjValue.password == null) {
                console.log('error');
            } else {
                this.loginObj.userName = loginObjValue.userName;
                this.loginObj.password = loginObjValue.password;
                this.loaderService.displayLoader(true);

                this.userService.login(this.loginObj)
                    .then((res) => {
                        console.log("data", res);
                        console.log("$localStorage.currentUser", localStorage);
                        let link = ['customercare/customer-ticket'];
                        this.loaderService.displayLoader(false);

                        this.router.navigate(link);
                    })
                    .catch(error => this.handleError(error));
            }
        }

        private handleError(error: any): Promise<any> {
            this.loaderService.displayLoader(false);

            if (error._body) {
                this.errorMessage = JSON.parse(error._body).error_description;
            }

            console.log('An error occurred', error);
            return Promise.reject(error.message || error);
        }

        ngOnInit(): void {


        }
    }
@Component({ templateUrl: './login.component.html' }) export class LoginComponent implements OnInit { errorMessage: string; loginForm: FormGroup; loginObj = new LoginUser(); constructor(private userService: UserService, private loaderService: LoaderService, private router: Router, fb: FormBuilder) { this.loginForm = fb.group({ userName: [null, Validators.required], password: [null, Validators.required] }) console.log(this.loginForm); } login(loginObjValue: any): void { if (loginObjValue.userName == null || loginObjValue.password == null) { console.log('error'); } else { this.loginObj.userName = loginObjValue.userName; this.loginObj.password = loginObjValue.password; this.loaderService.displayLoader(true); this.userService.login(this.loginObj) .then((res) => { console.log("data", res); console.log("$localStorage.currentUser", localStorage); let link = ['customercare/customer-ticket']; this.loaderService.displayLoader(false); this.router.navigate(link); }) .catch(error => this.handleError(error)); } } }

Partial Code of userservice.ts . Please refer this code . Partial Code of userservice.ts . Please refer this code . Partial Code of userservice.ts . Please refer this code . Partial Code of userservice.ts . Please refer this code . Partial Code of userservice.ts . Please refer this code .

@Injectable()
export class UserService {
    private URL = "";

    constructor(private http: Http) { }

    login(loginObj: LoginUser) {

        let body = 'userName=' + loginObj.userName + '&password=' + loginObj.password + '&grant_type=password';

        let headers = new Headers();
        headers.append('Content-Type', 'application/x-www-form-urlencoded');

        return this.http.post(this.URL + '/token', body, { headers: headers })
            .toPromise()
            .then((res: Response) => {
                let data = res.json();
                if (data && data.access_token) {
                    localStorage.setItem('currentUser', JSON.stringify(data));
                }
                return data;
            })
    }

}

SO FAR I HAVE WRITTEN : I am unable to call login function . Please guide me .

**

    describe('LoginComponent', () => {
      let component: LoginComponent;
      let UserService:UserService;
      let fixture: ComponentFixture<LoginComponent>;

    beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [ LoginComponent ],
        providers: [
            { provide: UserService, useValue: UserService },
                   ]
      })

      it('should call the login method from the UserService', 
        inject([TestBed, UserService], fakeAsync((tcb: TestBed, mockUserService: UserService) => {
          spyOn(mockUserService, 'login');
    tcb
            .createComponent(LoginComponent)
            .then((fixture: ComponentFixture<LoginComponent>) => {
              tick();
               fixture.detectChanges();
              expect(mockUserService.login).toHaveBeenCalled();
            });
        }))
      );

    });

**

So I'm not sure what the error is, but probably the biggest thing I see is not calling compileComponents before creating your component.

beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [ LoginComponent ],
        providers: [
            { provide: UserService, useValue: UserService },
                   ]
      }).compileComponents();
}); <--- also looked to be missing

This is just my advice, I'm not near a machine to test if your way could work, but I would also grab a reference to the fixture inside the before each and use that to create your component inside the test. So same as above but:

beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [ LoginComponent ],
        providers: [
            { provide: UserService, useValue: UserService },
                   ]
      }).compileComponents();
}); 

beforeEach(async(() => {
      // components are now compiled
      fixture = TestBed.createComponent(LoginComponent);
}); 

Mainly before you already created a reference to it. You try to recreate that reference inside your tests, but you could just assign to it in the beforeEach and use that.

Also, your test doesn't really DO anything that I can see to have triggered anything to be called. You can verify it exists if that's your goal.

 it('should call the login method when the component does something', 
        inject([UserService], ((userService: UserService) => {
          spyOn(userService, 'login');
          let component = fixture.componentInstance;
          component.doSomething();
          expect(userService.login).toHaveBeenCalled();
          });
 }));

Since you're only testing that the function was called, there's really no need to wrap anything in async. You're not waiting for a response in the DOM or anything else, only verifying the login() method on the service was indeed called when the component's own login() method was called. If ever in doubt, you can toss in a harmless fixture.detectChanges(), but I believe even that's generally to ensure elements have propagated back up if you changed something in a template.

Honestly, even that's kind of outside a pure unit test. You can write other unit tests for the UserService. If you want to verify some aspects of the LoginComponent, I would write tests asserting against whatever should mutate or be there once the LoginComponent has logged in. (maybe text in the DOM has changed, etc). Or if you're just testing business logic, you can intercept the login call to return true or false and verify doSomething() reacts appropriately.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM