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

Report screenshots as test metadata #3

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ module.exports = {
};
```

Besides, you can switch on or switch off the plugin depending on the environment, for example, this way:
## Options

### enabled

Boolean, condition for enabling the plugin.
For example, you can switch on or switch off the plugin depending on the environment:

```js
module.exports = {
Expand All @@ -33,3 +38,32 @@ module.exports = {
}
};
```

### reportScreenshots

`'always' | 'onlyFailures' | false`, whether to report screenshots as [test metadata](https://www.jetbrains.com/help/teamcity/reporting-test-metadata.html). `'onlyFailures'` by default.

```
module.exports = {
plugins: {
'teamcity-reporter': {
reportScreenshots: false
}
}
};
```

### imagesDir

String, directory to save images to. `hermione-images` by default.

```
module.exports = {
plugins: {
'teamcity-reporter': {
imagesDir: 'path/to/my/dir'
}
}
};
```

121 changes: 96 additions & 25 deletions lib/handlers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

const path = require('path');
const fs = require('fs-extra');
const tsm = require('teamcity-service-messages');

const formatTestName = (test) => {
Expand All @@ -8,33 +10,102 @@ const formatTestName = (test) => {
return `${fullTitle} [${test.browserId}]`;
};

module.exports = {
onTestPending: (test) => tsm.testIgnored({name: formatTestName(test)}),
exports.getHandlers = args => {
const imagesDir = args.imagesDir || 'hermione-images';
const reportScreenshotsOption = args.reportScreenshots !== undefined ? args.reportScreenshots : 'onlyFailures';
fs.ensureDirSync(imagesDir);

onTestPass: (test) => {
const testName = formatTestName(test);
const getImagePath = (test, imageName) => path.join(
imagesDir,
test.fullTitle().trim(),
test.browserId.trim(),
imageName + '.png'
);

tsm
.testStarted({name: testName})
.testFinished({
name: testName,
duration: test.duration || 0
const reportScreenshot = (test, imagePath) => {
tsm.publishArtifacts(
`${path.resolve(imagePath)} => ${path.dirname(imagePath)}`
);
tsm.testMetadata({
testName: formatTestName(test),
type: 'image',
value: imagePath
});
};

const copyAndReportScreenshot = (test, imageName, srcPath) => {
if (!srcPath || !srcPath.path) {
return;
}
const imagePath = getImagePath(test, imageName);
fs.copy(srcPath.path, imagePath).then(() => {
reportScreenshot(test, imagePath);
}, error => {
console.error(error);
});
};

const reportScreenshots = (test) => {
if (!reportScreenshotsOption) {
return;
}
if (test.err && test.err.screenshot) {
const errPath = getImagePath(test, 'Error');
fs.outputFile(errPath, test.err.screenshot.base64, 'base64').then(() => {
reportScreenshot(test, errPath);
});
},

onTestFail: (test) => {
const testName = formatTestName(test);

tsm
.testStarted({name: testName})
.testFailed({
name: testName,
message: test.err && test.err.message || 'Unknown Error',
details: test.err && test.err.stack || test.err
})
.testFinished({
name: testName,
duration: test.duration || test.hook && test.hook.duration || 0
}
if (test.assertViewResults) {
test.assertViewResults.forEach((assertResult) => {
const stateName = assertResult.stateName;
const refImg = assertResult.refImg;
const currImg = assertResult.currImg;
if (assertResult instanceof Error || reportScreenshotsOption === 'always') {
copyAndReportScreenshot(test, `${stateName}.reference`, refImg);
}

if (assertResult instanceof Error) {
copyAndReportScreenshot(test, `${stateName}.current`, currImg);

if (assertResult.saveDiffTo) {
const diffPath = getImagePath(test, `${stateName}.diff`);
assertResult.saveDiffTo(diffPath).then(() => reportScreenshot(test, diffPath));
}
}
});
}
}
};

return {
onTestPending: (test) => tsm.testIgnored({name: formatTestName(test)}),

onTestPass: (test) => {
const testName = formatTestName(test);

tsm
.testStarted({name: testName})
.testFinished({
name: testName,
duration: test.duration || 0
});
reportScreenshots(test);
},

onTestFail: (test) => {
const testName = formatTestName(test);

tsm
.testStarted({name: testName})
.testFailed({
name: testName,
message: test.err && test.err.message || 'Unknown Error',
details: test.err && test.err.stack || test.err
})
.testFinished({
name: testName,
duration: test.duration || test.hook && test.hook.duration || 0
});
reportScreenshots(test);
}
};
};
4 changes: 3 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

const handlers = require('./handlers');
const handlersModule = require('./handlers');

module.exports = (hermione, pluginConfig) => {
pluginConfig = pluginConfig || {};
Expand All @@ -9,6 +9,8 @@ module.exports = (hermione, pluginConfig) => {
return;
}

const handlers = handlersModule.getHandlers(pluginConfig);

hermione.on(hermione.events.TEST_PENDING, (test) => handlers.onTestPending(test));
hermione.on(hermione.events.TEST_PASS, (test) => handlers.onTestPass(test));

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"author": "Eugene Gavryushin <[email protected]>",
"license": "ISC",
"dependencies": {
"teamcity-service-messages": "^0.1.8"
"fs-extra": "^5.0.0",
"teamcity-service-messages": "^0.1.10"
},
"devDependencies": {
"chai": "^3.5.0",
Expand Down
Loading