Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I have all my tests and mocks inside a folder "tests" next to my "app" source code? #2726

Open
rfgamaral opened this issue Jan 28, 2017 · 46 comments

Comments

@rfgamaral
Copy link

rfgamaral commented Jan 28, 2017

I currently have all my app source code under app/ and all my tests source code under tests/. These folders follow the same folder structure. Everything is working fine with the following Jest configuration:

{
    "collectCoverageFrom": [
        "app/**/*.{ts,tsx}"
    ],
    "coverageDirectory": "build/coverage/",
    "coverageReporters": [
        "html",
        "text-summary"
    ],
    "moduleFileExtensions": [
        "js",
        "ts",
        "tsx"
    ],
    "moduleNameMapper": {
        "^.+\\.css$": "identity-obj-proxy"
    },
    "modulePaths": [
        "<rootDir>/app/"
    ],
    "snapshotSerializers": [
        "enzyme-to-json/serializer"
    ],
    "transform": {
        "^.+\\.(ts|tsx)$": "./utils/jest-typescript-transformer.js",
        "^.+\\.(gif|jpg|png)$": "./utils/jest-image-size-transformer.js"
    },
    "testPathDirs": [
        "<rootDir>/app/",
        "<rootDir>/tests/"
    ],
    "testRegex": "tests/.+\\.spec\\.(ts|tsx)$"
}

Now I need to mock some modules and the documentation states:

Manual mocks are defined by writing a module in a __mocks__/ subdirectory immediately adjacent to the module.

This means that the __mocks__ needs to be inside the app folder but I'd like to keep everything test related inside the tests folder. But there's the thing, if I have duplicate mocks on both app and tests I get this:

jest-haste-map: duplicate manual mock found:
  Module name: DialpadDigits
  Duplicate Mock path: C:\SampleApp\tests\constants\dialer\__mocks__\DialpadDigits.ts

This warning is caused by two manual mock files with the same file name.
Jest will use the mock file found in:

  C:\SampleApp\tests\constants\dialer\__mocks__\DialpadDigits.ts

Please delete one of the following two files:
  C:\SampleApp\app\constants\dialer\__mocks__\DialpadDigits.ts
  C:\SampleApp\tests\constants\dialer\__mocks__\DialpadDigits.ts

But the only file actually being used is the one under app... How do I know this? Say I have the same mock on both folders and this mock fails my tests and if I don't use the mock, the tests pass. If I remove the mocked module from app, the test passes. Which means the mock from tests is not being used, despite that Jest warning above.

To sum up, how can I have my mocks in the tests folder?

@danielhneville
Copy link

I have exactly the same question. I've been struggling with this for a while now, and I just can't put mock folders everywhere. I want them all in one mock folder in my test folder. Anyone know of a way to do this? I've tried everything I can think of, even importing a function then using it as the second argument in jest.mock(), but even then I get an error saying "the second argument of jest.mock() must be a function." It is a function, but for some reason jest doesn't like it.

@ljharb
Copy link
Contributor

ljharb commented Feb 23, 2017

Specifically, I do not want my mocks to be colocated with implementations, and I don't want any folder names with __ in them.

@cpojer
Copy link
Member

cpojer commented Feb 23, 2017

You can only have one manual mock per module. We will eventually introduce a way to configure it better that will continue to work with how we use mocks at FB (@ColCh has a PR for this). For now, I consider manual mocks broken and they aren't great. If anybody can conceive a model that will work better and enables us to codemod current manual mocks, I'm happy to hear it.

As far as customizing the folder location or name goes, Jest is opinionated about a few things and I'm not interested in supporting complexity around these things.

@ColCh
Copy link
Contributor

ColCh commented Feb 23, 2017

Any thing needed from me on that PR?

@ljharb
Copy link
Contributor

ljharb commented Feb 23, 2017

@cpojer it's disappointing that "colocation" and "__tests__" are considered worth changing for tests, but not for mocks. What opinionated stance supports customizing one, but not the other?

