Reputation: 3328
I'm new with Angular test and I have a problem.
The first problem is with the variable username
into a component that I use to show logged username into HTML page:
This is the test file:
describe('HeaderComponent', () => {
let component: HeaderComponent;
let fixture: ComponentFixture<HeaderComponent>;
let app;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeaderComponent, DialogListConfigurationComponent, DialogConfirmNewConfigurationComponent ],
providers: [ MessageService, JwtHelperService, AuthService ],
imports: [ DialogModule, MenubarModule, FontAwesomeModule, RouterTestingModule, TreeModule, HttpClientTestingModule, JwtModule.forRoot({
config: {
tokenGetter: () => {
return sessionStorage.getItem(environment.tokenName);
},
//Exclude this URL from JWT (doesn't add the authentication header)
blacklistedRoutes: [
'/api/login',
]
}
}), ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
The component is this:
export class HeaderComponent implements OnInit {
@Output() sidebarEvent = new EventEmitter();
@Output() clickOkButtonListConfigurationsEvent = new EventEmitter();
username: String = this.authService.decodeToken.username;
items = [] as MenuItem[];
dialogListConfigurationVisible: boolean = false;
faUserCircle = faUserCircle;
defaultConfigurations: Configuration[];
configurationCreated: boolean = false;
dialogConfirmCreationVisible: boolean = false;
constructor(private configurationService: ConfigurationService, private authService: AuthService) { }
ngOnInit() {
...
}
The auth service method:
get decodeToken(): Jwt {
return this.jwtHelper.decodeToken(this.getSessionToken);
}
The should create
test fails with TypeError: Cannot read property 'username' of null
Upvotes: 1
Views: 849
Reputation: 7012
You need to Mock your AuthService since this is a component test.
you can do that by providing an object in the module initialization code
TestBed.configureTestingModule({
declarations: [ HeaderComponent, DialogListConfigurationComponent, DialogConfirmNewConfigurationComponent ],
providers: [
MessageService,
JwtHelperService,
{provide: AuthService, useClass: AuthServiceMock} ],
imports: [ DialogModule, MenubarModule, FontAwesomeModule, RouterTestingModule, TreeModule, HttpClientTestingModule, JwtModule.forRoot({
config: {
tokenGetter: () => {
return sessionStorage.getItem(environment.tokenName);
},
//Exclude this URL from JWT (doesn't add the authentication header)
blacklistedRoutes: [
'/api/login',
]
}
}), ]
})
.compileComponents();
the AuthServiceMock
class should implement the same interface as the original one. it can be something like this:
export class AuthServiceMock {
// ...
decodeToken: {
username: 'testUser'
};
}
than, before creating the component, setup the mock class if you don't want to set a default inside the mock.
NOTE: you can do this last step without creating a mock, but that will break the separation of concerns in your tests.
beforeEach(() => {
let authServiceMock: AuthServiceMock = TestBed.get(AuthService);
authServiceMock.decodeToken = { username: 'anotheruser' };
fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
This should allow for the HeaderComponent
run the this.authService.decodedToken.username
line.
As a guideline: need to mock dependencies that rely on outside data.
You might also be able to remove dependencies of the original AuthService
if previously you included them in the test module initialization. for example, if JwtHelperService
is only used internally for AuthService
, the test module can exclude that provider.
Upvotes: 3
Reputation: 3328
From the @Thatkookooguy answer I got the problem and I add this two raw inside the beforeEach avoid so the use of mock object
const authService: AuthService = TestBed.get(AuthService);
authService.saveToken("token string");
Upvotes: 0