From ab6836216b6da5c28b9ca75e91d667f48aa326cb Mon Sep 17 00:00:00 2001 From: Jonas Amundsen Date: Wed, 25 Sep 2024 09:51:53 +0200 Subject: [PATCH] Allow features in arbitrary locations This fixes #1225 [1]. [1] https://github.com/badeball/cypress-cucumber-preprocessor/issues/1225 --- CHANGELOG.md | 2 ++ docs/step-definitions.md | 35 ++++++++++++++++++++++++++++++++++- lib/step-definitions.ts | 26 ++++++-------------------- lib/template.ts | 7 ++----- package.json | 1 - 5 files changed, 44 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06716025..81ffa8a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ Other changees: - Support project directories containing square brackets, EG. `/home/[foo] my project/`, relates to [#1196](https://github.com/badeball/cypress-cucumber-preprocessor/discussions/1196). +- Allow features in arbitrary locations, fixes [#1225](https://github.com/badeball/cypress-cucumber-preprocessor/issues/1225). + ## v20.1.2 - Updated all dependencies, including esbuild, relates to [#1068](https://github.com/badeball/cypress-cucumber-preprocessor/issues/1068). diff --git a/docs/step-definitions.md b/docs/step-definitions.md index c6bebb95..3a9f0fec 100644 --- a/docs/step-definitions.md +++ b/docs/step-definitions.md @@ -2,7 +2,7 @@ # Step definitions -Step definitions are resolved using search paths that are configurable through the `stepDefinitions` property. The preprocessor uses [cosmiconfig](https://github.com/davidtheclark/cosmiconfig), which means you can place configuration options in EG. `.cypress-cucumber-preprocessorrc.json` or `package.json`. The default search paths are shown below. +Step definitions are resolved using search paths that are configurable through the `stepDefinitions` property. The preprocessor uses [cosmiconfig](https://github.com/davidtheclark/cosmiconfig), which means you can place configuration options in EG. `.cypress-cucumber-preprocessorrc.json` or `package.json`. The default (almost true[^1]) search paths are shown below. ```json { @@ -147,3 +147,36 @@ All of these will be used to replace `[filepart]`. Thus, a single configuration The library makes use of [glob](https://github.com/isaacs/node-glob) to turn patterns into a list of files. This has some implications, explained below (list is non-exhaustive and will be expanded on demand). * Single term inside braces, EG. `foo/bar.{js}`, doesn't work as you might expect, ref. https://github.com/isaacs/node-glob/issues/434. + +[^1]: I claim that the default configuration is of that below and this is almost always true. + + ```json + { + "stepDefinitions": [ + "cypress/e2e/[filepath]/**/*.{js,ts}", + "cypress/e2e/[filepath].{js,ts}", + "cypress/support/step_definitions/**/*.{js,ts}", + ] + } + ``` + + The reality is a bit more complex, in order to support a variety of use-cases out-of-the-box. + Most users will place their feature files in `cypress/e2e` and in those cases, the default + configuration will be that of my claim. + + However, users that decide on a different location, let's say. `cypress/features` - in their + case, the default behavior of the preprocessor will be _as if_ you configured `stepDefinitions` + shown like below. + + ```json + { + "stepDefinitions": [ + "cypress/features/[filepath]/**/*.{js,ts}", + "cypress/features/[filepath].{js,ts}", + "cypress/support/step_definitions/**/*.{js,ts}", + ] + } + ``` + + Essentially, the first part of the two first elements, is determined finding out the common + ancestor path of all your feature files and thus the default configuration is dynamic. diff --git a/lib/step-definitions.ts b/lib/step-definitions.ts index 3077efae..e026a5a4 100644 --- a/lib/step-definitions.ts +++ b/lib/step-definitions.ts @@ -6,8 +6,6 @@ import util from "util"; import assert from "assert"; -import isPathInside from "is-path-inside"; - import debug from "./helpers/debug"; import { @@ -55,27 +53,15 @@ export function pathParts(relativePath: string): string[] { } export function getStepDefinitionPatterns( - configuration: { - cypress: Pick; - preprocessor: Pick< - IPreprocessorConfiguration, - "stepDefinitions" | "implicitIntegrationFolder" - >; - }, + configuration: Pick< + IPreprocessorConfiguration, + "stepDefinitions" | "implicitIntegrationFolder" + >, filepath: string, ): string[] { - const projectRoot = configuration.cypress.projectRoot; - - if (!isPathInside(filepath, projectRoot)) { - throw new Error(`${filepath} is not inside ${projectRoot}`); - } - const filepathReplacement = glob.escape( trimFeatureExtension( - path.relative( - configuration.preprocessor.implicitIntegrationFolder, - filepath, - ), + path.relative(configuration.implicitIntegrationFolder, filepath), ), { windowsPathsNoEscape: true }, ); @@ -86,7 +72,7 @@ export function getStepDefinitionPatterns( debug(`replacing [filepart] with ${util.inspect(parts)}`); - const stepDefinitions = [configuration.preprocessor.stepDefinitions].flat(); + const stepDefinitions = [configuration.stepDefinitions].flat(); return stepDefinitions.flatMap((pattern) => { if (pattern.includes("[filepath]") && pattern.includes("[filepart]")) { diff --git a/lib/template.ts b/lib/template.ts index 654925da..b1057657 100644 --- a/lib/template.ts +++ b/lib/template.ts @@ -84,14 +84,11 @@ export async function compile( const { stepDefinitions } = preprocessor; debug( - `resolving step definitions using template(s) ${inspect(stepDefinitions)}`, + `resolving step definitio|ns using template(s) ${inspect(stepDefinitions)}`, ); const stepDefinitionPatterns = getStepDefinitionPatterns( - { - cypress: configuration, - preprocessor, - }, + preprocessor, uri, ).map((pattern) => ensureIsRelative(configuration.projectRoot, pattern)); diff --git a/package.json b/package.json index 596a1b3a..445d9337 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "error-stack-parser": "^2.1.4", "find-cypress-specs": "^1.45.2", "glob": "^10.4.5", - "is-path-inside": "^3.0.3", "mocha": "^10.7.0", "seedrandom": "^3.0.5", "source-map": "^0.7.4",