Utilities for testing babel plugins
npm install babel-plugin-tester

Utilities for testing babel plugins ๐งช
[![Black Lives Matter!][x-badge-blm-image]][x-badge-blm-link]
[![Last commit timestamp][x-badge-lastcommit-image]][x-badge-repo-link]
[![Codecov][x-badge-codecov-image]][x-badge-codecov-link]
[![Source license][x-badge-license-image]][x-badge-license-link]
[![Uses Semantic Release!][x-badge-semanticrelease-image]][x-badge-semanticrelease-link]
[![NPM version][x-badge-npm-image]][x-badge-npm-link]
[![Monthly Downloads][x-badge-downloads-image]][x-badge-npm-link]
This is a fairly simple abstraction to help you write tests for your babel
plugin or preset. It was built to work with [Jest][4], but most of the
functionality will work with [Mocha][5], [Jasmine][6], [node:test][7],
[Vitest][8], and any other test runner that defines standard describe and it
globals with async support (see [appendix][9]).
This package is tested on both Windows and nix (Ubuntu) environments.
---
- Install
- Usage
- Import
- Invoke
- Execute
- Configure
- Examples
- Simple Example
- Full Example
- Fixtures Examples
- Appendix
- Testing Framework Compatibility
- Using Babel for Configuration Loading
- pluginName Inference Caveat
- Custom Snapshot Serialization
- Formatting Output with Prettier
- Built-In Debugging Support
- TEST_ONLY/TEST_NUM_ONLY and TEST_SKIP/TEST_NUM_SKIP Environment Variables
- setup and teardown Run Order
- Published Package Details
- License
- Contributing and Support
- Inspiration
- Contributors
``shell`
npm install --save-dev babel-plugin-tester
To use babel-plugin-tester:
1. Import babel-plugin-tester into your test file.
2. Invoke pluginTester in your test file.
3. Execute your test file.
ESM:
`javascript`
import { pluginTester } from 'babel-plugin-tester';
CJS:
`javascript`
const { pluginTester } = require('babel-plugin-tester');
`javascript
/ file: test/unit.test.js /
import { pluginTester } from 'babel-plugin-tester';
import yourPlugin from 'universe:your-plugin';
pluginTester({
plugin: yourPlugin,
tests: {
/ Your test objects /
}
});
`
> [!TIP]
>
> Note how pluginTester does not appear inside any test/it block norpluginTester
> within any [hook functions][10]. For advanced use cases, maydescribe
> appear within one or more blocks, though this is discouraged.
In your terminal of choice:
`shell`Prettier@3 requires --experimental-vm-modules for older Node versions
NODE_OPTIONS='--no-warnings --experimental-vm-modules' npx jest
This section lists the options you can pass to babel-plugin-tester. They are all
optional with respect to the following:
- When testing a preset, the [preset][11] option is required.plugin
- When testing a plugin, the [][12] option is required.preset
- You must test either a preset or a plugin.
- You cannot use preset-specific options ([][11], [presetName][13],presetOptions
[][14]) and plugin-specific options ([plugin][12],pluginName
[][15], [pluginOptions][16]) at the same time.
#### plugin
This is used to provide the babel plugin under test. For example:
`javascript
/ file: test/unit.test.js /
import { pluginTester } from 'babel-plugin-tester';
import identifierReversePlugin from 'universe:identifier-reverse-plugin';
pluginTester({
plugin: identifierReversePlugin,
tests: {
/ Your test objects /
}
});
/ file: src/identifier-reverse-plugin.js /
// Normally you would import this from your plugin module
function identifierReversePlugin() {
return {
name: 'identifier reverse',
visitor: {
Identifier(idPath) {
idPath.node.name = idPath.node.name.split('').reverse().join('');
}
}
};
}
`
#### pluginName
This is used as the [describe block name][17] and in your [tests' names][18]. If
pluginName can be inferred from the [plugin][12]'s [name][19], then it willpluginName
be and you do not need to provide this option. If it cannot be inferred for
whatever reason, defaults to "unknown plugin".
Note that there is a small [caveat][20] when relying on pluginName inference.
#### pluginOptions
This is used to pass options into your plugin at transform time. If provided,
the object will be [lodash.mergeWith][lodash.mergewith]'d with each [testpluginOptions
object's ][21]/[fixture's pluginOptions][22], with the latter
taking precedence. Note that arrays will be concatenated and explicitly
undefined values will unset previously defined values during merging.
#### preset
This is used to provide the babel preset under test. For example:
`javascript
/ file: cool-new-babel-preset.test.js /
import path from 'node:path';
import { pluginTester } from 'babel-plugin-tester';
import coolNewBabelPreset from './cool-new-babel-preset.js';
pluginTester({
preset: coolNewBabelPreset,
// A path to a directory containing your test fixtures
fixtures: path.join(__dirname, 'fixtures')
});
/ file: cool-new-babel-preset.js /
function identifierReversePlugin() {
return {
name: 'identifier reverse',
visitor: {
Identifier(idPath) {
idPath.node.name = idPath.node.name.split('').reverse().join('');
}
}
};
}
function identifierAppendPlugin() {
return {
name: 'identifier append',
visitor: {
Identifier(idPath) {
idPath.node.name = ${idPath.node.name}_appended;
}
}
};
}
export function coolNewBabelPreset() {
return { plugins: [identifierReversePlugin, identifierAppendPlugin] };
}
`
#### presetName
This is used as the [describe block name][17] and in your [tests' names][18].
Defaults to "unknown preset".
#### presetOptions
This is used to pass options into your preset at transform time. If provided,
the object will be [lodash.mergeWith][lodash.mergewith]'d with each [testpresetOptions
object's ][23]/[fixture's presetOptions][24], with the latter
taking precedence. Note that arrays will be concatenated and explicitly
undefined values will unset previously defined values during merging.
#### babel
This is used to provide your own implementation of babel. This is particularly
useful if you want to use a different version of babel than what's required by
this package.
#### babelOptions
This is used to configure babel. If provided, the object will be
[lodash.mergeWith][lodash.mergewith]'d with the [defaults][25] and each [testbabelOptions
object's ][26]/[fixture's babelOptions][27], with the latter
taking precedence.
Be aware that arrays will be concatenated and explicitly undefined values will
unset previously defined values during merging.
> [!IMPORTANT]
>
> For babel-plugin-tester@>=12, [duplicate entries][2] inbabelOptions.plugins
> [][55] and [babelOptions.presets][73] are reduced,babel.config.js
> with latter entries _completely overwriting_ any that came before. In other
> words: the last duplicate plugin or preset configuration wins. **They are not
> merged.** This makes it easy to provide an alternative one-off configuration
> for a plugin or preset that is also used elsewhere, such as a project's root
> file.babel-plugin-tester@<12
>
> Attempting the same with will cause babel [to
> throw][2] since duplicate entries are technically not allowed.
Also note that [babelOptions.babelrc][28] and [babelOptions.configFile][29]false
are set to by default, which disables automatic babel configuration
loading. [This can be re-enabled if desired][30].
To simply reuse your project's [babel.config.js][31] or some otherbabelOptions
configuration file, set like so:
`javascript
// file: /repos/my-project/tests/unit-plugin.test.ts
import path from 'node:path';
import { pluginTester } from 'babel-plugin-tester';
pluginTester({
plugin: yourPlugin,
// ...
babelOptions: require(path.join('..', 'babel.config.js')),
// ...
tests: {
/ Your test objects /
}
});
`
##### Custom Plugin and Preset Run Order
By default, when you include a custom list of [plugins][32] or [presets][3] in
babelOptions, the plugin or preset under test will always be the final plugin
or preset to run.
For example, consider the myPlugin plugin:
`javascript
import { pluginTester } from 'babel-plugin-tester';
pluginTester({
plugin: myPlugin,
pluginName: 'my-plugin',
babelOptions: {
plugins: [
['@babel/plugin-syntax-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }]
]
}
});
`
By default, myPlugin will be invoked _after_ @babel/plugin-syntax-decoratorsmyPlugin
and @babel/plugin-proposal-class-properties (i.e. is _appended_ by
default).
It is possible to specify a custom ordering using the exported
runPluginUnderTestHere symbol. For instance, to run myPlugin _after_
@babel/plugin-syntax-decorators but _before_
@babel/plugin-proposal-class-properties:
`javascript
import { pluginTester, runPluginUnderTestHere } from 'babel-plugin-tester';
pluginTester({
plugin: myPlugin,
pluginName: 'my-plugin',
babelOptions: {
plugins: [
['@babel/plugin-syntax-decorators', { legacy: true }],
runPluginUnderTestHere,
['@babel/plugin-proposal-class-properties', { loose: true }]
]
}
});
`
Or to run myPlugin _before_ both @babel/plugin-syntax-decorators and
@babel/plugin-proposal-class-properties:
`javascript
import { pluginTester, runPluginUnderTestHere } from 'babel-plugin-tester';
pluginTester({
plugin: myPlugin,
pluginName: 'my-plugin',
babelOptions: {
plugins: [
runPluginUnderTestHere,
['@babel/plugin-syntax-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }]
]
}
});
`
The same can be done when testing presets. Note that myPreset is normally
_prepended_ by default since, unlike plugins, [presets are run in reverse
order][33]:
`javascript
import { pluginTester, runPresetUnderTestHere } from 'babel-plugin-tester';
pluginTester({
preset: myPreset,
presetName: 'my-preset',
babelOptions: {
presets: [
'@babel/preset-typescript',
['@babel/preset-react', { pragma: 'dom' }],
runPresetUnderTestHere
]
}
});
`
In this example, myPreset will run first instead of last.
#### title
This is used to specify a custom title for the two top-level [describe
blocks][17], the first enclosing all [tests][34] (i.e. describe(title, ...))
and the second enclosing all [fixtures][35] (i.e.describe(${title} fixtures, ...)).
Explicitly setting this option will override any defaults or inferred values.
Set to false to prevent the creation of these enclosing describe blocks.pluginName
Otherwise, the title defaults to using [][15]/[presetName][13].
#### filepath
This is used to resolve relative paths provided by the [fixtures][35] option;codeFixture
the test object properties [][36], [outputFixture][37], andexecFixture
[][38]; and [during configuration resolution for prettier][39].path.join
That is: if the aforesaid properties are not absolute paths, they will be
[][40]'d with the [directory name][41] of filepath.
filepath is also passed to formatResult if a more specific path is notbabelOptions.filename
available, and it is used as the default value for in
[test objects][42].
This option defaults to the absolute path of the file that [invoked the
pluginTester function][43].
> [!NOTE]
>
> For backwards compatibility reasons, filepath is synonymous with filename.filename
> They can be used interchangeably, though care must be taken not to confuse the
> babel-plugin-tester option with babelOptions.filename. They are
> NOT the same!
#### endOfLine
This is used to control which line endings both the actual output from babel and
the expected output will be converted to. Defaults to "lf".
| Options | Description |
| ------------ | --------------------------------------- |
| "lf" | Use Unix-style line endings |"crlf"
| | Use Windows-style line endings |"auto"
| | Use the system default line endings |"preserve"
| | Use the line endings from the input |false
| | Disable line ending conversion entirely |
> [!NOTE]
>
> When disabling line ending conversion, note that [Babel will always output
> LF][44] even if the input is CRLF.
#### setup
This function will be run before every test runs, including fixtures. It can
return a function which will be treated as a [teardown][45] function. It canteardown
also return a promise. If that promise resolves to a function, that will be
treated as a [][45] function.
See [here][46] for the complete run order.
#### teardown
This function will be run after every test runs, including fixtures. You can
define this via teardown or you can return it from the [setup][47] function.
This can likewise return a promise if it is asynchronous.
This function, if provided, will be run _after_ any teardown function returned
by [setup][47]. See [here][46] for the complete run order.
#### formatResult
This function is used to format all babel outputs, and defaults to a function
that invokes [prettier][48]. If a prettier configuration file is [found][49],
then that will be used. Otherwise, prettier will use its own default
configuration.
You can also [override or entirely disable formatting][39].
#### snapshot
Equivalent to [snapshot][50] but applied globally across all [test
objects][42].
#### fixtureOutputName
Equivalent to [fixtureOutputName][51] but applied globally across all
[fixtures][35].
#### fixtureOutputExt
Equivalent to [fixtureOutputExt][52] but applied globally across all
[fixtures][35].
#### titleNumbering
Determines which test titles are prefixed with a number when registering [test
blocks][18] (e.g. 1. ${title} , 2. ${title} , etc). Defaults to"all".
| Options | Description |
| ----------------- | --------------------------------------------------- |
| "all" | All test object and fixtures tests will be numbered |"tests-only"
| | Only test object tests will be numbered |"fixtures-only"
| | Only fixtures tests will be numbered |false
| | Disable automatic numbering in titles entirely |
#### restartTitleNumbering
Normally, multiple [invocations][43] of babel-plugin-tester in the same test
file will share the same [test title numbering][53]. For example:
`javascript
/ file: test/unit.test.js /
import { pluginTester } from 'babel-plugin-tester';
import yourPlugin from 'universe:your-plugin';
pluginTester({
plugin: yourPlugin,
tests: { 'test one': testOne, 'test two': testTwo }
});
pluginTester({
plugin: yourPlugin,
tests: { 'test one': testOne, 'test x': testTwo }
});
pluginTester({
plugin: yourPlugin,
tests: { 'test five': testOne }
});
`
Will result in [test blocks][18] with names like:
`text`
1. Test one
2. Test two
3. Test one
4. Test x
5. Test five
However, setting this option to true will restart the numbering:
`javascript
/ file: test/unit.test.js /
import { pluginTester } from 'babel-plugin-tester';
import yourPlugin from 'universe:your-plugin';
pluginTester({
plugin: yourPlugin,
tests: { 'test one': testOne, 'test two': testTwo }
});
pluginTester({
plugin: yourPlugin,
restartTitleNumbering: true,
tests: { 'test one': testOne, 'test x': testTwo }
});
pluginTester({
plugin: yourPlugin,
tests: { 'test five': testOne }
});
`
Which will result in [test blocks][18] with names like:
`text`
1. Test one
2. Test two
1. Test one
2. Test x
3. Test five
This option is false by default.
#### fixtures
There are two ways to create tests: using the [tests][34] option to providefixtures
one or more [test objects][42] or using the option described here.
Both can be used simultaneously.
The fixtures option must be a path to a directory with a structure similar to
the following:
`textthrows
fixtures
โโโ first-test # test title will be: "1. first test"
โย ย โโโ code.js # required
โย ย โโโ output.js # required (unless using the option)throws
โโโ second-test # test title will be: "2. second test"
โ โโโ .babelrc.js # optional
โ โโโ options.json # optional
โ โโโ code.ts # required (other file extensions are allowed too)
โ โโโ output.js # required (unless using the option)throws
โโโ nested
โโโ options.json # optional
โโโ third-test # test title will be: "3. nested > third test"
โ โโโ code.mjs # required (other file extensions are allowed too)
โ โโโ output.js # required (unless using the option)`
โ โโโ options.js # optional (overrides props in nested/options.json)
โโโ x-fourth-test # test title will be: "4. nested > x fourth test"
โโโ exec.js # required (alternative to code/output structure)
> [!TIP]
>
> .babelrc, .babelrc.json, .babelrc.js, .babelrc.cjs, and .babelrc.mjs
> config files in fixture directories are supported out-of-the-box.
Assuming the fixtures directory is in the same directory as your test file,
you could use it with the following configuration:
`javascript`
pluginTester({
plugin,
fixtures: path.join(__dirname, 'fixtures')
});
> [!NOTE]
>
> If fixtures is not an absolute path, it will be [path.join][40]'d with thefilepath
> [directory name][41] of [][54].
And it would run four tests, one for each directory in fixtures containing a
file starting with "code" or "exec".
##### code.js
This file's contents will be used as the source code input into babel at
transform time. Any file extension can be used, even a multi-part extension
(e.g. .test.js in code.test.js) as long as the file name starts withcode.; the [expected output file][56] will have the same file extension suffix.js
(i.e. in code.test.js) as this file unless changed with thefixtureOutputExt
[][52] option.
After being transformed by babel, the resulting output will have whitespace
trimmed, line endings [converted][57], and then get [formatted by prettier][39].
Note that this file cannot appear in the same directory as [exec.js][58]. Ifcode.*
more than one file exists in a directory, the first one will be used
and the rest will be silently ignored.
##### output.js
This file, if provided, will have its contents compared with babel's output,
which is [code.js][59] transformed by babel and [formatted with prettier][39].throws
If this file is missing and neither [][60] nor [exec.js][58] are beingfixtureOutputName
used, this file will be automatically generated from babel's output.
Additionally, the name and extension of this file can be changed with the
[][51] and [fixtureOutputExt][52] options.
Before being compared to babel's output, this file's contents will have
whitespace trimmed and line endings [converted][57].
Note that this file cannot appear in the same directory as [exec.js][58].
##### exec.js
This file's contents will be used as the input into babel at transform time just
like the [code.js][59] file, except the output will be _evaluated_ in theexpect
[same _CJS_ context][61] as the test runner itself, meaning it supports features
like a/sync IIFEs, debugging breakpoints (!), and has access to mocked modules,, require, __dirname and __filename (derived from this file'simport
path), and other globals/features provided by your test framework. However, the
context does not support _, top-level await, or any other ESM syntax_..ts
Hence, while any file extension can be used (e.g. , .vue, .jsx), this
file will always be evaluated as CJS.
The test will always pass unless an exception is thrown (e.g. when an expect()
fails).
Use this to make advanced assertions on the output. For example, to test that
[babel-plugin-proposal-throw-expressions][62] actually throws, your exec.js
file might contain:
`javascript`
expect(() => throw new Error('throw expression')).toThrow('throw expression');
> [!CAUTION]
>
> Keep in mind that, despite sharing a global context, execution will occur in a
> [separate realm][63], which means native/intrinsic types will be different.
> This can lead to unexpectedly failing tests. For example:
>
> `javascript${__dirname}/imported-file.json
> expect(require()).toStrictEqual({`
> data: 'imported'
> });
> Object
>
> This may fail in some test frameworks with the message "serializes to the same
> string". This is because the former object's prototype comes from aObject
> different realm than the second object's prototype, meaning the two`
> objects are not technically _strictly_ equal. However, something like the
> following, which creates two objects in the same realm, will pass:
>
> javascript${__dirname}/imported-file.json
> expect(
> Object.fromEntries(
> Object.entries(require())`
> )
> ).toStrictEqual({ data: 'imported' });
> JSON.stringify
>
> Or use + toBe (or your testing framework's equivalent):`
>
> javascript${__dirname}/imported-file.json
> expect(JSON.stringify(require())).toBe(`
> JSON.stringify({ data: 'imported' })
> );
> isEqual
>
> Or use (or your testing framework's equivalent):`
>
> javascript${__dirname}/imported-file.json
> expect(require()).toEqual({`
> data: 'imported'
> });
>
After being transformed by babel but before being evaluated, the babel output
will have whitespace trimmed, line endings [converted][57], and then get
[formatted by prettier][39].
Note that this file cannot appear in the same directory as [code.js][59] oroutput.js
[][56]. If more than one exec.* file exists in a directory, the
first one will be used and the rest will be silently ignored.
##### options.json (Or options.js)
For each fixture, the contents of the entirely optional options.json file arelodash.mergeWith
[][lodash.mergewith]'d with the options provided to
babel-plugin-tester, with the former taking precedence. Note that arrays will be
concatenated and explicitly undefined values will unset previously defined
values during merging.
For added flexibility, options.json can be specified as options.js insteadmodule.exports
so long as a JSON object is exported via [][64]. If both filesoptions.js
exist in the same directory, will take precedence andoptions.json will be ignored entirely.
Fixtures support deeply nested directory structures as well as shared or "root"
options.json files. For example, placing an options.json file in thefixtures/nested directory would make its contents the "global configuration"fixtures/nested
for all fixtures under . That is: each fixture wouldlodash.mergeWith
[][lodash.mergewith] the options provided tofixtures/nested/options.json
babel-plugin-tester, , and the contents of theiroptions.json
local file as described above.
What follows are the properties you may use if you provide an options file, all
of which are optional:
###### babelOptions
This is used to configure babel. Properties specified here override
([lodash.mergeWith][lodash.mergewith]) those from the [babelOptions][65]
option provided to babel-plugin-tester.
Note that arrays will be concatenated, explicitly undefined values will unset
previously defined values, and (as of babel-plugin-tester@>=12) duplicate
plugin/preset configurations will override each other (last configuration wins)
during merging.
###### pluginOptions
This is used to pass options into your plugin at transform time. Properties
specified here override ([lodash.mergeWith][lodash.mergewith]) those from thepluginOptions
[][16] option provided to babel-plugin-tester. Note that arrays
will be concatenated and explicitly undefined values will unset previously
defined values during merging.
Unlike with babel-plugin-tester's options, you can safely mix plugin-specific
properties (like pluginOptions) with preset-specific properties (likepresetOptions
[][24]) in your options files.
###### presetOptions
This is used to pass options into your preset at transform time. Properties
specified here override ([lodash.mergeWith][lodash.mergewith]) those from thepresetOptions
[][14] option provided to babel-plugin-tester. Note that arrays
will be concatenated and explicitly undefined values will unset previously
defined values during merging.
Unlike with babel-plugin-tester's options, you can safely mix plugin-specific
properties (like [pluginOptions][22]) with preset-specific properties (likepresetOptions) in your options files.
###### title
If provided, this will be used as the title of the test. Otherwise, the
directory name will be used as the title by default (with spaces replacing
dashes).
###### only
Use this to run only the specified fixture. Useful while developing to help
focus on a small number of fixtures. Can be used in multiple options.json
files.
> [!IMPORTANT]
>
> Requires [Jest][66], an equivalent interface (like [Vitest][8]), or a
> manually-defined it object exposing an appropriate [only][67] method.
###### skip
Use this to skip running the specified fixture. Useful for when you are working
on a feature that is not yet supported. Can be used in multiple options.json
files.
> [!IMPORTANT]
>
> Requires [Jest][66], an equivalent interface (like [Vitest][8]), or a
> manually-defined it object exposing an appropriate [skip][68] method.
###### throws
> [!IMPORTANT]
>
> When using certain values, this property must be used in options.js insteadoptions.json
> of .
Use this to assert that a particular code.js file should cause babel to throw
an error during transformation. For example:
`javascript`
{
// ...
throws: true,
throws: 'should have this exact message',
throws: /should pass this regex/,
throws: SyntaxError, // Should be an instance of this class
throws: err => {
if (err instanceof SyntaxError && /message/.test(err.message)) {
return true; // Test will fail if this function's return value !== true
}
},
}
> [!CAUTION]
>
> Be careful using instanceof [across realms][69] as it can lead to [strange
> behavior][70] with [frontend frames/windows][71] and with tools that rely on
> [Node's VM module][72] (like Jest).
If the value of throws is a class, that class must [be a subtype ofError][77] or the behavior of babel-plugin-tester is undefined.
Note that this property cannot be present when using an [exec.js][58] oroutput.js
[][56] file or when using the [outputRaw][78] option.
> [!NOTE]
>
> For backwards compatibility reasons, throws is synonymous with error. Theythrows
> can be used interchangeably, with taking precedence.
###### setup
> [!IMPORTANT]
>
> As it requires a function value, this property must be used in options.jsoptions.json
> instead of .
This function will be run before a particular fixture's tests are run. It can
return a function which will be treated as a [teardown][79] function. It canteardown
also return a promise. If that promise resolves to a function, that will be
treated as a [][79] function.
This function, if provided, will run _after_ any [setup][47] function provided
as a babel-plugin-tester option. See [here][46] for the complete run order.
###### teardown
> [!IMPORTANT]
>
> As it requires a function value, this property must be used in options.jsoptions.json
> instead of .
This function will be run after a fixture's tests finish running. You can define
this via teardown or you can return it from the [setup][80] function. This
can likewise return a promise if it is asynchronous.
This function, if provided, will be run _after_ any teardown function returned
by the [setup][80] property, both of which will run _before_ anyteardown
[][45] function provided as a babel-plugin-tester option. See
[here][46] for the complete run order.
###### formatResult
> [!IMPORTANT]
>
> As it requires a function value, this property must be used in options.jsoptions.json
> instead of .
This function is used to format all babel outputs, and defaults to a function
that invokes [prettier][48]. If a prettier configuration file is [found][49],
then that will be used. Otherwise, prettier will use its own default
configuration.
You can also [entirely disable formatting][39].
This will override the [formatResult][81] function provided to
babel-plugin-tester.
###### outputRaw
> [!WARNING]
>
> This feature is only available in babel-plugin-tester@>=12.
> [!IMPORTANT]
>
> As it requires a function value, this property must be used in options.jsoptions.json
> instead of .
This option is similar in intent to [output.js][56] except it tests againstBabelFileResult
the _entire [][82] object_ returned by [babel's transformcode
function][83] instead of only the property of [BabelFileResult][82].
outputRaw must be a function with the following signature:
`typescript`
outputRaw: (output: BabelFileResult) => void
Where the output parameter is an instance of [BabelFileResult][82]:
`typescript`
interface BabelFileResult {
ast?: Node | undefined;
code?: string | undefined;
ignored?: boolean | undefined;
map?: object | undefined;
metadata?: BabelFileMetadata | undefined;
}
So long as the outputRaw function does not throw, it will never cause the testoutputRaw
to fail. On the other hand, if the function throws, such as whenexpect(output.metadata).toStrictEqual({ ... }) fails, the test will fail
regardless of other options.
The output parameter is not trimmed, converted, stripped, or modified at all.
Note that outputRaw does not _replace_ [output.js][56] etc, it only addsfixtures
additional (custom) expectations to your test. Further note that this option
_can_ appear alongside any other [][35] option except [throws][84].
###### fixtureOutputName
Use this to provide your own fixture output file name. Defaults to "output".
###### fixtureOutputExt
Use this to provide your own fixture output file extension. Including the
leading period is optional; that is: if you want output.jsx,fixtureOutputExt can be set to either "jsx" or ".jsx". If omitted, the
[input fixture][59]'s file extension will be used instead.
This is particularly useful if you are testing TypeScript input.
#### tests
There are two ways to create tests: using the [fixtures][35] option thattests
leverages the filesystem or using the option described here. Both can be
used simultaneously.
Using the tests option, you can provide [test objects][42] describing yourtests
expected transformations. You can provide as an object of test objectspluginName
or an array of test objects. If you provide an object, the object's keys will be
used as the default title of each test. If you provide an array, each test's
default title will be derived from its index and
[][15]/[presetName][13].
See [the example][85] for more details.
##### Test Objects
A minimal test object can be:
1. A string representing [code][86].object
2. An with a [code][86] property.
What follows are the properties you may use if you provide an object, most of
which are optional:
###### babelOptions
This is used to configure babel. Properties specified here override
([lodash.mergeWith][lodash.mergewith]) those from the [babelOptions][65]
option provided to babel-plugin-tester.
Note that arrays will be concatenated, explicitly undefined values will unset
previously defined values, and (as of babel-plugin-tester@>=12) duplicate
plugin/preset configurations will override each other (last configuration wins)
during merging.
###### pluginOptions
This is used to pass options into your plugin at transform time. Properties
specified here override ([lodash.mergeWith][lodash.mergewith]) those from thepluginOptions
[][16] option provided to babel-plugin-tester. Note that arrays
will be concatenated and explicitly undefined values will unset previously
defined values during merging.
Unlike with babel-plugin-tester's options, you can safely mix plugin-specific
properties (like pluginOptions) with preset-specific properties (likepresetOptions
[][23]) in your test objects.
###### presetOptions
This is used to pass options into your preset at transform time. Properties
specified here override ([lodash.mergeWith][lodash.mergewith]) those from thepresetOptions
[][14] option provided to babel-plugin-tester. Note that arrays
will be concatenated and explicitly undefined values will unset previously
defined values during merging.
Unlike with babel-plugin-tester's options, you can safely mix plugin-specific
properties (like [pluginOptions][21]) with preset-specific properties (likepresetOptions) in your test objects.
###### title
If provided, this will be used as the title of the test. Otherwise, the title
will be determined from test object by default.
###### only
Use this to run only the specified test. Useful while developing to help focus
on a small number of tests. Can be used on multiple tests.
> [!IMPORTANT]
>
> Requires [Jest][66], an equivalent interface (like [Vitest][8]), or a
> manually-defined it object exposing an appropriate [only][67] method.
###### skip
Use this to skip running the specified test. Useful for when you are working on
a feature that is not yet supported. Can be used on multiple tests.
> [!IMPORTANT]
>
> Requires [Jest][66], an equivalent interface (like [Vitest][8]), or a
> manually-defined it object exposing an appropriate [skip][68] method.
###### throws
Use this to assert that a particular test object should cause babel to throw an
error during transformation. For example:
`javascript`
{
// ...
throws: true,
throws: 'should have this exact message',
throws: /should pass this regex/,
throws: SyntaxError, // Should be an instance of this class
throws: err => {
if (err instanceof SyntaxError && /message/.test(err.message)) {
return true; // Test will fail if this function's return value !== true
}
},
}
> [!CAUTION]
>
> Be careful using instanceof [across realms][69] as it can lead to [strange
> behavior][70] with [frontend frames/windows][71] and with tools that rely on
> [Node's VM module][72] (like Jest).
If the value of throws is a class, that class must [be a subtype ofError][77] or the behavior of babel-plugin-tester is undefined.
Note that this property cannot be present when using the [output][87],outputRaw
[][88], [outputFixture][37], [exec][89], [execFixture][38], orsnapshot
[][50] properties.
> [!NOTE]
>
> For backwards compatibility reasons, throws is synonymous with error. Theythrows
> can be used interchangeably, with taking precedence.
###### setup
This function will be run before a particular test is run. It can return a
function which will be treated as a [teardown][90] function. It can alsoteardown
return a promise. If that promise resolves to a function, that will be treated
as a [][90] function.
This function, if provided, will run _after_ any [setup][47] function provided
as a babel-plugin-tester option. See [here][46] for the complete run order.
###### teardown
This function will be run after a test finishes running. You can define this via
teardown or you can return it from the [setup][91] function. This can
likewise return a promise if it is asynchronous.
This function, if provided, will be run _after_ any teardown function returned
by the [setup][91] property, both of which will run _before_ anyteardown
[][45] function provided as a babel-plugin-tester option. See
[here][46] for the complete run order.
###### formatResult
This function is used to format all babel outputs, and defaults to a function
that invokes [prettier][48]. If a prettier configuration file is [found][49],
then that will be used. Otherwise, prettier will use its own default
configuration.
You can also [entirely disable formatting][39].
This will override the [formatResult][81] function provided to
babel-plugin-tester.
###### snapshot
If you would prefer to take a snapshot of babel's output rather than compare it
to something you provide manually, specify snapshot: true. This will cause
babel-plugin-tester to generate a snapshot containing both the [source code][86]
and babel's output.
Defaults to false.
Note that this property cannot appear in the same test object as the
[output][87], [outputFixture][37], [exec][89], [execFixture][38], orthrows
[][84] properties. However, it _can_ be used with [outputRaw][88].
> [!IMPORTANT]
>
> Requires [Jest][66], an [appropriate shim][92] or equivalent interface (like
> [Vitest][8]), or a manually-defined expect object exposing an appropriatetoMatchSnapshot
> [][93] method.
###### code
The code that you want babel to transform using your plugin or preset. This must
be provided unless you are using the [codeFixture][36] or [exec][89]output
properties instead. If you do not provide the [][87] oroutputFixture
[][37] properties, and [snapshot][50] is not truthy, then the
assertion is that this code is unchanged by the transformation.
Before being transformed by babel, any indentation will be stripped as a
convenience for template literals. After being transformed, the resulting output
will have whitespace trimmed, line endings [converted][57], and then get
[formatted by prettier][39].
Note that this property cannot appear in the same test object as the
[codeFixture][36], [exec][89], or [execFixture][38] properties.
###### output
The value of this property will be compared with the output from [babel's
transform function][83].
Before being compared to babel's output, this value will have whitespace
trimmed, line endings [converted][57], and any indentation stripped as a
convenience for template literals.
Note that this property cannot appear in the same test object as the
[outputFixture][37], [exec][89], [execFixture][38], [throws][84], orsnapshot
[][50] properties. However, it _can_ be used with [outputRaw][88].
###### outputRaw
> [!WARNING]
>
> This feature is only available in babel-plugin-tester@>=12.
This property is similar to [output][87] and related properties except itBabelFileResult
tests against the _entire [][82] object_ returned by [babel'stransform function][83] instead of only the code property ofBabelFileResult
[][82].
outputRaw must be a function with the following signature:
`typescript`
outputRaw: (output: BabelFileResult) => void
Where the output parameter is an instance of [BabelFileResult][82]:
`typescript`
interface BabelFileResult {
ast?: Node | undefined;
code?: string | undefined;
ignored?: boolean | undefined;
map?: object | undefined;
metadata?: BabelFileMetadata | undefined;
}
So long as the outputRaw function does not throw, this property will neveroutputRaw
cause the test to fail. On the other hand, if the function throws,expect(output.metadata).toStrictEqual({ ... })
such as when fails, the test
will fail regardless of other properties.
The output parameter is not trimmed, converted, stripped, or modified at all.
Note that outputRaw does not _replace_ [output][87] etc, it only addsoutputRaw
additional (custom) expectations to your test. Further note that throws
_can_ appear in the same test object as any other property except
[][84].
###### exec
The provided source will be transformed just like the [code][86] property,expect
except the output will be _evaluated_ in the [same _CJS_ context][61] as the
test runner itself, meaning it supports features like a/sync IIFEs, debugging
breakpoints (!), and has access to mocked modules, , require,__dirname and __filename (derived from available path info and falling backfilepath
on [][54]), and other globals/features provided by your testimport
framework. However, the context does not support _, top-level await, or.ts
any other ESM syntax_. Hence, while any file extension can be used (e.g. ,.vue, .jsx), this file will always be evaluated as CJS.
The test will always pass unless an exception is thrown (e.g. when an expect()
fails).
Use this to make advanced assertions on the output. For example, you can test
that [babel-plugin-proposal-throw-expressions][62] actually throws using the
following:
`javascript
{
// ...
exec:
expect(() => throw new Error('throw expression')).toThrow('throw expression');
;`
}
> [!CAUTION]
>
> Keep in mind that, despite sharing a global context, execution will occur in a
> [separate realm][63], which means native/intrinsic types will be different.
> This can lead to unexpectedly failing tests. For example:
>
> `javascript${__dirname}/imported-file.json
> expect(require()).toStrictEqual({`
> data: 'imported'
> });
> Object
>
> This may fail in some test frameworks with the message "serializes to the same
> string". This is because the former object's prototype comes from aObject
> different realm than the second object's prototype, meaning the two`
> objects are not technically _strictly_ equal. However, something like the
> following, which creates two objects in the same realm, will pass:
>
> javascript${__dirname}/imported-file.json
> expect(
> Object.fromEntries(
> Object.entries(require())`
> )
> ).toStrictEqual({ data: 'imported' });
> JSON.stringify
>
> Or use + toBe (or your testing framework's equivalent):`
>
> javascript${__dirname}/imported-file.json
> expect(JSON.stringify(require())).toBe(`
> JSON.stringify({ data: 'imported' })
> );
> isEqual
>
> Or use (or your testing framework's equivalent):`
>
> javascript${__dirname}/imported-file.json
> expect(require()).toEqual({`
> data: 'imported'
> });
>
After being transformed by babel but before being evaluated, the babel output
will have whitespace trimmed, line endings [converted][57], and then get
[formatted by prettier][39].
Note that this property cannot appear in the same test object as the
[execFixture][38], [code][86], [codeFixture][36], [output][87],outputFixture
[][37], [throws][84], or [snapshot][50] properties. However,outputRaw
it _can_ be used with [][88].
###### codeFixture
If you would rather put your [code][86] in a separate file, you can specify acodeFixture
file path here instead. If it is an absolute path, then that's the file that
will be loaded. Otherwise, will be [path.join][40]'d with thefilepath
[directory name][41] of [][54].
After being transformed by babel, the resulting output will have whitespace
trimmed, line endings [converted][57], and then get [formatted by prettier][39].
Like [code][86], this property cannot appear in the same test object as theexec
[][89] or [execFixture][38] properties, nor the [code][86] property.
> [!TIP]
>
> If you find you are using this property more than a couple of times, consider
> using [fixtures][35] instead.
> [!NOTE]
>
> For backwards compatibility reasons, codeFixture is synonymous withfixture
> . They can be used interchangeably, though care must be taken not tofixture
> confuse the test object property with the babel-plugin-tester optionfixtures
> [__][35], the latter being plural.
###### outputFixture
If you would rather put your [output][87] in a separate file, you can specifyoutputFixture
a file path here instead. If it is an absolute path, then that's the file that
will be loaded. Otherwise, will be [path.join][40]'d with thefilepath
[directory name][41] of [][54].
Before being compared to babel's output, this file's contents will have
whitespace trimmed and line endings [converted][57].
Like [output][87], this property cannot appear in the same test object as theexec
[][89], [execFixture][38], [throws][84], or [snapshot][50]output
properties, nor the [][87] property. However, it _can_ be used withoutputRaw
[][88].
> [!TIP]
>
> If you find you are using this property more than a couple of times, consider
> using [fixtures][35] instead.
###### execFixture
If you would rather put your [exec][89] in a separate file, you can specify aexecFixture
file path here instead. If it is an absolute path, then that's the file that
will be loaded. Otherwise, will be [path.join][40]'d with thefilepath
[directory name][41] of [][54].
After being transformed by babel but before being evaluated, the babel output
will have whitespace trimmed, line endings [converted][57], and then get
[formatted by prettier][39].
Like [exec][89], this property cannot appear in the same test object as thecode
[][86], [codeFixture][36], [output][87], [outputFixture][37],throws
[][84], or [snapshot][50] properties, nor the [exec][89] property.outputRaw
However, it _can_ be used with [][88].
> [!TIP]
>
> If you find you are using this property more than a couple of times, consider
> using [fixtures][35] instead.
`javascript
import { pluginTester } from 'babel-plugin-tester';
import identifierReversePlugin from '../identifier-reverse-plugin';
// NOTE: you can use beforeAll, afterAll, beforeEach, and afterEach as usual,
// but initial configuration tasks, like loading content from fixture files,
// will complete at the point the pluginTester function is called which means
// BEFORE beforeAll and other Jest hooks are run.
pluginTester({
plugin: identifierReversePlugin,
// Defaults to false, but with this line we set the default to true across
// all tests.
snapshot: true,
tests: [
{
code: "'hello';"
// Snapshot should show that prettier has changed the single quotes to
// double quotes (using prettier's default configuration).
},
{
// This test will pass if and only if code has not changed.
code: '"hello";'
// To prevent false negatives (like with reckless use of npx jest -u),
// snapshots of code that does not change are forbidden. Snapshots
// succeed only when babel output !== code input.
snapshot: false;
},
{
code: 'var hello = "hi";',
output: 'var olleh = "hi";',
// You can't take a snapshot and also manually specify an output string.
// It's either one or the other.
snapshot: false
},
// A valid test can be a test object or a simple string.
function sayHi(person) {
return 'Hello ' + person + '!'
}
console.log(sayHi('Jenny'))
`
]
});
`javascript
import path from 'node:path';
import { pluginTester } from 'babel-plugin-tester';
import identifierReversePlugin from '../identifier-reverse-plugin';
pluginTester({
// One (and ONLY ONE) of the two following lines MUST be included.
plugin: identifierReversePlugin,
//preset: coolNewBabelPreset,
// Usually unnecessary if it is returned by the plugin. This will default to
// 'unknown plugin' if a name cannot otherwise be inferred.
pluginName: 'identifier reverse',
// Unlike with pluginName, there is no presetName inference. This will default
// to 'unknown preset' if a name is not provided.
//presetName: 'cool-new-babel-preset',
// Used to test specific plugin options.
pluginOptions: {
optionA: true
},
//presetOptions: {
// optionB: false,
//}
// Defaults to the plugin name.
title: 'describe block title',
// Only useful if you are using fixtures, codeFixture, outputFixture, or
// execFixture options. Defaults to the absolute path of the file the
// pluginTester function was invoked from, which in this case is equivalent
// to the following line:
filepath: __filename,
// These are the defaults that will be lodash.mergeWith'd with the provided
// babelOptions option.
babelOptions: {
parserOpts: {},
generatorOpts: {},
babelrc: false,
configFile: false
},
// Defaults to false but we're being explicit here: do not use snapshots
// across all tests. Note that snapshots are only guaranteed to work with
// Jest.
snapshot: false,
// Defaults to a function that formats with prettier.
formatResult: customFormatFunction,
// You can provide tests as an object:
tests: {
// The key is the title. The value is the code that is unchanged (because
// snapshot === false across all tests). Test title will be: "1. does not
// change code with no identifiers".
'does not change code with no identifiers': '"hello";',
// Test title will be: "2. changes this code".
'changes this code': {
// Input to the plugin.
code: 'var hello = "hi";',
// Expected output.
output: 'var olleh = "hi";'
}
},
See [fixtures][35] for an example directory layout or check out the use of
babel-plugin-tester fixtures in some of these other projects:
- [babel-plugin-transform-rewrite-imports][94]
- [babel-plugin-explicit-exports-references][95]
- [babel-plugin-transform-default-named-imports][96]
Further documentation can be found under [docs/][x-repo-docs].
This package was originally tested on and built to work with [Jest][4], but it
is also [tested][97] against [Vitest][8], [Mocha][5], [Jasmine][6], and
[node:test][7]. See below for details.
#### Jest
All babel-plugin-tester features work with Jest. No further action is necessary
๐
#### Vitest
All babel-plugin-tester features work with Vitest, though Vitest does not
provide global APIs by default. You can either supply some interoperability code
(see Jasmine or node:test below for an example) or run Vitest with the--globals
[ CLI option][98].
#### Mocha
Most babel-plugin-tester features work with Mocha, except Mocha does not
natively support snapshots.
#### Jasmine
Most babel-plugin-tester features work with Jasmine if you define the
appropriate globals:
`javascript
import { pluginTester } from 'babel-plugin-tester';
globalThis.it.skip = globalThis.xit;
globalThis.it.only = globalThis.fit;
pluginTester(...);
`
However, Jasmine does not natively support snapshots.
#### node:test
Most babel-plugin-tester features work with node:test if you define the
appropriate globals:
`javascript
import { describe, it } from 'node:test';
import { pluginTester } from 'babel-plugin-tester';
globalThis.describe = describe;
globalThis.it = it;
// globalThis.it.skip = ... (weirdly, this is already defined)
globalThis.it.only = (...args) => it(args[0], { only: true }, args[1]);
pluginTester(...);
`
However, node:test does not natively support snapshots.
#### Other Frameworks
Other testing frameworks and test runners should also work so long as they
define standard describe and it globals with async support, or appropriatenode:test
interoperability code is used like in the above Jasmine and
examples.
[babelOptions.babelrc][28] and [babelOptions.configFile][29] are set tofalse by default. This way, you can [manually import (or provide an objectbabelOptions.babelrc
literal)][65] the exact configuration you want to apply rather than relying on
babel's [somewhat complex configuration loading rules][99]. However, if your
plugin, preset, or project relies on a complicated external setup to do its
work, and you do not mind the [default run order][100], you can leverage
[babel's automatic configuration loading][101] via the babelOptions.configFile
and/or options.
> [!TIP]
>
> Fixtures provided via the [fixtures][35] option do not need to provide ababelOptions.filename
> separate since it will be set automatically. This
> section only applies to [test objects][42].
When relying on babelOptions.babelrc, you must also provide ababelOptions.filename
[][102] for each test object that does not include acodeFixture
[][36] or [execFixture][38] property. For example:
`javascript`
pluginTester({
plugin,
tests: [
{
code: '"blah"',
// This configuration is set at the test level
babelOptions: {
babelrc: true,
filename: path.join(__dirname, 'some-file.js')
}
},
{
code: '"hi"',
// This configuration is set at the test level
babelOptions: {
babelrc: true,
filename: path.join(__dirname, 'some-other-file.js')
}
},
{
// babelOptions.filename will be set to the value of codeFixture for you
// unless you set it manually here at the test level
codeFixture: path.join(__dirname, 'fixtures', 'my-file.js')
},
{
// babelOptions.filename will be set to the value of execFixture for you
// unless you set it manually here at the test level
execFixture: path.join(__dirname, 'fixtures', 'my-script.js')
}
]
});
This file does not actually have to exist either, so you can use whatever value
you want for filename as long as the .babelrc file is [resolved][103]
properly. Hence, the above example could be simplified further:
`javascript`
pluginTester({
plugin,
// This configuration is global: it applies to all tests by default!
babelOptions: {
babelrc: true,
// The value of filename does not have to point to a file that exists
filename: __filename
},
tests: [
'"blah"',
'"hi"',
{
// babelOptions.filename will be set to the value of codeFixture for you
// unless you set it manually here at the test level
codeFixture: path.join(__dirname, 'fixtures', 'my-file.js')
},
{
// babelOptions.filename will be set to the value of execFixture for you
// unless you set it manually here at the test level
execFixture: path.join(__dirname, 'fixtures', 'my-script.js')
}
]
});
Inferring [pluginName][15] during testing requires invoking [the plugin][12]
_at least twice_: once outside of babel to check for the plugin's name and then
again when run by babel. This is irrelevant to babel-plugin-tester (even if your
plugin crashes when run outside of babel) and to the overwhelming majority of
babel plugins in existence. This only becomes a problem if your plugin is
_aggressively stateful_, which is against the [babel handbook on plugin
design][104].
For example, the following plugin which replaces an import specifier using a
regular expression will exhibit strange behavior due to being invoked twice:
`javascript
/ --- BAD CODE DO NOT USE --- /
let source;
// vvv When first invoked outside of babel, all passed arguments are mocks vvv
function badNotGoodPlugin({ assertVersion, types: t }) {
// ^^^ Which means assertVersion is mocked and t is undefined ^^^
assertVersion(7);
// vvv So don't memoize t here (which among other things is poor design) vvv
if (!source) {
source = (value, original, replacement) => {
return t.stringLiteral(value.replace(original, replacement));
};
}
return {
name: 'bad-bad-not-good',
visitor: {
ImportDeclaration(path, state) {
path.node.source = source(
path.node.source.value,
state.opts.originalRegExp,
state.opts.replacementString
);
}
}
};
}
pluginTester({
plugin: badNotGoodPlugin,
pluginOptions: { originalRegExp: /^y$/, replacementString: 'z' },
tests: [{ code: 'import { x } from "y";', output: 'import { x } from "z";' }]
});
// Result: error!
// TypeError: Cannot read properties of undefined (reading 'stringLiteral')
`
If you still want to use global state despite the handbook's advice, either
initialize global state within your visitor:
`javascript
let source;
function okayPlugin({ assertVersion, types: t }) {
assertVersion(7);
return {
name: 'okay',
visitor: {
Program: {
enter() {
// vvv Initialize global state in a safe place vvv
if (!source) {
source = (value, original, replacement) => {
return t.stringLiteral(value.replace(original, replacement));
};
}
}
},
ImportDeclaration(path, state) {
path.node.source = source(
path.node.source.value,
state.opts.originalRegExp,
state.opts.replacementString
);
}
}
};
}
pluginTester({
plugin: okayPlugin,
pluginOptions: { originalRegExp: /^y$/, replacementString: 'z' },
tests: [{ code: 'import { x } from "y";', output: 'import { x } from "z";' }]
});
// Result: works!
`
Or do things the proper way and just use local state instead:
`javascript
function betterPlugin({ assertVersion, types: t }) {
assertVersion(7);
// vvv Use local state instead so t is memoized properly vvv
const source = (value, original, replacement) => {
return t.stringLiteral(value.replace(original, replacement));
};
return {
name: 'better',
visitor: {
ImportDeclaration(path, state) {
path.node.source = source(
path.node.source.value,
state.opts.originalRegExp,
state.opts.replacementString
);
}
}
};
}
pluginTester({
plugin: betterPlugin,
pluginOptions: { originalRegExp: /^y$/, replacementString: 'z' },
tests: [{ code: 'import { x } from "y";', output: 'import { x } from "z";' }]
});
// Result: works!
`
If you are using Jest and snapshots, then the snapshot output could have a bunch
of bothersome \" to escape quotes. This is because, when Jest serializes a
string, it will wrap everything in double quotes. This is not a huge deal, but
it makes the snapshots harder to read, so we automatically add a snapshot
serializer for you to remove those. Note that this serializer is added globally
and thus will affect _all_ snapshots taken in the test file, even those outside
of babel-plugin-tester.
If you would like to disable this feature, then use the "pure" import (also
disables formatting of babel output with prettier):
`diff`
- import { pluginTester } from 'babel-plugin-tester'
+ import { pluginTester } from 'babel-plugin-tester/pure'
> It seems recent versions of Jest already ship with easier-to-read snapshots,
> making this serializer redundant. Therefore, the built-in custom serializer
> will likely be removed entirely in a future version of babel-plugin-tester.
By default, a [formatter][81] is used which formats all babel output with
[prettier][48]. It will [look for][49] a prettier configuration file relative to
[the file that's being tested][54] or the [current working directory][105]. If
it cannot find one, then it uses the default configuration for prettier.
This makes your snapshots easier to read and your expectations easier to write,
but if you would like to disable this feature, you can either use the [pureformatResult
import][106] to disable automatic formatting (along with snapshot serialization)
or you can override the option manually like so:
`javascript`
pluginTester({
// ...
formatResult: (r) => r
// ...
});
This package uses [debug][107] under the hood. To view all possible debugging
output, including the results of all babel transformations, set the
DEBUG='babel-plugin-tester,babel-plugin-tester:*' [environment variable][108]
when running your tests.
For example:
`bash`Those using Windows (but not WSL) have to set environment variable differently
NODE_ENV='test' DEBUG='babel-plugin-tester,babel-plugin-tester:*' DEBUG_DEPTH='1' npx jest
#### Available Debug Namespaces
The following [debug namespaces][109] are available for activation:
- babel-plugin-tester:indexbabel-plugin-tester:formatter
- babel-plugin-tester:serializer
- babel-plugin-tester:tester
- babel-plugin-tester:tester:resolve-base
- babel-plugin-tester:tester:resolve-env
- babel-plugin-tester:tester:normalize
- babel-plugin-tester:tester:normalize:create-desc
- babel-plugin-tester:tester:normalize:create-fix
- babel-plugin-tester:tester:normalize:create-obj
- babel-plugin-tester:tester:register
- babel-plugin-tester:tester:wrapper
- babel-plugin-tester:tester:test
- babel-plugin-tester:tester:validate
- babel-plugin-tester:tester:read-opts
- babel-plugin-tester:tester:read-code
- babel-plugin-tester:tester:eol
- babel-plugin-tester:tester:finalize
- babel-plugin-tester:tester:finalize:order
- babel-plugin-tester:tester:finalize:duplicates
-
The babel-plugin-tester:tester namespace and its sub-namespaces each have anverbose
additional sub-namespace that can be activated or deactivated at will,babel-plugin-tester:tester:verbose
e.g. andbabel-plugin-tester:t