Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 / 4 - How to test Directive @Input values?

So I have a Directive that takes an input:

@Directive({
    selector: '[my-directive]'
})
export class MyDirective {

    @Input('some-input')
    public someInput: string;
}

As you can see, the input should be a string value. Now, I want to write a test for this Directive, and I want to test if the input satisfies the string type:

describe('MyDirective', () => {

    let fixture: ComponentFixture<DummyComponent>;
    let dummy: DummyComponent;
    let directive: DebugElement;

    beforeEach(async(() => {

        TestBed
            .configureTestingModule({
                imports: [
                    MyModule.forRoot()
                ],
                declarations: [
                    DummyComponent
                ]
            })
            .compileComponents();

        fixture = TestBed.createComponent(DummyComponent);
        dummy = fixture.componentInstance;
        directive = fixture.debugElement.query(By.directive(MyDirective));

        fixture.detectChanges();
    }));

    it('should satisfy only a string input and error on other inputs', () => {
        // How to test?
    });
});

@Component({
    selector: 'dummy',
    template: `
        <div my-directive [some-input]="'just-a-string-value'"></div>
    `
})
export class DummyComponent implements OnInit {
}

How can I test whether the @Input value(s) are of the proper type?

like image 937
Nicky Avatar asked Jul 24 '17 16:07

Nicky


People also ask

How do you mock a directive?

A mock directive in Angular tests can be created by MockDirective function. The mock directive has the same interface as its original directive, but all its methods are dummies. In order to create a mock directive, pass the original directive into MockDirective function.

How do you test Angular components?

To run your tests using the Angular CLI, you use the ng test command in your terminal. As a result, Karma will open up the default browser and run all the tests written with the aid of Jasmine and will display the outcome of those tests.

Can a directive have input?

Input data into a DirectiveWe can also extend or modify the behavior or functionality of a directive by inputtting data into the directive.

What does fixture detectChanges () do?

fixture. detectChanges() tells Angular to run change-detection. Finally! Every time it is called, it updates data bindings like ng-if, and re-renders the component based on the updated data. Calling this function will cause ngOnInit to run only the first time it is called.


1 Answers

So it's a bit late but I came here searching for the same problem, so I'll post my solution. Here is what I did to test a directive inputs (or other properties) values :

describe('MyDirective', () => {

    let fixture: ComponentFixture<DummyComponent>;
    let dummy: DummyComponent;
    let directive: DebugElement;

    beforeEach(async(() => {

        TestBed
            .configureTestingModule({
                imports: [
                    MyModule.forRoot()
                ],
                declarations: [
                    DummyComponent
                ]
            })
            .compileComponents();

        fixture = TestBed.createComponent(DummyComponent);
        dummy = fixture.componentInstance;
        directive = fixture.debugElement.query(By.directive(MyDirective));

        fixture.detectChanges();
    }));

    it('should satisfy only a string input and error on other inputs', () => {
        
        // needed so template is processed, inputs are updated
        fixture.detectChanges();
        
        // since we declared a ViewChild on the directive, we can access
        // and test directive properties values
        expect(component.directive.someInput).toEqual('just-a-string-value');
        // to test the input type :
        expect(component.directive.someInput).toEqual(Jasmine.any(String));
        // I thought TypeScript would complain when providing a wrong type input to a directive, but no...so I guess I'll test the input type too !
    });
});

@Component({
    selector: 'dummy',
    template: `
        <div my-directive [some-input]="'just-a-string-value'"></div>
    `
})
export class DummyComponent implements OnInit {

  // add a reference to the directive in template
  // so in your component you can access : this.directive, this.directive.someInput
  ViewChild(MyDirective) directive: MyDirective;
}
So : modify your testing component to hold a reference on the directive instance, and then access the directive properties through component.directive.[property-name]. By the way if you provide defaults values for your directive properties (that can be overridden by providing a value in the template), you can test them before calling fixture.detectChanges().
like image 145
Florian Motteau Avatar answered Oct 30 '22 13:10

Florian Motteau