Skip to content

Commit

Permalink
EPMRPP-90161 || Implement screenshot attachment support for Jest agent
Browse files Browse the repository at this point in the history
  • Loading branch information
AliakseiLiasnitski committed Apr 12, 2024
1 parent ab4a741 commit af9cbbd
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 88 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
### Added
- ReportingApi with attachment support [#122](https://github.com/reportportal/agent-js-jest/issues/122).
### Changed
- **Breaking change** Drop support of Node.js 10. The version [5.0.8](https://github.com/reportportal/agent-js-jest/releases/tag/v5.0.8) is the latest that supports it.
- `@reportportal/client-javascript` bumped to version `5.1.0`.
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,35 @@ This is for your convenience if you have a continuous job that runs your tests a
The agent has support of retries.
Read more about [retries in jest](https://jestjs.io/ru/docs/jest-object#jestretrytimesnumretries-options).

## Reporting API

This report provides `ReportingApi` in global variables to use it directly in tests to send some additional data to the report.

### Reporting API methods

The API provide methods for attaching data.<br/>

#### attachment
Send file to ReportPortal for the current test. Should be called inside of corresponding test.<br/>
`ReportingApi.attachment(file: {name: string; type: string; content: string | Buffer;}, description?: string);`<br/>
**required**: `file`<br/>
**optional**: `description`<br/>
Example:
```javascript
test('should be passed with attachment', () => {
const fileName = 'test.jpg';
const fileContent = fs.readFileSync(path.resolve(__dirname, './attachments', fileName));

ReportingApi.attachment({
name: fileName,
type: 'image/png',
content: fileContent.toString('base64'),
}, 'Description');

expect(true).toBe(true);
});
```

# Copyright Notice

Licensed under the [Apache License v2.0](LICENSE)
Expand Down
4 changes: 2 additions & 2 deletions __tests__/getOptions.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
const fs = require('fs');
const path = require('path');
const process = require('process');
const { options, getAppOptions, getEnvOptions } = require('../utils/getOptions');
const constants = require('../constants/index');
const { options, getAppOptions, getEnvOptions } = require('../src/utils/getOptions');
const constants = require('../src/constants');

describe('Get Options script', () => {
const OLD_ENV = process.env;
Expand Down
88 changes: 40 additions & 48 deletions __tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@
/* eslint-disable no-undef */
const path = require('path');
const { getOptions, RPClient } = require('./mocks/reportportal-client.mock');
const JestReportPortal = require('../index');
const JestReportPortal = require('../src');
const { TEST_ITEM_STATUSES, LOG_LEVEL } = require('../src/constants');
const pjson = require('../package.json');
const {
duration,
skippedTestResult,
testResult,
testObj,
mockDate,
mockFile,
} = require('./mocks/data');

const testItemStatuses = { PASSED: 'passed', FAILED: 'failed', SKIPPED: 'pending' };
const GLOBAL_CONFIG = {};
const options = getOptions();
const currentDate = new Date();
Expand All @@ -30,22 +38,6 @@ const systemAttr = {
value: `${pjson.name}|${pjson.version}`,
system: true,
};
const duration = 5;
const testResult = {
testResults: [
{
title: 'Title',
status: 'failed',
ancestorTitles: ['Suite name', 'Test name'],
failureMessages: 'error message',
invocations: 1,
duration,
},
],
};
const testObj = {
path: `C:${path.sep}testProject${path.sep}example.js`,
};

describe('index script', () => {
let reporter;
Expand Down Expand Up @@ -118,17 +110,13 @@ describe('index script', () => {
reporter.onTestResult(testObj, testResult);

expect(spyStartSuite).toHaveBeenCalledWith(
testResult.testResults[0].ancestorTitles[0],
skippedTestResult.ancestorTitles[0],
testObj.path,
duration,
);
expect(spyStartTest).toHaveBeenCalledWith(
testResult.testResults[0],
testObj.path,
duration,
);
expect(spyStartStep).toHaveBeenCalledWith(testResult.testResults[0], false, testObj.path);
expect(spyFinishStep).toHaveBeenCalledWith(testResult.testResults[0], false);
expect(spyStartTest).toHaveBeenCalledWith(skippedTestResult, testObj.path, duration);
expect(spyStartStep).toHaveBeenCalledWith(skippedTestResult, false, testObj.path);
expect(spyFinishStep).toHaveBeenCalledWith(skippedTestResult, false);
expect(spyFinishTest).toHaveBeenCalledWith('1234', 'tempTestId');
expect(spyFinishSuite).toHaveBeenCalledWith('4321', 'tempSuiteId');
},
Expand All @@ -143,8 +131,8 @@ describe('index script', () => {

reporter.onTestResult(testObj, testResult);

expect(spyStartStep).toHaveBeenCalledWith(testResult.testResults[0], false, testObj.path);
expect(spyFinishStep).toHaveBeenCalledWith(testResult.testResults[0], false);
expect(spyStartStep).toHaveBeenCalledWith(skippedTestResult, false, testObj.path);
expect(spyFinishStep).toHaveBeenCalledWith(skippedTestResult, false);
expect(spyStartStep).toHaveBeenCalledTimes(1);
expect(spyFinishStep).toHaveBeenCalledTimes(1);
},
Expand All @@ -156,13 +144,14 @@ describe('index script', () => {
() => {
const spyStartStep = jest.spyOn(reporter, '_startStep');
const spyFinishStep = jest.spyOn(reporter, '_finishStep');

const testResult = {
testResults: [
{
title: 'Title',
status: 'failed',
status: TEST_ITEM_STATUSES.SKIPPED,
ancestorTitles: ['Suite name', 'Test name'],
failureMessages: 'error message',
failureMessages: [],
invocations: 2,
},
],
Expand All @@ -187,9 +176,9 @@ describe('index script', () => {
testResults: [
{
title: 'Title',
status: 'failed',
status: TEST_ITEM_STATUSES.SKIPPED,
ancestorTitles: ['Suite name', 'Test name'],
failureMessages: 'error message',
failureMessages: [],
},
],
};
Expand Down Expand Up @@ -358,19 +347,20 @@ describe('index script', () => {
});
});

describe('_sendLog', () => {
describe('sendLog', () => {
test('sendLog should be called with parameters', () => {
const expectedLogObjectParameter = {
message: 'message',
level: 'error',
};
reporter.tempStepId = 'tempStepId';

reporter._sendLog('message');
reporter.sendLog({ message: 'message', level: LOG_LEVEL.ERROR, file: mockFile });

expect(reporter.client.sendLog).toHaveBeenCalledWith(
'tempStepId',
expectedLogObjectParameter,
{
message: 'message',
level: LOG_LEVEL.ERROR,
time: mockDate,
},
mockFile,
);
});
});
Expand All @@ -381,7 +371,7 @@ describe('index script', () => {
const spyFinishFailedTest = jest.spyOn(reporter, '_finishFailedStep');
const spyFinishSkippedTest = jest.spyOn(reporter, '_finishSkippedStep');

reporter._finishStep({ status: testItemStatuses.PASSED, failureMessages: [] });
reporter._finishStep({ status: TEST_ITEM_STATUSES.PASSED, failureMessages: [] });

expect(spyFinishPassedTest).toHaveBeenCalled();
expect(spyFinishFailedTest).not.toHaveBeenCalled();
Expand All @@ -394,7 +384,7 @@ describe('index script', () => {
const spyFinishSkippedTest = jest.spyOn(reporter, '_finishSkippedStep');

reporter._finishStep(
{ status: testItemStatuses.FAILED, failureMessages: ['error message'] },
{ status: TEST_ITEM_STATUSES.FAILED, failureMessages: ['error message'] },
false,
);

Expand All @@ -408,7 +398,7 @@ describe('index script', () => {
const spyFinishFailedTest = jest.spyOn(reporter, '_finishFailedStep');
const spyFinishSkippedTest = jest.spyOn(reporter, '_finishSkippedStep');

reporter._finishStep({ status: testItemStatuses.SKIPPED, failureMessages: [] });
reporter._finishStep({ status: TEST_ITEM_STATUSES.SKIPPED, failureMessages: [] });

expect(spyFinishSkippedTest).toHaveBeenCalled();
expect(spyFinishPassedTest).not.toHaveBeenCalled();
Expand Down Expand Up @@ -468,19 +458,21 @@ describe('index script', () => {
});

describe('_finishFailedStep', () => {
test('_sendLog should be called with failure message, finishTestItem should be called with parameters', () => {
const spySendLog = jest.spyOn(reporter, '_sendLog');
test('sendLog should be called with failure message, finishTestItem should be called with parameters', () => {
const spySendLog = jest.spyOn(reporter, 'sendLog');
const errorMessage = 'error message';
const tempStepId = 'tempStepId';
const expectedFinishTestItemParameter = {
status: 'failed',
retry: false,
};
reporter.tempStepId = 'tempStepId';
reporter.tempStepId = tempStepId;

reporter._finishFailedStep('error message', false);
reporter._finishFailedStep(errorMessage, false);

expect(spySendLog).toHaveBeenCalledWith('error message');
expect(spySendLog).toHaveBeenCalledWith({ message: errorMessage, level: LOG_LEVEL.ERROR });
expect(reporter.client.finishTestItem).toHaveBeenCalledWith(
'tempStepId',
tempStepId,
expectedFinishTestItemParameter,
);
});
Expand Down
38 changes: 38 additions & 0 deletions __tests__/mocks/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const path = require('path');
const { TEST_ITEM_STATUSES } = require('../../src/constants');

const mockDate = 1712900000000;
const duration = 5;
const failedTestResult = {
title: 'failed title',
status: TEST_ITEM_STATUSES.FAILED,
ancestorTitles: ['Failed suite name', 'Failed test name'],
failureMessages: ['error message'],
invocations: 1,
duration,
};
const skippedTestResult = {
title: 'skipped title',
status: TEST_ITEM_STATUSES.SKIPPED,
ancestorTitles: ['Skipped suite name', 'Skipped test name'],
failureMessages: [],
invocations: 1,
duration,
};
const testResult = {
testResults: [failedTestResult, skippedTestResult],
};
const testObj = {
path: `C:${path.sep}testProject${path.sep}example.js`,
};
const mockFile = { name: 'test_img_name', type: 'image/png', content: 'content' };

module.exports = {
mockDate,
duration,
failedTestResult,
skippedTestResult,
testResult,
testObj,
mockFile,
};
5 changes: 5 additions & 0 deletions __tests__/mocks/reportportal-client.mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

const { mockDate } = require('./data');

const reporterOptions = {
apiKey: '00000000-0000-0000-0000-000000000000',
endpoint: 'endpoint',
Expand All @@ -38,6 +40,9 @@ class RPClient {
this.startTestItem = this.mockStartTestItem();
this.finishTestItem = this.mockFinishTestItem();
this.sendLog = this.mockSendLog();
this.helpers = {
now: jest.fn().mockReturnValue(mockDate),
};
}

mockStartLaunch() {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/objectUtils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const {
getFullTestName,
getFullStepName,
getSystemAttributes,
} = require('../utils/objectUtils');
} = require('../src/utils/objectUtils');
const pjson = require('../package.json');

const defaultOptions = {
Expand Down
8 changes: 2 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@reportportal/agent-js-jest",
"version": "5.0.8",
"description": "A Jest reporter that uploads test results to ReportPortal",
"main": "index.js",
"main": "src/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/reportportal/agent-js-jest.git"
Expand All @@ -18,11 +18,7 @@
"engines": {
"node": ">=12.x"
},
"files": [
"index.js",
"utils",
"constants"
],
"files": ["src"],
"dependencies": {
"@reportportal/client-javascript": "^5.1.0",
"strip-ansi": "^6.0.1"
Expand Down
11 changes: 11 additions & 0 deletions constants/index.js → src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,15 @@ module.exports = {
FILEPATH_VAR: 'filepath',
TITLE_VAR: 'title',
DISPLAY_NAME_VAR: 'displayName',
STEP_META_TYPE: {
ATTACHMENT: 'attachment',
},
TEST_ITEM_STATUSES: { PASSED: 'passed', FAILED: 'failed', SKIPPED: 'pending' },
LOG_LEVEL: {
ERROR: 'error',
TRACE: 'trace',
DEBUG: 'debug',
INFO: 'info',
WARN: 'warn',
},
};
19 changes: 19 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2020 EPAM Systems
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

const JestReportPortal = require('./reporter');

module.exports = JestReportPortal;
Loading

0 comments on commit af9cbbd

Please sign in to comment.