cypress-cucumber-preprocessor: Error: Can't walk dependency graph: Cannot find module

Current behavior

I am trying to setup cypress-cucumber-preprocessor in my project. Cypress + React + Typescript

I have it all working as expected but when I try and setup cypress-cucumber-preprocessor with typescript I get the following error Error: Can't walk dependency graph: Cannot find module '^cypress/lib/auth.helper'

This happens with any custom module aliases used in my cypress files.

Here is my plugin index file:

const browserify = require('@cypress/browserify-preprocessor')
const cucumber = require('cypress-cucumber-preprocessor').default
const resolve = require('resolve')

module.exports = (on, config) => {
 const options = {
    ...browserify.defaultOptions,
    typescript: resolve.sync('typescript', { baseDir: config.projectRoot }),
  }

  on('file:preprocessor', cucumber(options))
}

Below is my tsconfig.json file in cypress directory

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "target": "es6",
    "lib": ["es6", "dom"],
    "types": ["cypress"],
    "isolatedModules": false,
    "allowJs": true,
    "noEmit": true,
    "baseUrl": "..",
    "paths": {
      "^cypress": [
        "../cypress/*"
      ]
    }
  },
  "include": [
    "../node_modules/cypress",
    "**/*.ts"
  ],
  "exclude": [],
}

Below is my tsconfig file at root

{
  "compilerOptions": {
    "target": "es6",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "allowSyntheticDefaultImports": true,
    "sourceMap": false,
    "noImplicitAny": false,
    "noImplicitReturns": false,
    "noImplicitThis": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "removeComments": false,
    "preserveConstEnums": true,
    "typeRoots": [
      "./node_modules/@types"
    ],
    "rootDirs": ["src/__generated__", "src/**/__generated__"],
    "baseUrl": ".",
    "paths": {
      "@static/*": [
        "./public/static/*"
      ],
      "@generated/*": [
        "./src/__generated__/*"
      ],
      "@*": [
        "./src/*"
      ]
    }
  },
  "include": [
    "src",
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "next.config.js",
    "public",
    "cypress",
    "jest.setup.js",
    "release.config.js"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts",
    "**/*.spec.tsx",
    "**/*.test.ts",
    "**/*.test.tsx",
    "**/*.graphql",
    "cache/Cypress/**"
  ]
}

I've tried different examples with typescript and tsify but they did not work as well and got same issue. 

Desired behavior

I would like to get the cypress-cucumber-preprocessor working with typescript in my current project.

Test code to reproduce

The code is a bit large but will try and provide a minimal working clone.

Versions

  • Cypress version: 6.8.0
  • Preprocessor version: 4.0.3
  • Node version:

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 8
  • Comments: 33 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Same issue here, cannot get Typescript’s “baseUrl” or “alias” honoured by the browserify pre-processor, with the setup described in this project. See reproduction repo here: https://github.com/yann-combarnous/cypress-cucumber-ts-baseurl

What worked for me (cypress + cucumber + typescript + webpack5) Webpack file

const path = require('path');
const webpack = require("webpack");

