vscode-jest icon indicating copy to clipboard operation
vscode-jest copied to clipboard

Support monorepos

Open Pajn opened this issue 7 years ago • 31 comments

It would be great if this plugin supported monorepos. Either by passing the --projects option to jest or by starting a jest process for every subproject (folder with package.json file in it). In the case of multiple Jest processes the current setting paths should be relative from each subproject.

Pajn avatar Jul 19 '17 07:07 Pajn

As you can customise the command used to trigger jest (jest.pathToJest) then I think specific support for projects probably doesn't need to go in

orta avatar Jul 19 '17 11:07 orta

I have tried adding a script to the root package.json with all projects specified with --projects and specifying yarn test -- as jest.pathToJest but then there are no changes detected even though the same command in the terminal detects changes and run just fine.

Pajn avatar Jul 19 '17 12:07 Pajn

It does support monorepos, we have it working here for one of our projects using lerna. Jest resides at the root of your monorepo, correct? We added this to our .vscode/settings.json file:

"jest.pathToConfig": "./jest.config.js",
"jest.pathToJest": "./node_modules/.bin/jest",

glambert avatar Jul 20 '17 13:07 glambert

we also have a lot of problems with vscode-jest for our lerna managed monorepo.

we would like to have the root vscode workspace able to watch for all file changes in the packages, report test failures on the problems inspector and update test decorators just like in the single project case.

We have tried both approaches:

  1. use jest's monoreport support, i.e. use the projects in jest configuration.
    • problem 1: during "--showConfig", jest report different config file format that includes all package's config into "configs" (instead of "config" for single project), therefore vscode-jest failed to parse the config output and will fallback to the default settings, which currently only looking for js(x) pattern.
    • problem 2: if the combo config data exceed 8K, the data received in the child_process.spawn is truncated for some reason, at least on Mac.
    • problem 3: this is not vscode-jest issue, but jest didn't seem to be able to run jest --watch for monoreport, it got stuck at the first package, so this approach might simply not feasible at this point...
  2. use lerna's test support, i.e. "jest.pathToJest": "lerna run --parallel test --",
    • problem 1: there are many config file chunks reported back during the --showConfig, which vscode-jest didn't seem to know how to handle, so again it fallback to the default settings.
    • problem 2: the jest runner used the --outputFile with a tmp file when running the tests, lerna will just copy this command to every package, therefore they keep override each other's test result.
    • problem 3: lerna will prefix every output with the package name, which confuses vscode-jest many string based lookup, such as stringValue.startsWith("Test results written to")... in Runner.js.

To further complicate the issue, our packages are not uniformed, i.e. there are typescript, javascript, react and react-native, therefore the default settings, which only look for js(x) patterns, doesn't work for us.

approach 2 is working, as far as running jest with --watch, but vscode-jest simply can't parse the result and update the editor accordingly. approach 1, as mentioned above, is not working with or without vscode-jest.

Maybe we are missing something obvious, @ls-guillaume-lambert, do you mind sharing with us how you get it to work? Thx.

connectdotz avatar Sep 24 '17 20:09 connectdotz

We have a much simpler setup with only React components, no TypeScript or any extra layer. The approach I mentioned in https://github.com/orta/vscode-jest/issues/129#issuecomment-316704770 works for us, nothing else is in place other than those .vscode/settings.json configs.

glambert avatar Sep 25 '17 15:09 glambert

thanks @ls-guillaume-lambert, so looks like you just run jest on the root project and has it watch and run for all tests below with the same jest config file. Yes that should work if all the tests are "uniform", i.e. same preset, rules, patterns etc. However, many monorepo projects are cross-platform and languages, it will be nice for vscode-jest to support a true "multi-jest" style monorepo...

connectdotz avatar Sep 25 '17 19:09 connectdotz

Indeed, we are using the same preset/rules/patterns for all our packages. Best of luck with your setup 👍

glambert avatar Sep 25 '17 19:09 glambert

ok, finally get the jest to work for our environment via command line. vscode-jest is still having quite a few problems:

  1. the jest 21.0.0+ has changed the output format in --showConfig, therefore, vscode-jest failed to parse the config. looks like there is already a PR but hasn't been accepted yet.
  2. vscode-jest doesn't report the failed test "suite", just the failed tests. So the tests in failed sub packages can be left out silently.
  3. vscode-jest do not show failed tests in the problem inspector until you open some test files.
  4. (feature) when vscode-jest first start up, it should run a full tests and report any test/test-suite failures in the problem inspector, then go into the watch mode. In addition to the bug mentioned above, vscode-jest just run jest in watch mode which will not guarantee to run all the tests initially. So maybe a 2 phase approach? run all tests once then go into the watch mode...

I will submit PR to address some of these issues...

connectdotz avatar Sep 27 '17 13:09 connectdotz

^ These are great ideas 👍

orta avatar Sep 27 '17 14:09 orta

@connectdotz can you please share with me your setup? i'm having the same issue Thanks!

Bnaya avatar Dec 30 '17 00:12 Bnaya

