In my test 'should emit action complete', I'm trying to test that the emit function of 'bookActionCompleted' is called when the 'OnBookActionClick' method is called. This emit function is called inside a method passed into the subscribe function of a void observable returned from my service methods.
Unfortunately the code passed into the subscribe method on the component is never called via running my tests. In these tests I'm mocking the response of 'publishBook' and 'unpublishBook' by returning of(), I suspect this might be the cause of the issue, however I'm at a complete loss of how to proceed.
Component
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Library, LibraryBook } from '../../models';
import { LibraryService } from '../../services';
@Component({
selector: 'librarycatalogue-books-view',
templateUrl: './books-view.component.html',
styleUrls: ['./books-view.component.scss']
})
export class BooksViewComponent {
@Input() library!: Library;
@Output() bookActionCompleted = new EventEmitter();
constructor(private libraryService: LibraryService) {}
onBookActionClick(book: LibraryBook) {
const action = book.isPublished
? this.libraryService.unpublishBook(this.library.libraryId, book.bookId)
: this.libraryService.publishBook(this.library.libraryId, book.bookId);
action.subscribe(() => {
this.bookActionCompleted.emit()
});
}
}
Service methods (which are being mocked)
publishBook(libraryId: string, bookId: string): Observable<void> {
return this.http.put<void>(`${this.baseUrl}/${libraryId}/book/${bookId}/publish`, null);
}
unpublishBook(libraryId: string, bookId: string): Observable<void> {
return this.http.put<void>(`${this.baseUrl}/${libaryId}/book/${bookId}/unpublish`, null);
}
Tests
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { createSpyObject, SpyObject } from '@ngneat/spectator/jest';
import { of } from 'rxjs';
import { Library, LibraryBook } from '../../models';
import { LibraryService } from '../../services';
import { BooksViewComponent } from './books-view.component';
describe('BooksViewComponent', () => {
let component: BooksViewComponent;
let fixture: ComponentFixture<BooksViewComponent>;
let libraryService: SpyObject<LibraryService>;
beforeEach(async () => {
libraryService = createSpyObject(LibraryService);
libraryService.publishBook.mockReturnValue(of());
libraryService.unpublishBook.mockReturnValue(of());
await TestBed.configureTestingModule({
declarations: [ BooksViewComponent ],
imports: [HttpClientTestingModule],
providers: [
{ provide: LibraryService, useValue: libraryService }
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(BooksViewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('On book action click', () => {
let library: Library;
let publishedBook: LibraryBook;
let unpublishedBook: LibraryBook;
beforeEach(() => {
library = { libraryId: '1',
name: 'New York Library',
books: [
{ book: 1, bookId: '1', isPublished: false},
{ book: 2, bookId: '2', isPublished: true }
]
};
publishedBook = library.books.filter(x => x.isPublished)[0];
unpublishedBook = library.books.filter(x => !x.isPublished)[0];
component.library = library;
jest.spyOn(component.bookActionCompleted, 'emit');
});
describe('If item is published', () => {
it('should be unpublished', () => {
component.onBookActionClick(publishedBook);
expect(libraryService.unpublishBook).toHaveBeenCalled();
})
it('should emit action complete', () => {
component.onBookActionClick(publishedBook);
expect(component.bookActionCompleted.emit).toHaveBeenCalledTimes(1);
})
});
});
});
CodePudding user response:
You could subscribe to your bookActionCompleted
EventEmitter and terminate the test with the help of the 'done' function paramter passed to the jest function.
it('should emit action complete', (done) => {
// test will be green if done cb is called:
component.bookActionCompleted.subscribe(done);
component.onBookActionClick(publishedBook);
})
CodePudding user response:
I've just stumbled on the answer somewhat by accident. Changing the mock to return of(undefined) instead of of() has made the emit method fire.
No idea why this is the case, would be curious to know if anyone has the answer.
Before (not working)
libraryService.publishBook.mockReturnValue(of());
libraryService.unpublishBook.mockReturnValue(of());
After (working)
libraryService.publishBook.mockReturnValue(of(defined));
libraryService.unpublishBook.mockReturnValue(of(defined));