Ashley Sheridan​.co.uk

Testing Private Member Classes with Jasmine in Angular2 Template Tests

Posted on

A little while ago I came across an issue when trying to implement template testing with Jasmine on an Angular2 project that was using private member classes. If you try this yourself, you'll get plenty of errors and warnings about various things that either can't be found, used, or can't be spied on. There's not a lot online about this, as it seems that private anything within Angular2 projects is just something that the average developer doesn't seem to be doing, or at least isn't doing in any of their online examples and tutorials. As such, discovering any kind of way around the problem is not easily discoverable for people.

The issue is that when you're testing templates, the typical way to do this is with a construct like this:

let fixture: ComponentFixture; beforeEach(() => { TestBed.configureTestingModule({ declarations: [ YourComponent, other components... ], providers: [ YourComponent, any services used... ] }); }); ... it('should test something', () => { fixture = TestBed.createComponent(YourComponent); let compiled = fixture.debugElement.nativeElement; fixture.detectChanges(); expect(compiled.querySelector('.someSelectorInYourComponent') ).toBeTruthy(); });

This is quite different from regular unit tests inside Jasmine, as using this approach does not allow you to inject instances of classes that are private within a component but that you still want to interact with inside of your test. If you're component is fairly simple, that might not actually be a problem for you, but the application I was working on had some more complex features and I needed to interact with those private classes being uses by my component.

As it turns out, the solution is simple (albeit not something I would recommend in anything but test code):

spyOn(YourService.prototype, 'someMethodCall');

That's it.

Now, there are many reasons (very good reasons) why doing anything to the prototype of a class is a bad idea, and I agree wholeheartedly. In this case though, there were not many options, and Jasmine quite neatly resets each and every class instance for every test (something which you expect for a testing framework, but sadly not all testing frameworks are created equally.)