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

[Feature]: reconsider how to handle file extensions in import path specifiers #4013

Open
thw0rted opened this issue Feb 2, 2023 · 3 comments
Labels
🚀 Feature Request new suggested feature

Comments

@thw0rted
Copy link

thw0rted commented Feb 2, 2023

🚀 Feature Proposal

The examples shipped with this project should include both tests and code-under-test which imports from relative paths using a file extension. Any additional configuration required to support this should work out of the box, without additional steps required by the user.

Motivation

TypeScript written to run in a Node environment is changing. Since the introduction of moduleResolution: 'nodeNext', users are being encouraged to write relative import path specifiers with an explicit file extension, which must be .js, regardless of whether the file being imported is written in JS or TS.

If you have a whole afternoon to kill, go ahead and read microsoft/TypeScript#50152, but otherwise take my word for it: this will become more common over time. This convention is not supported out of the box today, and it should be.

Jest does not officially support testing TS, so they aren't going to take responsibility for making this work. ts-jest should at least include examples of using this convention, and should either make it work without configuration, or specify which additional steps are required in the documentation.

Example

// @filename foo.ts
export const foo = "hello";

// @filename foo.spec.ts
import { foo } from './foo.js';

it('should exist', () => {
  expect(foo).toBeDefined();
});

ETA: previous discussion was here #1057

@thw0rted
Copy link
Author

thw0rted commented Feb 2, 2023

The docs include a custom resolver to support mapping mts extensions to mjs. I extended their solution to solve this problem as well:

// I named the file `jest-resolver.cjs` to ensure it's treated as CJS regardless of parent package-file.
// From https://github.com/kulshekhar/ts-jest/blob/main/e2e/native-esm-ts/mjs-resolver.ts
// Via https://kulshekhar.github.io/ts-jest/docs/guides/esm-support/#support-mts-extension

const mjsResolver = (path, options) => {
  const mjsExtRegex = /\.mjs$/i;
  const jsExtRegex = /\.js$/i;
  const resolver = options.defaultResolver;
  if (mjsExtRegex.test(path)) {
    try {
      return resolver(path.replace(mjsExtRegex, '.mts'), options);
    } catch (err) {
      // use default resolver
    }
  } else if (jsExtRegex.test(path)) {
    try {
      return resolver(path.replace(jsExtRegex, '.ts'), options);
    } catch (err) {
      // use default resolver
    }
  }

  return resolver(path, options);
};

module.exports = mjsResolver;

I still think this should be supported out of the box, FWIW.

@ahnpnl
Copy link
Collaborator

ahnpnl commented Feb 3, 2023

We can provide a default resolver and include in doc.

PR is welcome to update doc, examples and maybe add a resolver.

@sentience
Copy link

sentience commented Aug 30, 2023

Is a resolver necessary? In my project, I was able to build with .js relative import paths using the documented ESM configuration in my Jest config:

module.exports = {
  preset: "ts-jest/presets/default-esm",
  transform: {
    "<regex_match_files>": [
      "ts-jest",
      {
        tsconfig: "<rootDir>/tsconfig.json",
        isolatedModules: true,
        useESM: true,
      },
    ],
  },
  moduleNameMapper: {
    "^(\\.{1,2}/.*)\\.js$": "$1",
  },
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🚀 Feature Request new suggested feature
Projects
None yet
Development

No branches or pull requests

3 participants