module.exports = {
    resolve: {
        alias: {
            '@ALIAS/SOMETHING': path.resolve(path.join(__dirname, '../../dist/something')),
            '@ALIAS/SOMETHINGELSE': path.resolve(path.join(__dirname, '../../dist/somethingElse'))
        },
        extensions: ['.ts', '.js'],
        fallback: {
            path : require.resolve("path-browserify")
        }
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                exclude: [/node_modules/],
                use: [
                    {
                        loader: 'ts-loader',
                    }
                ]
            },
            {
                test: /\.feature$/,
                use: [
                    {
                        loader: 'cypress-cucumber-preprocessor/loader'
                    }
                ]
            },
            {
                test: /\.features$/,
                use: [
                    {
                        loader: 'cypress-cucumber-preprocessor/lib/featuresLoader'
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({
            process: 'process/browser',
        }),
    ]
};

plugins/index.js

const webpack = require("@cypress/webpack-preprocessor");

module.exports = (on, config) => {

    const options = {
        webpackOptions: require("PATH TO WEBPACK FILE")
    };
    on("file:preprocessor", webpack(options));
  
};

Think I have been over all the approaches I could find and kept running into one issue or the other.

Am currently using the following configuration in index.js:

const { preprocessTypescript } = require('@nrwl/cypress/plugins/preprocessor');
const webpack = require('webpack');

module.exports = (on, config) => {
  on('file:preprocessor', preprocessTypescript(config, (wpConfig) => {
    wpConfig.resolve.fallback = {
      ...wpConfig.resolve.fallback,
      'path': require.resolve("path-browserify")
    };
    wpConfig.plugins.push(
      new webpack.ProvidePlugin({
        process: 'process/browser',
      })
    );
    wpConfig.module.rules.push(
      {
        test: /\.feature$/,
        use: [{
          loader: 'cypress-cucumber-preprocessor/loader'
        }]
      },
    );
    return wpConfig
  }));
};

It is a workaround as it still contains the deprecated preprocessTypescript but it allows us to run our e2e tests after upgrading to Nx 12.9.0

The configuration was found here: https://github.com/nrwl/nx/issues/1276#issuecomment-856018301

@lgandecki Thanks for the response, and really appreciate the support you guys do on the plugin and the community.

@badeball Sorry I think I was not clear

The issue is more so related to module resolution using typescript + cucumber following the information here: https://github.com/TheBrainFamily/cypress-cucumber-preprocessor#with-out-of-the-box-support

I also have a lot of custom module resolvers trying to access them using @module/lib. It seems when I add cucumber following the documentation using browserify my custom module imports are no longer working which is the error you are getting in the reproducible project.

I’ve tried various recommended solutions:

I’m struggling to get the cucumber implementation to work with typescript and custom module imports. Without cucumber and just cypress + typescript it all works fine including the custom module imports.

Any help is greatly appreciated, thanks for the great plugin.

Thanks @zjkipping for taking the time to reproduce this.

We’re getting the same issue in our project. Any modules referenced from the paths in tsconfig.base.json break with the Can't walk dependency graph: error.

I’ve also spent the day battling webpack (without success) and the err.replace issue seems to be related to cypress not supporting webpack 5 yet. See https://github.com/cypress-io/cypress/issues/8948 and https://github.com/cypress-io/cypress/issues/8948#issuecomment-737156406

This Webpack 5 support issue claims to be almost released but I can’t see that its landed yet: https://github.com/cypress-io/cypress/issues/8900#issuecomment-867290832

Here is the github repo I promised @MateuszNowosad:

Issues with the “out-of-box support”: https://github.com/zjkipping/nx-cypress-cucumber/tree/out-of-box-support

Issues with the “webpack config”: https://github.com/zjkipping/nx-cypress-cucumber/tree/webpack-config

To run the branches you would just need to yarn install & then run yarn e2e.

The “out-of-box-support” branch is throwing an error with walking the dependency graph. The “webpack-config” branch is throwing an error about err.replace being undefined.

The webpack config one has Nx’s typescript preprocessor for TS thrown on top. I’ve had the same “error” using just a straight up normal webpack config as well as seen in that forked repository above.

+1 We have the same problem.

Just came across the same issue using browserify + typescript and solved it like this:

// cypress/plugins/index.js

/// <reference types="cypress" />
const browserify = require('@cypress/browserify-preprocessor');
const cucumber = require('cypress-cucumber-preprocessor').default;
const path = require('path');
const resolve = require('resolve');

module.exports = (on, config) => {
  const { browserifyOptions } = browserify.defaultOptions;

  browserifyOptions.paths = [
    // the process.cwd() depends on the cypress process being started from
    // the project root. You can also use an absolute path here.
    path.resolve(`${process.cwd()}/src`),
    // Include any other path you want to access from cypress here
  ];

  const options = {
    ...{ ...browserify.defaultOptions, browserifyOptions },

    typescript: resolve.sync('typescript'),
  };

  on('file:preprocessor', cucumber(options));

  // other config here

  return config;
};

Given my folder structure is

cypress
  |-- plugins
  |-- other folders
src
  |-- package_name
  |-- another_package

I can now successfully do the following in my tests:

import { MyFunctionOrWhatever } from 'package_name';

Hope this helps !

My solution is heavily inspired by this answer on stack overflow: https://stackoverflow.com/questions/58592497/how-to-use-import-with-absolute-paths-in-cypress-tests-built-with-parceljs

@JurajJakubov , correct me if I’m wrong, but that seems to be the webpack-based solution so that it does not use browserify, but we have seen similar configs before even for Webpack 5, like https://github.com/nrwl/nx/issues/1276#issuecomment-934324523 . One difference I could find in your code is paths configured in the webpack config, rather than in the tsconfig file… Which is unconventional.

@cyrixmorten , I just noticed this issue after bumping into the deprecation myself. I gave an alternative solution there that does not use deprecated Nx code.

As for TypeError: err.replace is not a function, that isn’t an issue anymore.

FYI Nx has a migration when migrating to 12.8.0 to remove usages of @nrwl/cypress/plugins/preprocessor, though it ignores this step if you have custom webpack config like in your example https://github.com/nrwl/nx/pull/6706

edit:

looks like @nrwl/cypress/plugins/preprocessor has been marked as deprecated and to be going away in Nx 14.

And the webpack method hits the same TypeError: err.replace is not a function when trying a basic webpack x typescript setting following https://github.com/TheBrainFamily/cypress-cucumber-webpack-typescript-example and https://github.com/cypress-io/cypress/tree/master/npm/webpack-preprocessor/examples/use-ts-loader 😞

Commenting back here. The systems we are using on our project (nx) is now using a newer version of cypress that (mostly) uses webpack5 now. So, this issue actually resolved itself in our case while using the webpack config approach listed here: https://github.com/zjkipping/nx-cypress-cucumber/blob/webpack-config/apps/example-e2e/src/plugins/index.js Though the dependency versions are still wrong in that repo.

I too was experiencing this issue, using the cypress-tags plugin, and was able to solve it with @8byr0 's solution. For anyone wanting to reduce this fix into a 1-liner, here’s what I did:

  // cypress/plugins/index.js
  const { tagify } = require('cypress-tags');
  module.exports = (on, config) => {
    
+   require('@cypress/browserify-preprocessor').defaultOptions.browserifyOptions.paths = [
+     './src' // (same value as in `tsconfig.json > baseUrl`)
+   ];
  
    on('file:preprocessor', tagify(options));
  
    return config;
  };

@yann-combarnous Hey, did u find any workaround?

Suspect this is an issue with Cypress Browserify preprocessor rather: https://github.com/cypress-io/cypress-browserify-preprocessor/issues/53

Cypress: 8.3.0 Webpack: 5.5.0

In the cypress/support/index.js file I have the following that loads the cypress-cucumber-preprocessor module.

  on('file:preprocessor', (file) => {
    if (file.filePath.match(/\.(feature|features)$/)) {
      return cucumber()(file);
    }
    return webpackPreprocessor(webpackPreprocessorOptions)(file);
  });

Because the file:preprocessor can only execute either the cypress-cucumber-preprocessor or the @cypress/webpack-preprocessor the alias paths do not get applied to the Cucumber step definitions and any alias imports they use causing the Error: Can't walk dependency graph: Cannot find module message to be displayed. For all other *.spec.js files, these are correctly processed with the specified webpack aliases correctly.

I actually tried the link-module-alias npm package and actually got past the dependency graph error as it created all the aliases as static links, however, I ran into the dreaded SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' error.

I tried configuring Babel to try and get around this, but no luck.

Hello, sorry to keep you waiting. The reproduction will definitely be very helpful, thanks for that. One of us should be able to take a look at it sooner than later. At the same time please remember we are volunteers and are doing this for free in our spare time. 😃 So silence here doesn’t mean there is something wrong with your report…

@MateuszNowosad maybe you would be able to take a look at this one? Besides veryfing that it fails on your end as well I’d check with older versions of cypress/our plugin. But obviously take any steps you feel are best 😃