Skip to content

Commit

Permalink
fix(config): include AST transformer's name and version into cache key (
Browse files Browse the repository at this point in the history
#2755)

Closes #2753
  • Loading branch information
ahnpnl committed Jul 19, 2021
1 parent 4a95c76 commit 310fb9a
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 19 deletions.
19 changes: 19 additions & 0 deletions src/__mocks__/hummy-transformer.js
@@ -0,0 +1,19 @@
const { LogContexts, LogLevels } = require('bs-logger')

function factory(tsCompiler) {
const logger = tsCompiler.configSet.logger.child({ namespace: 'hummy-transformer' })
const ts = tsCompiler.configSet.compilerModule
function createVisitor(_ctx, _) {
return (node) => node
}

return (ctx) =>
logger.wrap({ [LogContexts.logLevel]: LogLevels.debug, call: null }, 'visitSourceFileNode(): dummy', (sf) =>
ts.visitNode(sf, createVisitor(ctx, sf))
)
}

module.exports = {
factory,
version: 1,
}
40 changes: 40 additions & 0 deletions src/config/__snapshots__/config-set.spec.ts.snap
Expand Up @@ -59,6 +59,8 @@ Object {
"before": Array [
Object {
"factory": [Function],
"name": "hoist-jest",
"version": 1,
},
],
}
Expand All @@ -71,6 +73,8 @@ Object {
"before": Array [
Object {
"factory": [Function],
"name": "hoist-jest",
"version": 1,
},
Object {
"factory": [Function],
Expand All @@ -90,6 +94,8 @@ Object {
"before": Array [
Object {
"factory": [Function],
"name": "hoist-jest",
"version": 1,
},
],
}
Expand All @@ -106,6 +112,8 @@ Object {
"before": Array [
Object {
"factory": [Function],
"name": "hoist-jest",
"version": 1,
},
],
}
Expand All @@ -118,6 +126,8 @@ Object {
"before": Array [
Object {
"factory": [Function],
"name": "hoist-jest",
"version": 1,
},
Object {
"factory": [Function],
Expand All @@ -127,6 +137,36 @@ Object {
}
`;

exports[`customTransformers should return an object containing all resolved transformers: warning-log 1`] = `Array []`;

exports[`customTransformers should return an object containing all resolved transformers: warning-log 2`] = `
Array [
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
]
`;
exports[`customTransformers should return an object containing all resolved transformers: warning-log 3`] = `
Array [
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
]
`;
exports[`customTransformers should return an object containing all resolved transformers: warning-log 4`] = `
Array [
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
]
`;
exports[`customTransformers should return an object containing all resolved transformers: warning-log 5`] = `
Array [
"[level:40] The AST transformer {{file}} must have an \`export const version = <your_transformer_version>",
"[level:40] The AST transformer {{file}} must have an \`export const name = <your_transformer_name>",
]
`;
exports[`isTestFile should return a boolean value whether the file matches test pattern 1`] = `true`;
exports[`isTestFile should return a boolean value whether the file matches test pattern 2`] = `true`;
Expand Down
65 changes: 50 additions & 15 deletions src/config/config-set.spec.ts
Expand Up @@ -2,15 +2,17 @@
import { join, resolve } from 'path'

import type { Transformer } from '@jest/transform'
import { testing } from 'bs-logger'
import { LogLevels, testing } from 'bs-logger'
import ts from 'typescript'

import { createConfigSet } from '../__helpers__/fakers'
import { logTargetMock } from '../__helpers__/mocks'
import type { TsJestGlobalOptions } from '../types'
import type { AstTransformerDesc, TsJestGlobalOptions } from '../types'
import * as _backports from '../utils/backports'
import { getPackageVersion } from '../utils/get-package-version'
import { stringify } from '../utils/json'
import { normalizeSlashes } from '../utils/normalize-slashes'
import { sha1 } from '../utils/sha1'
import { mocked } from '../utils/testing'

import { ConfigSet, MY_DIGEST } from './config-set'
Expand Down Expand Up @@ -158,7 +160,9 @@ describe('customTransformers', () => {
],
},
])('should return an object containing all resolved transformers', (data) => {
const logger = testing.createLoggerMock()
const cs = createConfigSet({
logger,
jestConfig: {
rootDir: 'src',
cwd: 'src',
Expand All @@ -169,6 +173,9 @@ describe('customTransformers', () => {
resolve: null,
})

expect(
logger.target.filteredLines(LogLevels.warn).map((logLine) => logLine.substring(0, logLine.indexOf('>') + 1)),
).toMatchSnapshot('warning-log')
expect(cs.resolvedTransformers).toMatchSnapshot()
})
})
Expand Down Expand Up @@ -335,23 +342,51 @@ describe('babelJestTransformer', () => {

describe('tsCacheDir', () => {
const cacheName = 'configSetTmp'
const cacheDir = join(process.cwd(), cacheName)
const cacheDir = join(cacheName)
const partialTsJestCacheDir = join(cacheDir, 'ts-jest')

it.each([undefined, Object.create(null)])(
it.each([
undefined,
{
'ts-jest': {
astTransformers: {
before: ['hummy-transformer'],
},
},
},
])(
'should return value from which is the combination of ts jest config and jest config when running test with cache',
(data) => {
expect(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
createConfigSet({
jestConfig: {
cache: true,
cacheDirectory: cacheDir,
globals: data,
},
resolve: null,
}).tsCacheDir!.indexOf(partialTsJestCacheDir),
).toEqual(0)
const configSet = createConfigSet({
jestConfig: {
cache: true,
cacheDirectory: cacheDir,
globals: data,
},
resolve: null,
})

expect(configSet.cacheSuffix).toEqual(
sha1(
stringify({
version: configSet.compilerModule.version,
digest: configSet.tsJestDigest,
babelConfig: configSet.babelConfig,
tsconfig: {
options: configSet.parsedTsConfig.options,
raw: configSet.parsedTsConfig.raw,
},
isolatedModules: configSet.isolatedModules,
// @ts-expect-error testing purpose
diagnostics: configSet._diagnostics,
transformers: Object.values(configSet.resolvedTransformers)
.reduce((prevVal, currentVal) => [...prevVal, currentVal])
.map((transformer: AstTransformerDesc) => `${transformer.name}-${transformer.version}`),
}),
),
)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expect(configSet.tsCacheDir!.indexOf(partialTsJestCacheDir)).toEqual(0)
},
)

Expand Down
20 changes: 16 additions & 4 deletions src/config/config-set.ts
Expand Up @@ -299,13 +299,24 @@ export class ConfigSet {
this.resolvedTransformers.before = [require('../transformers/hoist-jest')]
const { astTransformers } = options
if (astTransformers) {
const resolveTransformerFunc = (transformerPath: string) => {
const transformerFunc = require(transformerPath)
if (!transformerFunc.version) {
this.logger.warn(Errors.MissingTransformerVersion, { file: transformerPath })
}
if (!transformerFunc.name) {
this.logger.warn(Errors.MissingTransformerName, { file: transformerPath })
}

return transformerFunc
}
const resolveTransformers = (transformers: Array<string | AstTransformer>): AstTransformerDesc[] =>
transformers.map((transformer) => {
if (typeof transformer === 'string') {
return require(this.resolvePath(transformer, { nodeResolve: true }))
return resolveTransformerFunc(this.resolvePath(transformer, { nodeResolve: true }))
} else {
return {
...require(this.resolvePath(transformer.path, { nodeResolve: true })),
...resolveTransformerFunc(this.resolvePath(transformer.path, { nodeResolve: true })),
options: transformer.options,
}
}
Expand Down Expand Up @@ -356,14 +367,15 @@ export class ConfigSet {
version: this.compilerModule.version,
digest: this.tsJestDigest,
babelConfig: this.babelConfig,
compilerModule: this.compilerModule,
tsconfig: {
options: this.parsedTsConfig.options,
raw: this.parsedTsConfig.raw,
},
isolatedModules: this.isolatedModules,
diagnostics: this._diagnostics,
transformers: this.resolvedTransformers,
transformers: Object.values(this.resolvedTransformers)
.reduce((prevVal, currentVal) => [...prevVal, currentVal])
.map((transformer: AstTransformerDesc) => `${transformer.name}-${transformer.version}`),
}),
)
if (!this._jestCfg.cache) {
Expand Down
8 changes: 8 additions & 0 deletions src/transformers/README.md
Expand Up @@ -9,6 +9,14 @@ import { SourceFile, TransformationContext, Transformer, Visitor } from 'typescr

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

/**
* Remember to increase the version whenever transformer's content is changed. This is to inform Jest to not reuse
* the previous cache which contains old transformer's content
*/
export const version = 1
// Used for constructing cache key
export const name = 'hoist-jest'

export function factory(compilerInstance: TsCompilerInstance) {
const ts = compilerInstance.configSet.compilerModule
function createVisitor(ctx: TransformationContext, sf: SourceFile) {
Expand Down
8 changes: 8 additions & 0 deletions src/transformers/hoist-jest.ts
Expand Up @@ -13,6 +13,14 @@ import type {

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

/**
* Remember to increase the version whenever transformer's content is changed. This is to inform Jest to not reuse
* the previous cache which contains old transformer's content
*/
export const version = 1
// Used for constructing cache key
export const name = 'hoist-jest'

/**
* What methods of `jest` we should hoist
*/
Expand Down
8 changes: 8 additions & 0 deletions src/transformers/path-mapping.ts
Expand Up @@ -11,6 +11,14 @@ import type * as _ts from 'typescript'

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

/**
* Remember to increase the version whenever transformer's content is changed. This is to inform Jest to not reuse
* the previous cache which contains old transformer's content
*/
export const version = 1
// Used for constructing cache key
export const name = 'hoist-jest'

const isBaseDir = (base: string, dir: string) => !relative(base, dir)?.startsWith('.')

/**
Expand Down
2 changes: 2 additions & 0 deletions src/utils/messages.ts
Expand Up @@ -19,6 +19,8 @@ export const enum Errors {
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',
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 `'.'`",
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}}",
MissingTransformerName = 'The AST transformer {{file}} must have an `export const name = <your_transformer_name>`',
MissingTransformerVersion = 'The AST transformer {{file}} must have an `export const version = <your_transformer_version>`',
}

/**
Expand Down

0 comments on commit 310fb9a

Please sign in to comment.