I can't manage to create a simple jasmine test for my Angular 2 project. This is what I'm trying to do:
Component to test (based on a service):
@Component({
providers: [AccountService],
selector: "account",
templateUrl: "app/account/account.component.html",
})
export class AccountComponent implements OnInit {
public accounts: Account[];
public error: string;
constructor(private accountService: AccountService) {}
public ngOnInit(): any {
this.getAccounts();
}
public getAccounts() {
this.accountService.getAccounts()
.then(
accounts => this.accounts = accounts,
error => this.error = error
);
}
}
The AccountService
uses Http
(from @angular/http
); getAccounts
method returns a promise with (hopefully) the list of accounts.
I'm trying to test the AccountComponent
with a fake AccountService
(mock). Based on Angular 2 documentation, here is the implementation of my spec
file:
describe('Account module test', () => {
let accountServiceMock;
let fixture;
let comp;
let spy;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ AccountComponent ],
providers: [ AccountService ],
});
fixture = TestBed.createComponent(AccountComponent);
comp = fixture.componentInstance;
// AccountService actually injected into the component
accountServiceMock = fixture.debugElement.injector.get(AccountService);
// Setup spy on the `getAccounts` method; return no account (basic test)
spy = spyOn(AccountService, 'getAccounts')
.and.returnValue(Promise.resolve([]));
});
it('Should get 0 account', () => {
comp.ngOnInit();
expect(comp.accounts.length).toBe(0);
});
});
But it does not work and I got a pretty ugly error message in the terminal:
**stuff**/node_modules/@angular/core/bundles/core.umd.js:334
var parameters = Reflect.getMetadata('parameters', cls) || [];
TypeError: Cannot read property 'getMetadata' of undefined
at ParamDecorator (**stuff**/node_modules/@angular/core/bundles/core.umd.js:334:41)
at __decorate (**stuff**/dist/js/app/account/account.service.js:5:95)
at **stuff**/dist/js/app/account/account.service.js:86:22
at Object.<anonymous> (**stuff**/dist/js/app/account/account.service.js:91:2)
at Module._compile (module.js:409:26)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
Any idea of what I'm missing? Can't figure out how to solve that problem... Thanks in advance!
EDIT: based on comments, I've tried another way:
describe('component: AccountComponent', () => {
let fixture;
let service;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AccountComponent
],
});
fixture = TestBed.createComponent(AccountComponent);
service = fixture.debugElement.injector.get(AccountService);
});
it('should get 0 account', () => {
spyOn(service, 'getAccounts').and.returnValue([]);
fixture.detectChanges();
expect(fixture.componentInstance.accounts).toBe([]);
});
});
I got exactly the same error... I though there was a problem outside of the test file, but when I remove the beforeEach
close and add a dummy test, the jasmine
command just runs fine. Back to square one I guess :/
EDIT2: as requested, here is my AccountService class:
import {Http, Response, Headers} from "@angular/http";
import {Injectable} from "@angular/core";
import "rxjs/add/operator/toPromise";
export interface IAccountService {
getAccounts();
}
@Injectable()
export class AccountService implements IAccountService {
private static BASE_URL: string = "/api/account/";
private static extractResult(res: Response) {
return res.json();
}
/**
* Extract error message from server response
*/
private static handleError(error: any) {
const errMsg: string = error._body;
console.error(error); // log to console
return Promise.reject(errMsg);
}
constructor(private http: Http) {
}
/**
* Get list of accounts from server
*/
public getAccounts() {
return this.http.get(AccountService.BASE_URL)
.toPromise()
.then(AccountService.extractResult)
.catch(AccountService.handleError);
}
}