Skip to content

Commit 310fb9a

Browse files
authored
fix(config): include AST transformer's name and version into cache key (#2755)
Closes #2753
1 parent 4a95c76 commit 310fb9a

8 files changed

Lines changed: 151 additions & 19 deletions

File tree

src/__mocks__/hummy-transformer.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const { LogContexts, LogLevels } = require('bs-logger')
2+
3+
function factory(tsCompiler) {
4+
const logger = tsCompiler.configSet.logger.child({ namespace: 'hummy-transformer' })
5+
const ts = tsCompiler.configSet.compilerModule
6+
function createVisitor(_ctx, _) {
7+
return (node) => node
8+
}
9+
10+
return (ctx) =>
11+
logger.wrap({ [LogContexts.logLevel]: LogLevels.debug, call: null }, 'visitSourceFileNode(): dummy', (sf) =>
12+
ts.visitNode(sf, createVisitor(ctx, sf))
13+
)
14+
}
15+
16+
module.exports = {
17+
factory,
18+
version: 1,
19+
}

src/config/__snapshots__/config-set.spec.ts.snap

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ Object {
5959
"before": Array [
6060
Object {
6161
"factory": [Function],
62+
"name": "hoist-jest",
63+
"version": 1,
6264
},
6365
],
6466
}
@@ -71,6 +73,8 @@ Object {
7173
"before": Array [
7274
Object {
7375
"factory": [Function],
76+
"name": "hoist-jest",
77+
"version": 1,
7478
},
7579
Object {
7680
"factory": [Function],
@@ -90,6 +94,8 @@ Object {
9094
"before": Array [
9195
Object {
9296
"factory": [Function],
97+
"name": "hoist-jest",
98+
"version": 1,
9399
},
94100
],
95101
}
@@ -106,6 +112,8 @@ Object {
106112
"before": Array [
107113
Object {
108114
"factory": [Function],
115+
"name": "hoist-jest",
116+
"version": 1,
109117
},
110118
],
111119
}
@@ -118,6 +126,8 @@ Object {
118126
"before": Array [
119127
Object {
120128
"factory": [Function],
129+
"name": "hoist-jest",
130+
"version": 1,
121131
},
122132
Object {
123133
"factory": [Function],
@@ -127,6 +137,36 @@ Object {
127137
}
128138
`;
129139

140+
exports[`customTransformers should return an object containing all resolved transformers: warning-log 1`] = `Array []`;
141+
142+
exports[`customTransformers should return an object containing all resolved transformers: warning-log 2`] = `
143+
Array [
144+
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
145+
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
146+
]
147+
`;
148+
149+
exports[`customTransformers should return an object containing all resolved transformers: warning-log 3`] = `
150+
Array [
151+
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
152+
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
153+
]
154+
`;
155+
156+
exports[`customTransformers should return an object containing all resolved transformers: warning-log 4`] = `
157+
Array [
158+
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
159+
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
160+
]
161+
`;
162+
163+
exports[`customTransformers should return an object containing all resolved transformers: warning-log 5`] = `
164+
Array [
165+
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
166+
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
167+
]
168+
`;
169+
130170
exports[`isTestFile should return a boolean value whether the file matches test pattern 1`] = `true`;
131171
132172
exports[`isTestFile should return a boolean value whether the file matches test pattern 2`] = `true`;

src/config/config-set.spec.ts

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
import { join, resolve } from 'path'
33

44
import type { Transformer } from '@jest/transform'
5-
import { testing } from 'bs-logger'
5+
import { LogLevels, testing } from 'bs-logger'
66
import ts from 'typescript'
77

88
import { createConfigSet } from '../__helpers__/fakers'
99
import { logTargetMock } from '../__helpers__/mocks'
10-
import type { TsJestGlobalOptions } from '../types'
10+
import type { AstTransformerDesc, TsJestGlobalOptions } from '../types'
1111
import * as _backports from '../utils/backports'
1212
import { getPackageVersion } from '../utils/get-package-version'
13+
import { stringify } from '../utils/json'
1314
import { normalizeSlashes } from '../utils/normalize-slashes'
15+
import { sha1 } from '../utils/sha1'
1416
import { mocked } from '../utils/testing'
1517

1618
import { ConfigSet, MY_DIGEST } from './config-set'
@@ -158,7 +160,9 @@ describe('customTransformers', () => {
158160
],
159161
},
160162
])('should return an object containing all resolved transformers', (data) => {
163+
const logger = testing.createLoggerMock()
161164
const cs = createConfigSet({
165+
logger,
162166
jestConfig: {
163167
rootDir: 'src',
164168
cwd: 'src',
@@ -169,6 +173,9 @@ describe('customTransformers', () => {
169173
resolve: null,
170174
})
171175

176+
expect(
177+
logger.target.filteredLines(LogLevels.warn).map((logLine) => logLine.substring(0, logLine.indexOf('>') + 1)),
178+
).toMatchSnapshot('warning-log')
172179
expect(cs.resolvedTransformers).toMatchSnapshot()
173180
})
174181
})
@@ -335,23 +342,51 @@ describe('babelJestTransformer', () => {
335342

336343
describe('tsCacheDir', () => {
337344
const cacheName = 'configSetTmp'
338-
const cacheDir = join(process.cwd(), cacheName)
345+
const cacheDir = join(cacheName)
339346
const partialTsJestCacheDir = join(cacheDir, 'ts-jest')
340347

341-
it.each([undefined, Object.create(null)])(
348+
it.each([
349+
undefined,
350+
{
351+
'ts-jest': {
352+
astTransformers: {
353+
before: ['hummy-transformer'],
354+
},
355+
},
356+
},
357+
])(
342358
'should return value from which is the combination of ts jest config and jest config when running test with cache',
343359
(data) => {
344-
expect(
345-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
346-
createConfigSet({
347-
jestConfig: {
348-
cache: true,
349-
cacheDirectory: cacheDir,
350-
globals: data,
351-
},
352-
resolve: null,
353-
}).tsCacheDir!.indexOf(partialTsJestCacheDir),
354-
).toEqual(0)
360+
const configSet = createConfigSet({
361+
jestConfig: {
362+
cache: true,
363+
cacheDirectory: cacheDir,
364+
globals: data,
365+
},
366+
resolve: null,
367+
})
368+
369+
expect(configSet.cacheSuffix).toEqual(
370+
sha1(
371+
stringify({
372+
version: configSet.compilerModule.version,
373+
digest: configSet.tsJestDigest,
374+
babelConfig: configSet.babelConfig,
375+
tsconfig: {
376+
options: configSet.parsedTsConfig.options,
377+
raw: configSet.parsedTsConfig.raw,
378+
},
379+
isolatedModules: configSet.isolatedModules,
380+
// @ts-expect-error testing purpose
381+
diagnostics: configSet._diagnostics,
382+
transformers: Object.values(configSet.resolvedTransformers)
383+
.reduce((prevVal, currentVal) => [...prevVal, currentVal])
384+
.map((transformer: AstTransformerDesc) => `${transformer.name}-${transformer.version}`),
385+
}),
386+
),
387+
)
388+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
389+
expect(configSet.tsCacheDir!.indexOf(partialTsJestCacheDir)).toEqual(0)
355390
},
356391
)
357392

src/config/config-set.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -299,13 +299,24 @@ export class ConfigSet {
299299
this.resolvedTransformers.before = [require('../transformers/hoist-jest')]
300300
const { astTransformers } = options
301301
if (astTransformers) {
302+
const resolveTransformerFunc = (transformerPath: string) => {
303+
const transformerFunc = require(transformerPath)
304+
if (!transformerFunc.version) {
305+
this.logger.warn(Errors.MissingTransformerVersion, { file: transformerPath })
306+
}
307+
if (!transformerFunc.name) {
308+
this.logger.warn(Errors.MissingTransformerName, { file: transformerPath })
309+
}
310+
311+
return transformerFunc
312+
}
302313
const resolveTransformers = (transformers: Array<string | AstTransformer>): AstTransformerDesc[] =>
303314
transformers.map((transformer) => {
304315
if (typeof transformer === 'string') {
305-
return require(this.resolvePath(transformer, { nodeResolve: true }))
316+
return resolveTransformerFunc(this.resolvePath(transformer, { nodeResolve: true }))
306317
} else {
307318
return {
308-
...require(this.resolvePath(transformer.path, { nodeResolve: true })),
319+
...resolveTransformerFunc(this.resolvePath(transformer.path, { nodeResolve: true })),
309320
options: transformer.options,
310321
}
311322
}
@@ -356,14 +367,15 @@ export class ConfigSet {
356367
version: this.compilerModule.version,
357368
digest: this.tsJestDigest,
358369
babelConfig: this.babelConfig,
359-
compilerModule: this.compilerModule,
360370
tsconfig: {
361371
options: this.parsedTsConfig.options,
362372
raw: this.parsedTsConfig.raw,
363373
},
364374
isolatedModules: this.isolatedModules,
365375
diagnostics: this._diagnostics,
366-
transformers: this.resolvedTransformers,
376+
transformers: Object.values(this.resolvedTransformers)
377+
.reduce((prevVal, currentVal) => [...prevVal, currentVal])
378+
.map((transformer: AstTransformerDesc) => `${transformer.name}-${transformer.version}`),
367379
}),
368380
)
369381
if (!this._jestCfg.cache) {

src/transformers/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ import { SourceFile, TransformationContext, Transformer, Visitor } from 'typescr
99

1010
import type { TsCompilerInstance } from 'ts-jest/dist/types'
1111

12+
/**
13+
* Remember to increase the version whenever transformer's content is changed. This is to inform Jest to not reuse
14+
* the previous cache which contains old transformer's content
15+
*/
16+
export const version = 1
17+
// Used for constructing cache key
18+
export const name = 'hoist-jest'
19+
1220
export function factory(compilerInstance: TsCompilerInstance) {
1321
const ts = compilerInstance.configSet.compilerModule
1422
function createVisitor(ctx: TransformationContext, sf: SourceFile) {

src/transformers/hoist-jest.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ import type {
1313

1414
import type { TsCompilerInstance } from '../types'
1515

16+
/**
17+
* Remember to increase the version whenever transformer's content is changed. This is to inform Jest to not reuse
18+
* the previous cache which contains old transformer's content
19+
*/
20+
export const version = 1
21+
// Used for constructing cache key
22+
export const name = 'hoist-jest'
23+
1624
/**
1725
* What methods of `jest` we should hoist
1826
*/

src/transformers/path-mapping.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ import type * as _ts from 'typescript'
1111

1212
import type { TsCompilerInstance } from '../types'
1313

14+
/**
15+
* Remember to increase the version whenever transformer's content is changed. This is to inform Jest to not reuse
16+
* the previous cache which contains old transformer's content
17+
*/
18+
export const version = 1
19+
// Used for constructing cache key
20+
export const name = 'hoist-jest'
21+
1422
const isBaseDir = (base: string, dir: string) => !relative(base, dir)?.startsWith('.')
1523

1624
/**

src/utils/messages.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export const enum Errors {
1919
MismatchNodeTargetMapping = 'There is a mismatch between your NodeJs version {{nodeJsVer}} and your TypeScript target {{compilationTarget}}. This might lead to some unexpected errors when running tests with `ts-jest`. To fix this, you can check https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping',
2020
CannotProcessFileReturnOriginal = "Unable to process '{{file}}', falling back to original file content. You can also configure Jest config option `transformIgnorePatterns` to ignore {{file}} from transformation or make sure that `outDir` in your tsconfig is neither `''` or `'.'`",
2121
CannotProcessFile = "Unable to process '{{file}}', please make sure that `outDir` in your tsconfig is neither `''` or `'.'`. You can also configure Jest config option `transformIgnorePatterns` to inform `ts-jest` to transform {{file}}",
22+
MissingTransformerName = 'The AST transformer {{file}} must have an `export const name = <your_transformer_name>`',
23+
MissingTransformerVersion = 'The AST transformer {{file}} must have an `export const version = <your_transformer_version>`',
2224
}
2325

2426
/**

0 commit comments

Comments
 (0)