Setting up tsconfig with spec/test folder
Asked Answered
C

7

133

Say I put my code under src and tests under spec:

+ spec
+ --- classA.spec.ts
+ src
+ --- classA.ts
+ --- classB.ts
+ --- index.ts
+ tsconfig.json

I want to only transpile src to the dist folder. Since index.ts is the entry point of my package, my tsconfig.json look like this:

{
  "compileOptions": {
    "module": "commonjs"
    "outDir": "dist"
  },
  "files": {
    "src/index.ts",
    "typings/main.d.ts"
  }
}

However, this tsconfig.json does not include the test files so I could not resolve dependencies in them.

On the other hand, if I include the test files into tsconfig.json then they are also transpiled to dist folder.

How do I solve this problem?

Carolinian answered 18/2, 2016 at 0:28 Comment(1)
Similar question and working (quite elegant) answer here: https://mcmap.net/q/174836/-vscode-ts-language-features-unavailable-when-tests-are-not-included-in-the-tsconfig.Wenona
C
100

I ended up defining multiple config files and use extends to simplify them.

Say I have two files: tsconfig.json and tsconfig.build.json

// tsconfig.json
{
  ...
  "exclude": [...]
}

// tsconfig.build.json
{
  ...
  "files": [ "typings/index.d.ts", "src/index.ts" ]
}

This way, I can have fine control on what to build (using tsc -p tsconfig.build.json) and what the ts language service (IDE) handles.

UPDATE: now as my projects grow, I ended up having more config files. I use the "extend" feature that is now available in TypeScript:

// tsconfig.base.json
{
  // your common settings. Mostly "compilerOptions".
  // Do not include "files" and "include" here,
  // let individual config handles that.
  // You can use "exclude" here, but with "include",
  // It's pretty much not necessary.
}

// tsconfig.json
{
  // This is used by `ts language service` and testing.
  // Includes source and test files.
  "extends": "./tsconfig.base.json",
  "atom": { ... },
  "compilerOptions": {
    // I set outDir to place all test build in one place,
    // and avoid accidentally running `tsc` littering test build to my `src` folder.
    "outDir": "out/spec"  
  }
  "include": [ ... ]
}

// tsconfig.commonjs.json or tsconfig.systemjs.json or tsconfig.global.json etc
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    // for some build this does not apply
    "declaration": true/false,
    "outDir": "dist/<cjs, sys, global, etc>",
    "sourceRoot": "..."
  },
  // Only point to typings and the start of your source, e.g. `src/index.ts`
  "files": [ ... ],
  "include": [ ... ]
 }
Carolinian answered 31/5, 2016 at 20:43 Comment(2)
It might now be worth using the Typescript 3 Project Refernces feature, as described in #51632286Excision
That is more for monorepo project referencing. I use it in my monorepos such as github.com/unional/standard-logCarolinian
D
63

Here is a detailed solution to manage sources and tests:

  • compilation includes sources and tests folders/files
  • build includes only sources
  • IDE (VSCode, ...)

Config

The solution is based on 2 tsconfig.json files as mentioned in other answers.

The main ./tsconfig.json (used for compilation and IDE):

{
  "compileOptions": {
    "module": "commonjs"
    "outDir": "dist"
  },
  "include": [
    "spec/**/*.spec.ts"
  ],
  "files": [
    "src/index.ts"
  ]
}

The second ./tsconfig-build.json (used for build):

{
  "extends": "./tsconfig.json",
  "exclude": [
    "spec/**/*.spec.ts"
  ]
}

Note: we exclude test files that have been included previously

Build

Build command: tsc -p tsconfig-build.json

Or npm run build if script is added in package.json:

{
  "scripts": {
    "build": "tsc -p tsconfig-build.json",
}

Danille answered 14/2, 2020 at 9:55 Comment(0)
S
18

This is somewhat dependent on whatever testing framework you're using but I like to use ts-node to compile my test files. Using mocha, your npm test script might look like:

"mocha": "mocha test/ --compilers ts:ts-node/register --recursive"

In your tsconfig.json, make sure to remove the rootDir option.

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6",
        "noImplicitAny": false,
        "removeComments": true,
        "sourceMap": true,
        "outDir": "lib"
    },
    "include": [
        "src/**/*.ts"
    ],
    "exclude": [
        "node_modules",
        "lib",
        "typings/**"
    ]
}

When you try to run typescript with rootDir set to src or whatever the base folder for your application code is, it'll disallow any compilation in a directory that sits outside, such a tests. Using ts-node, you can easily keep everything separate without having to have separate TypeScript configuration files.