@cpojer
Copy link
Member

cpojer commented Feb 23, 2017

@ljharb totally agree that's disappointing! It's absolutely my own subjective decision to be opinionated about this. If you are willing to build and maintain this feature, for the long-term, to customize both the mocks folder and snapshot folders, with all that comes with it, please be my guest. I won't stop you and I will probably merge it, but I have reservations regarding the necessary complexity this might add.

@ljharb
Copy link
Contributor

ljharb commented Feb 23, 2017

Understood, thanks! When I have the time I will both prepare a PR and commit to maintaining any complexity around it.

@rfgamaral
Copy link
Author

I guess my request:

This means that the mocks needs to be inside the app folder but I'd like to keep everything test related inside the tests folder.

Is not currently possible. Correct?

Maybe this should be closed then?

@ljharb
Copy link
Contributor

ljharb commented Feb 24, 2017

It'd be nice to keep it open so I can find it more easily when I get to the PR.

@cpojer
Copy link
Member

cpojer commented Feb 24, 2017

Thanks @ljharb, that is very much appreciated. Just for the record: both mocks and snapshots should be configurable and snapshots need to be configurable so you can look up a test from the snapshot file and vice-versa. Also, keep in mind that this cannot be a breaking change.

@danielhneville
Copy link

@rfgamaral : in the meantime, I've come up with a solution that seems to work for me. In my tests folder, I have a file mocks.js. In that file, I have, for example:

