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

fix(config): include AST transformer's name and version into cache key #2755

Merged
merged 1 commit into from Jul 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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