Snocat answered 11/12, 2016 at 9:40 Comment(1)
Not separating into multiple config files has the drawback of distributing extra (test) files in the package. Also, your two include are redundant. You only need src/**/*.tsCarolinian
C
2

I think you should not use 'files' option in your config. Instead you can exclude unwanted files and have it like this:

{ 
    "compilerOptions": { 
        "module": "commonjs", 
        "outDir": "dist"
    },
    "exclude": [
        "node_modules",
        "dist",
        "typings/browser.d.ts",
        "typings/browser/**"
    ]
} 

This will preserve your original structure in the 'dist' folder without mixing tests and app js files:

--dist
----spec
-------....
----src
-------....
Custer answered 18/2, 2016 at 7:48 Comment(1)
But he doesn't want the test files to end up in the dist folder at all. Which is logical, they are not for publication. Having them in a subdir there does not really help. I too want my project files and only those end up in lib/, and the files under test/ remain where they are. If the .js version of the test files is moved somewhere else I would have two new problems: a) Exclude them from publication, b) have test runners find them, sure solvable, but it piles hack on top of hack. Unnecessary if tsc could just store the test files in the test directory.Shaylynn
L
2

Simply add an include directory of the source files you want compiled and included in your build. Next, specify your exclude directory in tsconfig.json. For your use case it isn't necessary to have multiple tsconfig files.

{
  "include": [ "src/**/*" ],
  "exclude": [ "./spec" ]
}
Longrange answered 2/4, 2021 at 16:50 Comment(3)
Will this setup allow intellisense and refactoring in VSCode?Wenona
You will need to keep this tsconfig file updated manually when you do large refactors (changing the source folder or where your specs are). There might be a VSCode plugin to detect these changes, but I doubt it.Longrange
@Wenona nope, for VSCode to auto-import/code-complete your files, it must be included in the respective tsconfigPhail
S
0

For me it was because my jest version was 26 and my ts-jest version was 27 so they were out of sync.

yarn jest --version
yarn add ts-jest@26

my jest.config.js

module.exports = {
    preset: "ts-jest",
    moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
    transform: {
        "^.+\\.tsx?$": "ts-jest",
    },
    globals: {
        "ts-jest": {
            diagnostics: false,
        },
    },
    testMatch: ["**/*.(test|spec).(ts|tsx|js|jsx)"],
    coveragePathIgnorePatterns: ["/node_modules/"],
    coverageReporters: ["json", "lcov", "text", "text-summary"],
    transformIgnorePatterns: [
        "<rootDir>/node_modules/(?!(firebase/.*|react/.*)/)",
    ],
    testEnvironment: "jest-environment-jsdom-sixteen",
    moduleNameMapper: {
        "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
            "<rootDir>/__mocks__/mocks.js",
        "\\.(css|less|scss)$": "<rootDir>/__mocks__/mocks.js",
        "^src/(.*)": "<rootDir>/src/$1",
    },
};

Scorpius answered 22/8, 2021 at 6:19 Comment(0)
S
0

user1067920's answer was a good starting point, but I wanted to use vite, but you can't configure the vite tsconfig path. I found a plugin vite-plugin-tsconfig.

My goals:

  • I want tsconfig.json to include tests, so my IDE will show errors for tests
  • I want my build output to exclude tests

I had one issue with vite-plugin-tsconfig. The plugin works by replacing tsconfig.json with a file you specify in the config:

import tsconfig from "vite-plugin-tsconfig";

   ...
    tsconfig({
      filename: "tsconfig.build.json",
    }),

If I do what user1067920 suggests, "extends": "./tsconfig.json", would be a circular reference.

My solution

I have 4 tsconfig files 😂️:

  • tsconfig.node.json (unchanged, config used for vite (build process))
  • tsconfig.json
{
  "extends": "./tsconfig.base.json",
}
  • tsconfig.build.json
{
  "extends": "./tsconfig.base.json",
  "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"],
}

  • tsconfig.base.json
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noImplicitAny": true,
    "noUncheckedIndexedAccess": true,

    /* shadcn/ui as per https://ui.shadcn.com/docs/installation/vite */
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "exclude": ["node_modules"],
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

Severable answered 2/4 at 11:51 Comment(2)
Further thoughts: i don't think my approach here is very good. When debugging, my tsconfig.json gets replaced by the plugin, and doesn't get reset when the debug stops. Stuck with // GENERATED via 'vite-plugin-tsconfig' - this should be automatically created and deleted inside the build process.. I'll find a different approachSeverable
I noticed there was no different in bundle size if I include/exclude test files, so presumably they're not being included in the bundle. So my tsconfig.json which is used by IDEs and vite has "exclude": ["node_modules"], and doesn't exclude tests.Severable

© 2022 - 2024 — McMap. All rights reserved.