I have a hierarchy of components in my angular app which is as follows:
BookmarkContainer
has the following child components:
BookmarksListComponent
CreateBookmarkComponent
BookmarksListComponent
has a ngFor
of BookmarkItemComponent
I am trying to access the template of BookmarkItemComponent
from the test of the BookmarkContainer
using DebugElement
and its query()
method.
Here is the code for BookmarkContainer
:
@Component({
selector: 'app-bookmarks-container',
templateUrl: './bookmarks.container.html',
styleUrls: ['./bookmarks.container.scss']
})
export class BookmarksContainerComponent implements OnInit {
bookmarks$: Observable<Bookmark[]>;
newBookmark: Bookmark;
deletedBookmarkId: number;
constructor(private bookmarkService: BookmarkService) {}
ngOnInit(): void {
this.setBookmarks();
}
private setBookmarks() {
this.bookmarks$ = this.bookmarkService
.currentUser()
.pipe(
mergeMap(session => this.bookmarkService.search({ account: session.user.uid }))
);
}
}
Here is the corresponding test:
describe('BookmarkContainerComponent', () => {
let component: BookmarksContainerComponent;
let fixture: ComponentFixture<BookmarksContainerComponent>;
let httpTestingController: HttpTestingController;
const aBookmark: Bookmark = {
id: 42,
title: 'a bookmark',
url: 'http://www.example.com',
account: '1'
};
const anotherBookmark: Bookmark = {
id: 43,
title: 'another bookmark',
url: 'http://www.example.fr',
account: '1'
};
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule],
declarations: [BookmarksContainerComponent, BookmarksListComponent, BookmarkItemComponent, CreateBookmarkComponent],
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BookmarksContainerComponent);
component = fixture.componentInstance;
httpTestingController = TestBed.inject(HttpTestingController);
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should search bookmarks', fakeAsync(() => {
const sessionRequest = httpTestingController.expectOne('/api/system/connect');
sessionRequest.flush({ user: { uid: '1' } });
const bookmarksRequest = httpTestingController.expectOne('/api/bookmarks_link/search');
bookmarksRequest.flush([aBookmark, anotherBookmark]);
//Here I am not sure how to access the li(s) from the BookmarkItemComponent
const item = fixture.debugElement.query(By.directive(BookmarkItemComponent));
});
I have tried to access the li(s)
from the BookmarkItemComponent
but without success: item
is always null
. I suspect it has something to do with the level of nesting of the BookmarkItemComponent
... Can someone please help?
edit:
Template for BookmarkContainer
:
<app-bookmarks-list
[bookmarks]="bookmarks$ | async"
[newBookmark]="newBookmark"
[updatedBookmark]="updatedBookmark"
[deletedBookmark]="deletedBookmarkId"
(deleteBookmarkEvt)="confirmDeleteBookmark($event)"
(updateBookmarkEvt)="openUpdateForm($event)">
</app-bookmarks-list>
...
Template for BookmarksListComponent
:
<ng-container *ngFor="let bookmark of bookmarks">
<div class="bookmark">
<div class="">
<ul class="bookmark-list">
<app-bookmark-item
[bookmark]="bookmark"
(deleteBookmarkEvt)="deleteBookmark($event)"
(updateBookmarkEvt)="updateBookmark($event)"
>
</app-bookmark-item>
</ul>
</div>
</div>
</ng-container>
Template for BookmarkItemComponent
:
<li class="bookmark-item bookmark-item-{{ bookmark.id }}">
<span class="bookmark-icon"></span>
<span class="bookmark-text">
<a href="{{ bookmark.url }}" target="_blank" title="{{ 'BOOKMARKS.OPEN' | translate}}">
{{bookmark.title}}
</a>
</span>
<span class="bookmark-actions">
<a title="{{ 'GLOBAL.UPDATE' | translate}}" (click)="updateBookmark(bookmark)">
<i class="glyphicon glyphicon-pencil"></i>
</a>
<a title="{{ 'GLOBAL.DELETE' | translate}}" (click)="deleteBookmark(bookmark.id)">
<i class="glyphicon glyphicon-remove "></i>
</a>
</span>
</li>
In order to see the http response data appear in the DOM, you need to execute a fixture.detectChanges()
after your request.flush(...)
. Also, I would remove the fakeAsync
wrap. It should not be needed.
E.g.,
it('should search bookmarks', function() {
const sessionRequest = httpTestingController.expectOne('/api/system/connect');
sessionRequest.flush({ user: { uid: '1' } });
const bookmarksRequest = httpTestingController.expectOne('/api/bookmarks_link/search');
bookmarksRequest.flush([aBookmark, anotherBookmark]);
// add detectChanges here
fixture.detectChanges();
// item should be defined now.
const item = fixture.debugElement.query(By.directive(BookmarkItemComponent));
});