Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Unit Test a Directive In Angular 2?

Problem: I would like to be able to unit test a directive in Angular 2 to make sure that it properly compiles.

In Angular 1, it was possible to use$compile(angular.element(myElement) service and call $scope.$digest() after that. I specifically want to be able to do this in unit tests so I could test that when Angular ends up running across <div my-attr-directive/> in the code that my-attr-directive compiles.

Constraints:

  • Angular 2 using JAVASCRIPT. All sources somewhat related seem to require TS. Perhaps this resource truly does solve the problem and my understanding of TS is just that weak
  • Unit Test in Jasmine
  • Must be not be so hacky that my unit tests will eventually break. See a related SO post on compiling HTML manually in Angular 2
like image 323
daniel.caspers Avatar asked Apr 05 '16 16:04

daniel.caspers


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 a jasmine directive?

We should Unit Test directives by mocking all dependencies with jasmine mocks and spies. We should also Shallow / Deep Test directives using concrete Components (Compiled DOM). A reasonable approach is to create TestComponent or pick up any component which uses the directive we want to test.

How is unit testing done in Angular?

If Angular CLI is used to manage the Angular projects, it will automatically support Jasmine and Karma Configurations. All you need in order to test your application is to type the command ng test. As far as possible, run tests on real browsers and devices to ensure that software is verified under real user conditions.


1 Answers

Testing compiled directive using TestBed

Let's say you have a following directive:

@Directive({   selector: '[my-directive]', }) class MyDirective {   public directiveProperty = 'hi!'; } 

What you have to do, is to create a component that uses the directive (it can be just for testing purpose):

@Component({   selector: 'my-test-component',   template: '' }) class TestComponent {} 

Now you need to create a module that has them declared:

describe('App', () => {    beforeEach(() => {     TestBed.configureTestingModule({       declarations: [         TestComponent,         MyDirective       ]     });   });    // ...  }); 

You can add the template (that contains directive) to the component, but it can be handled dynamically by overwriting the template in test:

it('should be able to test directive', async(() => {   TestBed.overrideComponent(TestComponent, {     set: {       template: '<div my-directive></div>'     }   });    // ...        })); 

Now you can try to compile the component, and query it using By.directive. At the very end, there is a possibility to get a directive instance using the injector:

TestBed.compileComponents().then(() => {   const fixture = TestBed.createComponent(TestComponent);   const directiveEl = fixture.debugElement.query(By.directive(MyDirective));   expect(directiveEl).not.toBeNull();    const directiveInstance = directiveEl.injector.get(MyDirective);   expect(directiveInstance.directiveProperty).toBe('hi!'); });  

# Old answer:

To test a directive you need to create a fake component with it:

@Component({   selector: 'test-cmp',   directives: [MyAttrDirective],   template: '' }) class TestComponent {} 

You can add the template in the component itself but it can be handled dynamically by overwriting the template in test:

it('Should setup with conversation', inject([TestComponentBuilder], (testComponentBuilder: TestComponentBuilder) => {     return testComponentBuilder       .overrideTemplate(TestComponent, `<div my-attr-directive></div>`)       .createAsync(TestComponent)       .then((fixture: ComponentFixture<TestComponent>) => {         fixture.detectChanges();         const directiveEl = fixture.debugElement.query(By.css('[my-attr-directive]'));         expect(directiveEl.nativeElement).toBeDefined();       });   })); 

Note that you're able to test what directive renders but I couldn't find the way to test a directive in a way components are (there is no TestComponentBuilder for directives).

like image 118
Wojciech Kwiatek Avatar answered Oct 01 '22 21:10

Wojciech Kwiatek