exports.api = {
  getWeather: Promise.resolve({sky: 'Sunny', rain: '10%'}),
  somethingElse: Promise.resolve([{_id:'yg321i14', name:'example'},{...
}

Then, to mock an api call for any component that imports any function from 'root/api', all I need to do is this:

jest.mock('root/api', () => require('../mocks').api)

Hope that helps as a stopgap. You still need to directly mock components, but that's only two lines:

jest.mock('root/components/SomeComponentFolder/SomeComponent')
const SomeComponent = require('root/components/SomeComponentFolder/SomeComponent')

@scottmas
Copy link

scottmas commented Jun 13, 2017

@ljharb @cpojer It seems to me that a good option would be to have an config parameter that allows the mock location to be configured via a regex matcher with capture groups specifying the module that should be mocked. For instance, the existing behavior could be specified with a regex like so:

jest --mockModulesRegex=(^.+)\/__mocks__\/(.+$)
const regex = new RegExp(options.mockModulesRegex);
filePaths.forEach((file) => {
   const match = file.match(regex);
   if(match){
     const mockPath = match.shift();
     const moduleName = match.join(''); //concatenate capture groups
     //Do mocking
   }
})

To keep things sane, we could throw an error if the regexes don't have a single unique match.

Doing it this way would be beneficial for a use case I'm trying to support where I want different mock files for my unit tests (module.unit-mock.js) and my integration tests (module.e2e-mock.js)

@scottmas
Copy link

I'm not sure how this system would work though with node_modules and the like, since a module isn't always defined by its path. Any jest-haste guru on how node modules like "fs" could be accommodated with a regex scheme?

@ljharb
Copy link
Contributor

ljharb commented Jun 13, 2017

@scottmas does jest mocking currently work with node_modules? If so, then I'd say that the regex should only apply for relative paths - ie, not for npm-installed things.

@scottmas
Copy link

scottmas commented Jun 13, 2017

Yep, it does per https://facebook.github.io/jest/docs/manual-mocks.html. Just create a __mocks__ folder as a sibling to node_modules.

Actually, now that I think about it a bit more, as long as the array of files paths filePaths starts at the cwd, we should be fine with the current proposal as long as we make the first capture group optionally empty:

jest --mockModulesRegex="(^.*)\/__mocks__\/(.+$)"

However, we would need to verify that whatever array of file paths jest-haste is operating on (e.g. filePaths) does indeed start at the cwd. And we would need to ensure filePaths does not contain the file extension.

@scottmas
Copy link

Also, it would be nice if we could support multiple concurrent regex definitions. E.g. Support the existing module system but add on support for module.mock.js files and the like:

jest --mockModulesRegex="(^.*)\/__mocks__\/(.+$)" --mockModulesRegex="(^.*)\.mock"  

@ljharb
Copy link
Contributor

ljharb commented Jun 14, 2017

ftr, in my case, I would never want a .mock.js file - I want a mocks folder that is parallel to my code and to my tests, where every filename is identical to the thing it's mocking.

@scottmas
Copy link

scottmas commented Jun 14, 2017

Hmm, yeah, that would require an additional configuration option, since you'd be adding a custom path. At this point, it's probably worth removing this option from the CLI since it would get ugly on the command line. The config values could be similar to moduleNameMapper:

{
    "mockModulesRegex": {
       "^mocks\/(.+$)": "$1"
       "default": true  //Special flag to enable default Jest mocking
    }
}

What do you think? Depending on the implementation details of jest-haste-map, we may need to support a construct like <rootDir> in the regex.

@ljharb
Copy link
Contributor

ljharb commented Jun 14, 2017

For non-node_modules mocks, it should be able to work just like the tests regex does. It makes sense to me to put node_modules mocks under a separate setting.

@rfgamaral
Copy link
Author

I've eventually moved all my test files to the same location as the source files and I no longer have this issue. I'm closing it because this was originally a question and not a feature request.

Feel free to reopen it or open a new issue if necessary.

@ljharb
Copy link
Contributor

ljharb commented Jul 1, 2017

@rfgamaral i'd appreciate it being reopened; this still needs to be fixed.

@ColCh
Copy link
Contributor

ColCh commented Jul 1, 2017

are mocks global in current jest version ?

@rfgamaral rfgamaral reopened this Jul 2, 2017
@kuldeepkeshwar
Copy link

@rfgamaral any update or workaround for this?

@dmythro
Copy link

dmythro commented Jul 7, 2017

Also wanna make them in the same dir, called tests. I don't like those __naming__ at all.

@rfgamaral
Copy link
Author

@kuldeepkeshwar I don't know, I just reopened it per @ljharb's comment.

@OshotOkill
Copy link

Looking forward to a solution here. Creating a folder __mock__ as a sibling for every component or module that I want to mock really messes up my directory structure.

@LaloHao
Copy link

LaloHao commented Jan 12, 2018

You can setup .babelrc with module-resolver plugin and add your paths

{
 "plugins": [
   ["module-resolver", {
     "root": ["./src"],
     "alias": {
       "^mocks": "./__mock__",
       "underscore": "lodash"
     }
   }]
 ]
}

import { userMock } from 'mocks';

@nurbek-ab
Copy link

nurbek-ab commented May 21, 2018

I found out that specifying
"roots": ["<rootDir>/src/", "<rootDir>/tests/"]
in jest's config would allow to move the uppermost __mocks__ folder to tests directory.

@alvis
Copy link

alvis commented May 21, 2018

Does it sound like a bug rather than a feature?

@nurbek-ab
Copy link

@alvis No, it's not a bug. Actually this behavior is documented.

@alvis
Copy link

alvis commented May 22, 2018

yes, you're right!

@rfgamaral
Copy link
Author

Can this be closed now?

@ljharb
Copy link
Contributor

ljharb commented May 22, 2018

Having to define the tests dir as a root dir is a nice workaround, but it doesn’t do what this issue wants - to change where mocks live, as a direct setting.

@SimenB
Copy link
Member

SimenB commented May 22, 2018

FWIW, there's a PR for custom snapshot locations: #6143

@SimenB
Copy link
Member

SimenB commented May 22, 2018

And the conclusion in #6193 was that we need to expose the normal resolver - that should potentially allow you to extend ours, and implement your own lookup for mocks. Not sure about that last one, though, but it might be a starting point for anyone wanting to send a PR 🙂

@geekox86
Copy link

Greetings gentlemen,

I am really happy with your outstanding efforts with Jest.

I was wondering if we can have something similar to snapshotResolver for mocks? What is the status on this issue?

Thank you!

@bensampaio
Copy link
Contributor

I was wondering exactly the same as @geekox86. Are there any plans to create a resolver to change the location of mocks? For integration with my IDE it would be a lot better to be able to place mocks just next to the mocked file instead of inside a mocks folder.

@parzhitsky
Copy link

parzhitsky commented Jun 18, 2020

Enforcing these __conventions__ __around__ __filenames__ makes Jest grab much more attention to itself than it deserves, making testing a significantly bigger part of an application, and the application significantly less organized.

Compare this:

/
  src/
!   __tests__
!     index.test.js
    components/
!   __tests__
!     some-component.test.js
!     another-component.test.js
!     __snapshots__
!       some-component.test.js.snap
!       another-component.test.js.snap
      some-component.js
      another-component.js
    api/
!   __tests__
!     __mocks__
!       some-api-method.js
!       another-api-method.js
!     some-api-method.test.js
!     another-api-method.test.js
      some-api-method.js
      another-api-method.js
    index.js

… to this:

/
  src/
    components/
      some-component.js
!     some-component.test.js
!     some-component.test.js.snap
      another-component.js
!     another-component.test.js
!     another-component.test.js.snap
    api/
      some-api-method.js
!     some-api-method.test.js
!     some-api-method.mock.js
      another-api-method.js
!     another-api-method.test.js
!     another-api-method.mock.js
    index.js
!   index.test.js

… and this:

/
  src/
    components/
      some-component.js
      another-component.js
    api/
      some-api-method.js
      another-api-method.js
    index.js
! snapshots/
!   components/
!     some-component.test.js.snap
!     another-component.test.js.snap
! mocks/
!   api/
!     some-api-method.js
!     another-api-method.js
! tests/
!   components/
!     some-component.test.js
!     another-component.test.js
!   api/
!     some-api-method.test.js
!     another-api-method.test.js
!   index.test.js

Being highly opinionated about an open source project is always a pain for the users of this project; there has to be some flexibility when it comes to file structure.

@bartoszputek
Copy link

I found a solution to this problem with ES6 imports, similarly to @danielhneville answer #2726 (comment).

Example folder structure:
image

Let's say we'd like to mock User.ts class placed in frontend/components/user.

export default class User {
  name: string;

  constructor() {
    this.name = 'Tom';
  }
}

Next, prepare a mock for User.ts in tests/frontend/mocks/user

export default class User {
  name: string;

  constructor() {
    this.name = 'John';
  }
}

Finally, set up tests using our mock

import User from 'frontend/components/user'; // Mocked class
import UserMock from 'tests/frontend/mocks/user'; // Class mock

jest.mock('frontend/components/user', () => ({ // Path to Mocked class
  __esModule: true,
  default: jest.fn(() => new UserMock()),
}));

test('User constructor test', () => {
  const user = new User();

  expect(user.name).toBe('John');
});

and the test will pass because we are using the mock.

@SimenB SimenB removed the Question label Feb 25, 2022
@github-actions
Copy link

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Feb 25, 2023
@ljharb
Copy link
Contributor

ljharb commented Feb 25, 2023

bump

@github-actions github-actions bot removed the Stale label Feb 25, 2023
Copy link

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Feb 25, 2024
@ljharb
Copy link
Contributor

ljharb commented Feb 26, 2024

nothing's ever stale

@github-actions github-actions bot removed the Stale label Feb 26, 2024
@Jason-Terry
Copy link

Jest is a bad framework for this, and we should all feel bad.

2024 and we are still using this silly method?

@sepehr
Copy link

sepehr commented Feb 29, 2024

Chill, Jason, chill. It's opensource.

@sganot-r7
Copy link

That was disappointing, to scroll till the end and find only workarounds 😞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests