Search code examples
angularabstract-classangular-testangular-dom-sanitizer

How do I go about testing a Pipe which depends on DomSanitizer?


Angular version: 8.1.2
Testing tools: Karma and Jasmine, as pre-installed by ng new

I am currently working on my first ever Angular project. As a part of this, I have created a pipe which calls DomSanitizer.bypassSecurityTrustResourceUrl. I do this in order to be able to use them in iframes. I now want to implement tests for this pipe. Here is the code for it:

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from "@angular/platform-browser";

@Pipe({
  name: 'safe'
})
export class SafeResourceUrlPipe implements PipeTransform {

  constructor(private sanitizer: DomSanitizer) { }

  transform(url: string): SafeResourceUrl | string {
    return this.sanitizer.bypassSecurityTrustResourceUrl(url);
  }

}

The auto-generated spec file only looked like this:

import { TestBed, async } from '@angular/core/testing';
import { SafeResourceUrlPipe } from './safe-resource-url.pipe';
import { DomSanitizer } from '@angular/platform-browser';

describe('Pipe: SafeResourceUrle', () => {
  it('should create an instance', () => {
    let pipe = new SafeResourceUrlPipe();
    expect(pipe).toBeTruthy();
  });
});

That this wouldn't work VSCode told me before I even ran the tests, because SafeResourceUrlPipe's constructor expects an argument. So far so good, but I don't know what to do now. I can't just use new DomSanitizer, because it is an abstract class.

What I have tried is creating a mock class that implements DomSanitizer, but with that I can't do much more than testing whether the pipe is even created, and I knew that before already. What I would like to test is whether it properly does its job transforming inputs, but I can hardly test that when I'm pseudo-implementing the main dependency.

I have done some Googling about this and I suspect it will turn out to be something obvious, but I couldn't find it.


Solution

  • I'd recommend using the Angular Testbed to inject a mock of the dom sanitizer like this.

    beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [SafeResourceUrlPipe],
          providers: [
               SafeResourceUrlPipe,
              { provide: DomSanitizer, useValue: {bypassSecurityTrustResourceUrl(){}}
         ]
        });
      }));
    

    Then

    describe('Pipe: SafeResourceUrle', () => {
      it('should create an instance', () => {
        let pipe = TestBed.get(SafeResourceUrlPipe);
        expect(pipe).toBeTruthy();
      });
    });
    

    p.s. the useValue is important here. If you only provide a value here then its fine. If you want to replace that with a full mocked class you must useClass (small slip up that most people get stuck on)

    export class MockDomSanitizer {
        bypassSecurityTrustResourceUrl() {}
        otherMethods(){}
    }
    

    This should allow you to run the pipe with the mocked out dom sanitizer method.