@Bnaya sorry for the delay, basically you need a superset jest config with instructions for all of your packages.

Here is my jest config on the root/project level that will run jest for all packages including react-native package:

// jest.config.js
module.exports = {
  transform: {
    ".(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js",
    "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
  },
  mapCoverage: true,
  bail: false,
  verbose: true,
  collectCoverageFrom: ["src/**/*.ts[x]?", "!src/**/*.test.ts[x]?", "!src/**/*.d.ts"],
  coveragePathIgnorePatterns: ["/__tests__/", "/node_modules/"],
  testEnvironment: "node",
  testRegex: "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js|jsx)$",
  moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "core", "node"],
  cacheDirectory: ".jest/cache",
  coverageDirectory: "coverage",
  coverageReporters: ["text-summary", "html"],
  testPathIgnorePatterns: [
    "/node_modules/",
    "/lib/",
    "/dist/",
    "/integration-tests/",
    "\\.snap$",
    "/build/",
    "/coverage/",
    "/packages/.*/build",
    "/packages/.*/dist",
    "/packages/.*/lib"
  ],
  modulePathIgnorePatterns: [
    "./packages/ites/node_modules/react-native/.*",
    "./packages/ites/node_modules/react-native/Libraries/react-native/"
  ],

  transformIgnorePatterns: ["node_modules/(?!(jest-)?react-native|react-clone-referenced-element|react-navigation)"],
  moduleNameMapper: {
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
      "<rootDir>/__mocks__/fileMock.js",
    "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
    "^React$": "<rootDir>/node_modules/react"
  },
  projects: ["<rootDir>/packages/*"],
  // hacking because jest couldn't find the react-native preset under packages/ites
  // copied from react-native/jest-preset.json
  haste: {
    defaultPlatform: "ios",
    platforms: ["android", "ios", "native"],
    providesModuleNodeModules: ["react-native"]
  },
  setupFiles: ["<rootDir>/packages/ites/node_modules/react-native/jest/setup.js"]
};

and my tsconfig.json for completion:

{
  "compilerOptions": {
    "jsx": "react",
    "outDir": "./lib",
    "experimentalDecorators": true,
    "module": "commonjs",
    "target": "es5",
    "lib": [
      "es6",
      "dom"
    ],
    "emitDecoratorMetadata": true,
    "sourceMap": true,
    "declaration": true,
    "rootDir": "src",
    "removeComments": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  },
  "include": [
    "src/**/*",
    "packages/*/src/**/*"
  ],
  "exclude": [
    "node_modules",
    "build",
    "dist",
    "acceptance-tests",
    "webpack",
    "jest",
    "coverage",
    "src/setupTests.ts"
  ]
}

hope it help... good luck.

connectdotz avatar Jan 03 '18 17:01 connectdotz

@connectdotz Thanks! So if i got it correctly, it does not support different setup/config for each package? Like separate tsconfig.json when using ts-jest and

Bnaya avatar Jan 04 '18 19:01 Bnaya

@Bnaya that is correct

connectdotz avatar Jan 07 '18 14:01 connectdotz

Would just like to add my name to the list of people who would love this feature. We have a monorepo and currently the only way for us to debug tests is to have a different instance of vs code open for each package.

MaxboDev avatar May 14 '18 15:05 MaxboDev

A note that while this issue is about mono-repos the --projects argument isn't just for that and is also used for custom runners like jest-runner-eslint, jest-runner-stylelint, it'd be great to just see enhanced support for the projects feature where discovery of projects arrays in config or as argument lists for the command get output filtering like a dropdown that lets you pick which project to run.

wldcordeiro avatar May 25 '18 01:05 wldcordeiro

I'll help you build it if you can help with an example repo and Jest setup @wldcordeiro.

seanpoulter avatar May 25 '18 01:05 seanpoulter

@seanpoulter I don't have a repo on hand but I think we could make one with this as a starting point.

https://gist.github.com/wldcordeiro/6dc2eb97a26a52d548ed4aa86f2fc5c0

I pretty much lifted those as is from a real project.

wldcordeiro avatar May 25 '18 02:05 wldcordeiro

Sometimes I lose a state in __tests__ and I need to resave test file to get UI changes. Anyone knows how to fix it?

XBeg9 avatar Nov 22 '18 10:11 XBeg9

Those symptoms sound familiar @XBeg9. That used to happen when Jest ran in watch mode and there were no changes. I'd suggest running the extension locally and setting a conditional breakpoint to fire when we're getting the data back from Jest and it's empty.

seanpoulter avatar Nov 22 '18 22:11 seanpoulter

Sorry, not sure I understand this :) I'd suggest running the extension locally and setting a conditional breakpoint to fire when we're getting the data back from Jest and it's empty. @seanpoulter

XBeg9 avatar Nov 23 '18 06:11 XBeg9

This issue is pretty cold but as a new monorepo and vscode-jest user, this problem became evident fairly quick with no immediate solution. I really want to avoid extra files in the repo as a workaround.

jsphstls avatar Apr 10 '19 14:04 jsphstls

