In my project, I am utilizing ESM. The transpiled .ts
files are converted into .js
and stored in the 'dist' directory. Here is an example of how my directory structure looks:
dist/
├─ src/
│ ├─ store/
│ │ ├─ index.js
│ ├─ strategies/
│ │ ├─ scalping/
│ │ │ ├─ main.js
src/
├─ store/
│ │ ├─ index.ts
├─ strategies/
│ │ ├─ scalping/
│ │ │ ├─ main.ts
test/
├─ strategies/
│ │ ├─ scalping/
│ │ │ ├─ main.test.ts
The moduleResolution
specified in my tsconfig.json file is "NodeNext"
Here is a snippet from my jest.config.ts
:
import type { Config } from "jest"
const config: Config = {
preset: 'ts-jest/presets/default-esm',
displayName: "scalper",
testTimeout: 60000,
globalSetup: "<rootDir>/test/jest/setup.ts",
globalTeardown: "<rootDir>/test/jest/teardown.ts",
coveragePathIgnorePatterns: [ "/node_modules/" ],
testMatch: ["<rootDir>/test/**/?(*.)+(spec|test).[jt]s?(x)"],
modulePathIgnorePatterns: ["<rootDir>/test/.*/__mocks__", "<rootDir>/dist/"],
testEnvironment: "node",
coverageDirectory: "<rootDir>/coverage",
extensionsToTreatAsEsm: [".ts"],
moduleNameMapper: {
"^(.*)\\.js$": "$1",
},
transform: {
'^.+\\.ts?$': [
'ts-jest',
{
useESM: true
}
]
},
}
export default config
The content of my test/main/index.test.ts
is as follows:
import { jest } from '@jest/globals'
import * as fs from "fs"
import * as path from "path"
import appRoot from "app-root-path"
const params = JSON.parse(fs.readFileSync(path.join(appRoot.path, 'test/strategies/scalping/main/params.json'), 'utf8'))
import * as strategies from "../../../../src/strategies/scalping/index.js"
describe('main', () => {
it('Should create a valid scalp trade', async () => {
const { builtMarket, config } = params
// Mocking of ESM requires dynamic imports
jest.unstable_mockModule('../../../../src/store/index.js', () => ({
getScalpRunners: jest.fn().mockResolvedValue(params as never)
}))
const store = await import('../../../../src/store/index.js')
await strategies.scalping(builtMarket, config)
})
})
I expected the method getScalpRunners
to be mocked properly, but it's not working as intended and calls the main definition instead. I have referred to the documentation on mocking ESM modules as well as some external resources but haven't resolved this issue yet.
An excerpt from my src/strategies/scalping/main.ts
is included below:
import store from "../../store/index.js"
export default async function(builtMarket: BuiltMarket, config: Config): Promise<BuiltMarket | undefined> {
try {
const validMarket = isValidMarket(builtMarket, config)
if (validMarket) {
const polledRunners: ScalpRunner[] | undefined = await store.getScalpRunners({
eventId: builtMarket._eventId,
marketId: builtMarket._marketId
})
// other functionality...
}
} catch(err: any) {
throw err
}
}
Despite the fact that store
appears to be correctly mocked in index.test.ts
, it reverts back to being the un-mocked version in main.ts
.