I have a method called loadIssues() in an Angular component called BurndownComponent that is void and inserts values into an array. This method uses some async methods from a service and from the component itself. After running those asyncs it fills in the array.
I want to write test code for loadIssues(), but I do not know how to make the test wait for the array to be filled. Because loadIssues is void I cannot use async await. I also tried using a setTimeout but it ran asynchronously and did not wait for the execution of loadIssues().
Does anyone have an idea on how I could write such a test?
The relevant codes are below:
loadIssues():
loadIssues(): void {
this.selectedMilestone = this.milestone;
this.issues = [];
console.log(this.selectedMilestone.reviewDate);
this.gitlabService.getIssues(this.selectedMilestone?.title).then(issues => {
let allIssues = issues.filter(i => [RequirementLabel.StoryTask, RequirementLabel.Task, RequirementLabel.Story].includes(i.requirement));
this.getIssueEvents(allIssues).then(issues => {
allIssues = issues;
console.log('allIssues ', allIssues.length);
// issues could be moved out of the milestone towards the end of it
// we consider a limit of 3 days before the review meeting date
if (new Date().getTime() >= this.selectedMilestone.reviewDate.getTime() - (3 * MILLISECONDS_PER_DAY)) {
this.getMilestoneRolledIssues().then(rolledIssues => {
const issuesIds = allIssues.map(i => i.id);
console.log(issuesIds);
allIssues = allIssues.concat(...rolledIssues.filter(i => !issuesIds.includes(i.id))); // removes duplicated issues
this.gitlabService.getDiscussions(allIssues).then(discussions => {
allIssues.forEach((issue, index) => issue.discussions = discussions[index]);
this.issues = allIssues;
});
});
}
else {
this.gitlabService.getDiscussions(allIssues).then(discussions => {
allIssues.forEach((issue, index) => issue.discussions = discussions[index]);
this.issues = allIssues;
});
}
});
});
Test attempt (BurndownComponent.spec.ts):
describe('BurndownComponent', () => {
let component: BurndownComponent;
let fixture: ComponentFixture<BurndownComponent>;
const data: object = jsonData;
let httpMock: object;
let stubGitLabService: GitlabService;
beforeEach(async () => {
httpMock = {
'get': (url, headers): Observable<object[]> => {
const endpoint = 'https://git.tecgraf.puc-rio.br/api/v4/';
const discussions = data['discussions-test'][0]['discussions']
.map(d => Discussion.getDiscussion(d));
const urlDiscussions = [
`${endpoint}projects/1710/issues/120/discussions`,
`${endpoint}projects/1710/issues/97/discussions`,
`${endpoint}projects/1210/issues/920/discussions`
];
if(urlDiscussions.includes(url)) {
return new Observable(subscriber => discussions[urlDiscussions.indexOf(url)]);
}
return new Observable(subscriber => null);
}
}
stubGitLabService = new GitlabService(<any> httpMock);
await TestBed.configureTestingModule({
declarations: [ BurndownComponent ],
providers: [
{ provide: GitlabService, useValue: stubGitLabService }
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(BurndownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('loads all issues - loadIssues()', async () => {
const milestoneData = Milestone.getMilestone(data['milestone-test'][0]);
const milestoneEventsData = data['all-milestone-events'][0]['events']
.map(me => MilestoneEvent.getMilestoneEvent(me));
const labelEventsData = data['label-events-burndown-component-test'][0]['events']
.map(le => LabelEvent.getLabelEvent(le));
const issues = data['issues-test-passed-milestone']
.map(i => Issue.getIssue(i));
const discussions = data['discussions-test'][0]['discussions']
.map(d => Discussion.getDiscussion(d));
issues.forEach((issue, index) => {
issue.labelEvents = labelEventsData.map(le => LabelEvent.copy(le));
issue.milestoneEvents = milestoneEventsData.map(me => MilestoneEvent.copy(me));
});
component.milestone = milestoneData;
stubGitLabService['getDiscussions'] = (issues: Issue[]): Promise<Discussion[][]> => {
return new Promise<Discussion[][]>(resolve => resolve(discussions))
};
const spyMilestoneRolledIssues = spyOn(component, 'getMilestoneRolledIssues')
.and
.returnValue(Promise.resolve(issues));
const spyIssueEvents = spyOn(component, 'getIssueEvents')
.and
.returnValue(Promise.resolve(issues));
const getDiscussionsSpy = spyOn(stubGitLabService, 'getDiscussions')
.and
.returnValue(new Promise(
resolve => {
console.log('discussions');
resolve(discussions)
}
));
await component.loadIssues();
expect(component.issues.length).toBe(3);
expect(spyMilestoneRolledIssues).toHaveBeenCalled();
expect(getDiscussionsSpy).toHaveBeenCalled();
});
You are await
ing loadIssues
but it is not an async function. You can address this by returning the Promise
returned by then
which will complete at an appropriate time.
loadIssues() { // remove explicit void return type
this.selectedMilestone = this.milestone;
this.issues = [];
console.log(this.selectedMilestone.reviewDate);
// return the promise
return this.gitlabService.getIssues(this.selectedMilestone?.title).then(issues => {
...