Closed Sam-Levene closed 1 year ago
Unless there's some configuration you haven't shared here, it looks like you don't have anything set up to transpile your TypeScript code to JavaScript that Node.js can interpret.
You probably want to do one of:
--require-module
option pointing at something like ts-node or babel, if you have TypeScript configured to emit CommonJS modules--require
to --import
and declare an ES module loader, if you have TypeScript configured to emit ES modulesThere are some docs here offering a bit more detail: https://github.com/cucumber/cucumber-js/blob/main/docs/transpiling.md
Thanks David.
Can you please confirm what you mean by "if I have TypeScript configured to emit CommonJS or ES modules". How do I check which modules my TypeScript is configured to emit? (I am using VS Code)
EDIT: I tried to follow your link but it really wasn't very helpful. I tried installing ts-node and got the following error:
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/sam.levene/QA/playwright-automation/features/step_definitions/steps.ts
at new NodeError (internal/errors.js:322:7)
at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:71:15)
at Loader.getFormat (internal/modules/esm/loader.js:105:42)
at Loader.getModuleJob (internal/modules/esm/loader.js:243:31)
at async Loader.import (internal/modules/esm/loader.js:177:17)
at async importer (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/importer.js:10:10)
at async getSupportCodeLibrary (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/src/api/support.ts:33:5)
at async runCucumber (/Users/sam.levene/QA/cbfe-playwright-automation/node_modules/@cucumber/cucumber/src/api/run_cucumber.ts:45:9)
at async Cli.run (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/src/cli/index.ts:78:25)
at async Object.run [as default] (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/src/cli/run.ts:38:14)
and my updated package.json:
{
"name": "playwright-poc",
"version": "0.0.1",
"description": "A Proof of Concept for Playwright",
"scripts": {
"test": "npx cucumber-js --require-module ts-node/register --import features/step_definitions/steps.ts --exit"
},
"type": "module",
"keywords": [],
"author": "Sam Levene",
"license": "ISC",
"devDependencies": {
"@cucumber/cucumber": "^9.0.1",
"@playwright/test": "^1.31.2",
"ts-node": "^10.9.1"
}
}
How do I check which modules my TypeScript is configured to emit?
Normally you would have a tsconfig.json
in the root of your project. In particular under the compilerOptions
the combination of target
and module
would decide what is output. More from the TypeScript docs here https://www.typescriptlang.org/docs/handbook/2/modules.html. Without a config file, I think it would default to es5 and CommonJS modules, but I'm not sure.
Consider looking at the example TypeScript project here https://github.com/cucumber/cucumber-js-examples/tree/main/examples/typescript-node
@davidjgoss - Hi David - Thanks for that link. I followed your link and added a cucumber.js
file with the following:
module.exports = {
default: [
"--require-module ts-node/register",
"--require features/**/*.ts",
"--publish-quiet",
].join(" "),
};
and I see the following error:
ReferenceError: module is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/Users/sam.levene/QA/playwright-automation/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
at file:///Users/sam.levene/QA/playwright-automation/cucumber.js:1:1
at ModuleJob.run (internal/modules/esm/module_job.js:183:25)
at async Loader.import (internal/modules/esm/loader.js:178:24)
at async importer (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/importer.js:10:10)
at async loadFile (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/configuration/from_file.js:56:35)
at async fromFile (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/configuration/from_file.js:19:25)
at async loadConfiguration (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/api/load_configuration.js:29:11)
at async Cli.run (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/cli/index.js:45:71)
at async Object.run [as default] (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/cli/run.js:34:18)
@davidjgoss - Hi David,
I've had a look and it appears that, because I'm using an ES module, it doesn't like the module.exports config in cucumber.js and expects it to be in an ES module format as such:
export const default = [
"--require-module ts-node/register",
"--require features/**/*.ts",
"--publish-quiet",
].join(" ");
the only issue is that default is a reserved word in Node.JS and it doesn't let me compile the config. Can I use a different name here and can Cucumber pick up on it if I do?
For the default profile you'd just need to do export default
followed by the value. Also consider using JSON or YAML.
https://github.com/cucumber/cucumber-js/blob/main/docs/configuration.md#files
Hi @davidjgoss - when I try that, I get the same error as yesterday with an unknown file extension.ts
cucumber.yml
default:
require-module: ts-node/register
import: ["features/**/*.ts"]
or
cucumber.js
export default [
"--require-module ts-node/register",
"--import features/**/*.ts",
"--publish-quiet",
].join(" ");
Error when running script:
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/sam.levene/QA/playwright-automation/features/step_definitions/steps.ts
at new NodeError (internal/errors.js:322:7)
at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:71:15)
at Loader.getFormat (internal/modules/esm/loader.js:105:42)
at Loader.getModuleJob (internal/modules/esm/loader.js:243:31)
at async Loader.import (internal/modules/esm/loader.js:177:17)
at async importer (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/importer.js:10:10)
at async getSupportCodeLibrary (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/src/api/support.ts:33:5)
at async runCucumber (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/src/api/run_cucumber.ts:45:9)
at async Cli.run (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/src/cli/index.ts:78:25)
at async Object.run [as default] (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/src/cli/run.ts:38:14)
EDIT: Forgot to mention here's my tsconfig file:
tsconfig.json
{
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "node"
}
}
You can't combine --require-module
with --import
. Since your tsconfig is emitting ESM, you should remove the --require-module
and instead use the ESM loader (which you have to set outside of the process e.g. NODE_OPTIONS="--loader ts-node/esm" npx cucumber-js
)
That seems to get me somewhere, now I'm stuck somewhere elsem, to do with esm-resolve and not cuke, so thanks @davidjgoss
Hi,
I had the same problem. The suggested answers did not work for me. I am also using a shared package.json with my angular project. Finally I found a fix, which works for me and wanted to share it:
{
"compilerOptions": {
"module": "NodeNext",
"target": "ES2022",
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"moduleResolution": "NodeNext"
}
}
--resolve-module
flag set to ts-node/register
or put it in your cucumber config file.This will pick up the tsconfig from the current working directory.
If you have, like me, a project where the modules are resolved from the workspace root, you can set the baseurl in the tsconfi accordingly. So if your cucumber tsconfig is in <root>/e2etest
folder for example, just set your baseurl to "../"
. My IDE (VSCode) autocompletes the imports using the baseurl in my "main" tsconfig.json.
So I hope this helps somebody.
My current versions are:
node: v20.5.0
npm: 9.8.0
"@cucumber/cucumber": "^10.0.1",
"ts-node": "^10.9.1",
"typescript": "~5.1.3",
Here is my current cucumber config (as yaml)
default:
features:
- "features/**/*.feature"
requireModule:
- "ts-node/register"
require:
- "steps/**/*.ts"
- "setup/**/*.ts"
format:
- progress-bar
π What did you see?
I am seeing an error in my compilation of a Node.JS and Cucumber-JS automation framework where I am expecting to see a success, the error mentions that it cannot use import statements outside of a module, then references cucumber's location as the root cause.
β What did you expect to see?
I was expecting to see cucumber accept and work alongside my TypeScript ECMAScript6-compliant code using imports
π¦ Which tool/library version are you using?
Node.JS (npm v14.21.3) Cucucmber-JS ("@cucumber/cucumber": "^9.0.1") Playwright ("@playwright/test": "^1.31.2")
π¬ How could we reproduce it?
I honestly don't know how you're going to reproduce it without trying to write some sort of Cucumber/Node.JS automation yourselves.
Quite simply here's some example code for you to try yourselves:
and simply try to run that npx script in the terminal of your choice.
π Any additional context?
N/A
This text was originally generated from a template, then edited by hand. You can modify the template here.