From 9b3ce67ee1fb7f81238e4bed22510e31840782e0 Mon Sep 17 00:00:00 2001 From: Yaroslav Serhieiev Date: Thu, 15 Feb 2024 12:37:09 +0200 Subject: [PATCH] fix: status and statusDetails logic --- .../grouping/client/auth/LoginScreen.test.ts | 3 +- .../__snapshots__/forgotPassword.test.ts.snap | 8 ++ .../server/controllers/forgotPassword.test.ts | 4 +- src/environment/listener.ts | 108 +++++++++--------- src/metadata/MetadataSquasher.ts | 5 +- src/metadata/constants.ts | 4 +- src/metadata/proxies/AllureMetadataProxy.ts | 5 + src/metadata/utils/getStage.ts | 14 +++ src/metadata/utils/getStatus.ts | 23 ++++ src/metadata/utils/index.ts | 2 + src/options/default-options/testCase.ts | 3 +- src/realms/AllureRealm.ts | 4 +- 12 files changed, 121 insertions(+), 62 deletions(-) create mode 100644 e2e/src/programmatic/grouping/server/controllers/__snapshots__/forgotPassword.test.ts.snap create mode 100644 src/metadata/utils/getStage.ts create mode 100644 src/metadata/utils/getStatus.ts diff --git a/e2e/src/programmatic/grouping/client/auth/LoginScreen.test.ts b/e2e/src/programmatic/grouping/client/auth/LoginScreen.test.ts index 7485de4..e08f881 100644 --- a/e2e/src/programmatic/grouping/client/auth/LoginScreen.test.ts +++ b/e2e/src/programmatic/grouping/client/auth/LoginScreen.test.ts @@ -7,7 +7,7 @@ */ import LoginHelper from '../../../../utils/LoginHelper'; -import {allure} from "../../../../../../src/api"; +import {$Tag, $Epic, $Feature, $Story, allure} from 'jest-allure2-reporter/api'; $Tag('client'); $Epic('Authentication'); @@ -38,6 +38,7 @@ describe('Login screen', () => { }); it('should show error on short or invalid password format', () => { + allure.status('failed', { message: 'The password is too short' }); // ... }); }); diff --git a/e2e/src/programmatic/grouping/server/controllers/__snapshots__/forgotPassword.test.ts.snap b/e2e/src/programmatic/grouping/server/controllers/__snapshots__/forgotPassword.test.ts.snap new file mode 100644 index 0000000..1150bae --- /dev/null +++ b/e2e/src/programmatic/grouping/server/controllers/__snapshots__/forgotPassword.test.ts.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`POST /forgot-password should return 401 if user is not found 1`] = ` +{ + "code": 401, + "seed": 0.06426173461501827, +} +`; diff --git a/e2e/src/programmatic/grouping/server/controllers/forgotPassword.test.ts b/e2e/src/programmatic/grouping/server/controllers/forgotPassword.test.ts index 0fd8f04..1a460f6 100644 --- a/e2e/src/programmatic/grouping/server/controllers/forgotPassword.test.ts +++ b/e2e/src/programmatic/grouping/server/controllers/forgotPassword.test.ts @@ -1,10 +1,12 @@ +import { $Tag, $Epic, $Feature, $Story } from 'jest-allure2-reporter/api'; + $Tag('server'); $Epic('Authentication'); $Feature('Restore account'); describe('POST /forgot-password', () => { $Story('Validation'); it('should return 401 if user is not found', () => { - // ... + expect({ code: 401, seed: Math.random() }).toMatchSnapshot(); }); $Story('Happy path'); diff --git a/src/environment/listener.ts b/src/environment/listener.ts index adaaced..ce78d9c 100644 --- a/src/environment/listener.ts +++ b/src/environment/listener.ts @@ -1,9 +1,5 @@ import type { Circus } from '@jest/types'; -import type { - AllureTestCaseMetadata, - AllureTestStepMetadata, - Status, -} from 'jest-allure2-reporter'; +import type { Status, StatusDetails } from 'jest-allure2-reporter'; import type { EnvironmentListenerFn, TestEnvironmentCircusEvent, @@ -33,7 +29,7 @@ const listener: EnvironmentListenerFn = (context) => { .on('add_hook', addSourceLocation) .on('add_hook', addHookType) .on('add_test', addSourceLocation) - .on('test_start', executableStart) + .on('test_start', testStart) .on('test_todo', testSkip) .on('test_skip', testSkip) .on('test_done', testDone) @@ -111,13 +107,15 @@ function addSourceCode({ event }: TestEnvironmentCircusEvent) { } // eslint-disable-next-line no-empty-pattern -function executableStart({}: TestEnvironmentCircusEvent) { - const metadata: AllureTestStepMetadata = { - start: Date.now(), +function executableStart( + _event: TestEnvironmentCircusEvent< + Circus.Event & { name: 'hook_start' | 'test_fn_start' } + >, +) { + realm.runtimeContext.getCurrentMetadata().assign({ stage: 'running', - }; - - realm.runtimeContext.getCurrentMetadata().assign(metadata); + start: Date.now(), + }); } function executableFailure({ @@ -125,62 +123,62 @@ function executableFailure({ }: TestEnvironmentCircusEvent< Circus.Event & { name: 'test_fn_failure' | 'hook_failure' } >) { - const metadata: AllureTestStepMetadata = { - stop: Date.now(), - stage: 'interrupted', - status: 'failed', - }; + const current = realm.runtimeContext.getCurrentMetadata(); + let status: Status = 'broken'; + let statusDetails: StatusDetails | undefined; if (event.error) { - const message = event.error.message ?? `${event.error}`; - const trace = event.error.stack; - - metadata.statusDetails = { message, trace }; + status = isMatcherError(event.error) ? 'failed' : 'broken'; + statusDetails = { + message: event.error.message ?? `${event.error}`, + trace: event.error.stack, + }; } - realm.runtimeContext.getCurrentMetadata().assign(metadata); -} + // TODO: switch to defaults + current.assign({ + status, + statusDetails, + }); -// eslint-disable-next-line no-empty-pattern -function executableSuccess({}: TestEnvironmentCircusEvent) { - const metadata: AllureTestStepMetadata = { + current.assign({ + stage: 'interrupted', stop: Date.now(), - stage: 'finished', - status: 'passed', - }; - - realm.runtimeContext.getCurrentMetadata().assign(metadata); + }); } -function testSkip() { - const metadata: AllureTestCaseMetadata = { - stop: Date.now(), - stage: 'pending', - status: 'skipped', - }; +function executableSuccess( + _event: TestEnvironmentCircusEvent< + Circus.Event & { name: 'test_fn_success' | 'hook_success' } + >, +) { + realm.runtimeContext + .getCurrentMetadata() + .set('stage', 'finished') + .set('stop', Date.now()); +} - realm.runtimeContext.getCurrentMetadata().assign(metadata); +function testStart( + _event: TestEnvironmentCircusEvent, +) { + realm.runtimeContext.getCurrentMetadata().set('start', Date.now()); } -function testDone({ - event, -}: TestEnvironmentCircusEvent) { - const hasErrors = event.test.errors.length > 0; - const errorStatus: Status = event.test.errors.some((errors) => { - return Array.isArray(errors) - ? errors.some(isMatcherError) - : isMatcherError(errors); - }) - ? 'failed' - : 'broken'; - - const metadata: AllureTestCaseMetadata = { +function testSkip( + _event: TestEnvironmentCircusEvent< + Circus.Event & { name: 'test_skip' | 'test_todo' } + >, +) { + realm.runtimeContext.getCurrentMetadata().assign({ stop: Date.now(), - stage: hasErrors ? 'interrupted' : 'finished', - status: hasErrors ? errorStatus : 'passed', - }; + stage: 'pending', + }); +} - realm.runtimeContext.getCurrentMetadata().assign(metadata); +function testDone( + _event: TestEnvironmentCircusEvent, +) { + realm.runtimeContext.getCurrentMetadata().set('stop', Date.now()); } function isMatcherError(error: any) { diff --git a/src/metadata/MetadataSquasher.ts b/src/metadata/MetadataSquasher.ts index aaee65f..d31b6c6 100644 --- a/src/metadata/MetadataSquasher.ts +++ b/src/metadata/MetadataSquasher.ts @@ -6,7 +6,7 @@ import type { AllureTestStepMetadata, } from 'jest-allure2-reporter'; -import { getStart, getStop } from './utils'; +import { getStage, getStart, getStatus, getStop } from './utils'; import { PREFIX } from './constants'; import { mergeTestCaseMetadata, @@ -45,7 +45,8 @@ export class MetadataSquasher { return { ...result, - + ...getStatus(metadata), + stage: getStage(metadata), start: getStart(metadata), stop: getStop(metadata), steps: [...befores, ...steps, ...afters], diff --git a/src/metadata/constants.ts b/src/metadata/constants.ts index ec1b020..807f76e 100644 --- a/src/metadata/constants.ts +++ b/src/metadata/constants.ts @@ -1,8 +1,10 @@ export const PREFIX = 'allure2' as const; export const START = [PREFIX, 'start'] as const; - export const STOP = [PREFIX, 'stop'] as const; +export const STAGE = [PREFIX, 'stage'] as const; +export const STATUS = [PREFIX, 'status'] as const; +export const STATUS_DETAILS = [PREFIX, 'statusDetails'] as const; export const CURRENT_STEP = [PREFIX, 'currentStep'] as const; export const DESCRIPTION = [PREFIX, 'description'] as const; diff --git a/src/metadata/proxies/AllureMetadataProxy.ts b/src/metadata/proxies/AllureMetadataProxy.ts index 8cabaf5..c5e5ded 100644 --- a/src/metadata/proxies/AllureMetadataProxy.ts +++ b/src/metadata/proxies/AllureMetadataProxy.ts @@ -35,6 +35,11 @@ export class AllureMetadataProxy { return this; } + // defaults(values: Partial): this { + // this.$metadata.defaults(this.$localPath(), values); + // return this; + // } + protected $localPath(key?: keyof T, ...innerKeys: string[]): string[] { const allKeys = key ? [key as string, ...innerKeys] : innerKeys; return [PREFIX, ...allKeys]; diff --git a/src/metadata/utils/getStage.ts b/src/metadata/utils/getStage.ts new file mode 100644 index 0000000..7ec3b98 --- /dev/null +++ b/src/metadata/utils/getStage.ts @@ -0,0 +1,14 @@ +import type { TestInvocationMetadata } from 'jest-metadata'; +import type { Stage } from 'jest-allure2-reporter'; + +import { STAGE } from '../constants'; + +export const getStage = (testInvocation: TestInvocationMetadata) => { + for (const invocation of testInvocation.allInvocations()) { + if (invocation.get(STAGE) === 'interrupted') { + return 'interrupted'; + } + } + + return testInvocation.get(STAGE) as Stage | undefined; +}; diff --git a/src/metadata/utils/getStatus.ts b/src/metadata/utils/getStatus.ts new file mode 100644 index 0000000..451cb78 --- /dev/null +++ b/src/metadata/utils/getStatus.ts @@ -0,0 +1,23 @@ +import type { TestInvocationMetadata } from 'jest-metadata'; +import type { Status, StatusDetails } from 'jest-allure2-reporter'; + +import { STATUS, STATUS_DETAILS } from '../constants'; + +export const getStatus = (testInvocation: TestInvocationMetadata) => { + const items = [...testInvocation.allInvocations(), testInvocation].reverse(); + for (const item of items) { + const status = item.get(STATUS) as Status | undefined; + if (status !== undefined) { + const statusDetails = item.get(STATUS_DETAILS) as + | StatusDetails + | undefined; + + return { + status, + statusDetails, + }; + } + } + + return; +}; diff --git a/src/metadata/utils/index.ts b/src/metadata/utils/index.ts index ac3d3e4..bf575c8 100644 --- a/src/metadata/utils/index.ts +++ b/src/metadata/utils/index.ts @@ -1,2 +1,4 @@ +export * from './getStage'; export * from './getStart'; +export * from './getStatus'; export * from './getStop'; diff --git a/src/options/default-options/testCase.ts b/src/options/default-options/testCase.ts index da077d0..05063cc 100644 --- a/src/options/default-options/testCase.ts +++ b/src/options/default-options/testCase.ts @@ -64,7 +64,8 @@ export const testCase: ResolvedTestCaseCustomizer = { testCaseMetadata.start ?? (testCaseMetadata.stop ?? Date.now()) - (testCase.duration ?? 0), stop: ({ testCaseMetadata }) => testCaseMetadata.stop ?? Date.now(), - stage: ({ testCase }) => getTestCaseStage(testCase), + stage: ({ testCase, testCaseMetadata }) => + testCaseMetadata.stage ?? getTestCaseStage(testCase), status: ({ testCase, testCaseMetadata }) => testCaseMetadata.status ?? getTestCaseStatus(testCase), statusDetails: ({ testCase, testCaseMetadata }) => diff --git a/src/realms/AllureRealm.ts b/src/realms/AllureRealm.ts index 88c6b58..516d274 100644 --- a/src/realms/AllureRealm.ts +++ b/src/realms/AllureRealm.ts @@ -16,7 +16,9 @@ export class AllureRealm { 'config', ); if (!config) { - throw new Error('Shared reporter config is not defined'); + throw new Error( + "Cannot receive jest-allure2-reporter's config from the parent process. Have you set up Jest test environment correctly?", + ); } return config as SharedReporterConfig;