Closed quophyie closed 5 months ago
Strange...does this happen with any other modules, or just Helmet? Is ts-jest using the same TypeScript configuration as ts-node?
Hi @EvanHahn Thanks for the quick response
This only happens with helmet module only. Other modules are OK
jest, ts-jest and ts-node all use the same typescript config .
here is the jest.config.ts with the embedded ts-jest config
jest.config.ts
import type { JestConfigWithTsJest } from 'ts-jest';
const jestConfig: JestConfigWithTsJest = {
testFailureExitCode: 1,
moduleFileExtensions: ['ts', 'js', 'json'],
extensionsToTreatAsEsm: ['.ts'],
preset: 'ts-jest/presets/default-esm',
transform: {
'^.+\\.(ts|tsx)$': [
'ts-jest',
{
useESM: true,
tsconfig: 'tsconfig.json',
},
],
},
testMatch: [
'**/*.test.(ts|js)',
'**/*.spec.(ts|js)'
],
testPathIgnorePatterns: [
'<rootDir>/build',
'<rootDir>/node_modules/'
],
testEnvironment: 'node',
};
export default jestConfig;
ts-node also uses the exact same tsconfig.json
Here is the ts-node start script in the package.json
"start": "ts-node --esm --project tsconfig.json --transpile-only main.ts"
Everything looks okay at a glance, but ESM + TypeScript + Jest often causes problems.
What's the full error you're seeing? What happens if you add // @ts-ignore
before importing Helmet?
@EvanHahn Here is the full console log
yarn run v1.22.19
warning package.json: No license field
$ cross-env NODE_OPTIONS=--experimental-vm-modules jest -i --passWithNoTests --detectOpenHandles --forceExit --runInBand
FAIL ./main.test.ts
● Test suite failed to run
main.test.ts:4:1 - error TS2349: This expression is not callable.
Type 'typeof import("/home/dman/projects/helmet-issue-441/node_modules/helmet/index")' has no call signatures.
4 helmet();
~~~~~~
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.912 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Hi @EvanHahn
I added the //@ts-ignore
and that seems to have fixed it i.e.
in my main.test.ts
import {jest} from '@jest/globals'
import helmet from 'helmet'
//@ts-ignore
helmet();
describe('Helmet Issue 441', () => {
it('fails on call to helmut() function', () => {
expect(true).toBe(true);
});
});
Thanks for the help
Would you know why the //@ts-ignore
solves the issue?
It seems like ts-jest isn't pulling in the right type declarations for some reason. I don't know why.
// @ts-ignore
simply tells TypeScript to ignore the next line. This is not a true fix, but a workaround for this problem.
Is there a way to see what type declaration file ts-jest is using? Maybe some verbose logging mode or something?
I have the same problem. The type correctly points towards index.d.ts
. However, the types are starting to behave correctly only if I do const helmet = require('helmet').default
.
Awhile ago, I chatted with a TypeScript team member who endorsed the way Helmet exports its types. But I concede that it's complicated and it's possible I made a mistake somewhere.
Is it possible that ts-jest (or some sub-system) is getting confused, trying to treat an ES module as a CommonJS one? Or something like that?
when you use "moduleResolution": "node",
it will work.
Any other resolution method will fail. I see this issue happening in the validator.js codebase too. I have to add in another default import.
When I change the moduleResolution
to anything other than node
helmet will not work.
{
"compilerOptions": {
"target": "ESNext",
"lib": ["ESNext"],
"module": "ESNext",
"outDir": "./dist",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowImportingTsExtensions": true
},
"exclude": [
"node_modules"
],
"extends": "../../packages/tsconfig/base.json",
"include": ["."]
}
// base.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Default",
"compilerOptions": {
"composite": false,
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"allowImportingTsExtensions": true,
"noEmit": true,
"inlineSources": false,
"isolatedModules": true,
"moduleResolution": "node",
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true,
"skipLibCheck": true,
"strict": true,
"strictNullChecks": true
},
"exclude": ["node_modules"]
}
// package.json (abbreviated)
{
"name": "api",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"start": "node dist/index.js",
"dev": "nodemon",
"build": "tsup",
"clean": "rimraf dist",
"typecheck": "tsc --noEmit",
"lint": "eslint src/",
"test": "DOTENV_CONFIG_PATH=.env.test jest --detectOpenHandles"
},
"jest": {
"preset": "@repo/jest-presets/jest/node",
"setupFiles": [
"dotenv/config"
],
"globalSetup": "<rootDir>/test/global-setup.ts",
"globalTeardown": "<rootDir>/test/global-teardown.ts",
"setupFilesAfterEnv": [
"<rootDir>/test/setup-file.ts"
]
},
"dependencies": {
"express": "^4.18.2",
"helmet": "^7.1.0",
},
"devDependencies": {
"esbuild": "^0.19.7",
"esbuild-register": "^3.5.0",
"eslint": "*",
"jest": "^29.7.0",
"jest-fetch-mock": "^3.0.3",
"nodemon": "^3.0.2",
"supertest": "^6.3.3",
"ts-node": "^10.9.1",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
}
}
I'm just using a vanilla express js setup with the use(helmet())
and import helmet from 'helmet'
This a turbo monorepo using pnpm but the TS-Config is working fine with other packages.
doing the: const helmet = require('helmet').default
works when I change moduleResolution to ESNext only.
To work with Node, I expect that "moduleResolution"
needs to be set to "nodenext"
, "node10"
, or one of its aliases. According to the docs, you don't always get this by default.
If I downgrade to 6.1.4, the error is gone. The 6.1.5 commit: https://github.com/helmetjs/helmet/commit/f8ae480dbb984134713ef19d3ef546b9d1ea1dc1
@tbn-mm Could you create a sample project that reproduces your issue?
There hasn't been anything actionable on this issue for months so I'm going to close. Please open a new issue if you run into any problems!
Hi
I am getting the error below when I run tests with jest, ts-jest where a module uses helmet
I am using ESM (ECMAScript modules) and node version
19.9.0
and helmetv7.0.0
The weird thing is that, the app works fine when I just run it withts-node
Here is my setup (The github repo is helmut-issue-441 )
node-version
v19.9.0v
package.json
tsconfig.json
main.test.ts
main.ts