Skip to content

Latest commit

 

History

History
72 lines (40 loc) · 4.38 KB

transpiling.md

File metadata and controls

72 lines (40 loc) · 4.38 KB

Transpiling

Step definitions and support files can be written in a syntax or language that compiles (or, "transpiles") to JavaScript, and just-in-time compiled when you run Cucumber. This requires a little extra configuration of Cucumber, so we can use the correct mechanism to compile your code on the fly.

For this doc, we'll take the example of TypeScript since it's so prevalent in the ecosystem. But you'll do similar things if you want to use e.g. Babel or CoffeeScript instead.

For compiling TypeScript on the fly, you should install ts-node if it's not already a dependency of your project:

npm install --save-dev ts-node

Module format

The first thing you need to establish is the JavaScript module format you are compiling to. It'll be either of:

  • CommonJS produces require and module.exports in compiled output for imports and exports respectively in the source. If you aren't sure, there's a good chance it's this one.
  • ESM produces import and export in compiled output which should more closely match your source. This is newer than CommonJS but gaining adoption quickly as the industry transitions.

With TypeScript, your tsconfig.json should provide some clues. Specifically, if compilerOptions.module is not specified or CommonJS, then you're probably outputting CommonJS, whereas anything starting with ES or Node indicates ESM.

CommonJS

For CommonJS, you need to use the requireModule configuration option to register ts-node, and then require for your TypeScript support code, like this:

  • In a configuration file { requireModule: ['ts-node/register'], require: ['features/step-definitions/**/*.ts'] }
  • On the CLI npx cucumber-js --require-module ts-node/register --require 'features/step-definitions/**/*.ts'

ESM

There are two ways of doing this depending on your version of Cucumber. Given the transitional state of modules in Node.js, consider them both experimental for now.

Loader option

ℹ️ Added in v10.6.0

For ESM, you need to use the loader configuration option to register ts-node, and then import for your TypeScript support code, like this:

  • In a configuration file { loader: ['ts-node/esm'], import: ['features/step-definitions/**/*.ts'] }
  • On the CLI npx cucumber-js --loader ts-node/esm --import 'features/step-definitions/**/*.ts'

The value of loader will usually be a package/module name, but if you have a loader you've authored locally, you can provide a path that's relative to your project's working directory.

Note that some LTS version streams of Node.js introduced this loaders support fairly recently, and you might need to upgrade to a newer minor version:

  • 18.x - you need at least 18.19.0
  • 20.x - you need at least 20.6.0

Environment variable

In versions earlier than v10.6.0 (without the loader option), you can still instruct Node.js to register the loader on the process via the NODE_OPTIONS environment variable, like this:

NODE_OPTIONS=\"--loader ts-node/esm\"

You then just need to specify the import option as above for your support code.

(This approach is no longer recommended, and you might see a warning from Node.js telling you so.)

tsconfig-paths

It's not unusual for people to use some path remapping and tsconfig-paths as part of their TypeScript setup. See this open issue regarding ESM support in that library.

Source maps

Source maps are used to ensure accurate source references and stack traces in Cucumber's reporting, by giving traceability from a transpiled piece of code back to the original source code.

Just-in-time transpilers like ts-node and @babel/register have sensible default configuration that emits source maps and enables them in the runtime environment, so you shouldn't have to do anything in order for source maps to work.

If you're using step definition code that's already transpiled (maybe because it's a shared library) then you'll need to:

  1. Ensure source maps are emitted by your transpiler. You can verify by checking for a comment starting with //# sourceMappingURL= at the end of your transpiled file(s).
  2. Ensure source maps are enabled at runtime. Node.js supports this natively via the --enable-source-maps flag.