【问题标题】:Issue with deep testing components in Angular and accessing html with debugElementAngular 中的深度测试组件和使用 debugElement 访问 html 的问题
【发布时间】:2021-05-19 03:14:43
【问题描述】:

我的 Angular 应用程序中有一个组件层次结构,如下所示:

BookmarkContainer 有以下子组件:

  • BookmarksListComponent
  • CreateBookmarkComponent

BookmarksListComponent 有一个 ngForBookmarkItemComponent

我正在尝试使用DebugElement 及其query() 方法从BookmarkContainer 的测试中访问BookmarkItemComponent 的模板。

这是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 }))
      );
  }
}

下面是对应的测试:

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));

});

我尝试从BookmarkItemComponent 访问li(s),但没有成功:item 始终是null。我怀疑这与BookmarkItemComponent 的嵌套级别有关...有人可以帮忙吗?

编辑

BookmarkContainer 的模板:

<app-bookmarks-list
  [bookmarks]="bookmarks$ | async"
  [newBookmark]="newBookmark"
  [updatedBookmark]="updatedBookmark"
  [deletedBookmark]="deletedBookmarkId"
  (deleteBookmarkEvt)="confirmDeleteBookmark($event)"
  (updateBookmarkEvt)="openUpdateForm($event)">
</app-bookmarks-list>
...

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>

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>

【问题讨论】:

  • 只是为了进行完整性检查,您能否也发布 HTML 模板?
  • @garbear 我已经添加了相关模板

标签: angular jestjs angular-test


【解决方案1】:

为了在 DOM 中看到 http 响应数据,您需要在 request.flush(...) 之后执行 fixture.detectChanges()。另外,我会删除 fakeAsync 包装。应该不需要它。

例如,

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));
});

【讨论】:

    【解决方案2】:

    您可以尝试在 beforeEach 上添加 async 吗?

    beforeEach(async() => {
        fixture = TestBed.createComponent(BookmarksContainerComponent);
        component = fixture.componentInstance;
        httpTestingController = TestBed.inject(HttpTestingController);
        fixture.detectChanges();
      });
    

    【讨论】:

    • 你好@gaurav async 也没有运气......我已经按照建议尝试了。项目仍为空。
    • 我有类似的设置。在fixture.debugElement.query(By.directive(BookmarkItemComponent)) 之前使用beforeEachfixture.detectChanges() 上的异步给我实际的元素。否则,我也会得到空值。
    • 我开玩笑。有什么区别吗?
    • 这和我的笑话是一样的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-14
    • 2019-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    相关资源
    最近更新 更多