0

I have the following error when I try and compile my ECMAScript 6 compliant Node.js code:

$ npx cucumber-js --require features/step_definitions/steps.ts --exit
 
import { Before, Given, When, Then } from "@cucumber/cucumber";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1029:16)
    at Module._compile (internal/modules/cjs/loader.js:1078:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
    at Module.load (internal/modules/cjs/loader.js:979:32)
    at Function.Module._load (internal/modules/cjs/loader.js:819:12)
    at Module.require (internal/modules/cjs/loader.js:1003:19)
    at require (internal/modules/cjs/helpers.js:107:18)
    at /Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/api/support.js:18:32
    at Array.map (<anonymous>)
    at getSupportCodeLibrary (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/api/support.js:18:18)

Here's my code for analysis:

steps.ts

import { Before, Given, When, Then } from "@cucumber/cucumber";
import { Page, chromium } from "@playwright/test";
import { HomePage }  from "../../pages/HomePage";
import { SignInPage } from "../../pages/SignInPage";
import { SignInParameters } from "../../support/SignInParameters";

let homePage: HomePage;
let signInPage: SignInPage;
let signInParameters: SignInParameters;
let page: Page;

Before(async function() {
    var browser = await chromium.launch({
        headless: false,
    });
    var context = await browser.newContext();
    var page = await context.newPage();
    homePage = new HomePage(page);
    signInPage = new SignInPage(page);
    signInParameters = new SignInParameters();
});

(Step definition file. you get the gist.)

it seems as though the error is saying that cucumber-js doesn't support TypeScript type imports? But in my Npm modules, I am specifying the latest Cucumber-js version:

{
  "name": "playwright-poc",
  "version": "0.0.1",
  "description": "A Proof of Concept for Playwright",
  "scripts": {
    "test": "npx cucumber-js --require features/step_definitions/steps.ts --exit"
  },
  "type": "module",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@playwright/test": "^1.31.2",
    "@cucumber/cucumber": "^9.0.1"
  }
}

EDIT I attempted to follow the link from @ParzhFromUkraine and got the following error by editing the file to a .mjs:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/sam.levene/QA/playwright-automation/features/step_definitions/steps.mjs
    at new NodeError (internal/errors.js:322:7)
    at Module.load (internal/modules/cjs/loader.js:977:11)
    at Function.Module._load (internal/modules/cjs/loader.js:819:12)
    at Module.require (internal/modules/cjs/loader.js:1003:19)
    at require (internal/modules/cjs/helpers.js:107:18)
    at /Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/api/support.js:18:32
    at Array.map (<anonymous>)
    at getSupportCodeLibrary (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/api/support.js:18:18)
    at runCucumber (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/api/run_cucumber.js:34:53)
    at async Cli.run (/Users/sam.levene/QA/playwright-automation/node_modules/@cucumber/cucumber/lib/cli/index.js:50:29)

Can anyone assist with this?

Raisus
  • 148
  • 3
  • 23
  • Take a look at this: https://github.com/cucumber/cucumber-js/blob/main/docs/esm.md – Parzh from Ukraine Apr 14 '23 at 11:14
  • @ParzhfromUkraine - thanks for linking that, unfortunately, this too, returned a similar error: ``` Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/sam.levene/QA/playwright-automation/features/step_definitions/steps.mjs ``` – Raisus Apr 14 '23 at 11:21
  • @ParzhfromUkraine - I'll edit the main question with the attempt for the full error log when I tried this – Raisus Apr 14 '23 at 11:23
  • That's because all `import`s are transpiled to `require`s – Parzh from Ukraine Apr 14 '23 at 11:23
  • So how do I get it to actually work? Do I have to have some sort of custom config file? – Raisus Apr 14 '23 at 11:28
  • Take a look at these questions: 1) https://stackoverflow.com/questions/61670459/importing-in-node-js-error-must-use-import-to-load-es-module , and 2) https://stackoverflow.com/questions/58384179/syntaxerror-cannot-use-import-statement-outside-a-module . Does either of them help? – Parzh from Ukraine Apr 14 '23 at 11:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253155/discussion-between-raisus-and-parzh-from-ukraine). – Raisus Apr 14 '23 at 11:45

2 Answers2

0

With much effort from the devs at cucumber-js; I finally figured out what I was missing and how to fix it, so I'm now providing this here for future reference if anyone else is having the same issues.

Firstly, I was missing cucumber.js and tsconfig.json files with the following information:

cucumber.js

export default [
    "--import features/**/*.ts",
    "--publish-quiet"
].join(" ");
tsconfig.json

{
    "compilerOptions": {
      "allowJs": true,
      "baseUrl": ".",
      "forceConsistentCasingInFileNames": true,
      "module": "esnext",
      "moduleResolution": "nodenext",
      "noImplicitAny": true,
      "noImplicitReturns": true,
      "noImplicitThis": true,
      "noUnusedLocals": true,
      "sourceMap": true,
      "strictNullChecks": true,
      "esModuleInterop": true,
      "allowSyntheticDefaultImports": true,
      "target": "es6",
      "strict": true,
      "resolveJsonModule": true,
      "isolatedModules": true,
      "noEmit": true
    },
    "exclude": [
      "node_modules",
      ".idea",
      ".vscode"
    ],
    "include": [
      "features/**/*.ts",
    ]
  }

As this is using ES-Next; which is experimental, I also needed to edit the package.json such that it referenced the ESM loader and also installed ts-node:

package.json

{
  "name": "playwright-poc",
  "version": "0.0.2",
  "description": "A Proof of Concept for Playwright",
  "scripts": {
    "test": "NODE_OPTIONS=\"--loader ts-node/esm\" npx cucumber-js --parallel 10 --exit"
  },
  "type": "module",
  "keywords": [],
  "author": "Sam Levene",
  "license": "MIT",
  "devDependencies": {
    "@cucumber/cucumber": "^9.0.1",
    "@playwright/test": "^1.31.2",
    "ts-node": "^10.9.1"
  }
}

finally, I also had to edit my step definitions file to re-reference the imports such that it recognised the files correctly:

steps.ts

import { Before, Given, When, Then } from "@cucumber/cucumber";
import { Page, chromium } from "@playwright/test";
import { HomePage }  from "../../pages/HomePage.js";
import { SignInPage } from "../../pages/SignInPage.js";
import { ForgotPasswordPage } from "../../pages/ForgotPasswordPage.js";
import { SignInParameters } from "../../support/SignInParameters.js";

let homePage: HomePage;
let signInPage: SignInPage;
let signInParameters: SignInParameters;
let forgotPasswordPage: ForgotPasswordPage;
let page: Page;

Before(async function() {
    var browser = await chromium.launch({
        headless: false,
    });
    var context = await browser.newContext();
    page = await context.newPage();
    homePage = new HomePage(page);
    signInPage = new SignInPage(page);
    forgotPasswordPage = new ForgotPasswordPage(page);
    signInParameters = new SignInParameters();
});

NB: Even though in the steps.ts it says the imports are .js files, they are still .ts files

Raisus
  • 148
  • 3
  • 23
-2

You can solve this in two ways -

  • Either use require instead of directly importing the modules

like

const { Given, When, Then } = require('@cucumber/cucumber');
  • Or add this in the package.json to have it recognise that the type is a module.

In your package.json

{
   "type": "module"
}
demouser123
  • 4,108
  • 9
  • 50
  • 82
  • 1
    No. Using const makes the system complain about other imports specifically my local .ts files that should be exported as modules (but the complaint thinks isn't) – Raisus Apr 14 '23 at 14:42
  • Also, please check your answer as I already have the package.json set up as type: module – Raisus Apr 14 '23 at 14:42