Search code examples
typescriptjestjsmocking

How can I use this mock in multiple places using __mocks_folder using Jest and Typescript


I have a mock which I define in a test. I find I need to use that mock again and again. I tried using the manual __mocks__ folder but don't know to get it to work. When I using it directly in the test file it works perfectly. However, I don't want to copy and paste again and again and I have more complex tests which use many mocks.

Here is my mock definition in the __mocks__ folder

__mocks__/books/book-search-service.ts is shown below


         const findBooksMock = jest.fn()
         const createBookSearchRequestMock = jest.fn()
         jest.mock('../../services/book-search-service', () =>{
          return {
              BooksSearchService: jest.fn().mockImplementation(() =>{
                return {
                  findBooks: findBooksMock,
                  createBookSearchRequest: createBookSearchRequestMock
            }
        })
    }
})

In my project, I have the service in src/books/book-search-service.ts. However, when I create the service in my test, it calls the real service which tells me it is not using the mock service in __mocks__/books folder

In my test here is how I am using it

         
         import { BookSearchService } from '../../books/book-search-service'
         
         describe('books service suite', ()=> {

            const bookSearchService = new BookSearchService()
            // rest of code

         }

How do I get this to work? I tried reading the documentation but did not find an example similar to what I am trying to do. Is what I am doing a step in the right direction or am I doing it absolutely wrong? I'd appreciate a simple example which will allow me to get this working. Thank you in advance.


Solution

  • Mocking user modules

    When we require that module in our tests (meaning we want to use the manual mock instead of the real implementation), explicitly calling jest.mock('./moduleName') is required.

    You still need to call jest.mock('./books/book-search-service.ts') in each test file. Just don't need to provide a factory parameter.

    If you don't want to call jest.mock() in each test file, you can use setupFilesAfterEnv configuration,

    In other words, setupFilesAfterEnv modules are meant for code which is repeating in each test file

    Create a setup.js file and call jest.mock('./books/book-search-service.ts') in it.

    e.g.

    books/book-search-service.ts:

    export class BooksSearchService {
      findBooks() {
        throw new Error('Method not implemented.');
      }
    }
    

    books/__mocks__/book-search-service.ts:

    export const BooksSearchService = jest.fn(() => ({
      findBooks: jest.fn().mockReturnValue([1, 2, 3]),
    }));
    

    a.test.ts:

    import { BooksSearchService } from './books/book-search-service';
    
    describe('books service suite A', () => {
      test('should pass', () => {
        const bookSearchService = new BooksSearchService();
        expect(jest.isMockFunction(bookSearchService.findBooks)).toBeTruthy();
        expect(bookSearchService.findBooks()).toEqual([1, 2, 3]);
      });
    });
    

    b.test.ts:

    import { BooksSearchService } from './books/book-search-service';
    
    describe('books service suite B', () => {
      test('should pass', () => {
        const bookSearchService = new BooksSearchService();
        expect(jest.isMockFunction(bookSearchService.findBooks)).toBeTruthy();
        expect(bookSearchService.findBooks()).toEqual([1, 2, 3]);
      });
    });
    

    setup.js:

    jest.mock('./books/book-search-service.ts');
    

    jest.config.js

    module.exports = {
      testEnvironment: 'jsdom',
      setupFiles: [
        '<rootDir>/setup.js',
      ],
      transform: {
        '\\.[jt]sx?$': 'babel-jest',
      } 
    };
    

    Test result:

     PASS  stackoverflow/78976486/a.test.ts
     PASS  stackoverflow/78976486/b.test.ts
                                                                                                                                                                                                                                                   
    Test Suites: 2 passed, 2 total                                                                                                                                                                                                                 
    Tests:       2 passed, 2 total
    Snapshots:   0 total
    Time:        0.864 s, estimated 1 s
    Ran all test suites related to changed files.