From 27e9a2211593bbcf2be8780ea4111e2b3bdf86b4 Mon Sep 17 00:00:00 2001 From: "reportportal.io" Date: Tue, 16 Jul 2024 17:20:32 +0000 Subject: [PATCH 1/9] 5.1.0 -> 5.1.1-SNAPSHOT --- VERSION | 2 +- version_fragment | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 831446c..99a2954 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.0 +5.1.1-SNAPSHOT diff --git a/version_fragment b/version_fragment index acb503f..9eb7b90 100644 --- a/version_fragment +++ b/version_fragment @@ -1 +1 @@ -minor +patch From 32520f6e9f936e4f90507f14129feaf2cb3246b1 Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Tue, 16 Jul 2024 19:27:37 +0200 Subject: [PATCH 2/9] Fix test runs in workflow files --- .github/workflows/CI-pipeline.yml | 2 +- .github/workflows/publish.yml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI-pipeline.yml b/.github/workflows/CI-pipeline.yml index a4a19bd..9cb6ec1 100644 --- a/.github/workflows/CI-pipeline.yml +++ b/.github/workflows/CI-pipeline.yml @@ -37,5 +37,5 @@ jobs: run: npm install - name: Run lint run: npm run lint - - name: Check coverage + - name: Run tests and check coverage run: npm run test:coverage diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9c0803c..da6cb95 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -31,9 +31,7 @@ jobs: run: npm install - name: Run lint run: npm run lint - - name: Run tests - run: npm test - - name: Check coverage + - name: Run tests and check coverage run: npm run test:coverage publish-to-npm-and-gpr: From b92515b093848c2c1be48d3b97dee9bd1b011219 Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Wed, 17 Jul 2024 17:56:36 +0200 Subject: [PATCH 3/9] Update test npm script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b163ad4..8af7547 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "lint": "eslint .", "format": "npm run lint -- --fix", - "test": "jest --detectOpenHandles --config ./jest.config.js", + "test": "jest", "test:coverage": "jest --coverage" }, "dependencies": { From af8fc514dcdd3cf03f4ac2f42019b57429557124 Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Thu, 3 Oct 2024 16:17:49 +0200 Subject: [PATCH 4/9] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2be652..9d05af0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### Changed +- **Breaking change** Drop support of Node.js 12. The version [5.1.0](https://github.com/reportportal/agent-js-jasmine/releases/tag/v5.1.0) is the latest that supports it. +- The agent now supports reporting the time for launches, test items and logs with microsecond precision in the ISO string format. +For logs, microsecond precision is available on the UI from ReportPortal [version 24.2](https://reportportal.io/docs/releases/Version24.2/#:~:text=import%20plugin.-,Microseconds,-added%20to%20timestamps). +- `@reportportal/client-javascript` bumped to version `5.3.0`. ## [5.1.0] - 2024-07-16 ### Added From 88df82f82a37b416bb1b8a529a22c18b06dddf4c Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Thu, 3 Oct 2024 16:18:20 +0200 Subject: [PATCH 5/9] Drop support of Node.js 12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8af7547..6f6262f 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "/lib" ], "engines": { - "node": ">=12.x" + "node": ">=14.x" }, "author": "ReportPortal.io", "license": "Apache-2.0", From 385259d277599b076314357c270ae1a791b4c918 Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Thu, 3 Oct 2024 19:00:03 +0200 Subject: [PATCH 6/9] EPMRPP-95590 || Time with microseconds support --- CHANGELOG.md | 2 + __mocks__/@reportportal/client-javascript.js | 56 +++ .../jasmine-reportportal-reporter.spec.js | 43 +-- __tests__/reportportal-agent.spec.js | 7 +- __tests__/specificUtils.spec.js | 28 ++ lib/jasmine-reportportal-reporter.js | 4 +- lib/specificUtils.js | 329 ++++++++++-------- package-lock.json | 59 +++- package.json | 2 +- 9 files changed, 343 insertions(+), 187 deletions(-) create mode 100644 __mocks__/@reportportal/client-javascript.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d05af0..d878e09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ - The agent now supports reporting the time for launches, test items and logs with microsecond precision in the ISO string format. For logs, microsecond precision is available on the UI from ReportPortal [version 24.2](https://reportportal.io/docs/releases/Version24.2/#:~:text=import%20plugin.-,Microseconds,-added%20to%20timestamps). - `@reportportal/client-javascript` bumped to version `5.3.0`. +### Security +- Updated versions of vulnerable packages (micromatch). ## [5.1.0] - 2024-07-16 ### Added diff --git a/__mocks__/@reportportal/client-javascript.js b/__mocks__/@reportportal/client-javascript.js new file mode 100644 index 0000000..9ca0445 --- /dev/null +++ b/__mocks__/@reportportal/client-javascript.js @@ -0,0 +1,56 @@ +/* + * Copyright 2024 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. + * + */ + +class RPClientMock { + config; + + constructor(config) { + this.config = config; + } + + startLaunch = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + tempId: 'tempLaunchId', + }); + + finishLaunch = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); + + startTestItem = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + tempId: 'tempTestItemId', + }); + + finishTestItem = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); + + getPromiseFinishAllItems = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); + + sendLog = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); + + checkConnect = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); +} + +module.exports = RPClientMock; diff --git a/__tests__/jasmine-reportportal-reporter.spec.js b/__tests__/jasmine-reportportal-reporter.spec.js index b0a1d2c..d55338a 100644 --- a/__tests__/jasmine-reportportal-reporter.spec.js +++ b/__tests__/jasmine-reportportal-reporter.spec.js @@ -13,26 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +const helpers = require('@reportportal/client-javascript/lib/helpers'); +const Reporter = require('../lib/jasmine-reportportal-reporter'); +const SpecificUtils = require('../lib/specificUtils'); -describe('jasmine Report Portal reporter', () => { - const Reporter = require('../lib/jasmine-reportportal-reporter'); - const SpecificUtils = require('../lib/specificUtils'); +const mockedDate = '2024-09-23T12:20:59.392987Z'; +describe('jasmine Report Portal reporter', () => { let reporter; const tempLaunchId = 'ewrf35432r'; let promise; - let baseTime; beforeEach(() => { - jest.useFakeTimers(); + jest.spyOn(helpers, 'now').mockReturnValue(mockedDate); + // TODO: should be replaced with unregistering specific listeners only + process.removeAllListeners(); const client = { startTestItem() {}, finishTestItem() {}, sendLog() {}, }; const onSetLaunchStatus = function () {}; - baseTime = new Date(2020, 4, 8); - jest.setSystemTime(baseTime); reporter = new Reporter( { client, @@ -363,7 +364,7 @@ describe('jasmine Report Portal reporter', () => { level: 'level', file: null, message: 'message', - time: baseTime.valueOf(), + time: mockedDate, }, ], }; @@ -381,13 +382,13 @@ describe('jasmine Report Portal reporter', () => { level: 'level', file: null, message: 'message', - time: baseTime.valueOf(), + time: mockedDate, }, { level: 'level1', file: null, message: 'message1', - time: baseTime.valueOf(), + time: mockedDate, }, ], }; @@ -448,7 +449,7 @@ describe('jasmine Report Portal reporter', () => { { message: 'message', level: 'level', - time: baseTime.valueOf(), + time: mockedDate, }, null ); @@ -465,7 +466,7 @@ describe('jasmine Report Portal reporter', () => { { message: '', level: 'level', - time: baseTime.valueOf(), + time: mockedDate, }, undefined ); @@ -604,7 +605,7 @@ describe('jasmine Report Portal reporter', () => { description: 'text description', testCaseId: 'testCaseId', codeRef: 'codeRef', - startTime: baseTime.valueOf(), + startTime: mockedDate, }, tempLaunchId, null @@ -653,7 +654,7 @@ describe('jasmine Report Portal reporter', () => { description: 'test description', name: 'test description', codeRef: 'codeRef', - startTime: baseTime.valueOf(), + startTime: mockedDate, }, tempLaunchId, null @@ -674,7 +675,7 @@ describe('jasmine Report Portal reporter', () => { promise.then(() => { expect(reporter.setParentInfo).toHaveBeenCalledWith({ tempId: '3452', - startTime: baseTime.valueOf(), + startTime: mockedDate, }); done(); @@ -759,14 +760,14 @@ describe('jasmine Report Portal reporter', () => { tempId: '3452', promise: Promise.resolve(), }); - jest.spyOn(reporter, 'getHookStartTime').mockReturnValue(baseTime.valueOf()); + jest.spyOn(reporter, 'getHookStartTime').mockReturnValue(mockedDate); reporter.hookStarted('beforeAll'); expect(reporter.client.startTestItem).toHaveBeenCalledWith( { type: 'BEFORE_SUITE', - startTime: baseTime.valueOf(), + startTime: mockedDate, name: 'beforeAll', }, tempLaunchId, @@ -787,7 +788,7 @@ describe('jasmine Report Portal reporter', () => { expect(reporter.client.finishTestItem).toHaveBeenCalledWith('3452', { status: 'passed', - endTime: baseTime.valueOf(), + endTime: mockedDate, }); expect(reporter.itemStartTime).toEqual(null); }); @@ -802,7 +803,7 @@ describe('jasmine Report Portal reporter', () => { expect(reporter.client.finishTestItem).toHaveBeenCalledWith('3452', { status: 'failed', - endTime: baseTime.valueOf(), + endTime: mockedDate, }); }); @@ -879,7 +880,7 @@ describe('jasmine Report Portal reporter', () => { { message: 'message: error\nstackTrace: stack', level: 'ERROR', - time: baseTime.valueOf(), + time: mockedDate, }, null ); @@ -978,7 +979,7 @@ describe('jasmine Report Portal reporter', () => { { message: 'message: error\nstackTrace: stack', level: 'ERROR', - time: baseTime.valueOf(), + time: mockedDate, }, null ); diff --git a/__tests__/reportportal-agent.spec.js b/__tests__/reportportal-agent.spec.js index 8c45204..eb6b5c8 100644 --- a/__tests__/reportportal-agent.spec.js +++ b/__tests__/reportportal-agent.spec.js @@ -20,7 +20,7 @@ const SpecificUtils = require('../lib/specificUtils'); const reporterOptions = { apiKey: 'reportportalApiKey', - endpoint: 'endpoint', + endpoint: 'http://reportportal.example.com/api/v1', project: 'projectName', launch: 'launcherName', description: 'description', @@ -44,10 +44,13 @@ describe('Report Portal agent', () => { let agent; beforeAll(() => { - jest.clearAllMocks(); // Clear mocks before initialization agent = new ReportportalAgent(options); }); + beforeEach(() => { + jest.clearAllMocks(); // Clear mocks before initialization + }) + it('should be properly initialized', () => { expect(agent.tempLaunchId).toBeDefined(); expect(agent.client).toBeDefined(); diff --git a/__tests__/specificUtils.spec.js b/__tests__/specificUtils.spec.js index a2b20a3..96b8517 100644 --- a/__tests__/specificUtils.spec.js +++ b/__tests__/specificUtils.spec.js @@ -348,5 +348,33 @@ describe('Specific Utils', () => { expect(escapeString).toBe('\\_test\\*'); }); }); + + describe('convertIsoStringToMicroseconds', () => { + it('converts ISO string with microseconds correctly', () => { + const isoString = '2024-09-20T14:32:35.304456Z'; + const expectedMicroseconds = 1726842755304456; + expect(SpecificUtils.convertIsoStringToMicroseconds(isoString)).toBe(expectedMicroseconds); + }); + + it('handles microseconds accurately', () => { + const isoString = '2021-03-15T12:00:00.000001Z'; + const expectedMicroseconds = 1615809600000001; + expect(SpecificUtils.convertIsoStringToMicroseconds(isoString)).toBe(expectedMicroseconds); + }); + + it('returns correct microseconds at epoch start', () => { + const isoString = '1970-01-01T00:00:00.000001Z'; + const expectedMicroseconds = 1; + expect(SpecificUtils.convertIsoStringToMicroseconds(isoString)).toBe(expectedMicroseconds); + }); + }); + + describe('getBeforeHookStartTime', () => { + it('should return the start time for the hook as reduced time from test item start by 1 millisecond', () => { + const itemStartTime = '2024-09-20T14:32:35.304456Z'; + const expectedHookStartTime = '2024-09-20T14:32:35.303456Z'; + expect(SpecificUtils.getBeforeHookStartTime(itemStartTime)).toBe(expectedHookStartTime); + }); + }); }); }); diff --git a/lib/jasmine-reportportal-reporter.js b/lib/jasmine-reportportal-reporter.js index 698628a..f4f92fb 100644 --- a/lib/jasmine-reportportal-reporter.js +++ b/lib/jasmine-reportportal-reporter.js @@ -16,6 +16,7 @@ const { EVENTS } = require('@reportportal/client-javascript/lib/constants/events'); const { RP_STATUSES } = require('@reportportal/client-javascript/lib/constants/statuses'); +const clientHelpers = require('@reportportal/client-javascript/lib/helpers'); const SpecificUtils = require('./specificUtils'); const { entityType, hookTypes, hookTypesMap } = require('./constants/itemTypes'); const LOG_LEVELS = require('./constants/logLevels'); @@ -84,7 +85,7 @@ class ReportportalReporter { } getTime() { - return new Date().valueOf(); + return clientHelpers.now(); } addAttributes(attr) { @@ -282,6 +283,7 @@ class ReportportalReporter { }); } + // TODO: update getHookStartTime(hookType, parent) { if (hookType === entityType.BEFORE_METHOD || hookType === entityType.BEFORE_SUITE) { return Math.max(parent && parent.startTime, this.itemStartTime - 1); diff --git a/lib/specificUtils.js b/lib/specificUtils.js index 0baf970..f7bc0e0 100644 --- a/lib/specificUtils.js +++ b/lib/specificUtils.js @@ -16,6 +16,7 @@ const path = require('path'); const process = require('process'); +const clientHelpers = require('@reportportal/client-javascript/lib/helpers'); const { RP_STATUSES } = require('@reportportal/client-javascript/lib/constants/statuses'); const pjson = require('./../package.json'); const LOG_LEVELS = require('./constants/logLevels'); @@ -23,167 +24,201 @@ const LOG_LEVELS = require('./constants/logLevels'); const PJSON_VERSION = pjson.version; const PJSON_NAME = pjson.name; -const SpecificUtils = { - takeScreenshot(fileName) { - let promiseResolve; - const promise = new Promise((resolve, reject) => { - promiseResolve = resolve; - }); - if (global.browser) { - global.browser.takeScreenshot().then( - (png) => { - promiseResolve({ - name: fileName, - type: 'image/png', - content: png, - }); - }, - (error) => { - console.dir(error); - promiseResolve(null); - } - ); - } else { - promiseResolve(null); - } - return promise; - }, - - escapeMarkdown(string) { - return string.replace(/_/gm, '\\_').replace(/\*/gm, '\\*'); - }, - - getAllLogs(spec, fileObject, logs) { - const failures = []; - spec.failedExpectations.forEach((failure) => { - failures.push(`message: ${this.escapeMarkdown(failure.message)}`); - failures.push(`stackTrace: ${this.escapeMarkdown(failure.stack)}`); - }); - - if (failures.length) { - const message = failures.join('\n'); - - return [{ level: LOG_LEVELS.ERROR, message, file: fileObject }, ...logs]; - } - - return logs; - }, - - getLaunchObj(conf) { - const systemAttr = this.getSystemAttributes(conf.skippedIssue); - const launchObj = Object.assign( - { - attributes: conf.attributes ? [...conf.attributes, ...systemAttr] : systemAttr, - description: conf.description, +function takeScreenshot(fileName) { + let promiseResolve; + const promise = new Promise((resolve, reject) => { + promiseResolve = resolve; + }); + if (global.browser) { + global.browser.takeScreenshot().then( + (png) => { + promiseResolve({ + name: fileName, + type: 'image/png', + content: png, + }); }, - conf.id && { id: conf.id }, - conf.rerun && { rerun: conf.rerun }, - conf.rerunOf && { rerunOf: conf.rerunOf }, - conf.mode && { mode: conf.mode } + (error) => { + console.dir(error); + promiseResolve(null); + } ); + } else { + promiseResolve(null); + } + return promise; +} + +function escapeMarkdown(string) { + return string.replace(/_/gm, '\\_').replace(/\*/gm, '\\*'); +} + +function getAllLogs(spec, fileObject, logs) { + const failures = []; + spec.failedExpectations.forEach((failure) => { + failures.push(`message: ${this.escapeMarkdown(failure.message)}`); + failures.push(`stackTrace: ${this.escapeMarkdown(failure.stack)}`); + }); + + if (failures.length) { + const message = failures.join('\n'); + + return [{ level: LOG_LEVELS.ERROR, message, file: fileObject }, ...logs]; + } + + return logs; +} + +function getLaunchObj(conf) { + const systemAttr = this.getSystemAttributes(conf.skippedIssue); + const launchObj = Object.assign( + { + attributes: conf.attributes ? [...conf.attributes, ...systemAttr] : systemAttr, + description: conf.description, + }, + conf.id && { id: conf.id }, + conf.rerun && { rerun: conf.rerun }, + conf.rerunOf && { rerunOf: conf.rerunOf }, + conf.mode && { mode: conf.mode } + ); + + return launchObj; +} + +function getSystemAttributes(skippedIssue) { + const systemAttr = [ + { + key: 'agent', + value: `${PJSON_NAME}|${PJSON_VERSION}`, + system: true, + }, + ]; + + if (skippedIssue === false) { + const skippedIssueAttribute = { + key: 'skippedIssue', + value: 'false', + system: true, + }; - return launchObj; - }, + systemAttr.push(skippedIssueAttribute); + } - getSystemAttributes(skippedIssue) { - const systemAttr = [ - { - key: 'agent', - value: `${PJSON_NAME}|${PJSON_VERSION}`, - system: true, - }, - ]; + return systemAttr; +} - if (skippedIssue === false) { - const skippedIssueAttribute = { - key: 'skippedIssue', - value: 'false', - system: true, - }; +function getAgentInfo() { + return { + version: PJSON_VERSION, + name: PJSON_NAME, + }; +} - systemAttr.push(skippedIssueAttribute); - } +function getCodeRef(currentSpecIndex, fullTestName) { + if (!global.browser) { + return Promise.resolve(null); + } - return systemAttr; - }, - - getAgentInfo() { - return { - version: PJSON_VERSION, - name: PJSON_NAME, - }; - }, - - getCodeRef(currentSpecIndex, fullTestName) { - if (!global.browser) { - return Promise.resolve(null); - } - - return global.browser.getProcessedConfig().then((config) => { - const currentTestFilePath = config.specs[currentSpecIndex].replace( - new RegExp('\\\\', 'g'), - '/' - ); - const processCwd = process.cwd().replace(/\\/g, '/'); - - const testFileDir = path.parse( - path.normalize(path.relative(processCwd, currentTestFilePath)) - ).dir; - - const separator = testFileDir ? '/' : ''; - const testFile = path.parse(currentTestFilePath); - - return `${testFileDir}${separator}${testFile.base}/${fullTestName}`; - }); - }, - - getFullTestName(test) { - if (test.description === test.fullName) { - return test.description; - } - - const parentName = test.fullName.replace(test.description, '').slice(0, -1); - - return `${parentName}/${test.description}`; - }, - - isPromise(obj) { - return ( - !!obj && - (typeof obj === 'object' || typeof obj === 'function') && - typeof obj.then === 'function' + return global.browser.getProcessedConfig().then((config) => { + const currentTestFilePath = config.specs[currentSpecIndex].replace( + new RegExp('\\\\', 'g'), + '/' ); - }, + const processCwd = process.cwd().replace(/\\/g, '/'); + + const testFileDir = path.parse( + path.normalize(path.relative(processCwd, currentTestFilePath)) + ).dir; + + const separator = testFileDir ? '/' : ''; + const testFile = path.parse(currentTestFilePath); + + return `${testFileDir}${separator}${testFile.base}/${fullTestName}`; + }); +} + +function getFullTestName(test) { + if (test.description === test.fullName) { + return test.description; + } - isHookShouldBeCalled(action) { - return !(this.isPromise(action) && action !== undefined && action.valueOf() === undefined); - }, + const parentName = test.fullName.replace(test.description, '').slice(0, -1); - makeHooksWrapper(wrapped, funcStart, funcFinish) { - return function (action, timeout) { - wrapped((done) => { - let isFuncBeCalled = true; + return `${parentName}/${test.description}`; +} - try { - isFuncBeCalled = SpecificUtils.isHookShouldBeCalled(action(done)); +function isPromise(obj) { + return ( + !!obj && + (typeof obj === 'object' || typeof obj === 'function') && + typeof obj.then === 'function' + ); +} - if (isFuncBeCalled) { - funcStart(); - funcFinish(); - } +function isHookShouldBeCalled(action) { + return !(this.isPromise(action) && action !== undefined && action.valueOf() === undefined); +} - done(); - } catch (err) { - if (isFuncBeCalled) { - funcStart(); - funcFinish(RP_STATUSES.FAILED, err); - } +function makeHooksWrapper(wrapped, funcStart, funcFinish) { + return function (action, timeout) { + wrapped((done) => { + let isFuncBeCalled = true; - done.fail(err); + try { + isFuncBeCalled = SpecificUtils.isHookShouldBeCalled(action(done)); + + if (isFuncBeCalled) { + funcStart(); + funcFinish(); } - }, timeout); - }; - }, + + done(); + } catch (err) { + if (isFuncBeCalled) { + funcStart(); + funcFinish(RP_STATUSES.FAILED, err); + } + + done.fail(err); + } + }, timeout); + }; +} + +const formatMicrosecondsToISOString = (timestampInMicroseconds) => { + const milliseconds = Math.floor(timestampInMicroseconds / 1000); + const microseconds = String(timestampInMicroseconds).slice(-3); + const isoDate = new Date(milliseconds).toISOString(); + + return isoDate.replace('Z', `${microseconds}Z`); }; -module.exports = SpecificUtils; +function convertIsoStringToMicroseconds(isoDateStringWithMicroseconds) { + const [datePart, microsecondsPart] = isoDateStringWithMicroseconds.split('.'); + const date = new Date(`${datePart}Z`); + const microseconds = parseInt(microsecondsPart.slice(0, -1), 10); + + return (date.getTime() * 1000) + microseconds; +} + +function getBeforeHookStartTime(itemStartTime) { + return clientHelpers.formatMicrosecondsToISOString( + convertIsoStringToMicroseconds(itemStartTime) - 1000 + ); +} + +module.exports = { + takeScreenshot, + escapeMarkdown, + getAllLogs, + getLaunchObj, + getSystemAttributes, + getAgentInfo, + getCodeRef, + getFullTestName, + isPromise, + isHookShouldBeCalled, + makeHooksWrapper, + convertIsoStringToMicroseconds, + getBeforeHookStartTime, +}; diff --git a/package-lock.json b/package-lock.json index 45d965e..afec6e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,10 +6,10 @@ "packages": { "": { "name": "@reportportal/agent-js-jasmine", - "version": "5.0.3", + "version": "5.1.0", "license": "Apache-2.0", "dependencies": { - "@reportportal/client-javascript": "~5.1.4" + "@reportportal/client-javascript": "~5.3.0" }, "devDependencies": { "eslint": "^8.57.0", @@ -22,7 +22,7 @@ "prettier": "^2.8.8" }, "engines": { - "node": ">=12.x" + "node": ">=14.x" } }, "../examples-js/example-jasmine": { @@ -1188,19 +1188,20 @@ } }, "node_modules/@reportportal/client-javascript": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@reportportal/client-javascript/-/client-javascript-5.1.4.tgz", - "integrity": "sha512-Pk00dSYX8TANmEkg2CN06PxoSW1f83d1mew1M0kw5pDZOif+1cYrjy1E4HNrdLBoYhAH6oQIISvJSKc7K6A8fg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@reportportal/client-javascript/-/client-javascript-5.3.0.tgz", + "integrity": "sha512-328279/aC6rXe6BNEZeCXJ1/b5k05RdC5HSR8GYnr6TFWvYV5DQd4/E33ekhT0+Psenf6sMcccl24lZZdxKOvA==", "dependencies": { - "axios": "^1.6.8", + "axios": "^1.7.7", "axios-retry": "^4.1.0", "glob": "^8.1.0", "ini": "^2.0.0", + "microtime": "^3.1.1", "uniqid": "^5.4.0", "uuid": "^9.0.1" }, "engines": { - "node": ">=12.x" + "node": ">=14.x" } }, "node_modules/@reportportal/client-javascript/node_modules/brace-expansion": { @@ -1637,9 +1638,9 @@ } }, "node_modules/axios": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", - "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -4623,18 +4624,31 @@ "dev": true }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, + "node_modules/microtime": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/microtime/-/microtime-3.1.1.tgz", + "integrity": "sha512-to1r7o24cDsud9IhN6/8wGmMx5R2kT0w2Xwm5okbYI3d1dk6Xv0m+Z+jg2vS9pt+ocgQHTCtgs/YuyJhySzxNg==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.4.0" + }, + "engines": { + "node": ">= 14.13.0" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -4696,6 +4710,21 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node_modules/node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", diff --git a/package.json b/package.json index 6f6262f..21e6e09 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "test:coverage": "jest --coverage" }, "dependencies": { - "@reportportal/client-javascript": "~5.1.4" + "@reportportal/client-javascript": "~5.3.0" }, "devDependencies": { "eslint": "^8.57.0", From 1f520a20c27f47ed467b538e9a3398ec2566caf0 Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Thu, 3 Oct 2024 19:04:53 +0200 Subject: [PATCH 7/9] Fix linter errors --- __mocks__/@reportportal/client-javascript.js | 50 ++++++++++---------- __tests__/reportportal-agent.spec.js | 2 +- lib/specificUtils.js | 2 +- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/__mocks__/@reportportal/client-javascript.js b/__mocks__/@reportportal/client-javascript.js index 9ca0445..145ed89 100644 --- a/__mocks__/@reportportal/client-javascript.js +++ b/__mocks__/@reportportal/client-javascript.js @@ -16,41 +16,39 @@ */ class RPClientMock { - config; - constructor(config) { this.config = config; - } - startLaunch = jest.fn().mockReturnValue({ - promise: Promise.resolve('ok'), - tempId: 'tempLaunchId', - }); + this.startLaunch = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + tempId: 'tempLaunchId', + }); - finishLaunch = jest.fn().mockReturnValue({ - promise: Promise.resolve('ok'), - }); + this.finishLaunch = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); - startTestItem = jest.fn().mockReturnValue({ - promise: Promise.resolve('ok'), - tempId: 'tempTestItemId', - }); + this.startTestItem = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + tempId: 'testItemId', + }); - finishTestItem = jest.fn().mockReturnValue({ - promise: Promise.resolve('ok'), - }); + this.finishTestItem = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); - getPromiseFinishAllItems = jest.fn().mockReturnValue({ - promise: Promise.resolve('ok'), - }); + this.sendLog = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); - sendLog = jest.fn().mockReturnValue({ - promise: Promise.resolve('ok'), - }); + this.getPromiseFinishAllItems = jest.fn().mockResolvedValue({ + promise: Promise.resolve('ok'), + }); - checkConnect = jest.fn().mockReturnValue({ - promise: Promise.resolve('ok'), - }); + this.checkConnect = jest.fn().mockReturnValue({ + promise: Promise.resolve('ok'), + }); + } } module.exports = RPClientMock; diff --git a/__tests__/reportportal-agent.spec.js b/__tests__/reportportal-agent.spec.js index eb6b5c8..0f4c06d 100644 --- a/__tests__/reportportal-agent.spec.js +++ b/__tests__/reportportal-agent.spec.js @@ -49,7 +49,7 @@ describe('Report Portal agent', () => { beforeEach(() => { jest.clearAllMocks(); // Clear mocks before initialization - }) + }); it('should be properly initialized', () => { expect(agent.tempLaunchId).toBeDefined(); diff --git a/lib/specificUtils.js b/lib/specificUtils.js index f7bc0e0..1cbca28 100644 --- a/lib/specificUtils.js +++ b/lib/specificUtils.js @@ -198,7 +198,7 @@ function convertIsoStringToMicroseconds(isoDateStringWithMicroseconds) { const date = new Date(`${datePart}Z`); const microseconds = parseInt(microsecondsPart.slice(0, -1), 10); - return (date.getTime() * 1000) + microseconds; + return date.getTime() * 1000 + microseconds; } function getBeforeHookStartTime(itemStartTime) { From 5aaddaa9c99cbdf6aee630fdb34b7e8a4171f582 Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Thu, 3 Oct 2024 19:06:10 +0200 Subject: [PATCH 8/9] Fix links in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7786e6a..9d4eea0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Agent to integrate Jasmine with ReportPortal. * More about [Jasmine](https://jasmine.github.io/) -* More about [ReportPortal](http://reportportal.io/) +* More about [ReportPortal](https://reportportal.io/) ## Installation @@ -43,7 +43,7 @@ The full list of available options presented below. | project | Required | | The name of the project in which the launches will be created. | | attributes | Optional | [] | Launch attributes. | | description | Optional | '' | Launch description. | -| rerun | Optional | false | Enable [rerun](https://reportportal.io/docs/dev-guides/RerunDevelopersGuide) | +| rerun | Optional | false | Enable [rerun](https://reportportal.io/docs/developers-guides/RerunDevelopersGuide/) | | rerunOf | Optional | Not set | UUID of launch you want to rerun. If not specified, ReportPortal will update the latest launch with the same name | | mode | Optional | 'DEFAULT' | Results will be submitted to Launches page
*'DEBUG'* - Results will be submitted to Debug page. | | skippedIssue | Optional | true | ReportPortal provides feature to mark skipped tests as not 'To Investigate'.
Option could be equal boolean values:
*true* - skipped tests considered as issues and will be marked as 'To Investigate' on ReportPortal.
*false* - skipped tests will not be marked as 'To Investigate' on application. | From 8aeaaf630f4fd2f381fc00f54271dc094c01910c Mon Sep 17 00:00:00 2001 From: Ilya Hancharyk Date: Thu, 3 Oct 2024 19:06:29 +0200 Subject: [PATCH 9/9] Update version fragment to minor --- version_fragment | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_fragment b/version_fragment index 9eb7b90..acb503f 100644 --- a/version_fragment +++ b/version_fragment @@ -1 +1 @@ -patch +minor