marchaos / jest-mock-extended

Type safe mocking extensions for Jest https://www.npmjs.com/package/jest-mock-extended
MIT License
828 stars 57 forks source link

Angular Services cannot be mocked in Angular TestBed #43

Open tpischke-bedag opened 4 years ago

tpischke-bedag commented 4 years ago

If I mock an Angular Injectable Service, I get the following as soon as I include it in the module providers list:

TypeError: function is not iterable (cannot read property Symbol(Symbol.iterator))
    at new Set (<anonymous>)

Pseudo code (edited for simplicity)

const issueServiceMock = mock<IssueService>();
TestBed.configureTestingModule({
  imports: [ReactiveFormsModule, RouterTestingModule],
  declarations: [
    IssueDashboardContainerComponent
  ],
  providers: [
    {provide: IssueService, useValue: issueServiceMock},
  ]
});
fixture = TestBed.createComponent(IssueDashboardContainerComponent);  // CRASHES HERE
tpischke-bedag commented 4 years ago

Relates to #9

tpischke-bedag commented 4 years ago

Probably worth mentioning that the service in question is generated by the openapi code generator. Perhaps the problem only occurs in combination with code from this generator. I can provide the actual generated service code if you like.

https://github.com/OpenAPITools/openapi-generator

tpischke-bedag commented 4 years ago

I also get the same error with simpler services, not just the generated ones mentioned above,

tpischke-bedag commented 4 years ago

Angular 8.3, latest jest and jest-mock-extended

myin142 commented 4 years ago

I fixed this issue by providing the service using factory. But another problem is that the fixture is not updated in jest when async code is finished. Do you also have this problem?

Edit: Nevermind the problem. It happens only inside NX Workspaces.

tpischke-bedag commented 4 years ago

The workaround described by @myin142 works well with minimal inconvenience.

dgradwell-ams commented 3 years ago

The problem was, in my case, I had a template using an async pipe on an observable that would have been on my mock.

const foo = mock<IFoo>();
   <div *ngFor="let item of foo.someObservable$ | async"> 
       ...

The async pipe is trying to use someObservable$ as an iterable, but it's really a function. The solution is to override those props after creating the mock:

const foo = Object.assign(mock<IFoo>(), { someObservable$: of(...) });