Merge pull request #9490 from backstage/rugvip/maps
cli: add test source maps and update docs
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Updated the default [sucrase](https://github.com/alangpierce/sucrase)-based Jest transform to include source maps if the environment variable `ENABLE_SOURCE_MAPS` is non-empty. This can be used to better support editor test debugging integrations.
|
||||
@@ -444,8 +444,9 @@ working directory to the package that the test is in.
|
||||
|
||||
Where small customizations are needed, such as setting coverage thresholds or
|
||||
support for specific transforms, it is possible to override the Jest
|
||||
configuration through the `"jest"` field in `package.json`. These overrides will
|
||||
be loaded in from all `package.json` files in the directory ancestry, meaning
|
||||
configuration through the `"jest"` field in `package.json`. For a full list of
|
||||
options, see the [Jest documentation](https://jestjs.io/docs/en/configuration).
|
||||
These overrides will be loaded in from all `package.json` files in the directory ancestry, meaning
|
||||
that you can place common configuration in the `package.json` at the root of a
|
||||
monorepo. If multiple overrides are found, they will be merged together with
|
||||
configuration further down in the directory tree taking precedence.
|
||||
@@ -464,6 +465,45 @@ The overrides in a single `package.json` may for example look like this:
|
||||
},
|
||||
```
|
||||
|
||||
If you want to configure editor integration for tests we recommend executing the bundled configuration directly with Jest rather than running through the Yarn test script. For example, with the Jest extension for VS Code the configuration would look something like this:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"jest.jestCommandLine": "node_modules/.bin/jest --config node_modules/@backstage/cli/config/jest.js",
|
||||
// In a large repo like the Backstage main repo you likely want to disable
|
||||
// watch mode and the initial test run too, leaving just manual and perhaps
|
||||
// on-save test runs in place.
|
||||
"jest.autoRun": {
|
||||
"watch": false,
|
||||
"onSave": "test-src-file"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you also want to enable source maps when debugging tests, you can do so by setting the `ENABLE_SOURCE_MAPS` environment variable. For example, a complete launch configuration for VS Code debugging may look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "node",
|
||||
"name": "vscode-jest-tests",
|
||||
"request": "launch",
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"disableOptimisticBPs": true,
|
||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {
|
||||
"ENABLE_SOURCE_MAPS": "true"
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"node_modules/@backstage/cli/config/jest.js",
|
||||
"--runInBand",
|
||||
"--watchAll=false"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Publishing
|
||||
|
||||
Package publishing is an optional part of the Backstage build system and not
|
||||
|
||||
@@ -440,22 +440,7 @@ a yarn workspaces monorepo by automatically creating one grouped configuration
|
||||
that includes all packages that have `backstage-cli test` in their package
|
||||
`test` script.
|
||||
|
||||
If needed, the configuration can be extended using a `"jest"` field in
|
||||
`package.json`, both within the target package and the monorepo root, with
|
||||
configuration in the target package taking precedence. Refer to the
|
||||
[Jest configuration documentation](https://jestjs.io/docs/en/configuration) for
|
||||
a full list of configuration options.
|
||||
|
||||
In addition to the Jest configuration there's an optional `transformModules`
|
||||
option, which is an array of module names to include in transformations.
|
||||
Normally modules inside `node_modules` are not transformed, but there are cases
|
||||
were published packages are not transpiled far enough to be usable by Jest, in
|
||||
which case you need to enable transform of them.
|
||||
|
||||
Another way to override the Jest configuration is to place a `jest.config.js` or
|
||||
`jest.config.ts` file in the package root. As opposed to the `package.json` way
|
||||
of overriding config, this completely removes the base config, and so you need
|
||||
to set it up from scratch.
|
||||
For more information about configuration overrides and editor support, see the [Jest Configuration section](./cli-build-system.md#jest-configuration) in the build system documentation.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli test [options]
|
||||
|
||||
@@ -102,9 +102,10 @@ async function getProjectConfig(targetPath, displayName) {
|
||||
},
|
||||
|
||||
transform: {
|
||||
'\\.(js|jsx|ts|tsx|mjs|cjs)$': require.resolve(
|
||||
'./jestSucraseTransform.js',
|
||||
),
|
||||
'\\.(js|jsx|ts|tsx|mjs|cjs)$': [
|
||||
require.resolve('./jestSucraseTransform.js'),
|
||||
{ enableSourceMaps: Boolean(process.env.ENABLE_SOURCE_MAPS) },
|
||||
],
|
||||
'\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$':
|
||||
require.resolve('./jestFileTransform.js'),
|
||||
'\\.(yaml)$': require.resolve('jest-transform-yaml'),
|
||||
|
||||
@@ -21,50 +21,71 @@ const sucrasePluginPkg = require('@sucrase/jest-plugin/package.json');
|
||||
|
||||
const ESM_REGEX = /\b(?:import|export)\b/;
|
||||
|
||||
function process(source, filePath) {
|
||||
let transforms;
|
||||
function createTransformer(config) {
|
||||
const process = (source, filePath) => {
|
||||
let transforms;
|
||||
|
||||
if (filePath.endsWith('.esm.js')) {
|
||||
transforms = ['imports'];
|
||||
} else if (filePath.endsWith('.js')) {
|
||||
// This is a very rough filter to avoid transforming things that we quickly
|
||||
// can be sure are definitely not ESM modules.
|
||||
if (ESM_REGEX.test(source)) {
|
||||
transforms = ['imports', 'jsx']; // JSX within .js is currently allowed
|
||||
if (filePath.endsWith('.esm.js')) {
|
||||
transforms = ['imports'];
|
||||
} else if (filePath.endsWith('.js')) {
|
||||
// This is a very rough filter to avoid transforming things that we quickly
|
||||
// can be sure are definitely not ESM modules.
|
||||
if (ESM_REGEX.test(source)) {
|
||||
transforms = ['imports', 'jsx']; // JSX within .js is currently allowed
|
||||
}
|
||||
} else if (filePath.endsWith('.jsx')) {
|
||||
transforms = ['jsx', 'imports'];
|
||||
} else if (filePath.endsWith('.ts')) {
|
||||
transforms = ['typescript', 'imports'];
|
||||
} else if (filePath.endsWith('.tsx')) {
|
||||
transforms = ['typescript', 'jsx', 'imports'];
|
||||
}
|
||||
} else if (filePath.endsWith('.jsx')) {
|
||||
transforms = ['jsx', 'imports'];
|
||||
} else if (filePath.endsWith('.ts')) {
|
||||
transforms = ['typescript', 'imports'];
|
||||
} else if (filePath.endsWith('.tsx')) {
|
||||
transforms = ['typescript', 'jsx', 'imports'];
|
||||
}
|
||||
|
||||
// Only apply the jest transform to the test files themselves
|
||||
if (transforms && filePath.includes('.test.')) {
|
||||
transforms.push('jest');
|
||||
}
|
||||
// Only apply the jest transform to the test files themselves
|
||||
if (transforms && filePath.includes('.test.')) {
|
||||
transforms.push('jest');
|
||||
}
|
||||
|
||||
if (transforms) {
|
||||
return transform(source, {
|
||||
transforms,
|
||||
filePath,
|
||||
disableESTransforms: true,
|
||||
}).code;
|
||||
}
|
||||
if (transforms) {
|
||||
const { code, sourceMap: map } = transform(source, {
|
||||
transforms,
|
||||
filePath,
|
||||
disableESTransforms: true,
|
||||
sourceMapOptions: {
|
||||
compiledFilename: filePath,
|
||||
},
|
||||
});
|
||||
if (config.enableSourceMaps) {
|
||||
const b64 = Buffer.from(JSON.stringify(map), 'utf8').toString('base64');
|
||||
const suffix = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${b64}`;
|
||||
// Include both inline and object source maps, as inline source maps are
|
||||
// needed for support of some editor integrations.
|
||||
return { code: `${code}\n${suffix}`, map };
|
||||
}
|
||||
// We only return the `map` result if source maps are enabled, as they
|
||||
// have a negative impact on the coverage accuracy.
|
||||
return code;
|
||||
}
|
||||
|
||||
return source;
|
||||
return source;
|
||||
};
|
||||
|
||||
// TODO: contribute something like this to @sucrase/jest-plugin
|
||||
const getCacheKey = sourceText => {
|
||||
return createHash('md5')
|
||||
.update(sourceText)
|
||||
.update(Buffer.alloc(1))
|
||||
.update(sucrasePkg.version)
|
||||
.update(Buffer.alloc(1))
|
||||
.update(sucrasePluginPkg.version)
|
||||
.update(Buffer.alloc(1))
|
||||
.update(JSON.stringify(config))
|
||||
.update(Buffer.alloc(1))
|
||||
.update('1') // increment whenever the transform logic in this file changes
|
||||
.digest('hex');
|
||||
};
|
||||
|
||||
return { process, getCacheKey };
|
||||
}
|
||||
|
||||
// TODO: contribute something like this to @sucrase/jest-plugin
|
||||
function getCacheKey(sourceText) {
|
||||
return createHash('md5')
|
||||
.update(sourceText)
|
||||
.update(Buffer.alloc(1))
|
||||
.update(sucrasePkg.version)
|
||||
.update(Buffer.alloc(1))
|
||||
.update(sucrasePluginPkg.version)
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
module.exports = { process, getCacheKey };
|
||||
module.exports = { createTransformer };
|
||||
|
||||
Reference in New Issue
Block a user