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

esm: rename bin script file to avoid loader issues #1993

Merged
merged 6 commits into from Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from 5 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CONTRIBUTING.md) on how to contribute to Cucumber.

## [Unreleased]
### Changed
- Rename the `cucumber-js` binary's underlying file to have a `.js` extension, so it doesn't fall foul of Node.js module conventions and plays nicely with ESM loaders (see [documentation](./docs/esm.md#transpiling)) ([#1993](https://github.com/cucumber/cucumber-js/pull/1993))
davidjgoss marked this conversation as resolved.
Show resolved Hide resolved

### Fixed
- Correctly escape backslashes in generated expressions for snippets ([#1324](https://github.com/cucumber/cucumber-js/issues/1324) [#1995](https://github.com/cucumber/cucumber-js/pull/1995))

Expand Down
File renamed without changes.
6 changes: 5 additions & 1 deletion docs/esm.md
Expand Up @@ -58,4 +58,8 @@ export const ci = {

## Transpiling

When using a transpiler for e.g. TypeScript, ESM isn't supported - you'll need to configure your transpiler to output modules in CommonJS syntax (for now). See [this GitHub issue](https://github.com/cucumber/cucumber-js/issues/1844) for the latest on support for ESM loaders.
You can use [ESM loaders](https://nodejs.org/api/esm.html#loaders) to transpile your support code on the fly. The `requireModule` configuration option only works with CommonJS (i.e. `require` hooks) and is not applicable here. Cucumber doesn't have an equivalent option for ESM loaders because they currently can't be registered in-process, so you'll need to declare the loader externally, like this:

```shell
$ NODE_OPTIONS="--loader <loader>" npx cucumber-js
```
43 changes: 19 additions & 24 deletions docs/transpiling.md
Expand Up @@ -20,10 +20,6 @@ Your `tsconfig.json` should have these `compilerOptions` on:

Other than that, a pretty standard TypeScript setup should work as expected.

> ⚠️ Some TypeScript setups use `esnext` modules by default,
> which doesn't marry well with Node. You may consider using commonjs instead.
> See how to add [extra configuration](#extra-configuration) below.

You'll also need to specify where your support code is, since `.ts` files won't be picked up by default.

### With ts-node
Expand All @@ -33,32 +29,31 @@ If you are using [ts-node](https://github.com/TypeStrong/ts-node):
- In a configuration file `{ requireModule: ['ts-node/register'], require: ['step-definitions/**/*.ts'] }`
- On the CLI `$ cucumber-js --require-module ts-node/register --require 'step-definitions/**/*.ts'`

### With Babel
#### ESM

If you are using babel with [@babel/preset-typescript](https://babeljs.io/docs/en/babel-preset-typescript):
For ESM projects, you can use `ts-node`'s ESM loader and then `import` your TypeScript files:

- In a configuration file `{ requireModule: ['@babel/register'], require: ['step-definitions/**/*.ts'] }`
- On the CLI `$ cucumber-js --require-module @babel/register --require 'step-definitions/**/*.ts'`

## Extra Configuration
```shell
$ NODE_OPTIONS"--loader ts-node/esm" cucumber-js --import 'step-definitions/**/*.ts'
```

Sometimes the required module (say `ts-node/register`) needs extra configuration. For example, you might want to configure it such that it prevents the compiled JS being written out to files, and pass some compiler options. In such cases, create a script (say, `tests.setup.js`):
Don't forget to set your `tsconfig.json` to emit JavaScript with `import` and `export` statements:

```js
require('ts-node').register({
transpileOnly: true,
compilerOptions: {
"module": "commonjs",
"resolveJsonModule": true,
},
});
```json
{
"compilerOptions": {
"module": "esnext"
}
}
```

And then require it using the `require` option:
### With Babel

If you are using babel with [@babel/preset-typescript](https://babeljs.io/docs/en/babel-preset-typescript):

- In a configuration file `{ require: ['tests.setup.js', 'features/**/*.ts'] }`
- On the CLI `$ cucumber-js --require tests.setup.js --require 'features/**/*.ts'`
- In a configuration file `{ requireModule: ['@babel/register'], require: ['step-definitions/**/*.ts'] }`
- On the CLI `$ cucumber-js --require-module @babel/register --require 'step-definitions/**/*.ts'`

## ESM
### ESM

Cucumber doesn't yet support native ESM loader hooks ([see GitHub issue](https://github.com/cucumber/cucumber-js/issues/1844)).
See [ESM](./esm.md) for general advice on using loaders for transpilation in ESM projects.
4 changes: 2 additions & 2 deletions features/support/hooks.ts
Expand Up @@ -45,7 +45,7 @@ Before(function (
} catch (error) {
warnUserAboutEnablingDeveloperMode(error)
}
this.localExecutablePath = path.join(projectPath, 'bin', 'cucumber-js')
this.localExecutablePath = path.join(projectPath, 'bin', 'cucumber.js')
})

Before('@esm', function (this: World) {
Expand Down Expand Up @@ -102,7 +102,7 @@ Before('@global-install', function (this: World) {
this.globalExecutablePath = path.join(
globalInstallCucumberPath,
'bin',
'cucumber-js'
'cucumber.js'
)
})

Expand Down
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -291,7 +291,7 @@
"cck-test": "mocha 'compatibility/**/*_spec.ts'",
"docs:ci": "api-extractor run --verbose",
"docs:local": "api-extractor run --verbose --local && api-documenter markdown --input-folder ./tmp/api-extractor --output-folder ./docs/api",
"feature-test": "node ./bin/cucumber-js",
"feature-test": "node bin/cucumber.js",
"lint-autofix": "eslint --fix \"{compatibility,example,features,scripts,src,test}/**/*.ts\"",
"lint-code": "eslint \"{compatibility,example,features,scripts,src,test}/**/*.ts\"",
"lint-dependencies": "dependency-lint",
Expand All @@ -303,14 +303,14 @@
"prepublishOnly": "rm -rf lib && npm run build-local",
"pretest-coverage": "npm run build-local",
"pretypes-test": "npm run build-local",
"test-coverage": "nyc --silent mocha 'src/**/*_spec.ts' 'compatibility/**/*_spec.ts' && nyc --silent --no-clean node ./bin/cucumber-js && nyc report --reporter=lcov",
"test-coverage": "nyc --silent mocha 'src/**/*_spec.ts' 'compatibility/**/*_spec.ts' && nyc --silent --no-clean node bin/cucumber.js && nyc report --reporter=lcov",
"test": "npm run lint && npm run types-test && npm run unit-test && npm run cck-test && npm run feature-test",
"types-test": "tsd",
"unit-test": "mocha 'src/**/*_spec.ts'",
"update-dependencies": "npx npm-check-updates --upgrade"
},
"bin": {
"cucumber-js": "./bin/cucumber-js"
"cucumber-js": "bin/cucumber.js"
},
"license": "MIT",
"files": [
Expand Down
3 changes: 1 addition & 2 deletions src/configuration/argv_parser.ts
@@ -1,6 +1,5 @@
import { Command } from 'commander'
import merge from 'lodash.merge'
import path from 'path'
import { dialects } from '@cucumber/gherkin'
import Formatters from '../formatter/helpers/formatters'
import { version } from '../version'
Expand Down Expand Up @@ -65,7 +64,7 @@ const ArgvParser = {
},

parse(argv: string[]): IParsedArgv {
const program = new Command(path.basename(argv[1]))
const program = new Command('cucumber-js')
aurelien-reeves marked this conversation as resolved.
Show resolved Hide resolved

program
.storeOptionsAsProperties(false)
Expand Down