diff --git a/src/__tests__/reporter/onStepBeginReporting.spec.ts b/src/__tests__/reporter/onStepBeginReporting.spec.ts index db062b4..0a9cdfa 100644 --- a/src/__tests__/reporter/onStepBeginReporting.spec.ts +++ b/src/__tests__/reporter/onStepBeginReporting.spec.ts @@ -18,6 +18,7 @@ import { RPReporter } from '../../reporter'; import { mockConfig } from '../mocks/configMock'; import { RPClientMock } from '../mocks/RPClientMock'; import { TEST_ITEM_TYPES } from '../../constants'; +import { createSHA256Hash } from '../../utils'; const playwrightProjectName = 'projectName'; const suiteName = 'suiteName'; @@ -69,14 +70,16 @@ describe('onStepBegin reporting', () => { test('client.startTestItem should be called with test item id as a parent id', () => { const step = { + category: 'pw:api', + startTime: new Date(2023, 5, 12, 12, 0, 0, 0), + duration: 21, title: 'stepName', - id: 'fb3d9c5c-e7f9-488d-b9cd-47f1618d9f69', error: { message: 'some error', }, titlePath: () => ['stepName'], }; - const expectedFullStepName = `testItemId/stepName-fb3d9c5c-e7f9-488d-b9cd-47f1618d9f69`; + const expectedFullStepName = `testItemId/stepName/${createSHA256Hash(step)}`; const expectedNestedSteps = new Map([ [expectedFullStepName, { id: tempTestItemId, name: 'stepName' }], ]); @@ -96,34 +99,31 @@ describe('onStepBegin reporting', () => { tempTestItemId, ); - reporter.nestedSteps = new Map([ - [ - 'testItemId/stepName-fb3d9c5c-e7f9-488d-b9cd-47f1618d9f69', - { id: tempTestItemId, name: 'stepName' }, - ], - ]); - expect(reporter.nestedSteps).toEqual(expectedNestedSteps); }); test('client.startTestItem should be called with test step parent id', () => { const stepParent = { - id: 'f96293c4-bc29-42a6-b60f-e0840ffa0648', + category: 'pw:api', + startTime: new Date(2023, 5, 12, 12, 0, 0, 0), title: 'stepParent', + duration: 21, titlePath: () => ['stepParent'], }; reporter.nestedSteps = new Map([ [ - 'testItemId/stepParent-f96293c4-bc29-42a6-b60f-e0840ffa0648', + `testItemId/stepParent/${createSHA256Hash(stepParent)}`, { id: 'parentStepId', name: 'stepParent' }, ], ]); const step = { + category: 'pw:api', + startTime: new Date(2023, 5, 12, 12, 0, 0, 123), + duration: 22, title: 'stepName', parent: stepParent, - id: '0b3a78c1-521a-4a80-a125-52074991426a', error: { message: 'some error', }, diff --git a/src/__tests__/reporter/onStepEndReporting.spec.ts b/src/__tests__/reporter/onStepEndReporting.spec.ts index 5362c1c..7219ac4 100644 --- a/src/__tests__/reporter/onStepEndReporting.spec.ts +++ b/src/__tests__/reporter/onStepEndReporting.spec.ts @@ -15,6 +15,7 @@ */ import { RPReporter } from '../../reporter'; +import { createSHA256Hash } from '../../utils'; import { mockConfig } from '../mocks/configMock'; import { RPClientMock } from '../mocks/RPClientMock'; @@ -31,13 +32,6 @@ describe('onStepBegin reporting', () => { reporter.testItems = new Map([['testItemId', { id: tempTestItemId, name: 'testTitle' }]]); - reporter.nestedSteps = new Map([ - [ - 'testItemId/stepName-b91c7967-f32d-4cb7-843f-78a7b62e0055', - { id: tempTestItemId, name: 'stepName' }, - ], - ]); - const testCase = { title: 'testTitle', id: 'testItemId', @@ -53,14 +47,20 @@ describe('onStepBegin reporting', () => { }; const step = { + category: 'pw:api', + startTime: new Date(2023, 5, 12, 12, 0, 0, 123), + duration: 22, title: 'stepName', - id: 'b91c7967-f32d-4cb7-843f-78a7b62e0055', error: { message: 'some error', }, titlePath: () => ['stepName'], }; + reporter.nestedSteps = new Map([ + [`testItemId/stepName/${createSHA256Hash(step)}`, { id: tempTestItemId, name: 'stepName' }], + ]); + // @ts-ignore reporter.onStepEnd(testCase, undefined, step); diff --git a/src/models/index.ts b/src/models/index.ts index f7b7574..07baef2 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -21,7 +21,6 @@ import { FinishTestItemObjType, LogRQ, Attachment, - TestStepWithId, } from './reporting'; import { ReportPortalConfig, AttachmentsConfig } from './configs'; import { Attribute } from './common'; @@ -35,5 +34,4 @@ export { Attachment, Attribute, LogRQ, - TestStepWithId, }; diff --git a/src/models/reporting.ts b/src/models/reporting.ts index c2021ae..95ff85a 100644 --- a/src/models/reporting.ts +++ b/src/models/reporting.ts @@ -17,7 +17,6 @@ import { Attribute, Issue } from './common'; import { TEST_ITEM_TYPES, LOG_LEVELS, LAUNCH_MODES } from '../constants'; -import { TestStep } from '@playwright/test/reporter'; export interface StartLaunchObjType { startTime?: Date | number; @@ -62,7 +61,3 @@ export interface LogRQ { time?: number; file?: Attachment; } - -export interface TestStepWithId extends TestStep { - id: string; -} diff --git a/src/reporter.ts b/src/reporter.ts index b128fd8..bd5b294 100644 --- a/src/reporter.ts +++ b/src/reporter.ts @@ -17,7 +17,13 @@ import RPClient from '@reportportal/client-javascript'; import stripAnsi from 'strip-ansi'; -import { Reporter, Suite as PWSuite, TestCase, TestResult } from '@playwright/test/reporter'; +import { + Reporter, + Suite as PWSuite, + TestCase, + TestResult, + TestStep, +} from '@playwright/test/reporter'; import { Attribute, FinishTestItemObjType, @@ -25,7 +31,6 @@ import { ReportPortalConfig, StartLaunchObjType, StartTestObjType, - TestStepWithId, } from './models'; import { LAUNCH_MODES, @@ -37,6 +42,7 @@ import { } from './constants'; import { calculateRpStatus, + createSHA256Hash, getAgentInfo, getAttachments, getCodeRef, @@ -46,7 +52,6 @@ import { promiseErrorHandler, } from './utils'; import { EVENTS } from '@reportportal/client-javascript/lib/constants/events'; -import { randomUUID } from 'crypto'; export interface TestItem { id: string; @@ -385,7 +390,7 @@ export class RPReporter implements Reporter { } } - onStepBegin(test: TestCase, result: TestResult, step: TestStepWithId): void { + onStepBegin(test: TestCase, result: TestResult, step: TestStep): void { if (this.isLaunchFinishSend) { return; } @@ -395,9 +400,7 @@ export class RPReporter implements Reporter { let parent; if (step.parent) { const stepParentName = getCodeRef(step.parent, step.parent.title); - const fullStepParentName = `${test.id}/${stepParentName}-${ - (step.parent as TestStepWithId).id - }`; + const fullStepParentName = `${test.id}/${stepParentName}/${createSHA256Hash(step.parent)}`; parent = this.nestedSteps.get(fullStepParentName); } else { parent = this.testItems.get(test.id); @@ -410,13 +413,10 @@ export class RPReporter implements Reporter { hasStats: false, startTime: this.client.helpers.now(), }; - - Object.defineProperty(step, 'id', { - value: randomUUID(), - }); + const hash = createSHA256Hash(step); const stepName = getCodeRef(step, step.title); - const fullStepName = `${test.id}/${stepName}-${step.id}`; + const fullStepName = `${test.id}/${stepName}/${hash}`; const { tempId, promise } = this.client.startTestItem(stepStartObj, this.launchId, parent.id); this.addRequestToPromisesQueue(promise, 'Failed to start nested step.'); @@ -427,13 +427,14 @@ export class RPReporter implements Reporter { }); } - onStepEnd(test: TestCase, result: TestResult, step: TestStepWithId): void { + onStepEnd(test: TestCase, result: TestResult, step: TestStep): void { const { includeTestSteps } = this.config; if (!includeTestSteps) return; const stepName = getCodeRef(step, step.title); - const fullStepName = `${test.id}/${stepName}-${step.id}`; + const fullStepName = `${test.id}/${stepName}/${createSHA256Hash(step)}`; const nestedStep = this.nestedSteps.get(fullStepName); + if (!nestedStep) return; const stepFinishObj = { @@ -444,6 +445,7 @@ export class RPReporter implements Reporter { const { promise } = this.client.finishTestItem(nestedStep.id, stepFinishObj); this.addRequestToPromisesQueue(promise, 'Failed to finish nested step.'); + this.nestedSteps.delete(fullStepName); } diff --git a/src/utils.ts b/src/utils.ts index 1a29c85..d64205d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -15,7 +15,7 @@ * */ -import { TestCase, TestStatus, TestResult } from '@playwright/test/reporter'; +import { TestCase, TestStatus, TestResult, TestStep } from '@playwright/test/reporter'; import fs from 'fs'; import path from 'path'; // @ts-ignore @@ -30,6 +30,7 @@ import { TEST_ANNOTATION_TYPES, TEST_OUTCOME_TYPES, } from './constants'; +import { createHash } from 'crypto'; const fsPromises = fs.promises; @@ -146,6 +147,17 @@ export const isErrorLog = (message: string): boolean => { return message.toLowerCase().includes('error'); }; +export const createSHA256Hash = ({ + category, + startTime, + title, + titlePath, +}: Partial): string => { + const valueToHash = `${category}/${startTime.getTime()}/${titlePath().join('/')}/${title}`; + + return createHash('sha256').update(valueToHash).digest('hex'); +}; + // https://playwright.dev/docs/api/class-testresult#test-result-status export const calculateRpStatus = ( outcome: TestOutcome,