1

Update:

for now I solved it by creating the class a Singleton but am told not an ideal way/pattern.

This answer seems to have it all but for the life of me, I can't figure out why my test is failing. The app simply:

Datatabase.js : a class that is not directly accessed by components and works with sqllite

class Database {
 ........
}

MembersService.js

class MembersService {
  _db = new Database();
 getMembers = async () => { 
     try {
       const members = await this._db.getMembers();
     }

    catch (e){

    }


  }
}

now I have a component that makes use of MembersService button click.

handleListMembers = async () =>{
   console.log('button clicked')
   const members = await membersService.getMembers();
   updateMembers(members)
}

now I want to test the button click and mock with my mocked members. I want the getMembers method of membersService to return empty result but so far I can't. My test fails when I do:

   expect(spy).toHaveBeenCalled()

I tried the following:

   const spy = jest.spyOn(MembersService.prototype, 'getMembers')
   //fails with Cannot spy the getMembers property because it is not a function; undefined given instead. console.log(MembersService.prototype) returns {}

  // second attempt: no error but never gets called. I get data that is stored in sqllite instead of an empty list

  const service = new MembersService();
  const spy = jest.spyOn(service, 'getMembers');
  spy.mockResolvedValue([])

 //third

  const service = new MembersService();
  const spy =  jest.spyOn(service, 'getMembers').mockImplementation(() => Promise.resolve([]));

So far the only way I can get an actual empty resutlset is if I mock the Database class itself but none of my components import the class and i don't think my tests should. What am I doing wrong?

it('should render members on button click', async () => {


    const service = new MembersService();
    const spy = jest.spyOn(service, 'getMembers').mockResolvedValue([])

    const wrapper = render(
      <MembersScreen testID="MembersScreen" />,
    );
    //wait for the component to load. it contains button with testID listMembers
    await act(async () => {
      await flushMicrotasksQueue();
    });

    // click the button now
    const btn = wrapper.getByTestId('listMembers');
    fireEvent.press(btn);
    await act(async () => {
      await flushMicrotasksQueue();
    });
    expect(spy).toHaveBeenCalled();
})

I can see button clicked in my console so the button is being pressed in my test.

Lin Du
  • 88,126
  • 95
  • 281
  • 483
elimey
  • 43
  • 4
  • Could you please provide the whole test? – Christian May 24 '20 at 08:29
  • @Christian check it out. – elimey May 24 '20 at 08:53
  • you're spying on a method of a `MemberService` instance. This instance, however, isn't used in your code anywhere else. You need to spy on the `membersService` used in the click handler. – Christian May 24 '20 at 09:20
  • Get into the habit of injecting dependencies, it'll make life much easier. – Christian May 24 '20 at 09:23
  • @Christian: const members = await membersService.getMembers(); in the click handler is based on instance of the class, if I get your point right. membersService = new MembersService() declared outside the button click. Thanks still. Will look at the injection if it will help. – elimey May 24 '20 at 12:01

0 Answers0