Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: provide option to overwrite historyId hash with own function, a… #2

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,35 @@ It will be used for:

In lower versions some other heuristics would be used, but they are not as reliable as `after:spec`.

## Test name duplicates

By default Allure calculates hash from test title to identify test and show its' proper previous results.
This may lead to tests having the same name being counted by allure as retries of the same test.
There are several ways to avoid this situation:

- the best way to avoid it is basically using unique test names

- update specific test name
```js
cy.allure().testName('new_test_name')
```

- specify your own function for all tests to not only take test.title, but also concatenate it with some other information in `cypress/support/index` or `cypress/support/e2e.js` file, for example:
- use relative spec file path like "cypress/e2e/results2/test.cy.js" and test title:
```js
Cypress.Allure.reporter.getInterface().defineHistoryId((title) => {
return `${Cypress.spec.relative}${title}`;
});
```
- use browser name and test title:
```js
Cypress.Allure.reporter.getInterface().defineHistoryId((title) => {
return `${Cypress.browser.name}${title}`;
});
```

The rule is that this function should return any string (folder name, project name, platform, browser name, Cypress.spec content, etc.), and if those strings will be different - their test historyId hashes will be different - tests will be recognized as different by allure.

## Suite structuring

Allure support 3 levels of suite structure:
Expand Down
7 changes: 7 additions & 0 deletions reporter/allure-cypress/AllureInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ Allure.prototype.defineSuiteLabels = function (defineSuiteLabelsFn) {
this.reporter.defineSuiteLabelsFn = defineSuiteLabelsFn;
};

Allure.prototype.defineHistoryId = function (defineHistoryId) {
if (!defineHistoryId) {
return;
}
this.reporter.defineHistoryId = defineHistoryId;
};

Allure.prototype.label = function (name, value) {
if (this.reporter.currentTest && !this.reporter.currentHook) {
const labelIndex = (name) =>
Expand Down
3 changes: 2 additions & 1 deletion reporter/allure-cypress/AllureReporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module.exports = class AllureReporter {
this.gherkin = new CucumberHandler(this);
this.config = options;
this.defineSuiteLabelsFn = (titles) => titles;
this.defineHistoryId = (testTitle) => testTitle;
}

/**
Expand Down Expand Up @@ -221,7 +222,7 @@ module.exports = class AllureReporter {
}

this.currentTest.info.historyId = crypto
.MD5(test.title)
.MD5(this.defineHistoryId(test.title))
.toString(crypto.enc.Hex);
this.currentTest.info.stage = Stage.RUNNING;
this.addPackageLabel();
Expand Down
5 changes: 5 additions & 0 deletions reporter/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ declare global {
fileInfo: SuiteLabelFunctionFileInfo
) => string[]
): void;

/**
* Specify string which will be used to calculate historyId for test
*/
defineHistoryId(fn: (testTitle: string) => string): void;
}
}
}
3 changes: 2 additions & 1 deletion reporter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ const invokeResultsWriter = (allure, isGlobal) => {
files: allure.reporter.files || [],
mapping: allure.reporter.mochaIdToAllure,
clearSkipped: config.clearSkipped(),
isGlobal
isGlobal,
defineHistoryId: allure.reporter.defineHistoryId
},
{ log: false }
).catch((e) =>
Expand Down
1 change: 1 addition & 0 deletions reporter/stubbedAllure.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ const stubbedAllure = {
testParameter: () => {},
testName: () => {},
defineSuiteLabels: () => {},
defineHistoryId: () => {},
logCommandSteps: () => {}
};
6 changes: 4 additions & 2 deletions writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ function allureWriter(on, config) {
files,
mapping,
clearSkipped,
isGlobal
isGlobal,
defineHistoryId
}) => {
const { resultsDir: relativeResultsDir, writer } = results;

Expand All @@ -76,7 +77,8 @@ function allureWriter(on, config) {
clearSkipped,
writer,
allureMapping,
isGlobal
isGlobal,
defineHistoryId
});

return null;
Expand Down
2 changes: 1 addition & 1 deletion writer/clearEmptyHookSteps.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const logger = require('../reporter/debug');

