Cypress-cucumber-preprocessor: Feature file in different directory gives missing step implemantation error with nonGlobalStepBaseDir defined

Created on 17 Jun 2020  路  4Comments  路  Source: TheBrainFamily/cypress-cucumber-preprocessor


Thank you for building this preprocessor and latest update to define nonGlobalStepBaseDir is very helpful.

With the current setup tests are working well. Configurations are set as following with feature files placed in the cypress/integration directory:

 "cypress-cucumber-preprocessor": {
    "nonGlobalStepDefinitions": true,
    "commonPath":"../../../shared",
    "nonGlobalStepBaseDir": "cypress/integration/steps/onboarding/customer"
    }
}

I would like to move the feature files to another directory say:
cypress/integration/features/onboarding/customer

Current behavior


Moving the feature files from cypress/integration to another path gives step implementation missing error.

Is it possible move the feature files to another directory with nonGlobalStepBaseDir path defined?

Desired behavior


To be able to define feature file location similar to step definitions.

Test code to reproduce

Versions

  • Cypress version: 4.8
  • Preprocessor version: 2.5.0

All 4 comments

This still seems to be an issue after #319 was merged.

Current behaviour

With default cypress/integration path as integrationFolder in cypress.json (that is NOT specifying one). Then using

"cypress-cucumber-preprocessor": {
    "nonGlobalStepDefinitions": true,
    "nonGlobalStepBaseDir": "test/cypress/integration"
    }
}

will result in .feature files being found correctly in cypress/integration with step definitions found in test/cypress/integration.

However, with test/cypress/integration path as integrationFolder in cypress.json and using

 "cypress-cucumber-preprocessor": {
    "nonGlobalStepDefinitions": true,
    "nonGlobalStepBaseDir": "cypress/integration"
    }
}

Then .feature files are found correctly but step definitions are NOT found. Unless "nonGlobalStepDefinitions": false

So it seems if feature files are not in the default cypress folder then step files can not be located away from the same folder.

Expected Behaviour

It should be possible to have feature files in an arbitrary location and specify a separate arbitrary location for the base dir of step definitions whilst still using "nonGlobalStepDefinitions": true

Example

cypress
-Integration
-sign-in
-sign-in.js <-- step definition
tests
-features
- sign-in.feature <-- feature file

cypress.json

{
    "integrationFolder": "tests/features",
    "testFiles": ["**/*.feature"]
}

package.json

"cypress-cucumber-preprocessor": {
    "nonGlobalStepDefinitions": true,
    "nonGlobalStepBaseDir": "cypress/integration"
 }

Versions

  • Cypress version: 6.6.0
  • Preprocessor version: 4.0.1

@bkapadia01 are you still having difficulty with your original question?

TLDR

to have .feature files in a different directory with the step definition, set the stepDefinitions exacly the same as your cypress integrationFolder and nonGlobalStepBaseDir to path to step definition folder.

See last section for example


@goesbysteve I think I found the problem to the current behavior. There is this block of code in cypress-cucumber-preprocessor/lib/getStepDefinitionsPaths.js file which will list all the files the modules need to require (which is the step definitions)

const getStepDefinitionsPaths = (filePath) => {
  const appRoot = process.cwd();
  let paths = [];
  const config = getConfig();
  if (config && config.nonGlobalStepDefinitions) {
    let nonGlobalPath = getStepDefinitionPathsFrom(filePath);
    // nonGlobalPath == feature file path without .feature
    let commonPath = config.commonPath || `${stepDefinitionPath()}/common/`;
    if (config.commonPath) {
      commonPath = path.resolve(appRoot, commonPath);
    }

    if (config.nonGlobalStepBaseDir) {
      const stepBase = `${appRoot}/${config.nonGlobalStepBaseDir}`;
      nonGlobalPath = nonGlobalPath.replace(stepDefinitionPath(), stepBase);
      commonPath = `${stepBase}/${config.commonPath || "common/"}`;
    }

    const nonGlobalPattern = `${nonGlobalPath}/**/*.+(js|ts)`;

    const commonDefinitionsPattern = `${commonPath}**/*.+(js|ts)`;
    paths = paths.concat(
      glob.sync(nonGlobalPattern),
      glob.sync(commonDefinitionsPattern)
    );
  } else {
    const pattern = `${stepDefinitionPath()}/**/*.+(js|ts)`;
    paths = paths.concat(glob.sync(pattern));
  }
  return paths;
};

