How to mock Pipe when testing Component

Unit TestingAngularAngular2 TestingAngular2 Pipe

Unit Testing Problem Overview


Currently I am overriding providers to use mocked services like this:

beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    tcb.overrideProviders(AddFieldToObjectDropdownComponent,
        [
             provide(ServiceA, { useClass: MockServiceA })),
             provide(ServiceB, { useClass: MockServiceB }))
        ])
    ...

I want to do same thing for pipes that the component uses. I tried, provide(PipeA, { useClass: MockPipeA }) and provide(PipeA, { useValue: new MockPipeA() }) but both didn't work.

Unit Testing Solutions


Solution 1 - Unit Testing

You can add your mockpipes in the declarations of the TestBed:

TestBed.configureTestingModule({
             declarations: [
                 AppComponent,
                 MockPipe
             ],
            ...

The MockPipe needs to have the @Pipe decorator with the original name.

import {Pipe, PipeTransform} from '@angular/core';

@Pipe({name: 'pipename'})
class MockPipe implements PipeTransform {
    transform(value: number): number {
        //Do stuff here, if you want
        return value;
    }
}

Solution 2 - Unit Testing

To stub the pipe, use Dinistro's answer. To spy on the pipe, you can complement that with the following:

let pipeSpy: jasmine.Spy;

beforeEach(() => {
    TestBed.configureTestingModule...

    pipeSpy = spyOn(MockPipe.prototype, 'transform');
};

it('should do whatever', () => {
    doYourStuff();

    expect(pipeSpy).toHaveBeenCalled();
}

Solution 3 - Unit Testing

If you want reusable util function for mocking pipes, you can try this option:

export function mockPipe(options: Pipe): Pipe {
    const metadata: Pipe = {
      name: options.name
    };
   
    return <any>Pipe(metadata)(class MockPipe {});
}

And then just call this function inside the TestBed declarations array:

TestBed.configureTestingModule({
    declarations: [
        SomeComponent,
        mockPipe({ name: 'myPipe' }),
        mockPipe({ name: 'myOtherPipe' })
    ],
    // ...
}).compileComponents();

Solution 4 - Unit Testing

One possibility is to use the ng-mocks library and use it like this:

TestBed.configureTestingModule({
  declarations: [
    TestedComponent,
    MockPipe(ActualPipe, (...args) => args[0]),
  ]
}).compileComponents();

The second argument to MockPipe defines what the transform function returns for an array of args.

Solution 5 - Unit Testing

Mocking my pipe into simple class like

export class DateFormatPipeMock {
 transform() {
  return '29.06.2018 15:12';
 }
}

and simple use of useClass in my spec file

providers: [
  ...
  {provide: DateFormatPipe, useClass: DateFormatPipeMock}
  ...
]

worked for me :-)

Solution 6 - Unit Testing

Building on top of @shohrukh 's answer, the following code gives you a reusable mock pipe that works in Angular 11/12:

import { Pipe, PipeTransform } from '@angular/core';

export function mockPipe(name: string): Pipe {
  const metadata: Pipe = {
    name
  };

  return Pipe(metadata)(
    class MockPipe implements PipeTransform {
      transform() {}
    }
  );
}

Then use it in your test:

TestBed.configureTestingModule({
  declarations: [
    MyComponent,
    mockPipe('myPipe')
  ],
  ...
}).compileComponents();

Solution 7 - Unit Testing

You can MockPipe from ng-mocks, or MockBuilder if you inject pipes as services.

MockPipe

beforeEach(() => {
  TestBed.configureTestingModule({
    declarations: [
      MockPipe(PipeA),
      MockPipe(PipeB, value => `transformed:${value}`),
    ],
  });
});

MockBuilder

beforeEach(() => {
  return MockBuilder(MyComponent, MyModule)
    .mock(PipeA)
    .mock(PipeB, value => `transformed:${value}`);
});

Solution 8 - Unit Testing

You can use MockPipe npm package, but you need to import it like below.

import { MockPipe } from 'mock-pipe';

After that, all you need to do is to define your mock pipe in providers..

providers: [     
        {
            provide: HighlightPipe,
            useValue: MockPipe(HighlightPipe, () => 'mock')
        }
]

That's all.

Solution 9 - Unit Testing

Often, we use pipes in templates. Here’s how you can mock a pipe. Note that the name of the pipe has to be the same as the pipe you are mocking.

@Pipe({ name: 'myPipe' })
class MyPipeMock implements PipeTransform {
  transform(param) {
    console.log('mocking');
    return true;
  }
}

You need to include the pipe when configuring your TestingModule if you are using it in a component’s template in the declarations.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionharunurhanView Question on Stackoverflow
Solution 1 - Unit TestingDinistroView Answer on Stackoverflow
Solution 2 - Unit TestingJoão MendesView Answer on Stackoverflow
Solution 3 - Unit TestingshohrukhView Answer on Stackoverflow
Solution 4 - Unit TestingKojaView Answer on Stackoverflow
Solution 5 - Unit TestingPavel PazderníkView Answer on Stackoverflow
Solution 6 - Unit TestingfikkatraView Answer on Stackoverflow
Solution 7 - Unit TestingsatanTimeView Answer on Stackoverflow
Solution 8 - Unit TestingRecep SelliView Answer on Stackoverflow
Solution 9 - Unit TestingMehdi EL AZRAKView Answer on Stackoverflow