1

I have defined an action in my mobx store like this:

// CardsStore.js

import FetchData from './FetchData';

export default class CardsStore {

  @observable cards = [];

  @action fetchCards = async () => {
    try {
      this.cards = await FetchData();
    } catch (error) {
      // handling error
    }
  };

  ...
  other actions and computed values
  ...
}

and this is the implementation for FetchData:

import EndpointService from 'app/services/EndpointService';

const endpointService = new EndpointService();

export default async function fetchData() {
  try {
      return await endpointService.getCards();
    } catch (e) {
    return 'caught';
  }
}

I have created a mock module for FetchData inside __ mocks __ folder that instead of calling the endpoint service returns a hard coded array like this:

// ./__mocks__/FetchData.js

const cards = [
  {
    id: 'some-id-1',
    name: 'Test1',
  },
  {
    id: 'some-id-2',
    name: 'Test2',
  },
];

export default function FetchData() {
  return new Promise((resolve, reject) => {
  process.nextTick(() =>
  cards ? resolve(cards) : reject({ error: 'Cards are not found.' })
   );
 });
}

In my cards.test.js file I test it like this and it works:

import CardsStore from './CardsStore.js';

jest.mock('./FetchData');

const cards = [
  {
    id: 'some-id-1',
    name: 'Test1',
  },
  {
    id: 'some-id-2',
    name: 'Test2',
  },
];

describe('when fetch cards is called', () => {

  const cardsStore = new CardsStore();

  it('should load the cards', async () => {
    await cardsStore.fetchCards();
    expect(cardsStore.cards).toEqual(cards);
  });
});

The problem is if I want to test my other action addNewCard then I need to dynamically change the cards and add a new card and then check to see if the expected cards list is equal to the new one (that should contain 3 cards)

I can't find a way to dynamically update the cards array inside ./__mocks__/FetchData.js

HTB
  • 413
  • 1
  • 9
  • 22

1 Answers1

1

use jest.spyOn and mockReturnValue...

jest.spyOn(cardsStore.prototype, "fetchCards").mockReturnValue(Promise.resolve(obj));

Replace obj with whatever you want to return

example,

describe('when fetch cards is called', () => {

  const cardsStore = new CardsStore();

  it('should load the cards', async () => {
    jest.spyOn(cardsStore.prototype, "fetchCards").mockReturnValue(Promise.resolve(obj));
    await cardsStore.fetchCards();
    expect(cardsStore.cards).toEqual(cards);
  });
});
Bill Cheng
  • 926
  • 7
  • 9
  • Thanks Bill for your reply. I tried it but it gives me this error: `Cannot spy the FetchCards property because it is not a function; undefined given instead`. Please also note that I wanted to mock FetchData and not FetchCards action. FetchCards itself doesn't return any value. However, just in case, I tried both and got the same result. Any ideas? – HTB Jul 19 '19 at 17:51
  • Thanks for providing the example. I used it in my code and now it says: `Cannot spyOn on a primitive value; undefined given` – HTB Jul 19 '19 at 18:20
  • Can you try it by changing cardsStore to CardsStore? – Bill Cheng Jul 19 '19 at 18:31
  • When I change it to CardsStore first I get a lint error saying : `CardsStore is already declared in the upper scope` because I have imported it at the top `import CardsStore from './CardsStore.js';` And if I ignore it and run it it says : `TypeError: CardsStore is not a constructor` – HTB Jul 19 '19 at 18:38
  • if you can upload your code somewhere, i can take a look at it as i am not able to visualize what you have changed – Bill Cheng Jul 19 '19 at 18:45