Home > Mobile >  jest.js and useValue stub for provider not working in angular
jest.js and useValue stub for provider not working in angular

Time:04-01

I have a service with a simple GET method:

export class MyService {
  constructor(private http: HttpClient) {}

  getUsers() {
    const path = 'https://gorest.co.in/public/v2/users'

    return this.http.get(path)
  }
}

Next I'm injecting it into a component:

export class AppComponent implements OnInit {
  users: any[]

  constructor(private _myService: MyService) {}

  ngOnInit() {
    this._myService.getUsers().subscribe((usersRes) => {
      this.users = usersRes
    })
  }
}

I Also have a simple stub for users:

const usersMock = [
  {
    gender: 'female',
    id: 3971,
    name: 'Piotreczi Krawaczi',
  },
]

const myServiceStub = jest.fn().mockImplementation(() => ({
  getUsers: jest.fn().mockReturnValue(of(usersMock))
})

...and then I want to use it in TestBed in app.components.spec.ts.

beforeEach(waitForAsync(() => {
  TestBed.configureTestingModule({
    imports: [HttpClientTestingModule],
    declarations: [AppComponent],
    providers: [{ MyService, useValue: myServiceStub }],
  }).compileComponents()

  fixture = TestBed.createComponent(AppComponent)
  component = fixture.componentInstance
}))

...finally I want to test that, users isn't empty:

it('should get Users', fakeAsync(() => {
  fixture.detectChanges()
  expect(component.users.length).toBeGreaterThan(0)
  flush()
}))

I'm getting error: TypeError: Cannot read property 'length' of undefined, whcich is related to expect(component.todos.length).toBeGreaterThan(0). Does anybody know why todos isn't updated and code in getUsers().subscribe isn't executed?

I tried also useClass insead useValue with: providers: [{ MyServiceService, useClass: MyServiceStubClass }], and:

class MyServiceStubClass {
  getTodos() {
    return of(todosMock)
  }

  getUsers() {
    return of(usersMock)
  }
}

...but it doesn't work.

CodePudding user response:

I am thinking you may need to have a tick for the subscribe to take effect before your expect.

Try this:

class MyServiceStubClass {
  getTodos() {
    return of(todosMock)
  }

  getUsers() {
    return of(usersMock)
  }
}

providers: [{ MyService, useClass: MyServiceStubClass }],
....

it('should get Users', fakeAsync(() => {
  // first fixture.detectChanges() calls ngOnInit
  fixture.detectChanges();
  // tick should wait for the subscribe to be completed before going to expect
  tick();
  expect(component.users.length).toBeGreaterThan(0);
  flush();
}))

CodePudding user response:

I have the soultion. I had to use:

@Injectable()
class MockMyService extends MyService {
  override getUsers() {
    return of(usersMock)
  }

  override getTodos() {
    return of(todosMock)
  }
}

and in TestBed.configureTestingModule:

providers: [{provide: MyService, useClass: MockMyService}],
  • Related