Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: cannot set return value of DI'ed pipe #7937

Open
JPtenBerge opened this issue Jan 13, 2024 · 1 comment
Open

Bug: cannot set return value of DI'ed pipe #7937

JPtenBerge opened this issue Jan 13, 2024 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@JPtenBerge
Copy link

HI there!

Description of the bug

I try to set the return value of a DI'ed pipe's transform() function, but it doesn't. I also expect() the function .toHaveBeenCalled(), but it's never called. It's as if my test and my component have different instances of the pipe.

It could simply be that I'm doing something wrong or just forgot something somewhere. Couldn't find this specific use case in the docs and I believe I'm doing everything correctly, so I'd thought I'd file a bug.

An example of the bug

I have this relatively boring pipe:

@Pipe({ name: 'bla' })
export class BlaPipe implements PipeTransform {
  transform(value: any, ...args: any[]) {
    return `hi there ${value}`;
  }
}

It resides in this module, where I provide the pipe for use with DI:

@NgModule({
  declarations: [BlaPipe],
  exports: [BlaPipe],
  providers: [BlaPipe],
})
export class PipesModule {}

I then try to use this pipe:

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [PipesModule],
  templateUrl: './app.component.html',
})
export class AppComponent {
  constructor(private blaPipe: BlaPipe) {}

  doSomething() {
    let val = this.blaPipe.transform('Frank');
    console.log('result of pipe transform:', val);
    return val;
  }
}

Which all works as expected. But then I try to test it. I have the autoSpy() set:

ngMocks.autoSpy('jasmine');

getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());

and then the test itself:

describe('AppComponent', () => {
  let blaPipe: jasmine.SpyObj<BlaPipe>;
  let sut: AppComponent;

  beforeEach(() => MockBuilder(AppComponent));

  beforeEach(() => {
    blaPipe = TestBed.inject(BlaPipe) as jasmine.SpyObj<BlaPipe>;
    // blaPipe = ngMocks.findInstance(BlaPipe) as jasmine.SpyObj<BlaPipe>;

    blaPipe.transform.and.returnValue('test');

    sut = TestBed.createComponent(AppComponent).componentInstance;
  });

  it('should use the blaPipe', () => {
    let result = sut.doSomething();

    expect(blaPipe.transform).toHaveBeenCalled();
    expect(result).toBe('test');
  });
});

And I ran into assertion failures:

Expected spy MockOfBlaPipe.transform to have been called.
Expected undefined to be 'test'.

Link: https://github.com/JPtenBerge/ng-mocks-mock-pipe-bug

Expected vs actual behavior

Expected: that the pipe's transform function would've returned my configured return value.
Actual: it just returns undefined. It seems to not have been setup. It's as if my component receives a different instance than when I use TestBed.inject() or ngMocks.findInstance().

@JPtenBerge JPtenBerge added the bug Something isn't working label Jan 13, 2024
@Morad-m11
Copy link
Contributor

I can't get the example from the 'Auto Spy' documentation to work either.
This test passes. It's clear here that findInstance() gets it right.
You tried finding the instance before creating the component though.

describe('AppComponent', () => {
  let blaPipe: jasmine.SpyObj<BlaPipe>;
  let blaPipe_found: jasmine.SpyObj<BlaPipe>;
  let sut: AppComponent;

  beforeEach(() => MockBuilder(AppComponent));

  beforeEach(() => {
    sut = TestBed.createComponent(AppComponent).componentInstance;
    
    blaPipe = TestBed.inject(BlaPipe) as jasmine.SpyObj<BlaPipe>;
    blaPipe_found = ngMocks.findInstance(BlaPipe) as jasmine.SpyObj<BlaPipe>;
    
    blaPipe.transform.and.returnValue('test');
    blaPipe_found.transform.and.returnValue('test_found');

    console.log("injected: ", blaPipe);
    console.log("findInstance: ", blaPipe_found);
  });

  it('should use the blaPipe', () => {
    let result = sut.doSomething();

    expect(blaPipe_found.transform).toHaveBeenCalled();
    expect(result).toBe('test_found');
  });
});

I noticed here that the injectors are different. Not sure if this is relevant

image

Tested on Angular 17.0.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants