Reputation: 43
Hello I spend a lot of time trying to find out a solution without posting something but I don't understand what's going wrong, so I decided to post question.
Here the file I want to test : home.page.ts
import { Component, OnInit } from '@angular/core';
import { distinctUntilChanged } from 'rxjs/internal/operators/distinctUntilChanged';
import { AlertController, LoadingController } from '@ionic/angular';
import { DataService } from '../service/data.service';
import { League } from '../interfaces/League';
import { LeaguesImageLink } from '../types/leaguesImgLink.enum';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
searchTerm: string = '';
leaguesItems: League[] = [];
constructor(
private apiService: ApiService,
private route: ActivatedRoute,
private router: Router,
private dataService: DataService,
private loadingCtrl: LoadingController,
private alertController: AlertController
) { }
ngOnInit() {
this.loadLeagues();
}
async loadLeagues(): Promise<void> {
(await this.showSpinner()).present
this.apiService
.getAllLeagues()
.pipe(distinctUntilChanged())
.subscribe((res: League[]) => {
this.leaguesItems = res;
this.addImgLink();
});
(await this.showSpinner()).dismiss()
}
async showSpinner(): Promise<HTMLIonLoadingElement> {
const loading = await this.loadingCtrl.create({
message: 'Loading..',
spinner: 'bubbles',
});
return loading;
}
addImgLink(): void {
this.leaguesItems = this.leaguesItems.map((item: League) => {
return {
...item,
imgLink:
LeaguesImageLink[
item.name.split(' ').join('') as keyof typeof LeaguesImageLink
],
};
});
}
async showAlert(): Promise<void> {
const alert = await this.alertController.create({
header: "Alert",
message: "Il n'y a pas encore d'équipes !",
buttons: ['OK'],
});
await alert.present();
}
setLeaguesData(league: League): void {
if (league.teams?.length === 0) {
this.showAlert()
return;
} else {
this.dataService.setleaguesData(this.leaguesItems);
this.router.navigate(['../teams', league._id], {
relativeTo: this.route,
});
}
}
}
here my test file home.page.spect.ts
import { MockLoadingController } from './../../mocks/IonicMock';
import { League } from './../interfaces/League';
import { mockLeagueArray, mockLeagueArrayImageLink } from './../../mocks/mockLeagues';
import { ApiService } from 'src/app/service/api.service';
import { FormsModule } from '@angular/forms';
import { Ng2SearchPipeModule } from 'ng2-search-filter/';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
waitForAsync,
} from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { HomePage } from './home.page';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { of } from 'rxjs';
fdescribe('HomePage', () => {
let component: HomePage;
let fixture: ComponentFixture<HomePage>;
let apiService: ApiService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [HomePage],
teardown: { destroyAfterEach: false },
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
IonicModule.forRoot(),
HttpClientTestingModule,
RouterTestingModule,
Ng2SearchPipeModule,
FormsModule,
],
providers: [
ApiService
]
}).compileComponents();
fixture = TestBed.createComponent(HomePage);
component = fixture.componentInstance;
apiService = TestBed.inject(ApiService)
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
it('should call ngOnInit', () => {
let loadLeagues = spyOn(component, 'loadLeagues');
component.ngOnInit();
expect(loadLeagues).toHaveBeenCalled();
});
it('should call getAllLeagues service and fill leaguesItems array', fakeAsync(() => {
//ARRANGE
spyOn(apiService, 'getAllLeagues').and.returnValue(of(mockLeagueArray))
//ACT
component.loadLeagues()
tick(1000)
fixture.detectChanges()
//ASSERT
expect(component.leaguesItems).toEqual(mockLeagueArray)
}))
});
my mock file : mockLeagues.ts
import { League } from "src/app/interfaces/League";
export const mockLeagueArray: League[] = [{
_id: "1",
name: "Supercopa de Espana",
sport: "sport1",
teams: ["t1", "t11"],
}, {
_id: "2",
name: "English Premier League",
sport: "sport2",
teams: ["t2", "t22"],
}]
export const mockLeagueArrayImageLink: League[] = [{
_id: "1",
name: "Supercopa de Espana",
sport: "sport1",
teams: ["t1", "t11"],
imgLink: "https://www.thesportsdb.com/images/media/league/badge/sp4q7d1641378531.png",
}, {
_id: "2",
name: "English Premier League",
sport: "sport2",
teams: ["t2", "t22"],
imgLink: "https://www.thesportsdb.com/images/media/league/badge/pdd43f1610891709.png",
}]
Nothing fancy ! And the response I get when I run ng test :
Chrome 107.0.0.0 (Windows 10) HomePage should call getAllLeagues service and fill leaguesItems array FAILED
Expected $.length = 0 to equal 2.
Expected $[0] = undefined to equal Object({ _id: '1', name: 'Supercopa de Espana', sport: 'sport1', teams: [ 't1', 't11' ] }).
Expected $[1] = undefined to equal Object({ _id: '2', name: 'English Premier League', sport: 'sport2', teams: [ 't2', 't22' ] }).
at <Jasmine>
at UserContext.apply (src/app/home/home.page.spec.ts:81:36)
at UserContext.apply (node_modules/zone.js/fesm2015/zone-testing.js:2030:30)
at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:372:26)
at ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:39)
Chrome 107.0.0.0 (Windows 10): Executed 3 of 12 (1 FAILED) (skipped 9) (0.799 secs / 0.601 secs)
TOTAL: 1 FAILED, 2 SUCCESS
I spend 7 days (reading angular doc, checking on internet..) , now I'm done, someone has a solution ?
Thanks.
Upvotes: 1
Views: 380
Reputation: 18809
Should present
not have brackets?
// !! Like this
(await this.showSpinner()).present();
Also, this distinctUntilChanged
does nothing because what is being emitted is an array and every time it emits, it will be a new array. It's like saying [] === []
, it will always be false so it will always emit. Check out With Object Streams
here: https://www.leonelngande.com/an-in-depth-look-at-rxjss-distinctuntilchanged-operator/ but for you it is an array. You can do more research and you can pass a callback in distinctUntilChanged
to fine tune when you want it to emit and when you don't.
If I were you, I would change loadLeagues
like so:
async loadLeagues(): Promise<void> {
// (await this.showSpinner()).present
this.apiService
.getAllLeagues()
// !! This distinctUntilChanged does nothing since the source is an array
// .pipe(distinctUntilChanged())
.subscribe((res: League[]) => {
this.leaguesItems = res;
this.addImgLink();
});
// (await this.showSpinner()).dismiss()
}
Comment out this.showSpinner
dismiss and present and see if the test passes. If it does, you know those 2 lines could be the issue.
This is a good resource in learning unit testing with Angular: https://testing-angular.com/.
Upvotes: 2