Testing component is using the original service and not spying itUnit Testing C CodeWhat is Unit test, Integration Test, Smoke test, Regression Test?How to write a test which expects an Error to be thrown in Jasmine?What's the difference between unit, functional, acceptance, and integration tests?Components and modules exported from shared modules with forRoot option not available in lazy loaded moduleAngular 2 Routing Does Not Work When Deployed to Http ServerAngular 4 ERROR Error: Uncaught (in promise): RangeError: Maximum call stack size exceededAngular testing with keycloack “user is not logged in”error TS2707 : Generic type 'MatDialogRef<T,R>' requiers between 1 and 2 argumentsCore module component and Shared module implementation in angular
Proto-Indo-European (PIE) words with IPA
Which values for voltage divider
Were there any developed countries that became "undeveloped" for reasons other than war?
What pc resources are used when bruteforcing?
Is being an extrovert a necessary condition to be a manager?
Is there a fox people race in D&D 5e?
How to make Flex Markers appear in Logic Pro X?
Team member is vehemently against code formatting
What defines a person who is circumcised "of the heart"?
Is it safe to redirect stdout and stderr to the same file without file descriptor copies?
Illustrating that universal optimality is stronger than sphere packing
Keeping the dodos out of the field
Must every right-inverse of a linear transformation be a linear transformation?
Three knights or knaves, three different hair colors
What is the winged creature on the back of the Mordenkainen's Tome of Foes book?
Why are logically related bit fields in MCU registers often in separate locations
Informal question construction: "Anyone know what...", "Everyone finished?"
What technology is there beyond RAID for disk cluster in a server
Coloring lines in a graph the same color if they are the same length
Singular Integration
Managing heat dissipation in a magic wand
Why does the -OH group in β-naphthol direct the incoming diazonium salt towards the ortho position?
How to become an Editorial board member?
(For training purposes) Are there any openings with rook pawns that are more effective than others (and if so, what are they)?
Testing component is using the original service and not spying it
Unit Testing C CodeWhat is Unit test, Integration Test, Smoke test, Regression Test?How to write a test which expects an Error to be thrown in Jasmine?What's the difference between unit, functional, acceptance, and integration tests?Components and modules exported from shared modules with forRoot option not available in lazy loaded moduleAngular 2 Routing Does Not Work When Deployed to Http ServerAngular 4 ERROR Error: Uncaught (in promise): RangeError: Maximum call stack size exceededAngular testing with keycloack “user is not logged in”error TS2707 : Generic type 'MatDialogRef<T,R>' requiers between 1 and 2 argumentsCore module component and Shared module implementation in angular
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
When I test if the button is clicked and it calls the onSignIn() method on the component this test pass.
But when I try to test if the onSignIn() calls signIn() method on the AuthService, the test not pass and call the original service doing a network call.
Here is my code:
sign-in.component.ts
import Component, OnInit from '@angular/core';
import FormBuilder, FormGroup, Validators from '@angular/forms';
import ActivatedRoute, Router from '@angular/router';
import faTimes from '@fortawesome/free-solid-svg-icons';
import AuthService from '../../core';
import AlertService, FormErrorHandler from '../../shared';
@Component(
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.scss']
)
export class SignInComponent implements OnInit
signInForm!: FormGroup;
...
constructor(
private formBuilder: FormBuilder,
private router: Router,
private activatedRoute: ActivatedRoute,
private authService: AuthService,
private alertService: AlertService
)
ngOnInit()
...
...
onSignIn()
...
this.authService
.signIn(this.signInForm.value)
.subscribe(
user =>
this.authService.setSession(user, this.rememberMe.value);
this.router.navigate([this.returnUrl]);
,
error =>
if (error instanceof Object)
FormErrorHandler.errorHandler(this.signInForm, error);
else
this.alertService.error(error);
);
sign-in.module.ts
import NgModule from '@angular/core';
import CommonModule from '@angular/common';
import AuthRoutingModule from './auth-routing.module';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import FormsModule, ReactiveFormsModule from '@angular/forms';
import HttpClientModule from '@angular/common/http';
import SharedModule from '../shared';
import AuthComponent from './auth.component';
import SignInComponent from './sign-in/sign-in.component';
import SignUpComponent from './sign-up/sign-up.component';
import PasswordRecoverComponent from './password-recover/password-recover.component';
import PasswordResetComponent from './password-reset/password-reset.component';
@NgModule(
declarations: [
AuthComponent,
SignInComponent,
SignUpComponent,
PasswordRecoverComponent,
PasswordResetComponent
],
imports: [
CommonModule,
AuthRoutingModule,
SharedModule,
FontAwesomeModule,
ReactiveFormsModule,
FormsModule,
HttpClientModule,
]
)
export class AuthModule
auth.service.ts
import HttpClient from '@angular/common/http';
import Injectable from '@angular/core';
import Router from '@angular/router';
import map from 'rxjs/operators';
import config from '../../../config';
import User from '../../../shared';
import Subject from 'rxjs';
@Injectable( providedIn: 'root' )
export class AuthService
public isAuthenticated = false;
public authStatusSubject = new Subject<boolean>();
public currentUserId = '';
public currentUserToken = '';
get id() return localStorage.getItem('id');
get token() return localStorage.getItem('token');
get expiration() return localStorage.getItem('expires_at');
getAuthStatusSubject() return this.authStatusSubject.asObservable();
constructor(private http: HttpClient, private router: Router)
...
signIn(user: User)
return this.http.post<
message: string;
user: id: string; token: string; expiresAt: string ;
>(`$config.URL/api/auth/login`,
email: user.email,
password: user.password
)
.pipe(map(data => return data.user; ));
setSession(user, rememberMe: boolean)
if (rememberMe)
const expiresAt = new Date(user.expiresAt);
localStorage.setItem('id', user.id);
localStorage.setItem('token', user.token);
localStorage.setItem('expires_at', expiresAt.toUTCString());
this.isAuthenticated = true;
this.authStatusSubject.next(true);
this.currentUserId = user.id;
this.currentUserToken = user.token;
...
The AuthService is provided in the core.module
core.module.ts
import CommonModule from '@angular/common';
import NgModule from '@angular/core';
import RouterModule from '@angular/router';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import NgbModule from '@ng-bootstrap/ng-bootstrap';
import HeaderComponent from './components';
import AuthService, UserService from './services';
@NgModule(
declarations: [ HeaderComponent ],
imports: [
CommonModule,
RouterModule,
FontAwesomeModule,
NgbModule,
],
providers: [
AuthService,
UserService
],
exports: [ HeaderComponent ]
)
export class CoreModule
sign-in.component.spec.ts
import HttpClientTestingModule from '@angular/common/http/testing';
import async, ComponentFixture, TestBed from '@angular/core/testing';
import AbstractControl, FormsModule, ReactiveFormsModule from '@angular/forms';
import By from '@angular/platform-browser';
import RouterTestingModule from '@angular/router/testing';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import AuthService, CoreModule from '../../core';
import SharedModule from '../../shared';
import SignInComponent from './sign-in.component';
describe('SignInComponent', () =>
let signInComponent: SignInComponent;
let fixture: ComponentFixture<SignInComponent>;
let signInButton: any;
let authService: AuthService;
...
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [SignInComponent],
imports: [
HttpClientTestingModule,
FormsModule,
ReactiveFormsModule,
RouterTestingModule,
FontAwesomeModule,
CoreModule,
SharedModule
]
)
.compileComponents()
.then(() =>
fixture = TestBed.createComponent(SignInComponent);
signInComponent = fixture.componentInstance;
signInComponent.ngOnInit();
authService = TestBed.get(AuthService);
);
));
beforeEach(() =>
fixture.detectChanges();
);
it('should be created', () =>
expect(signInComponent).toBeTruthy();
);
describe('#form', () =>
describe('#signInButton', () =>
beforeEach(() =>
signInButton = fixture.debugElement.query(By.css('button[type=submit]')).nativeElement;
);
it('should render button for submit form', () =>
expect(signInButton).toBeTruthy();
);
it('should sign in when submited', () =>
spyOn(signInComponent, 'onSignIn');
spyOn(authService, 'signIn');
signInForm.triggerEventHandler('submit', null);
expect(signInComponent.onSignIn).toHaveBeenCalled(); // This test pass
expect(authService.signIn).toHaveBeenCalled(); // This test fails and do a network call.
);
);
);
);
add a comment |
When I test if the button is clicked and it calls the onSignIn() method on the component this test pass.
But when I try to test if the onSignIn() calls signIn() method on the AuthService, the test not pass and call the original service doing a network call.
Here is my code:
sign-in.component.ts
import Component, OnInit from '@angular/core';
import FormBuilder, FormGroup, Validators from '@angular/forms';
import ActivatedRoute, Router from '@angular/router';
import faTimes from '@fortawesome/free-solid-svg-icons';
import AuthService from '../../core';
import AlertService, FormErrorHandler from '../../shared';
@Component(
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.scss']
)
export class SignInComponent implements OnInit
signInForm!: FormGroup;
...
constructor(
private formBuilder: FormBuilder,
private router: Router,
private activatedRoute: ActivatedRoute,
private authService: AuthService,
private alertService: AlertService
)
ngOnInit()
...
...
onSignIn()
...
this.authService
.signIn(this.signInForm.value)
.subscribe(
user =>
this.authService.setSession(user, this.rememberMe.value);
this.router.navigate([this.returnUrl]);
,
error =>
if (error instanceof Object)
FormErrorHandler.errorHandler(this.signInForm, error);
else
this.alertService.error(error);
);
sign-in.module.ts
import NgModule from '@angular/core';
import CommonModule from '@angular/common';
import AuthRoutingModule from './auth-routing.module';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import FormsModule, ReactiveFormsModule from '@angular/forms';
import HttpClientModule from '@angular/common/http';
import SharedModule from '../shared';
import AuthComponent from './auth.component';
import SignInComponent from './sign-in/sign-in.component';
import SignUpComponent from './sign-up/sign-up.component';
import PasswordRecoverComponent from './password-recover/password-recover.component';
import PasswordResetComponent from './password-reset/password-reset.component';
@NgModule(
declarations: [
AuthComponent,
SignInComponent,
SignUpComponent,
PasswordRecoverComponent,
PasswordResetComponent
],
imports: [
CommonModule,
AuthRoutingModule,
SharedModule,
FontAwesomeModule,
ReactiveFormsModule,
FormsModule,
HttpClientModule,
]
)
export class AuthModule
auth.service.ts
import HttpClient from '@angular/common/http';
import Injectable from '@angular/core';
import Router from '@angular/router';
import map from 'rxjs/operators';
import config from '../../../config';
import User from '../../../shared';
import Subject from 'rxjs';
@Injectable( providedIn: 'root' )
export class AuthService
public isAuthenticated = false;
public authStatusSubject = new Subject<boolean>();
public currentUserId = '';
public currentUserToken = '';
get id() return localStorage.getItem('id');
get token() return localStorage.getItem('token');
get expiration() return localStorage.getItem('expires_at');
getAuthStatusSubject() return this.authStatusSubject.asObservable();
constructor(private http: HttpClient, private router: Router)
...
signIn(user: User)
return this.http.post<
message: string;
user: id: string; token: string; expiresAt: string ;
>(`$config.URL/api/auth/login`,
email: user.email,
password: user.password
)
.pipe(map(data => return data.user; ));
setSession(user, rememberMe: boolean)
if (rememberMe)
const expiresAt = new Date(user.expiresAt);
localStorage.setItem('id', user.id);
localStorage.setItem('token', user.token);
localStorage.setItem('expires_at', expiresAt.toUTCString());
this.isAuthenticated = true;
this.authStatusSubject.next(true);
this.currentUserId = user.id;
this.currentUserToken = user.token;
...
The AuthService is provided in the core.module
core.module.ts
import CommonModule from '@angular/common';
import NgModule from '@angular/core';
import RouterModule from '@angular/router';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import NgbModule from '@ng-bootstrap/ng-bootstrap';
import HeaderComponent from './components';
import AuthService, UserService from './services';
@NgModule(
declarations: [ HeaderComponent ],
imports: [
CommonModule,
RouterModule,
FontAwesomeModule,
NgbModule,
],
providers: [
AuthService,
UserService
],
exports: [ HeaderComponent ]
)
export class CoreModule
sign-in.component.spec.ts
import HttpClientTestingModule from '@angular/common/http/testing';
import async, ComponentFixture, TestBed from '@angular/core/testing';
import AbstractControl, FormsModule, ReactiveFormsModule from '@angular/forms';
import By from '@angular/platform-browser';
import RouterTestingModule from '@angular/router/testing';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import AuthService, CoreModule from '../../core';
import SharedModule from '../../shared';
import SignInComponent from './sign-in.component';
describe('SignInComponent', () =>
let signInComponent: SignInComponent;
let fixture: ComponentFixture<SignInComponent>;
let signInButton: any;
let authService: AuthService;
...
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [SignInComponent],
imports: [
HttpClientTestingModule,
FormsModule,
ReactiveFormsModule,
RouterTestingModule,
FontAwesomeModule,
CoreModule,
SharedModule
]
)
.compileComponents()
.then(() =>
fixture = TestBed.createComponent(SignInComponent);
signInComponent = fixture.componentInstance;
signInComponent.ngOnInit();
authService = TestBed.get(AuthService);
);
));
beforeEach(() =>
fixture.detectChanges();
);
it('should be created', () =>
expect(signInComponent).toBeTruthy();
);
describe('#form', () =>
describe('#signInButton', () =>
beforeEach(() =>
signInButton = fixture.debugElement.query(By.css('button[type=submit]')).nativeElement;
);
it('should render button for submit form', () =>
expect(signInButton).toBeTruthy();
);
it('should sign in when submited', () =>
spyOn(signInComponent, 'onSignIn');
spyOn(authService, 'signIn');
signInForm.triggerEventHandler('submit', null);
expect(signInComponent.onSignIn).toHaveBeenCalled(); // This test pass
expect(authService.signIn).toHaveBeenCalled(); // This test fails and do a network call.
);
);
);
);
Don't spy on the component you're testing. Use the TestBed to provide test doubles for its collaborators, not recreate the real app. See e.g. angular.io/guide/testing, blog.jonrshar.pe/2017/Apr/16/async-angular-tests.html
– jonrsharpe
Mar 23 at 20:37
Thanks for your quick response @jonrsharpe . Spying is the only way I know to know if the component's method has been called or triggered, Why do you say that I should not spy on the component's method? By the way, spying on the component method works, but what does not work for me is spying on the service method and I do not understand why, it should be called once the component method is triggered.
– Andrea Contreras
Mar 26 at 1:25
I say you shouldn't spy on the component's method because the component is the unit you're testing, and you should test its behaviour not its implementation. The service isn't called because you spy on the component method, too; you don't call through.
– jonrsharpe
Mar 26 at 7:12
If the call to the service is within the onSignIn() method of the component, this is not part of its behavior, then, I should not test that onSignIn() is called and it invokes a service method, right? I should only test that the component's method is called, not if it is calling the service, right?
– Andrea Contreras
Mar 28 at 19:17
No that's exactly wrong. You should test that it's calling the service with the right data when the inputs are filled and the button is clicked, what method gets called is an implementation detail you should be free to refactor.
– jonrsharpe
Mar 28 at 19:22
add a comment |
When I test if the button is clicked and it calls the onSignIn() method on the component this test pass.
But when I try to test if the onSignIn() calls signIn() method on the AuthService, the test not pass and call the original service doing a network call.
Here is my code:
sign-in.component.ts
import Component, OnInit from '@angular/core';
import FormBuilder, FormGroup, Validators from '@angular/forms';
import ActivatedRoute, Router from '@angular/router';
import faTimes from '@fortawesome/free-solid-svg-icons';
import AuthService from '../../core';
import AlertService, FormErrorHandler from '../../shared';
@Component(
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.scss']
)
export class SignInComponent implements OnInit
signInForm!: FormGroup;
...
constructor(
private formBuilder: FormBuilder,
private router: Router,
private activatedRoute: ActivatedRoute,
private authService: AuthService,
private alertService: AlertService
)
ngOnInit()
...
...
onSignIn()
...
this.authService
.signIn(this.signInForm.value)
.subscribe(
user =>
this.authService.setSession(user, this.rememberMe.value);
this.router.navigate([this.returnUrl]);
,
error =>
if (error instanceof Object)
FormErrorHandler.errorHandler(this.signInForm, error);
else
this.alertService.error(error);
);
sign-in.module.ts
import NgModule from '@angular/core';
import CommonModule from '@angular/common';
import AuthRoutingModule from './auth-routing.module';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import FormsModule, ReactiveFormsModule from '@angular/forms';
import HttpClientModule from '@angular/common/http';
import SharedModule from '../shared';
import AuthComponent from './auth.component';
import SignInComponent from './sign-in/sign-in.component';
import SignUpComponent from './sign-up/sign-up.component';
import PasswordRecoverComponent from './password-recover/password-recover.component';
import PasswordResetComponent from './password-reset/password-reset.component';
@NgModule(
declarations: [
AuthComponent,
SignInComponent,
SignUpComponent,
PasswordRecoverComponent,
PasswordResetComponent
],
imports: [
CommonModule,
AuthRoutingModule,
SharedModule,
FontAwesomeModule,
ReactiveFormsModule,
FormsModule,
HttpClientModule,
]
)
export class AuthModule
auth.service.ts
import HttpClient from '@angular/common/http';
import Injectable from '@angular/core';
import Router from '@angular/router';
import map from 'rxjs/operators';
import config from '../../../config';
import User from '../../../shared';
import Subject from 'rxjs';
@Injectable( providedIn: 'root' )
export class AuthService
public isAuthenticated = false;
public authStatusSubject = new Subject<boolean>();
public currentUserId = '';
public currentUserToken = '';
get id() return localStorage.getItem('id');
get token() return localStorage.getItem('token');
get expiration() return localStorage.getItem('expires_at');
getAuthStatusSubject() return this.authStatusSubject.asObservable();
constructor(private http: HttpClient, private router: Router)
...
signIn(user: User)
return this.http.post<
message: string;
user: id: string; token: string; expiresAt: string ;
>(`$config.URL/api/auth/login`,
email: user.email,
password: user.password
)
.pipe(map(data => return data.user; ));
setSession(user, rememberMe: boolean)
if (rememberMe)
const expiresAt = new Date(user.expiresAt);
localStorage.setItem('id', user.id);
localStorage.setItem('token', user.token);
localStorage.setItem('expires_at', expiresAt.toUTCString());
this.isAuthenticated = true;
this.authStatusSubject.next(true);
this.currentUserId = user.id;
this.currentUserToken = user.token;
...
The AuthService is provided in the core.module
core.module.ts
import CommonModule from '@angular/common';
import NgModule from '@angular/core';
import RouterModule from '@angular/router';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import NgbModule from '@ng-bootstrap/ng-bootstrap';
import HeaderComponent from './components';
import AuthService, UserService from './services';
@NgModule(
declarations: [ HeaderComponent ],
imports: [
CommonModule,
RouterModule,
FontAwesomeModule,
NgbModule,
],
providers: [
AuthService,
UserService
],
exports: [ HeaderComponent ]
)
export class CoreModule
sign-in.component.spec.ts
import HttpClientTestingModule from '@angular/common/http/testing';
import async, ComponentFixture, TestBed from '@angular/core/testing';
import AbstractControl, FormsModule, ReactiveFormsModule from '@angular/forms';
import By from '@angular/platform-browser';
import RouterTestingModule from '@angular/router/testing';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import AuthService, CoreModule from '../../core';
import SharedModule from '../../shared';
import SignInComponent from './sign-in.component';
describe('SignInComponent', () =>
let signInComponent: SignInComponent;
let fixture: ComponentFixture<SignInComponent>;
let signInButton: any;
let authService: AuthService;
...
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [SignInComponent],
imports: [
HttpClientTestingModule,
FormsModule,
ReactiveFormsModule,
RouterTestingModule,
FontAwesomeModule,
CoreModule,
SharedModule
]
)
.compileComponents()
.then(() =>
fixture = TestBed.createComponent(SignInComponent);
signInComponent = fixture.componentInstance;
signInComponent.ngOnInit();
authService = TestBed.get(AuthService);
);
));
beforeEach(() =>
fixture.detectChanges();
);
it('should be created', () =>
expect(signInComponent).toBeTruthy();
);
describe('#form', () =>
describe('#signInButton', () =>
beforeEach(() =>
signInButton = fixture.debugElement.query(By.css('button[type=submit]')).nativeElement;
);
it('should render button for submit form', () =>
expect(signInButton).toBeTruthy();
);
it('should sign in when submited', () =>
spyOn(signInComponent, 'onSignIn');
spyOn(authService, 'signIn');
signInForm.triggerEventHandler('submit', null);
expect(signInComponent.onSignIn).toHaveBeenCalled(); // This test pass
expect(authService.signIn).toHaveBeenCalled(); // This test fails and do a network call.
);
);
);
);
When I test if the button is clicked and it calls the onSignIn() method on the component this test pass.
But when I try to test if the onSignIn() calls signIn() method on the AuthService, the test not pass and call the original service doing a network call.
Here is my code:
sign-in.component.ts
import Component, OnInit from '@angular/core';
import FormBuilder, FormGroup, Validators from '@angular/forms';
import ActivatedRoute, Router from '@angular/router';
import faTimes from '@fortawesome/free-solid-svg-icons';
import AuthService from '../../core';
import AlertService, FormErrorHandler from '../../shared';
@Component(
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.scss']
)
export class SignInComponent implements OnInit
signInForm!: FormGroup;
...
constructor(
private formBuilder: FormBuilder,
private router: Router,
private activatedRoute: ActivatedRoute,
private authService: AuthService,
private alertService: AlertService
)
ngOnInit()
...
...
onSignIn()
...
this.authService
.signIn(this.signInForm.value)
.subscribe(
user =>
this.authService.setSession(user, this.rememberMe.value);
this.router.navigate([this.returnUrl]);
,
error =>
if (error instanceof Object)
FormErrorHandler.errorHandler(this.signInForm, error);
else
this.alertService.error(error);
);
sign-in.module.ts
import NgModule from '@angular/core';
import CommonModule from '@angular/common';
import AuthRoutingModule from './auth-routing.module';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import FormsModule, ReactiveFormsModule from '@angular/forms';
import HttpClientModule from '@angular/common/http';
import SharedModule from '../shared';
import AuthComponent from './auth.component';
import SignInComponent from './sign-in/sign-in.component';
import SignUpComponent from './sign-up/sign-up.component';
import PasswordRecoverComponent from './password-recover/password-recover.component';
import PasswordResetComponent from './password-reset/password-reset.component';
@NgModule(
declarations: [
AuthComponent,
SignInComponent,
SignUpComponent,
PasswordRecoverComponent,
PasswordResetComponent
],
imports: [
CommonModule,
AuthRoutingModule,
SharedModule,
FontAwesomeModule,
ReactiveFormsModule,
FormsModule,
HttpClientModule,
]
)
export class AuthModule
auth.service.ts
import HttpClient from '@angular/common/http';
import Injectable from '@angular/core';
import Router from '@angular/router';
import map from 'rxjs/operators';
import config from '../../../config';
import User from '../../../shared';
import Subject from 'rxjs';
@Injectable( providedIn: 'root' )
export class AuthService
public isAuthenticated = false;
public authStatusSubject = new Subject<boolean>();
public currentUserId = '';
public currentUserToken = '';
get id() return localStorage.getItem('id');
get token() return localStorage.getItem('token');
get expiration() return localStorage.getItem('expires_at');
getAuthStatusSubject() return this.authStatusSubject.asObservable();
constructor(private http: HttpClient, private router: Router)
...
signIn(user: User)
return this.http.post<
message: string;
user: id: string; token: string; expiresAt: string ;
>(`$config.URL/api/auth/login`,
email: user.email,
password: user.password
)
.pipe(map(data => return data.user; ));
setSession(user, rememberMe: boolean)
if (rememberMe)
const expiresAt = new Date(user.expiresAt);
localStorage.setItem('id', user.id);
localStorage.setItem('token', user.token);
localStorage.setItem('expires_at', expiresAt.toUTCString());
this.isAuthenticated = true;
this.authStatusSubject.next(true);
this.currentUserId = user.id;
this.currentUserToken = user.token;
...
The AuthService is provided in the core.module
core.module.ts
import CommonModule from '@angular/common';
import NgModule from '@angular/core';
import RouterModule from '@angular/router';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import NgbModule from '@ng-bootstrap/ng-bootstrap';
import HeaderComponent from './components';
import AuthService, UserService from './services';
@NgModule(
declarations: [ HeaderComponent ],
imports: [
CommonModule,
RouterModule,
FontAwesomeModule,
NgbModule,
],
providers: [
AuthService,
UserService
],
exports: [ HeaderComponent ]
)
export class CoreModule
sign-in.component.spec.ts
import HttpClientTestingModule from '@angular/common/http/testing';
import async, ComponentFixture, TestBed from '@angular/core/testing';
import AbstractControl, FormsModule, ReactiveFormsModule from '@angular/forms';
import By from '@angular/platform-browser';
import RouterTestingModule from '@angular/router/testing';
import FontAwesomeModule from '@fortawesome/angular-fontawesome';
import AuthService, CoreModule from '../../core';
import SharedModule from '../../shared';
import SignInComponent from './sign-in.component';
describe('SignInComponent', () =>
let signInComponent: SignInComponent;
let fixture: ComponentFixture<SignInComponent>;
let signInButton: any;
let authService: AuthService;
...
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [SignInComponent],
imports: [
HttpClientTestingModule,
FormsModule,
ReactiveFormsModule,
RouterTestingModule,
FontAwesomeModule,
CoreModule,
SharedModule
]
)
.compileComponents()
.then(() =>
fixture = TestBed.createComponent(SignInComponent);
signInComponent = fixture.componentInstance;
signInComponent.ngOnInit();
authService = TestBed.get(AuthService);
);
));
beforeEach(() =>
fixture.detectChanges();
);
it('should be created', () =>
expect(signInComponent).toBeTruthy();
);
describe('#form', () =>
describe('#signInButton', () =>
beforeEach(() =>
signInButton = fixture.debugElement.query(By.css('button[type=submit]')).nativeElement;
);
it('should render button for submit form', () =>
expect(signInButton).toBeTruthy();
);
it('should sign in when submited', () =>
spyOn(signInComponent, 'onSignIn');
spyOn(authService, 'signIn');
signInForm.triggerEventHandler('submit', null);
expect(signInComponent.onSignIn).toHaveBeenCalled(); // This test pass
expect(authService.signIn).toHaveBeenCalled(); // This test fails and do a network call.
);
);
);
);
edited Mar 23 at 20:35
jonrsharpe
79.9k11115232
79.9k11115232
asked Mar 23 at 20:08
Andrea ContrerasAndrea Contreras
11
11
Don't spy on the component you're testing. Use the TestBed to provide test doubles for its collaborators, not recreate the real app. See e.g. angular.io/guide/testing, blog.jonrshar.pe/2017/Apr/16/async-angular-tests.html
– jonrsharpe
Mar 23 at 20:37
Thanks for your quick response @jonrsharpe . Spying is the only way I know to know if the component's method has been called or triggered, Why do you say that I should not spy on the component's method? By the way, spying on the component method works, but what does not work for me is spying on the service method and I do not understand why, it should be called once the component method is triggered.
– Andrea Contreras
Mar 26 at 1:25
I say you shouldn't spy on the component's method because the component is the unit you're testing, and you should test its behaviour not its implementation. The service isn't called because you spy on the component method, too; you don't call through.
– jonrsharpe
Mar 26 at 7:12
If the call to the service is within the onSignIn() method of the component, this is not part of its behavior, then, I should not test that onSignIn() is called and it invokes a service method, right? I should only test that the component's method is called, not if it is calling the service, right?
– Andrea Contreras
Mar 28 at 19:17
No that's exactly wrong. You should test that it's calling the service with the right data when the inputs are filled and the button is clicked, what method gets called is an implementation detail you should be free to refactor.
– jonrsharpe
Mar 28 at 19:22
add a comment |
Don't spy on the component you're testing. Use the TestBed to provide test doubles for its collaborators, not recreate the real app. See e.g. angular.io/guide/testing, blog.jonrshar.pe/2017/Apr/16/async-angular-tests.html
– jonrsharpe
Mar 23 at 20:37
Thanks for your quick response @jonrsharpe . Spying is the only way I know to know if the component's method has been called or triggered, Why do you say that I should not spy on the component's method? By the way, spying on the component method works, but what does not work for me is spying on the service method and I do not understand why, it should be called once the component method is triggered.
– Andrea Contreras
Mar 26 at 1:25
I say you shouldn't spy on the component's method because the component is the unit you're testing, and you should test its behaviour not its implementation. The service isn't called because you spy on the component method, too; you don't call through.
– jonrsharpe
Mar 26 at 7:12
If the call to the service is within the onSignIn() method of the component, this is not part of its behavior, then, I should not test that onSignIn() is called and it invokes a service method, right? I should only test that the component's method is called, not if it is calling the service, right?
– Andrea Contreras
Mar 28 at 19:17
No that's exactly wrong. You should test that it's calling the service with the right data when the inputs are filled and the button is clicked, what method gets called is an implementation detail you should be free to refactor.
– jonrsharpe
Mar 28 at 19:22
Don't spy on the component you're testing. Use the TestBed to provide test doubles for its collaborators, not recreate the real app. See e.g. angular.io/guide/testing, blog.jonrshar.pe/2017/Apr/16/async-angular-tests.html
– jonrsharpe
Mar 23 at 20:37
Don't spy on the component you're testing. Use the TestBed to provide test doubles for its collaborators, not recreate the real app. See e.g. angular.io/guide/testing, blog.jonrshar.pe/2017/Apr/16/async-angular-tests.html
– jonrsharpe
Mar 23 at 20:37
Thanks for your quick response @jonrsharpe . Spying is the only way I know to know if the component's method has been called or triggered, Why do you say that I should not spy on the component's method? By the way, spying on the component method works, but what does not work for me is spying on the service method and I do not understand why, it should be called once the component method is triggered.
– Andrea Contreras
Mar 26 at 1:25
Thanks for your quick response @jonrsharpe . Spying is the only way I know to know if the component's method has been called or triggered, Why do you say that I should not spy on the component's method? By the way, spying on the component method works, but what does not work for me is spying on the service method and I do not understand why, it should be called once the component method is triggered.
– Andrea Contreras
Mar 26 at 1:25
I say you shouldn't spy on the component's method because the component is the unit you're testing, and you should test its behaviour not its implementation. The service isn't called because you spy on the component method, too; you don't call through.
– jonrsharpe
Mar 26 at 7:12
I say you shouldn't spy on the component's method because the component is the unit you're testing, and you should test its behaviour not its implementation. The service isn't called because you spy on the component method, too; you don't call through.
– jonrsharpe
Mar 26 at 7:12
If the call to the service is within the onSignIn() method of the component, this is not part of its behavior, then, I should not test that onSignIn() is called and it invokes a service method, right? I should only test that the component's method is called, not if it is calling the service, right?
– Andrea Contreras
Mar 28 at 19:17
If the call to the service is within the onSignIn() method of the component, this is not part of its behavior, then, I should not test that onSignIn() is called and it invokes a service method, right? I should only test that the component's method is called, not if it is calling the service, right?
– Andrea Contreras
Mar 28 at 19:17
No that's exactly wrong. You should test that it's calling the service with the right data when the inputs are filled and the button is clicked, what method gets called is an implementation detail you should be free to refactor.
– jonrsharpe
Mar 28 at 19:22
No that's exactly wrong. You should test that it's calling the service with the right data when the inputs are filled and the button is clicked, what method gets called is an implementation detail you should be free to refactor.
– jonrsharpe
Mar 28 at 19:22
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55317917%2ftesting-component-is-using-the-original-service-and-not-spying-it%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55317917%2ftesting-component-is-using-the-original-service-and-not-spying-it%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Don't spy on the component you're testing. Use the TestBed to provide test doubles for its collaborators, not recreate the real app. See e.g. angular.io/guide/testing, blog.jonrshar.pe/2017/Apr/16/async-angular-tests.html
– jonrsharpe
Mar 23 at 20:37
Thanks for your quick response @jonrsharpe . Spying is the only way I know to know if the component's method has been called or triggered, Why do you say that I should not spy on the component's method? By the way, spying on the component method works, but what does not work for me is spying on the service method and I do not understand why, it should be called once the component method is triggered.
– Andrea Contreras
Mar 26 at 1:25
I say you shouldn't spy on the component's method because the component is the unit you're testing, and you should test its behaviour not its implementation. The service isn't called because you spy on the component method, too; you don't call through.
– jonrsharpe
Mar 26 at 7:12
If the call to the service is within the onSignIn() method of the component, this is not part of its behavior, then, I should not test that onSignIn() is called and it invokes a service method, right? I should only test that the component's method is called, not if it is calling the service, right?
– Andrea Contreras
Mar 28 at 19:17
No that's exactly wrong. You should test that it's calling the service with the right data when the inputs are filled and the button is clicked, what method gets called is an implementation detail you should be free to refactor.
– jonrsharpe
Mar 28 at 19:22