Skip to content

Instantly share code, notes, and snippets.

@lukasholzer
Last active April 19, 2021 05:59
Show Gist options
  • Save lukasholzer/46a1c620710b2db5ebe5c6686e0146d9 to your computer and use it in GitHub Desktop.
Save lukasholzer/46a1c620710b2db5ebe5c6686e0146d9 to your computer and use it in GitHub Desktop.
bazel jest testing rule
diff --git a/node_modules/jest-haste-map/build/crawlers/node.js b/node_modules/jest-haste-map/build/crawlers/node.js
index 1e7372c..ab36178 100644
--- a/node_modules/jest-haste-map/build/crawlers/node.js
+++ b/node_modules/jest-haste-map/build/crawlers/node.js
@@ -168,10 +168,6 @@ function find(roots, extensions, ignore, callback) {
}
if (typeof entry !== 'string') {
- if (entry.isSymbolicLink()) {
- return;
- }
-
if (entry.isDirectory()) {
search(file);
return;
@@ -183,7 +179,7 @@ function find(roots, extensions, ignore, callback) {
activeCalls--; // This logic is unnecessary for node > v10.10, but leaving it in
// since we need it for backwards-compatibility still.
- if (!err && stat && !stat.isSymbolicLink()) {
+ if (!err && stat) {
if (stat.isDirectory()) {
search(file);
} else {
@@ -217,8 +213,13 @@ function find(roots, extensions, ignore, callback) {
function findNative(roots, extensions, ignore, callback) {
const args = Array.from(roots);
+ args.push('(');
args.push('-type', 'f');
+ args.push('-o');
+ args.push('-type', 'l');
+ args.push(')');
+
if (extensions.length) {
args.push('(');
}
// @ts-check
/* eslint-disable no-console */
/** Custom bazel reporter that tells how to update snapshots */
class BazelReporter {
/**
* lifecycle hook that is triggered after the run is completed
* @param contexts
* @param results The Test results
*/
onRunComplete(contexts, results) {
if (results.numFailedTests && results.snapshot.failure) {
console.log(`================================================================================
Snapshot failed, you can update the snapshot by running
$ bazel run ${process.env['TEST_TARGET'].replace(/_bin$/, '')}.update
`);
}
}
}
module.exports = BazelReporter;
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires,@typescript-eslint/typedef */
const runfilesHelper = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);
const { sep } = require('path');
/**
*
* @param {string} request
* @param {*} options
*/
module.exports = (request, options) => {
// resolve a request like `dynatrace/developer-portal/src/App`
// this originates through bazel if no module name is present
// it will prefixes the path with the bazel workspace and omit the file
// ending
if (request.startsWith(process.env['BAZEL_WORKSPACE'])) {
const resolved = resolveModule(request, ['.js', `${sep}index.js`, '']);
if (resolved?.length) {
return resolved;
}
}
// Call the defaultResolver, so we leverage its cache, error handling, etc.
return options.defaultResolver(request, options);
};
/**
* Try to resolve a bazel module id (amd module name of a umd bundle)
* @param {string} id the module id that should be resolved
* @param {string[]} extensions a list of extensions to try to resolve
* @returns {string|undefined} The resolved module id
*/
function resolveModule(id, extensions) {
if (extensions.length) {
try {
const [extension] = extensions.splice(0, 1);
return runfilesHelper.resolve(`${id}${extension}`);
} catch {
return resolveModule(id, extensions);
}
}
}
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires */
const { relative, join, parse, sep } = require('path');
/** @type {import('jest-snapshot').SnapshotResolver} */
module.exports = {
// resolves from test to snapshot path
resolveSnapshotPath: (testPath, snapshotExtension) => {
const updatedPath = process.env.BUILD_WORKING_DIRECTORY
? join(
process.env.BUILD_WORKING_DIRECTORY,
relative(process.cwd(), testPath),
)
: testPath;
const { dir, base } = parse(updatedPath);
return `${join(dir, '__snapshots__', base)}${snapshotExtension}`;
},
// resolves from snapshot to test path
resolveTestPath: (snapshotFilePath, snapshotExtension) => {
const clean = process.env.BUILD_WORKING_DIRECTORY
? snapshotFilePath
.replace(process.env.BUILD_WORKING_DIRECTORY, '')
.replace(/^[\\/]/, '')
: snapshotFilePath;
return clean
.replace(`__snapshots__${sep}`, '')
.slice(0, -snapshotExtension.length);
},
// Example test path, used for preflight consistency check of the implementation above
testPathForConsistencyCheck: `some${sep}example.test.js`,
};
"Jest testing macro that can compile typescript files for testing as well"
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load("@npm//jest-cli:index.bzl", "jest", _jest_test = "jest_test")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
def jest_test(
srcs,
tsconfig,
config = None,
# jest does not understand only commonjs the default would be umd
devmode_module = "commonjs",
name = "test",
size = "medium",
flaky = False,
deps = [],
data = [],
**kwargs):
"""Jest testing rule that compiles the typescript sources and run jest tests
Args:
srcs: The sources passed
tsconfig: The typescript config for compiling typescript files
config: The jest configuration file
devmode_module: The jest compile devmode module
name: The name of the test rule
size: test size
flaky: Whether this test is flaky
deps: The dependencies that are needed for the test
data: Additional data for the test_run (like snapshots)
**kwargs: Keyword arguments
"""
# compile the spec files first
ts_library(
name = "%s_compile" % name,
srcs = srcs,
tsconfig = tsconfig,
devmode_module = devmode_module,
deps = [
"@npm//tslib",
"@npm//@types/jest",
"@npm//@testing-library/jest-dom",
"@npm//jest-junit",
] + deps,
)
test_data = [
"%s_compile" % name,
"@npm//@testing-library/jest-dom",
# c8 is used for bazel collecting coverage
"@npm//c8",
"@npm//jest-junit",
# prettier is used to format inline snapshots
"@npm//prettier",
"//:jest.preset.js",
"//tools/bazel_rules/jest:test-setup.js",
"//tools/bazel_rules/jest:jest-reporter.js",
"//tools/bazel_rules/jest:jest-resolver.js",
"//tools/bazel_rules/jest:jest-snapshot-resolver.js",
] + deps + data
test_args = [
"--no-cache",
"--no-watchman",
"--ci",
"--colors",
]
# if we have a config file than add it
if config:
test_data.append(config)
test_args.append("--config $(rootpath %s)" % config)
else:
write_file(
name = "%s_config" % name,
out = "jest.config.js",
content = ["""
const { relative, join } = require('path');
module.exports = {
preset: relative(__dirname, join(process.cwd(), 'jest.preset.js'))
}"""],
)
test_data.append("%s_config" % name)
test_args.append("--config %s/jest.config.js" % native.package_name())
_jest_test(
name = name,
args = test_args,
data = test_data,
size = size,
flaky = flaky,
**kwargs
)
# This target is used to update the snapshot
# e.g bazel run //packages/react-intl:unit.update
jest(
name = "%s.update" % name,
data = test_data,
templated_args = test_args + ["-u"],
**kwargs
)
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires */
const { join, dirname } = require('path');
/** @type {import('./tools/utils/src/runfiles-helper').RunfilesHelper} */
const runfilesHelper = require(process.env['BAZEL_NODE_RUNFILES_HELPER']);
const [_, target] = process.env.BAZEL_TARGET.split(':');
/** @type {import('@jest/types').Config.InitialOptions['reporters']} */
const reporters = [
'default',
join(process.cwd(), 'tools/bazel_rules/jest/jest-reporter.js'),
];
// The xml output file is only set on `bazel test` and not on `bazel run`
if (process.env.XML_OUTPUT_FILE) {
reporters.push([
runfilesHelper.resolve('npm/node_modules/jest-junit/index.js'),
{
outputDirectory: dirname(process.env.XML_OUTPUT_FILE),
outputName: `${target}.xml`,
suiteName: process.env.BAZEL_TARGET,
// Not setting class and title templates leads to weird default formatting
classNameTemplate: `{classname} (${process.env.BAZEL_TARGET})`,
titleTemplate: '{title}',
ancestorSeparator: ' › ',
usePathForSuiteName: 'true',
},
]);
}
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
setupFilesAfterEnv: [
join(process.cwd(), 'tools/bazel_rules/jest/test-setup.js'),
],
moduleNameMapper: {
'\\.(css)$': 'identity-obj-proxy',
},
resolver: join(process.cwd(), 'tools/bazel_rules/jest/jest-resolver.js'),
snapshotResolver: join(
process.cwd(),
'tools/bazel_rules/jest/jest-snapshot-resolver.js',
),
testMatch: ['**/*.test.js'],
// make sure jest prints out console.logs
verbose: false,
watchman: false,
prettierPath: runfilesHelper.resolve('npm/node_modules/prettier/index.js'),
logHeapUsage: true,
collectCoverage: Boolean(process.env.IBAZEL),
collectCoverageFrom: process.env.IBAZEL
? undefined
: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/coverage/**/*',
'!**/jest.config.js',
'!**/*_loader.js',
'!**/*_require_patch.js',
'!**/fixtures/**/*',
],
reporters,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment