Skip to content

Commit

Permalink
feat(allure-cypress): impose some limits on step parameter values cre…
Browse files Browse the repository at this point in the history
…ated from Cypress command arguments (#1127)
  • Loading branch information
delatrie authored Sep 6, 2024
1 parent 6a95475 commit 5ac84d4
Show file tree
Hide file tree
Showing 14 changed files with 478 additions and 92 deletions.
69 changes: 61 additions & 8 deletions packages/allure-cypress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,30 @@ Learn more about Allure Cypress from the official documentation at


## Allure Cypress options
| Option | Description | Default |
|-----------------|----------------------------------------------------------------------------------------------------------------------|--------------------|
| resultsDir | The path of the results folder. | `./allure-results` |
| videoOnFailOnly | When video capturing is enabled, set this option to `true` to attach the video to failed specs only. | `undefined` |
| links | Allure Runtime API link templates. | `undefined` |
| environmentInfo | A set of key-value pairs to display in the Environment section of the report | `undefined` |
| categories | An array of category definitions, each describing a [category of defects](https://allurereport.org/docs/categories/) | `undefined` |

Customize Allure Cypress by providing a configuration object as the third argument
of `allureCypress`.

The following options are supported:

| Option | Description | Default |
|-------------------|----------------------------------------------------------------------------------------------------------------------|---------------------------------|
| resultsDir | The path of the results folder. | `./allure-results` |
| videoOnFailOnly | When video capturing is enabled, set this option to `true` to attach the video to failed specs only. | `false` |
| links | Allure Runtime API link templates. | `undefined` |
| stepsFromCommands | Options that affect how Allure creates steps from Cypress commands | See [below](#stepsfromcommands) |
| environmentInfo | A set of key-value pairs to display in the Environment section of the report | `undefined` |
| categories | An array of category definitions, each describing a [category of defects](https://allurereport.org/docs/categories/) | `undefined` |

### stepsFromCommands

| Property | Description | Default |
|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------|---------|
| maxArgumentLength | The maximum length of the parameter value created from Cypress command argument. The rest of the characters are replaces with `...`. | 128 |
| maxArgumentDepth | The maximum depth of the Cypress command argument (an array or an object) that will be converted to the corresponding step parameter value. | 3 |


### Example

Here is an example of the Allure Cypress configuration:

Expand All @@ -100,6 +117,10 @@ export default defineConfig({
nameTemplate: "ISSUE-%s",
},
},
stepsFromCommands: {
maxArgumentLength: 64,
maxArgumentDepth: 5,
},
environmentInfo: {
OS: os.platform(),
Architecture: os.arch(),
Expand Down Expand Up @@ -157,7 +178,39 @@ export default defineConfig({
});
```

## Known limitations
## Common issues

### The test plan feature doesn't work

Make sure you pass the Cypress config as the second argument of `allureCypress`.

Correct:

```javascript
allureCypress(on, config);
```

Also correct:

```javascript
allureCypress(on, config, {
resultsDir: "output",
});
```

Incorrect (the test plan won't work):

```javascript
allureCypress(on);
```

Also incorrect (the legacy style; the test plan won't work either):

```javascript
allureCypress(on, {
resultsDir: "output",
});
```

### `setupNodeEvents` limitations

Expand Down
7 changes: 7 additions & 0 deletions packages/allure-cypress/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const ALLURE_REPORT_STEP_COMMAND = "__allure_report_step_command__";

export type AllureCypressConfig = ReporterConfig & {
videoOnFailOnly?: boolean;
stepsFromCommands?: Partial<AllureSpecState["config"]["stepsFromCommands"]>;
};

export type CypressSuite = Mocha.Suite & {
Expand Down Expand Up @@ -174,6 +175,12 @@ export type SpecContext = {
};

export type AllureSpecState = {
config: {
stepsFromCommands: {
maxArgumentLength: number;
maxArgumentDepth: number;
};
};
initialized: boolean;
testPlan: TestPlanV1 | null | undefined;
messages: CypressMessage[];
Expand Down
29 changes: 19 additions & 10 deletions packages/allure-cypress/src/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import type {
CypressTestStartMessage,
SpecContext,
} from "./model.js";
import { last } from "./utils.js";
import { DEFAULT_RUNTIME_CONFIG, last } from "./utils.js";

export class AllureCypress {
allureRuntime: ReporterRuntime;
Expand Down Expand Up @@ -489,19 +489,28 @@ export class AllureCypress {
};
}

const getInitialSpecState = (): AllureSpecState => ({
const createRuntimeState = (allureConfig?: AllureCypressConfig): AllureSpecState => ({
config: getRuntimeConfigDefaults(allureConfig),
initialized: false,
messages: [],
testPlan: parseTestPlan(),
});

/**
* Explicitly enables the selective run feature.
* @param config The Cypress configuration.
*/
export const enableTestPlan = (config: Cypress.PluginConfigOptions) => {
config.env.allure = getInitialSpecState();
return config;
const getRuntimeConfigDefaults = ({
stepsFromCommands: {
maxArgumentLength = DEFAULT_RUNTIME_CONFIG.stepsFromCommands.maxArgumentLength,
maxArgumentDepth = DEFAULT_RUNTIME_CONFIG.stepsFromCommands.maxArgumentDepth,
} = DEFAULT_RUNTIME_CONFIG.stepsFromCommands,
}: AllureCypressConfig = DEFAULT_RUNTIME_CONFIG): AllureSpecState["config"] => ({
stepsFromCommands: {
maxArgumentDepth,
maxArgumentLength,
},
});

const initializeRuntimeState = (cypressConfig: Cypress.PluginConfigOptions, allureConfig?: AllureCypressConfig) => {
cypressConfig.env.allure = createRuntimeState(allureConfig);
return cypressConfig;
};

/**
Expand Down Expand Up @@ -539,7 +548,7 @@ export const allureCypress = (
allureCypressReporter.attachToCypress(on);

if (cypressConfig && "env" in cypressConfig) {
enableTestPlan(cypressConfig);
initializeRuntimeState(cypressConfig, allureConfig);
}

return allureCypressReporter;
Expand Down
9 changes: 8 additions & 1 deletion packages/allure-cypress/src/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getStatusFromError,
getUnfinishedStepsMessages,
isPromise,
serialize,
} from "allure-js-commons/sdk";
import type { RuntimeMessage } from "allure-js-commons/sdk";
import { getGlobalTestRuntime, setGlobalTestRuntime } from "allure-js-commons/sdk/runtime";
Expand All @@ -26,6 +27,7 @@ import { ALLURE_REPORT_STEP_COMMAND } from "./model.js";
import {
dropCurrentTest,
enqueueRuntimeMessage,
getConfig,
getCurrentTest,
getRuntimeMessages,
setCurrentTest,
Expand Down Expand Up @@ -361,11 +363,16 @@ export const reportTestSkip = (test: CypressTest) => {
};

export const reportCommandStart = (command: CypressCommand) => {
const {
stepsFromCommands: { maxArgumentDepth, maxArgumentLength },
} = getConfig();
enqueueRuntimeMessage({
type: "cypress_command_start",
data: {
name: `Command "${command.attributes.name}"`,
args: command.attributes.args.map((arg) => (typeof arg === "string" ? arg : JSON.stringify(arg, null, 2))),
args: command.attributes.args.map((arg) =>
serialize(arg, { maxDepth: maxArgumentDepth, maxLength: maxArgumentLength }),
),
start: Date.now(),
},
});
Expand Down
4 changes: 4 additions & 0 deletions packages/allure-cypress/src/state.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { AllureSpecState, CypressMessage, CypressTest } from "./model.js";
import { DEFAULT_RUNTIME_CONFIG } from "./utils.js";

export const getAllureState = () => {
let state = Cypress.env("allure") as AllureSpecState;
if (!state) {
state = {
config: DEFAULT_RUNTIME_CONFIG,
initialized: false,
messages: [],
testPlan: undefined,
Expand Down Expand Up @@ -41,3 +43,5 @@ export const setCurrentTest = (test: CypressTest) => {
export const dropCurrentTest = () => {
getAllureState().currentTest = undefined;
};

export const getConfig = () => getAllureState().config;
7 changes: 7 additions & 0 deletions packages/allure-cypress/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { ALLURE_REPORT_STEP_COMMAND, ALLURE_REPORT_SYSTEM_HOOK } from "./model.j
import type { CypressCommand, CypressHook, CypressSuite, CypressTest } from "./model.js";
import { getAllureTestPlan } from "./state.js";

export const DEFAULT_RUNTIME_CONFIG = {
stepsFromCommands: {
maxArgumentLength: 128,
maxArgumentDepth: 3,
},
};

export const uint8ArrayToBase64 = (data: unknown) => {
// @ts-ignore
const u8arrayLike = Array.isArray(data) || data.buffer;
Expand Down
Loading

0 comments on commit 5ac84d4

Please sign in to comment.