the problem is in this block of code

    if (config.nonGlobalStepBaseDir) {
      const stepBase = `${appRoot}/${config.nonGlobalStepBaseDir}`;
      nonGlobalPath = nonGlobalPath.replace(stepDefinitionPath(), stepBase);
      commonPath = `${stepBase}/${config.commonPath || "common/"}`;
    }

that code will run when we specify nonGlobalStepBaseDir in the config. What that code does is get the path to your nonGlobalstepBaseDir change your step definitions path to that and also change the common folder path.

But here's the problem, the second line in the if block replace the current nonGlobalPath path that match with the result of stepDefinitionPath() to stepBase. The value in nonGlobalPath is the path to the .feature file without the extension.

The stepDefinitionPath function supposed to return the path to step definitions. But currently this function will return

  • if nonGlobalStepDefinitions is true, then return cwd + config.stepDefinitions if it is not undefined or return cwd + /cypress/integration
  • if nonGlobalStepDefinitions is false, then return cwd + config.stepDefinitions if it is not undefined
  • else return cwd + /cypress/support/step_definitions

So basically it will return cwd + stepDefinitions or /cypress/integration or /cypress/support/step_definitions, but the nonGlobalPath in the if block might not have all these value if our feature files is not in /cypress/integration or /cypress/support/step_definitions or in the directory we specify in the stepDefinitions (which supposed to be our step definitions folder), so the .replace function won't change anything and the nonGlobalPath will still have the path to your feature files without the extension. But the common folder is correct since it use the stepBase which is from the nonGlobalStepBaseDir.

To have the .feature files in a complete different directory with the step definitions, all we need to do is to specify the path to the root of step definitions file in nonGlobalStepBaseDir and the path to the root of .feature files in stepDefinitions.

Make sure the path to step definition still follow the cypress-cucumber-preprocessor convention

Example

# feature file location
path/to/you/project/test/feature_files/feature_a/interesting_feature.feature

# step definition file location
path/to/your/project/implementations/step_definitions/feature_a/interesting_feature/folder-1/step_a.step.js

# common step definition file location
path/to/your/project/implementations/step_definitions/common/common.step.js

your cypress-cucumber-preprocessor config would looks like this:

"cypress-cucumber-preprocessor": {
    "nonGlobalStepDefinitions": true,
    "nonGlobalStepBaseDir": "implementations/step_definitions",
    "stepDefinitions": "test/feature_files"
  }

your cypress config would looks like this:

{
  ...
  "integrationFolder": "test/feature_files",
  ...
}

the ... means there is other configs there.

You can check the stepDefinitionPath function at cypress-cucumber-preprocessor/lib/stepDefinitionPath.js

I did not open a PR since I'm not sure which solution to use. My solution is:

  1. rename the stepDefinitions to featureFilesPath but not sure if it will break any
  2. or somehow get the cypress integrationFolder config value and use that for the .replace value

Any solution for this? I'm stuck too with same need: feature files in a totally different path of steps.

update:
I solved in this way:

// package.json
"cypress-cucumber-preprocessor": {
    "nonGlobalStepDefinitions": true,
    "nonGlobalStepBaseDir": "cypress/integration",
    "step_definitions": "path/to/feature/files"
  }

// cypress.json
{
  "testFiles": "**/*.{feature,features}",
  "integrationFolder": "path/to/feature/files"
}

with this configuration you can put feature files and step definition files in two totally different paths

Was this page helpful?
0 / 5 - 0 ratings

Related issues

NoNameProvided picture NoNameProvided  路  8Comments

aleccool213 picture aleccool213  路  5Comments

flowt-au picture flowt-au  路  3Comments

ngocthuan1208 picture ngocthuan1208  路  6Comments

hiaux0 picture hiaux0  路  6Comments