Skip to content

TestBed: rethink interactions with the @Input / @output of the root component #12313

@mattdistefano

Description

@mattdistefano

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

TBH I'm not sure if this is a bug, a feature request, or just a product of my ignorance/incomplete docs.

Current behavior

When I have a component using ChangeDetectionStrategy.OnPush, I can create a test fixture via const fixture = TestBed.createComponent(TestComponent) but can't figure out how to force a change detection after altering one of the input properties. Just calling fixture.detectChanges() like I would for a ChangeDetectionStrategy.Default component doesn't seem to do it. I've also tried in conjunction with fixture.changeDetectorRef.markForCheck() but still no luck. However, if I wrap my OnPush component in another component for testing purposes, it works as expected.

Expected behavior

Should be some way to force a change detection on a OnPush component when changing its inputs directly via the component fixture (rather than via a wrapper component).

Minimal reproduction of the problem with instructions

test.component:

import { Component, Input, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'my-test',
  template: '<p>{{ content }}</p>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestComponent {
  @Input() content: string;
}

test.component.spec.ts (this test fails w/ OnPush but passes with Default):

import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { TestComponent } from './test.component';

describe('Test Component', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({declarations: [TestComponent]});
  });
  it('should render the bound content within a p element', () => {
    const fixture = TestBed.createComponent(TestComponent);
    fixture.detectChanges();
    const p = fixture.debugElement.query(By.css('p'));
    expect((p.nativeElement as HTMLParagraphElement).innerText).toBeFalsy();
    fixture.componentInstance.content = 'Test!';
    fixture.detectChanges();
    expect((p.nativeElement as HTMLParagraphElement).innerText).toEqual('Test!');
  });
});

test.component.wrapped.spec.ts (this passes with OnPush or Default):

import { Component } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { TestComponent } from './test.component';

@Component({
  selector: 'my-wrapper',
  template: '<my-test [content]="content"></my-test>'
})
class WrapperComponent {
  content: string;
}
describe('Test Component (Wrapped)', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({declarations: [TestComponent, WrapperComponent]});
  });

  it('should render the bound content within a p element', () => {
    const fixture = TestBed.createComponent(WrapperComponent);
    fixture.detectChanges();
    const p = fixture.debugElement.query(By.css('p'));
    expect((p.nativeElement as HTMLParagraphElement).innerText).toBeFalsy();
    fixture.componentInstance.content = 'Test!';
    fixture.detectChanges();
    expect((p.nativeElement as HTMLParagraphElement).innerText).toEqual('Test!');
  });
});

What is the motivation / use case for changing the behavior?

Would prefer to use roughly the same testing patterns regardless of which change detection strategy I'm using.

Please tell us about your environment:

  • Angular version: 2.1.0
  • Browser: all
  • Language: TS 2.0.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions