Implementing TypeScript module resolution with Cucumber-js can be a bit tricky

Currently, I am in the process of creating a Proof of Concept for Cucumber-js using TypeScript. Everything is going smoothly except for one issue - I am facing difficulties when it comes to configuring the module resolution while utilizing tsconfig-paths.

This is the structure of my project:

.
├── cucumber.js
├── features
│   └── bank-account.feature
├── package.json
├── package-lock.json
├── step-definitions
│   └── bank-account.steps.ts
├── support
│   └── model
│       └── bank-account.model.ts
├── tsconfig.json
└── tslint.json

I am using cucumber-tsflow, hence my "step definitions" appear as follows:

// import { BankAccount } from "@model/bank-account.model"; // ...trouble!
import { BankAccount } from "../support/model/bank-account.model";

import { expect } from "chai";
import { binding, given, then, when } from "cucumber-tsflow";

@binding()
export class BankAccountSteps {
  ...

  @when("{int} is deposited")
  public when(amount: number) {
    this.account.deposit(amount);
  }

  ...
}

Despite correctly configuring @model/bank-account.model in both tsconfig.json and cucumber.js, I am unable to utilize it:

# file: tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    ...
    "paths": {
      "*": ["./*"],
      "@model/*": ["./support/model/*"]
    },
    ...
    "types": [
      "@types/chai",
      "@types/cucumber",
      "node"
    ]
  },
  "exclude": ["node_modules/"],
  "include": ["./step-definitions/**/*", "./support/**/*"]
}
# file: cucumber.js
const common = [
  "features/**/*.feature",
  "--require-module ts-node/register",
  // "--require-module tsconfig-paths/register",
  "--require step-definitions/**/*.ts",
  "--require support/**/*.ts"
].join(" ");

module.exports = {
  default: common,
};

Once I include

"--require-module tsconfig-paths/register"
in cucumber.js, an error message pops up:

$ npm run test

> cucumber-js --profile default

TypeError: cucumber_1.Before is not a function
    at _.once (/home/x80486/Workshop/Development/cucumber-basics/node_modules/cucumber-tsflow/src/binding-decorator.ts:78:3)
    at /home/x80486/Workshop/Development/cucumber-basics/node_modules/underscore/underscore.js:957:21
    at /home/x80486/Workshop/Development/cucumber-basics/node_modules/cucumber-tsflow/src/binding-decorator.ts:38:5
    at __decorate (/home/x80486/Workshop/Development/cucumber-basics/step-definitions/bank-account.steps.ts:5:95)
    at Object.<anonymous> (/home/x80486/Workshop/Development/cucumber-basics/step-definitions/bank-account.steps.ts:8:30)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Module.m._compile (/home/x80486/Workshop/Development/cucumber-basics/node_modules/ts-node/src/index.ts:473:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/home/x80486/Workshop/Development/cucumber-basics/node_modules/ts-node/src/index.ts:476:12)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:690:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at supportCodePaths.forEach.codePath (/home/x80486/Workshop/Development/cucumber-basics/node_modules/cucumber/lib/cli/index.js:142:42)
    at Array.forEach (<anonymous>)

I would greatly appreciate any insights from those experienced with TypeScript or Cucumber regarding this issue.


UPDATE

Interestingly, by removing cucumber.js and passing all options directly through the npm script (

"test": "cucumber-js features/**/*.feature --require-module ts-node/register --require-module tsconfig-paths/register --require step-definitions/**/*.ts --require support/**/*.ts"
), everything works flawlessly :mind-blowing:

Furthermore, changing the baseUrl to something different, such as "./support" instead of "./", also resolves the issue without the need to delete cucumber.js.

Answer №1

One thing that immediately catches my attention is that in your cucumber profile, you are referencing the .ts files instead of the compiled TypeScript files that cucumber-js typically looks for. You may want to try this updated configuration:

const common = [
  "features/**/*.feature",
  "--require-module ts-node/register",
  // "--require-module tsconfig-paths/register",
  "--require step-definitions/**/*.js",
  "--require support/**/*.js"
].join(" ");

Additionally, while it might not be a critical issue, I always make sure to specify the file type at the end of my includes in the tsconfig file.

I've actually been considering creating an example cucumber-js project using TypeScript and sharing it on GitHub for others to use. Perhaps now is the time for me to finally do so!

Answer №2

While not a definitive solution to the issue at hand, I have found success using @cucumber/cucumber version 7.x. It's likely that this update has also been applied to previous stable releases.

For those interested, you can find a functional example project for testing purposes here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Challenges surrounding asynchronous functionality in React hooks

I've been facing some issues with this code and have resorted to debugging it using console.log(). However, the results I'm getting are not making any sense. Can someone help me identify what's wrong with this code? I noticed that my console ...

What is the TypeScript definition for the return type of a Reselect function in Redux?

Has anyone been able to specify the return type of the createSelector function in Redux's Reselect library? I didn't find any information on this in the official documentation: https://github.com/reduxjs/reselect#q-are-there-typescript-typings ...

What is the best way to generate a switch statement based on an enum type that will automatically include a case for each enum member?

While Visual Studio Professional has this feature, I am unsure how to achieve it in VS Code. Take for instance the following Colors enum: enum Colors { Red, Blue, When writing a switch statement like this: function getColor(colors: Colors) { swi ...

Developing a type specifically for this function to operate on tuples of varying lengths

I am currently developing a parser combinator library and I am in need of creating a map function that can take N parsers in a tuple, along with a function that operates on those N arguments and returns a parser that parses into the return type specified b ...

Having trouble installing dependencies in a React project with TypeScript due to conflicts

I encountered a TypeScript conflict issue whenever I tried to install any dependency in my project. Despite attempting various solutions such as updating dependencies, downgrading them, and re-installing by removing node_modules and package-lock.json, the ...

The power of Vue reactivity in action with Typescript classes

Currently, I am working on a Vue application that is using Vue 2.6.10 along with Typescript 3.6.3. In my project, I have defined a Typescript class which contains some standard functions for the application. There is also a plugin in place that assigns an ...

Issue with <BrowserRouter>: TS2769: No suitable overload for this call available

I encountered this error and have been unable to find a solution online. As a beginner in typescript, I am struggling to resolve it. The project was originally in JavaScript and is now being migrated to TypeScript using ts-migrate. I am currently fixing er ...

Strategies for effectively mocking an Angular service: During Karma Jasmine testing, ensure that the spy on service.getShipPhotos is expected to be called once. In the test, it should

Currently, I am working on testing a function called getSingleShip in Angular 12 using Karma-Jasmine 4. The aim is to verify if this function is being called by another function named retrieveShip. However, the test results indicate that getSingleShip has ...

Batch requesting in Typescript with web3 is an efficient way to improve

When attempting to send a batch request of transactions to my contract from web3, I encountered an issue with typing in the .request method. My contract's methods are defined as NonPayableTransactionObject<void> using Typechain, and it seems tha ...

An email value being recognized as NULL

create-employee.html <div class="form-group"> <label for="exampleInputEmail1">Email address</label> <span><input type="text" [required]="!standingQueue" class="form-control" name="exampleInputEmail1" ...

Tips for overlaying a webpage with several Angular components using an element for disabling user interactions

I currently have an asp.net core Angular SPA that is structured with a header menu and footer components always visible while the middle section serves as the main "page" - comprised of another angular component. What I am looking to achieve is ...

What is the method for adjusting the spacing between binding tags within HTML code formatting specifically for TypeScript elements in IntelliJ?

My Angular binding currently defaults to <h1>{{typeScriptVar}}</h1>, but I would like it to be set as <h1>{{ typeScriptVar }}</h1> when I use the format code shortcut in InteliJ. Can anyone assist me with this issue? I have resear ...

Using Typescript to test with Karma, we can inject a service for our

I'm currently experiencing a problem with running tests in my application. I recently transitioned to using TypeScript and am still in the learning process. The specific error I'm encountering is: Error: [$injector:unpr] Unknown provider: movie ...

Troubleshooting Angular: Issues with Table Data Display and Source Map Error

I'm currently tackling a challenge in my Angular application where I am unable to display data in a table. When I fetch data from a service and assign it to a "rows" variable within the ngOnInit of my component, everything seems to be working fine bas ...

What is preventing me from accessing a JavaScript object property when using a reactive statement in Svelte 3?

Recently, while working on a project with Svelte 3, I encountered this interesting piece of code: REPL: <script lang="ts"> const players = { men: { john: "high", bob: "low", }, }; // const pl ...

Angular 6 Material now allows for the selection of a mat-tab-link by displaying an underlining bar

My website features a mat-tab-nav-bar navigation bar, but I'm facing an issue with the mat-tab-link blue underlining bar. It doesn't move to highlight the active button, instead, it stays on the first button. However, the buttons do change into t ...

When checking for a `null` value, the JSON property of Enum type does not respond in

Within my Angular application, I have a straightforward enum known as AlertType. One of the properties in an API response object is of this enum type. Here is an example: export class ScanAlertModel { public alertId: string; public alertType: Aler ...

"Enable email delivery in the background on a mobile app without relying on a server

I am currently in the process of developing a mobile app using Ionic. One feature I would like to incorporate is sending an email notification to admins whenever a post is reported within the app. However, I am facing challenges with implementing this succ ...

What steps can I take to resolve a dependency update causing issues in my code?

My program stopped working after updating one of the dependencies and kept throwing the same error. Usually, when I run 'ng serve' in my project everything works fine, but after updating Chartist, I encountered this error: An unhandled exception ...

Improving my solution with PrimeNG in Angular2 - fixing the undefined tag error

After working with Angular for just three days, I successfully set up a login page dashboard using a web API solution. Everything was working great until I encountered an issue when trying to load the PrimeNG DataTableModule into my components. After searc ...