DOM interaction

Now we are going to cover the DOM interaction, based on the previous code snippets we will find out how we can test a specific section of the DOM.

describe('CoursesCardListComponent', () => {

  let component: CoursesCardListComponent;
  let fixture: ComponentFixture<CoursesCardListComponent>;
  let el: DebugElement;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [CoursesModule],
      declarations: [AppComponent]
    })
      .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(CoursesCardListComponent);
        component = fixture.componentInstance;
        el = fixture.debugElement;
      });
  }));

  it("should create the component", () => {
    expect(component).toBeTruthy();
  });


  it("should display the course list", () => {
    component.courses = setupCourses();
    const cards = el.queryAll(By.css(".course-card"));
    expect(cards).toBeTruthy("Could not find cards");
    expect(cards.length).toBe(12, "Unexpected number or courses");
  });
});

DebugElement

The Angular fixture provides the component's element directly through the fixture.nativeElement.

content_copyconst bannerElement: HTMLElement = fixture.nativeElement;

This is actually a convenience method, implemented as fixture.debugElement.nativeElement.

content_copyconst bannerDe: DebugElement = fixture.debugElement;
const bannerEl: HTMLElement = bannerDe.nativeElement;

There's a good reason for this circuitous path to the element.

The properties of the nativeElement depend upon the runtime environment. You could be running these tests on a non-browser platform that doesn't have a DOM or whose DOM-emulation doesn't support the full HTMLElement API.

Angular relies on the DebugElement abstraction to work safely across all supported platforms. Instead of creating an HTML element tree, Angular creates a DebugElement tree that wraps the native elements for the runtime platform. The nativeElement property unwraps the DebugElement and returns the platform-specific element object.

Because the sample tests for this guide are designed to run only in a browser, a nativeElement in these tests is always an HTMLElement whose familiar methods and properties you can explore within a test.

By.css()

Although the tests in this guide all run in the browser, some apps might run on a different platform at least some of the time.

For example, the component might render first on the server as part of a strategy to make the application launch faster on poorly connected devices. The server-side renderer might not support the full HTML element API. If it doesn't support querySelector, the previous test could fail.

The DebugElement offers query methods that work for all supported platforms. These query methods take a predicate function that returns true when a node in the DebugElement tree matches the selection criteria.

You create a predicate with the help of a By class imported from a library for the runtime platform. Here's the By import for the browser platform:

content_copyThe code sample is missing for
testing/src/app/banner/banner-initial.component.spec.ts#import-by

The following example re-implements the previous test with DebugElement.query() and the browser's By.css method.

content_copyit('should find the <p> with fixture.debugElement.query(By.css)', () => {
  const bannerDe: DebugElement = fixture.debugElement;
  const paragraphDe = bannerDe.query(By.css('p'));
  const p: HTMLElement = paragraphDe.nativeElement;
  expect(p.textContent).toEqual('banner works!');
});

Some noteworthy observations:

Last updated