Skip to content

Commit 36e15f0

Browse files
committed
Allow config options to be overriden through environment
1 parent 257eee1 commit 36e15f0

12 files changed

+398
-25
lines changed

docs/configuration.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Configuration
2+
3+
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`, with corresponding examples shown below.
4+
5+
```
6+
// .cypress-cucumber-preprocessorrc.json
7+
{
8+
"json": {
9+
"enabled": true
10+
}
11+
}
12+
```
13+
14+
```
15+
// package.json
16+
{
17+
"dependencies": {
18+
"@badeball/cypress-cucumber-preprocessor": "latest"
19+
},
20+
"cypress-cucumber-preprocessor": {
21+
"json": {
22+
"enabled": true
23+
}
24+
}
25+
}
26+
```
27+
28+
## Configuration overrides
29+
30+
Configuration options can be overriden using (Cypress-) [environment variable](https://docs.cypress.io/guides/guides/environment-variables). The `filterSpecs` options (described in [docs/tags.md](tags.md)) can for instance be overriden by running Cypress like shown below.
31+
32+
```
33+
$ cypress run -e filterSpecs=true
34+
```
35+
36+
Cypress environment variables can also be configured through ordinary environment variables, like shown below.
37+
38+
```
39+
$ CYPRESS_filterSpecs=true cypress run
40+
```
41+
42+
Every configuration option has a similar key which can be use to override it, shown in the table below.
43+
44+
| JSON path | Environment key | Example(s) |
45+
|--------------------|-------------------|------------------------------------------|
46+
| `stepDefinitions` | `stepDefinitions` | `cypress/integration/[filepath].{js,ts}` |
47+
| `messages.enabled` | `messagesEnabled` | `true`, `false` |
48+
| `messages.output` | `messagesOutput` | `cucumber-messages.ndjson` |
49+
| `json.enabled` | `jsonEnabled` | `true`, `false` |
50+
| `json.formatter` | `jsonFormatter` | `/usr/bin/cucumber-json-formatter` |
51+
| `json.output` | `jsonOutput` | `cucumber-report.json` |
52+
| `filterSpecs` | `filterSpecs` | `true`, `false` |
53+
| `omitFiltered` | `omitFiltered` | `true`, `false` |

docs/quick-start.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Configure your preferred bundler to process features files, with examples for
2020
* [Webpack](../examples/webpack)
2121
* [Esbuild](../examples/esbuild)
2222

23+
Read more about configuration options at [docs/configuration.md](configuration.md).
24+
2325
# Write a test
2426

2527
Write Gherkin documents anywhere in your configured integration folder (defaults to `cypress/integration`) and add a file for type definitions with a corresponding name (read more about how step definitions are resolved in [docs/step-definitions.md](step-definitions.md)). Reading [docs/cucumber-basics.md](cucumber-basics.md) is highly recommended.

docs/readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
* [Tags](tags.md)
88
* [JSON report](json-report.md)
99
* [Localisation](localisation.md)
10+
* [Configuration](configuration.md)
1011
* [Frequently asked questions](faq.md)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
Feature: configuration overrides
2+
Scenario: overriding stepDefinitions through -e
3+
Given a file named "cypress/integration/a.feature" with:
4+
"""
5+
Feature: a feature name
6+
Scenario: a scenario name
7+
Given a step
8+
"""
9+
And a file named "foobar.js" with:
10+
"""
11+
const { Given } = require("@badeball/cypress-cucumber-preprocessor");
12+
Given("a step", function() {});
13+
"""
14+
When I run cypress with "-e stepDefinitions=foobar.js"
15+
Then it passes
16+
17+
Scenario: overriding stepDefinitions through environment variables
18+
Given a file named "cypress/integration/a.feature" with:
19+
"""
20+
Feature: a feature name
21+
Scenario: a scenario name
22+
Given a step
23+
"""
24+
And a file named "foobar.js" with:
25+
"""
26+
const { Given } = require("@badeball/cypress-cucumber-preprocessor");
27+
Given("a step", function() {});
28+
"""
29+
When I run cypress with environment variables
30+
| Key | Value |
31+
| CYPRESS_stepDefinitions | foobar.js |
32+
Then it passes

features/step_definitions/cli_steps.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ When(
3737
}
3838
);
3939

40+
When(
41+
"I run cypress with environment variables",
42+
{ timeout: 60 * 1000 },
43+
async function (table) {
44+
await this.run([], Object.fromEntries(table.rows()));
45+
}
46+
);
47+
4048
Then("it passes", function () {
4149
assert.equal(this.lastRun.exitCode, 0, "Expected a zero exit code");
4250
});

features/support/world.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function combine(...streams: Readable[]) {
2020
}
2121

2222
class World {
23-
async run(this: IWorld, extraArgs = []) {
23+
async run(this: IWorld, extraArgs = [], extraEnv = {}) {
2424
const child = childProcess.spawn(
2525
path.join(
2626
projectPath,
@@ -35,6 +35,7 @@ class World {
3535
env: {
3636
...process.env,
3737
NO_COLOR: "1",
38+
...extraEnv,
3839
},
3940
}
4041
);

lib/add-cucumber-preprocessor-plugin.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ let currentTestStepStartedId: string;
5252
let currentSpecMessages: messages.IEnvelope[];
5353

5454
export async function beforeRunHandler(config: Cypress.PluginConfigOptions) {
55-
const preprocessor = await resolve(config.projectRoot);
55+
const preprocessor = await resolve(config.projectRoot, config.env);
5656

5757
if (!preprocessor.messages.enabled) {
5858
return;
@@ -67,7 +67,7 @@ export async function beforeRunHandler(config: Cypress.PluginConfigOptions) {
6767
}
6868

6969
export async function afterRunHandler(config: Cypress.PluginConfigOptions) {
70-
const preprocessor = await resolve(config.projectRoot);
70+
const preprocessor = await resolve(config.projectRoot, config.env);
7171

7272
if (!preprocessor.messages.enabled) {
7373
return;
@@ -128,7 +128,7 @@ export async function afterSpecHandler(
128128
spec: Cypress.Spec,
129129
results: CypressCommandLine.RunResult
130130
) {
131-
const preprocessor = await resolve(config.projectRoot);
131+
const preprocessor = await resolve(config.projectRoot, config.env);
132132

133133
const messagesPath = path.join(
134134
config.projectRoot,
@@ -166,7 +166,7 @@ export async function afterScreenshotHandler(
166166
config: Cypress.PluginConfigOptions,
167167
details: Cypress.ScreenshotDetails
168168
) {
169-
const preprocessor = await resolve(config.projectRoot);
169+
const preprocessor = await resolve(config.projectRoot, config.env);
170170

171171
if (!preprocessor.messages.enabled || !currentSpecMessages) {
172172
return details;
@@ -208,7 +208,7 @@ export default async function addCucumberPreprocessorPlugin(
208208
config: Cypress.PluginConfigOptions,
209209
options: AddOptions = {}
210210
) {
211-
const preprocessor = await resolve(config.projectRoot);
211+
const preprocessor = await resolve(config.projectRoot, config.env);
212212

213213
if (!options.omitBeforeRunHandler) {
214214
on("before:run", () => beforeRunHandler(config));
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import assert from "assert";
2+
3+
import { resolve } from "./preprocessor-configuration";
4+
5+
describe("resolve()", () => {
6+
it("overriding stepDefinitions", async () => {
7+
const { stepDefinitions } = await resolve(
8+
"/foo/bar",
9+
{ stepDefinitions: "foo/bar/**" },
10+
() => null
11+
);
12+
13+
assert.strictEqual(stepDefinitions, "foo/bar/**");
14+
});
15+
16+
it("overriding messages.enabled (1)", async () => {
17+
const {
18+
messages: { enabled },
19+
} = await resolve("/foo/bar", { messagesEnabled: "" }, () => ({
20+
messages: { enabled: true },
21+
}));
22+
23+
assert.strictEqual(enabled, true);
24+
});
25+
26+
it("overriding messages.enabled (2)", async () => {
27+
const {
28+
messages: { enabled },
29+
} = await resolve("/foo/bar", { messagesEnabled: "true" }, () => ({
30+
messages: { enabled: false },
31+
}));
32+
33+
assert.strictEqual(enabled, true);
34+
});
35+
36+
it("overriding messages.enabled (3)", async () => {
37+
const {
38+
messages: { enabled },
39+
} = await resolve("/foo/bar", { messagesEnabled: "foobar" }, () => ({
40+
messages: { enabled: false },
41+
}));
42+
43+
assert.strictEqual(enabled, true);
44+
});
45+
46+
it("overriding messages.enabled (4)", async () => {
47+
const {
48+
messages: { enabled },
49+
} = await resolve("/foo/bar", { messagesEnabled: true }, () => ({
50+
messages: { enabled: false },
51+
}));
52+
53+
assert.strictEqual(enabled, true);
54+
});
55+
56+
it("overriding messages.enabled (5)", async () => {
57+
const {
58+
messages: { enabled },
59+
} = await resolve("/foo/bar", { messagesEnabled: "false" }, () => ({
60+
messages: { enabled: true },
61+
}));
62+
63+
assert.strictEqual(enabled, false);
64+
});
65+
66+
it("overriding messages.enabled (6)", async () => {
67+
const {
68+
messages: { enabled },
69+
} = await resolve("/foo/bar", { messagesEnabled: "false" }, () => ({
70+
messages: { enabled: true },
71+
}));
72+
73+
assert.strictEqual(enabled, false);
74+
});
75+
76+
it("overriding messages.enabled (7)", async () => {
77+
const {
78+
messages: { enabled },
79+
} = await resolve("/foo/bar", { messagesEnabled: false }, () => ({
80+
messages: { enabled: true },
81+
}));
82+
83+
assert.strictEqual(enabled, false);
84+
});
85+
});

0 commit comments

Comments
 (0)