Speaking for myself here, it's not clear that "we the maintainers" have much bandwidth these days. If you're motivated to move this forward @jsphstls, we could probably nudge @connectdotz and @ls-guillaume-lambert to weigh in on their experience and how we'd need to update the extension. From what I can gather from skimming the issue, the "solution" was to add extra setup per project.

seanpoulter avatar Apr 10 '19 15:04 seanpoulter

What's about to do something like that? (I didn't look at your code yet, but this would be an idea to get the root folder for the current active file)

import * as pkgUp from 'pkg-up';

async function getRootFolder(document: vscode.TextDocument) {
	const pkg = await pkgUp({ cwd: document.fileName });
	if (pkg) {
		const rootFolder = dirname(pkg);
		return rootFolder;
	}
}

export function activate(context: vscode.ExtensionContext) {
      // ... some code
		if (vscode.window.activeTextEditor) {
			const rootFolder = getRootFolder(vscode.window.activeTextEditor.document);
                        // ....
		}
}

apiel avatar May 13 '19 10:05 apiel

for people with monorepo projects, multi-root support has finally arrived, feel free to give it a try: 3.0.0-preRelease ...

connectdotz avatar Jun 20 '19 19:06 connectdotz

The workspace feature didn't help in my case.

I have tests that contain JSX and are written in TypeScript, and here are two "manual" examples of how to possibly run the tests:

✅ This works:

yarn workspace @example/lib test

🚫 This doesn't work:

node_modules/.bin/jest packages/example/src/Test.tsx

The extension probably invokes the test close to the second example as I get the same, well-known error:

Jest encountered an unexpected token. This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

borekb avatar Oct 01 '19 09:10 borekb

Same – the workspace feature doesn't help me either. My only workspace root is the root of my monorepo. My individual packages are just in a packages directory.

If I set up an instance of vscode with my package as the workspace root, vscode-jest can't find Jest, because it's installed above the individual package.

schmod avatar Oct 23 '19 14:10 schmod

this plugin does some simple "guess" of how to run your tests with jest, while it is right for most simple cases, it most likely will not be able to cover the more sophisticated use cases, and that is where jest.pathToJest customization comes in...

for your workspace folders (the directory under "packages" for most monorepo setup), you might need to customize the jest.pathToJest to tell this plugin how do you run your tests there.

For example, if you have a React package, most likely you are running yarn test or npm test there, you can add jest.pathTojest in vscode's folder setting accordingly; If all of your packages are running yarn test, then you only need to set up jest.pathToJest once in your workspace settings. (see here for vscode multi-root workspace settings). The setting you wangt to add will be something like this:

"jest.pathToJest": "yarn test",

As long as you can run your tests from your package, you can construct this plug in to do the same via the custom settings provided, such as jest.pathToJest...

connectdotz avatar Oct 23 '19 21:10 connectdotz

I can confirm that the solution provided by @connectdotz does work for a collection of create-react-apps without typescript.

Bit of some-monorepo.code-workspace:

{
  "settings": {
    "jest.pathToJest": "yarn run jest", // the "jest" command exists in each package
    "jest.disabledWorkspaceFolders": ["Root"] // contains everything, would duplicate test runs
  },
  "folders": [
    {
      "name": "Root",
      "path": "."
    },
    {
      "name": "SomePackage",
      "path": "packages/some-package/"
    }
}

Bit of some-package/package.json:

{
  "name": "@namespace/some-package",
  "private": true,
  "scripts": {
    "jest": "react-scripts test"
  },
  "devDependencies": {
    "react-scripts": "^3.1.1"
  }
}

jsphstls avatar Oct 23 '19 22:10 jsphstls

Goal

My goal is to get this vscode-jest "Debug" button to work with yarn workspaces and VS Code workspaces.

image

<root>/package.json

This is my yarn workspace configuration. The jest dependencies for my packages is installed in <root>/node_modules/jest. The dependencies DOES NOT live inside <root>/packages/@organization/**/node_modules

{
  "name": "project-name",
  "version": "0.0.0",
  "private": true,
  "workspaces": {
    "packages": [
      "packages/**"
    ]
  },

Solution that works for me

I manage to get it working with these configuration

<root>/project-name.code-workspace

{
  "folders": [
    {
      "name": "root",
      "path": "."
    },
    {
      "name": "@organization/project-abc",
      "path": "./packages/@organization/project-abc"
    }
  ],

  "settings": {
    "jest.pathToJest": "node_modules/.bin/jest",
    "jest.pathToConfig": "./jest.config.js",
  },
}

<root>/packages/@organization/project-abc/.vscode/launch.json

  1. Add a default jest launch configuration image
  2. Edit its program path to reference the root folder
{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "name": "vscode-jest-tests",
      "request": "launch",
      "program": "${workspaceFolder}/../../../node_modules/jest/bin/jest"
      "args": [
        "--runInBand"
      ],
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
    }
  ]
}

amoshydra avatar Dec 26 '19 08:12 amoshydra

@amoshydra You saved my day !!!

lwyj123 avatar Jul 14 '20 07:07 lwyj123