const clearEmptyHookSteps = (test) => {
if (!test.steps.length) {
if (!test || !test.steps || !test.steps.length) {
return test;
}

Expand Down
8 changes: 6 additions & 2 deletions writer/customTestName.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
const crypto = require('crypto-js');
const logger = require('../reporter/debug');

const overwriteTestNameMaybe = (test) => {
const defaultHistoryId = (title) => title;

const overwriteTestNameMaybe = (test, defineHistoryId) => {
const historyIdFn = defineHistoryId || defaultHistoryId;

const overrideIndex = test.parameters.findIndex(
(p) => p.name === 'OverwriteTestName'
);
Expand All @@ -10,7 +14,7 @@ const overwriteTestNameMaybe = (test) => {
logger.writer('overwriting test "%s" name to "%s"', test.name, name);
test.name = name;
test.fullName = name;
test.historyId = crypto.MD5(name).toString(crypto.enc.Hex);
test.historyId = crypto.MD5(historyIdFn(name)).toString(crypto.enc.Hex);
test.parameters.splice(overrideIndex, 1);
}
return test;
Expand Down
1 change: 1 addition & 0 deletions writer/handleMultiDomain.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const sanitizeSuites = (folder, files = [], isGlobal = false) => {
(file) =>
file.historyId === child.historyId &&
file.uuid !== child.uuid &&
file.steps &&
file.steps.length
);

Expand Down
63 changes: 51 additions & 12 deletions writer/results.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,13 @@ const writeSuites = ({ groups, resultsDir, tests, clearSkipped }) => {
});
};

const writeTests = ({ tests, resultsDir, clearSkipped, allureMapping }) => {
const writeTests = ({
tests,
resultsDir,
clearSkipped,
allureMapping,
defineHistoryId
}) => {
if (!tests || !tests.length) {
return;
}
Expand All @@ -140,7 +146,7 @@ const writeTests = ({ tests, resultsDir, clearSkipped, allureMapping }) => {
const fileName = `${test.uuid}-result.json`;
logger.writer('write test "%s" to file "%s"', test.name, fileName);
const testResultPath = path.join(resultsDir, fileName);
const updatedTest = overwriteTestNameMaybe(test);
const updatedTest = overwriteTestNameMaybe(test, defineHistoryId);
const testResult = clearEmptyHookSteps(updatedTest);
fs.writeFileSync(testResultPath, JSON.stringify(testResult));
});
Expand Down Expand Up @@ -172,7 +178,10 @@ const catchError = (fn, ...args) => {
try {
fn(...args);
} catch (e) {
process.stdout.write(`error while writing allure results: ${e}`);
const entity = args[args.length - 1];
process.stdout.write(
`error while writing allure results for ${entity}: ${e}`
);
logger.writer('failed to write allure results: %O', e);
}
};
Expand All @@ -183,7 +192,8 @@ const writeResultFiles = ({
clearSkipped,
writer,
allureMapping,
isGlobal
isGlobal,
defineHistoryId
}) => {
!fs.existsSync(resultsDir) && fs.mkdirSync(resultsDir, { recursive: true });

Expand All @@ -192,20 +202,49 @@ const writeResultFiles = ({
const { groups, tests, attachments, envInfo, categories, executorInfo } =
writer;

catchError(writeAttachmentFiles, { files, resultsDir, tests });
catchError(writeSuites, { groups, resultsDir, tests, clearSkipped });
catchError(writeTests, { tests, resultsDir, clearSkipped, allureMapping });
catchError(writeAttachments, { attachments, resultsDir });
catchError(handleAfterTestWrites, { resultsDir, isGlobal });
catchError(writeAttachmentFiles, { files, resultsDir, tests }, 'files');
catchError(
writeSuites,
{ groups, resultsDir, tests, clearSkipped },
'suites'
);
catchError(
writeTests,
{
tests,
resultsDir,
clearSkipped,
allureMapping,
defineHistoryId
},
'tests'
);
catchError(writeAttachments, { attachments, resultsDir }, 'attachments');
catchError(
handleAfterTestWrites,
{ resultsDir, isGlobal },
'after test writes'
);

const allureResultsPath = (file) => path.join(resultsDir, file);

catchError(writeInfoFile, allureResultsPath('categories.json'), categories);
catchError(writeInfoFile, allureResultsPath('executor.json'), executorInfo);
catchError(
writeInfoFile,
allureResultsPath('categories.json'),
categories,
'cetegories file'
);
catchError(
writeInfoFile,
allureResultsPath('executor.json'),
executorInfo,
'executor file'
);
catchError(
writeEnvProperties,
allureResultsPath('environment.properties'),
envInfo
envInfo,
'env file'
);
logger.writer('finished writing allure results');
};
Expand Down