From 242d63c07784305499a17a0b6e2447885cf5944a Mon Sep 17 00:00:00 2001 From: Taisia Pitko Date: Sat, 29 Jun 2024 01:04:02 +0200 Subject: [PATCH] [patch] Fix suite structure when before hook fails in nested suite - fixes issue #95 and issue #149 (#151) --- .eslintrc.js | 1 + jest.config.ts | 3 + src/plugins/allure-types.ts | 7 +- src/setup/allure-mocha-reporter.ts | 37 +- tests/.eslintrc.js | 2 + tests/cy-helper/utils.ts | 470 ++++++++++++++++-- .../fail-one-test-before-all-fail.test.ts | 8 +- .../nested-suite-after-fail-simple-04.ts | 310 ++++++++++++ .../nested-suite-before-fail-01.ts | 320 ++++++++++++ .../nested-suite-before-fail-simple-03.ts | 273 ++++++++++ .../nested-suite-before-pass-02.ts | 235 +++++++++ .../nested-suites-cy/nested-suites.test.ts | 18 + .../hooks/suites/before-and-after-failure.ts | 231 +++++++++ .../mocha-events/hooks/suites/suites.test.ts | 15 + ...es-nested-with-global-hooks-parent.test.ts | 21 +- .../suites-nested-with-hooks-parent.test.ts | 15 +- tests/tsconfig.json | 6 +- 17 files changed, 1891 insertions(+), 81 deletions(-) create mode 100644 tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-after-fail-simple-04.ts create mode 100644 tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-01.ts create mode 100644 tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-simple-03.ts create mode 100644 tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-pass-02.ts create mode 100644 tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suites.test.ts create mode 100644 tests/test-folder/mocha-events/hooks/suites/before-and-after-failure.ts create mode 100644 tests/test-folder/mocha-events/hooks/suites/suites.test.ts diff --git a/.eslintrc.js b/.eslintrc.js index 89db4bba..078858dc 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,6 +12,7 @@ module.exports = { ignorePatterns: ['*.yaml', '*.yml', '*.csv'], rules: { + 'jest/no-export': 'off', '@typescript-eslint/no-explicit-any': 'warn', 'prefer-template': 'error', quotes: ['error', 'single', { avoidEscape: true }], diff --git a/jest.config.ts b/jest.config.ts index dc258a8d..9b66925d 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -42,6 +42,9 @@ export default { '!**/tests/test-folder/allure-plugin/**/?(*.)+(spec|test).[tj]s?(x)', '!**/lib/**/*.*', ], + moduleNameMapper: { + '^@test-utils$': '/tests/cy-helper/utils.ts', + }, transform: { '^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tests/tsconfig.json' }], diff --git a/src/plugins/allure-types.ts b/src/plugins/allure-types.ts index 41dc3964..bce8e212 100644 --- a/src/plugins/allure-types.ts +++ b/src/plugins/allure-types.ts @@ -1,6 +1,9 @@ -import type { StatusDetails } from 'allure-js-commons'; import type { ContentType } from '../common/types'; +export type StatusDetails = { + message?: string; + trace?: string; +}; export interface AutoScreen { screenshotId?: string; specName?: string; @@ -61,7 +64,7 @@ type AllureTask = { screenshotOne: { name: string | undefined; forStep?: boolean }; screenshotAttachment: AutoScreen; testResult: { - title: string; + title?: string; id: string; result: Status; details?: StatusDetails; diff --git a/src/setup/allure-mocha-reporter.ts b/src/setup/allure-mocha-reporter.ts index 6a9ef040..adc3b24e 100644 --- a/src/setup/allure-mocha-reporter.ts +++ b/src/setup/allure-mocha-reporter.ts @@ -8,11 +8,12 @@ import { Status, Category, LabelName, + LinkType, } from '../plugins/allure-types'; // todo import { registerScreenshotHandler } from './screenshots'; import StatusDetails = Cypress.StatusDetails; import { logClient } from './helper'; -import { tmsIssueUrl } from '../common'; +import { packageLog, tmsIssueUrl } from '../common'; import { EventEmitter } from 'events'; import AllureEvents = Cypress.AllureEvents; @@ -126,10 +127,22 @@ export const allureInterface = ( }, link: (url: string, name?: string, type?: 'issue' | 'tms') => fn({ task: 'link', arg: { url, name, type } }), - tms: (url: string, name?: string) => - fn({ task: 'link', arg: { url: tmsIssueUrl(env, url, 'tms'), name: name ?? url, type: 'tms' } }), - issue: (url: string, name?: string) => - fn({ task: 'link', arg: { url: tmsIssueUrl(env, url, 'issue'), name: name ?? url, type: 'issue' } }), + tms: (url: string, name?: string) => { + const type: LinkType = 'tms'; + const fullUrl = tmsIssueUrl(env, url, type); + const linkName = name ?? url; + + return fn({ task: 'link', arg: { url: fullUrl, name: linkName, type } }); + }, + + issue: (url: string, name?: string) => { + const type: LinkType = 'issue'; + const fullUrl = tmsIssueUrl(env, url, type); + const linkName = name ?? url; + + return fn({ task: 'link', arg: { url: fullUrl, name: linkName, type } }); + }, + label: (name: string, value: string) => fn({ task: 'label', arg: { name, value } }), suite: (name: string) => fn({ task: 'suite', arg: { name } }), parentSuite: (name: string) => fn({ task: 'parentSuite', arg: { name } }), @@ -176,7 +189,7 @@ const isHook = (test: Mocha.Test) => { return (test as any).type === 'hook'; }; -const createTests = (runner: Mocha.Runner, test: Mocha.Test) => { +const createTestsForFailedBeforeHook = (runner: Mocha.Runner, test: Mocha.Test) => { let index = 0; test.parent?.eachTest(ts => { ts.err = test.err; @@ -186,6 +199,15 @@ const createTests = (runner: Mocha.Runner, test: Mocha.Test) => { if (ts) { if (index === 1) { ts.state = 'failed'; + + if (ts.err) { + // Cypress error cannot be taken here - it will be updated only on 'test:after:run' event + // so to simplify events chain creating own error message + // need to watch cypress error text message when it changes - and update it here + ts.err.message = + `${ts.err.message}\n\n` + + `Because this error occurred during a \`before all\` hook we are skipping the remaining tests in the current suite: \`${ts.parent?.title}\` (added by ${packageLog})`; + } } runner.emit(CUSTOM_EVENTS.TEST_BEGIN, ts); runner.emit(CUSTOM_EVENTS.TEST_FAIL, ts); @@ -393,7 +415,8 @@ export const registerMochaReporter = (ws: WebSocket) => { return; } - createTestsCallb = () => createTests(runner, test); + runner.emit(CUSTOM_EVENTS.TEST_END, test); + createTestsForFailedBeforeHook(runner, test); return; } diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js index e8b46668..36c7dae9 100644 --- a/tests/.eslintrc.js +++ b/tests/.eslintrc.js @@ -6,6 +6,8 @@ module.exports = { extends: [...original.extends, 'plugin:jest/recommended'], rules: { ...original.rules, + + '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-explicit-any': 'off', 'jest/no-standalone-expect': 'off', '@typescript-eslint/no-non-null-assertion': 'off', diff --git a/tests/cy-helper/utils.ts b/tests/cy-helper/utils.ts index aa9d0cfb..1cb55842 100644 --- a/tests/cy-helper/utils.ts +++ b/tests/cy-helper/utils.ts @@ -1,11 +1,11 @@ import { execSync } from 'child_process'; import path, { basename } from 'path'; import { delay } from 'jest-test-each/dist/tests/utils/utils'; -import { AllureTest, getParentsArray } from 'allure-js-parser'; +import { AllureTest, getParentsArray, parseAllure } from 'allure-js-parser'; import { StepResult } from 'allure-js-commons'; import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; import { parseBoolean } from 'cypress-redirect-browser-log/utils/functions'; -import { AllureHook } from 'allure-js-parser/types'; +import { AllureHook, Parent } from 'allure-js-parser/types'; jest.setTimeout(120000); @@ -13,16 +13,21 @@ jest.setTimeout(120000); export const mapSteps = ( steps: StepResult[], map?: (m: StepResult) => T, + filter?: (m: StepResult) => boolean, ): (T & any)[] => { if (steps?.length === 0) { return []; } - return steps.map(s => { - const obj = map ? map(s) : { name: s.name }; + return steps + .filter(s => { + return filter ? filter(s) : true; + }) + .map(s => { + const obj = map ? map(s) : { name: s.name }; - return { ...obj, steps: mapSteps(s.steps, map) }; - }); + return { ...obj, steps: mapSteps(s.steps, map, filter) }; + }); }; // eslint-disable-next-line jest/no-export @@ -47,21 +52,22 @@ export const fixResult = (results: AllureTest[]): AllureTest[] => { })); }; - return results.map(r => { - return { - ...r, - historyId: 'no', - uuid: 'no', - start: date, - stop: date + 10, - parent: { - ...r.parent, + const fixParent = (parent: Parent | undefined) => { + if (parent) { + return { + ...parent, + parent: fixParent(parent.parent), uuid: 'no', - befores: r.parent?.befores?.map(b => ({ + befores: parent?.befores?.map(b => ({ ...b, steps: replaceSteps(b.steps), start: date, stop: date + 10, + attachments: b.attachments.map(t => ({ + ...t, + name: t.name.replace(/\d{5,}/g, 'number'), + source: `source${path.extname(t.source)}`, + })), statusDetails: b.statusDetails?.message ? { message: b.statusDetails.message, @@ -69,7 +75,7 @@ export const fixResult = (results: AllureTest[]): AllureTest[] => { } : undefined, })), - afters: r.parent?.afters?.map(b => ({ + afters: parent?.afters?.map(b => ({ ...b, steps: replaceSteps(b.steps), start: date, @@ -86,7 +92,20 @@ export const fixResult = (results: AllureTest[]): AllureTest[] => { } : undefined, })), - }, + }; + } + + return undefined; + }; + + return results.map(r => { + return { + ...r, + historyId: 'no', + uuid: 'no', + start: date, + stop: date + 10, + parent: fixParent(r.parent), labels: r.labels.map(l => ({ name: l.name, value: l.value.replace(/\d{5,}/g, 'number'), @@ -172,10 +191,26 @@ export const sortAttachments = (res: AllureTest[]) => { }); }; +// eslint-disable-next-line jest/no-export +export const labelsForTest = (res: AllureTest[], filterLabels?: string[]) => { + return res + .map(t => ({ labels: t.labels, name: t.name })) + .sort((a, b) => ((a as any).name < (b as any).name ? -1 : 1)) + .map(t => ({ + ...t, + labels: t.labels.filter(x => + filterLabels && filterLabels.length > 0 + ? filterLabels.includes(x.name) + : true, + ), + })); +}; + // eslint-disable-next-line jest/no-export export const fullStepAttachment = ( res: AllureTest[], mapStep?: (m: StepResult) => any, + options?: { noAddParents?: boolean }, ) => { const parents = res .map(x => ({ @@ -205,38 +240,63 @@ export const fullStepAttachment = ( skipItems.every(y => x.name?.toLowerCase().indexOf(y) === -1), ), })) + .filter(x => + skipItems.every(y => x.name?.toLowerCase().indexOf(y) === -1), + ) .sort((z1, z2) => (z1.name && z2.name && z1.name < z2.name ? -1 : 1)) ?? [] ); }; - const full = parents.map(t => ({ - name: t.name, - status: t.status, - attachments: t.attachments.sort((z1, z2) => - z1.name && z2.name && z1.name < z2.name ? -1 : 1, - ), - steps: mapSteps(t.steps, mapStep).filter(x => - skipItems.every(y => x.name?.toLowerCase().indexOf(y) === -1), - ), - parents: t.parents?.map(x => ({ - suiteName: x.name, - befores: mapItem(x.befores) - .filter(z => - skipItems.every(y => z.name.toLowerCase().indexOf(y) === -1), - ) - .sort((z1, z2) => (z1.name && z2.name && z1.name < z2.name ? -1 : 1)), - afters: mapItem(x.afters) - .filter(z => - skipItems.every(y => z.name.toLowerCase().indexOf(y) === -1), - ) - .sort((z1, z2) => (z1.name && z2.name && z1.name < z2.name ? -1 : 1)), - })), - })); + const full = parents + .map(t => ({ + name: t.name, + status: t.status, + attachments: t.attachments.sort((z1, z2) => + z1.name && z2.name && z1.name < z2.name ? -1 : 1, + ), + steps: mapSteps(t.steps, mapStep).filter(x => + skipItems.every(y => x.name?.toLowerCase().indexOf(y) === -1), + ), + ...(!options?.noAddParents + ? { + parents: t.parents?.map(x => ({ + suiteName: x.name, + befores: mapItem(x.befores) + .filter(z => + skipItems.every(y => z.name.toLowerCase().indexOf(y) === -1), + ) + .sort((z1, z2) => + z1.name && z2.name && z1.name < z2.name ? -1 : 1, + ), + afters: mapItem(x.afters) + .filter(z => + skipItems.every(y => z.name.toLowerCase().indexOf(y) === -1), + ) + .sort((z1, z2) => + z1.name && z2.name && z1.name < z2.name ? -1 : 1, + ), + })), + } + : {}), + })) + .filter(x => skipItems.every(y => x.name?.toLowerCase().indexOf(y) === -1)); return full; }; +// eslint-disable-next-line jest/no-export +export const fullStepMap = ( + res: AllureTest, + mapStep?: (m: StepResult) => any, +) => { + const skipItems = ['generatereport', 'coverage']; + + return mapSteps(res.steps as StepResult[], mapStep, z => + skipItems.every(y => z.name?.toLowerCase().indexOf(y) === -1), + ); +}; + // eslint-disable-next-line jest/no-export export const checkCyResults = ( res: @@ -263,11 +323,14 @@ export const readWithRetry = (path: string, attempt = 0) => { }; // eslint-disable-next-line jest/no-export -export const createResTest2 = ( - specTexts: string[], - envConfig?: Record, - shouldBeResults?: boolean, -): { +export const eventsForFile = (res: Result, fileName: string): string[] => { + return readWithRetry(res.specs.filter(x => x.indexOf(fileName) !== -1)[0]) + ?.toString() + .split('\n') + .filter(t => t !== ''); +}; + +type Result = { watch: string; specs: string[]; result: { @@ -276,7 +339,14 @@ export const createResTest2 = ( | CypressCommandLine.CypressFailedRunResult | undefined; }; -} => { +}; + +// eslint-disable-next-line jest/no-export +export const createResTest2 = ( + specTexts: string[], + envConfig?: Record, + shouldBeResults?: boolean, +): Result => { const result: { res: | CypressCommandLine.CypressRunResult @@ -343,6 +413,8 @@ export const createResTest2 = ( }; it('create results jest', async () => { + jest.retryTimes(1); + // eslint-disable-next-line @typescript-eslint/no-var-requires const cy = require('cypress'); @@ -405,7 +477,7 @@ export const createResTest2 = ( } }) .then(() => { - if (shouldBeResults) { + if (shouldBeResults !== false) { return checkFilesExist(10); } }); @@ -541,3 +613,305 @@ export const covergeBeforeAll = [ stop: 1323475200010, }, ]; + +export type TestData = { + name: string; + rootSuite: string; + spec: string; + fileName: string; + expect: { + labels?: { filter: string[]; expected: any[] }; + events?: string[]; + testsNames: string[]; + + testStatuses?: { + testName: string; + status: string; + statusDetails?: { message: string[] | undefined }; + }[]; + + testAttachments?: { + expectMessage?: string; // message to show in test title + testName: string; + attachments: any[]; + }[]; + + testParents?: { + testName: string; + parents: { name: string; parent: string | undefined }[]; + }[]; + + testSteps?: { + testName: string; + mapStep?: (m: StepResult) => any; + expected: any[]; + }[]; + + parents?: { + testName: string; + containers: { + name: string; + stepMap?: (x: StepResult) => any; + befores?: { + name?: string; + attachments?: any[]; + steps?: any[]; + }[]; + afters?: { + name?: string; + attachments?: any[]; + steps?: any[]; + }[]; + }[]; + }[]; + }; +}; + +const wrapExpectCreate = (addition: string) => (fn: () => any) => { + try { + fn(); + } catch (e) { + const err = e as Error; + err.message = addition + err.message; + throw err; + } +}; + +export const generateChecksTests = (res: Result, testsForRun: TestData[]) => { + testsForRun.forEach((testData, i) => { + // path.relative(process.cwd(), testData.fileName) + const wrapError = wrapExpectCreate( + `Failed test file: ${basename(testData.fileName)}\nRoot suite: ${testData.name}\n\n`, + ); + + describe(`${testData.name}`, () => { + let resFixed: AllureTest[]; + + beforeAll(() => { + const results = parseAllure(res.watch).filter( + t => t.fullName?.indexOf(testData.rootSuite) !== -1, + ); + resFixed = fixResult(results); + }); + + if (testData.expect.testsNames) { + it('check test full names', () => { + wrapError(() => + expect(resFixed.map(t => t.fullName).sort()).toEqual( + testData.expect.testsNames, + ), + ); + }); + } + + if (testData.expect.testStatuses) { + testData.expect.testStatuses.forEach(t => { + it(`should have test '${t.testName}' status - ${t.status}`, () => { + expect(resFixed.find(x => t.testName === x.name)?.status).toEqual( + t.status, + ); + }); + + if (t.statusDetails) { + it(`should have test '${t.testName}' statusDetails`, () => { + wrapError(() => + expect( + resFixed + .find(x => t.testName === x.name) + ?.statusDetails?.message?.split('\n'), + ).toEqual(t.statusDetails?.message), + ); + }); + } + }); + } + + if (testData.expect.labels) { + it(`check ${testData.expect.labels?.filter?.join(',') ?? ' all'} labels`, () => { + wrapError(() => + expect( + labelsForTest(resFixed, testData.expect.labels?.filter), + ).toEqual(testData.expect.labels?.expected), + ); + }); + } + + if (testData.expect.events) { + it('should have correct events for spec', () => { + const specName = basename(res.specs[i]); + const events = eventsForFile(res, specName); + + const skipItems = [ + 'collectBackendCoverage', + 'mergeUnitTestCoverage', + 'generateReport', + ]; + + wrapError(() => + expect( + events.filter(x => skipItems.every(z => x.indexOf(z) === -1)), + ).toEqual(testData.expect.events), + ); + }); + } + + if (testData.expect.testAttachments) { + testData.expect.testAttachments.forEach(t => { + it(`check '${t.testName}' attachments${t.expectMessage ? `: ${t.expectMessage}` : ''}`, () => { + wrapError(() => + expect( + resFixed.find(x => t.testName === x.name)?.attachments, + ).toEqual(t.attachments), + ); + }); + }); + } + + if (testData.expect.testParents) { + testData.expect.testParents.forEach(testItem => { + it(`parents for test ${testItem.testName}`, () => { + const test = resFixed.find(x => testItem.testName === x.name); + const parents = getParentsArray(test); + + wrapError(() => + expect( + parents.map(x => ({ name: x.name, parent: x.parent?.name })), + ).toEqual(testItem.parents), + ); + }); + }); + } + + if (testData.expect.testSteps) { + testData.expect.testSteps.forEach(testItem => { + it(`steps for test ${testItem.testName}`, () => { + const test = resFixed.find(x => testItem.testName === x.name); + + const obj = fullStepMap(test!, m => ({ + name: m.name, + ...(testItem.mapStep?.(m) ?? {}), + })); + + wrapError(() => expect(obj).toEqual(testItem.expected)); + }); + }); + } + + if (testData.expect.parents) { + testData.expect.parents.forEach(testData => { + describe(`parents for ${testData.testName}`, () => { + let test; + let parents: Parent[]; + const skipItems = ['generatereport', 'coverage']; + + beforeAll(() => { + test = resFixed.find(x => testData.testName === x.name); + parents = getParentsArray(test); + }); + + describe('before and after hooks', () => { + testData.containers.forEach(container => { + if (container.befores) { + it(`check befores for '${testData.testName}' parent '${container.name}'`, () => { + const actualParent = parents.find( + pp => pp.name === container.name, + ); + + const actualBefores = ( + actualParent?.befores as AllureHook[] + ) + ?.filter(z => + skipItems.every( + y => z.name.toLowerCase().indexOf(y) === -1, + ), + ) + ?.filter(z => { + return !z.steps.some( + s => s.name?.indexOf('code-coverage') !== -1, + ); + }) + .sort((z1, z2) => + z1.name && z2.name && z1.name < z2.name ? -1 : 1, + ); + + wrapError(() => + expect(actualBefores?.map(x => x.name)).toEqual( + container.befores?.map(x => x.name), + ), + ); + + if (container.befores?.some(t => t.attachments)) { + wrapError(() => + // eslint-disable-next-line jest/no-conditional-expect + expect(actualBefores?.map(x => x.attachments)).toEqual( + container.befores?.map(x => x.attachments), + ), + ); + } + + if (container.befores?.some(t => t.steps)) { + const beforesSteps = actualBefores?.map(x => + mapSteps(x.steps, container.stepMap), + ); + + wrapError(() => + // eslint-disable-next-line jest/no-conditional-expect + expect(beforesSteps).toEqual( + container.befores?.map(x => x.steps), + ), + ); + } + }); + } + + if (container.afters) { + it(`check afters for '${testData.testName}' parent '${container.name}'`, () => { + const actualParent = parents.find( + pp => pp.name === container.name, + ); + + const actualAfters = (actualParent?.afters as AllureHook[]) + ?.filter(z => + skipItems.every( + y => z.name.toLowerCase().indexOf(y) === -1, + ), + ) + .sort((z1, z2) => + z1.name && z2.name && z1.name < z2.name ? -1 : 1, + ); + + expect(actualAfters?.map(x => x.name)).toEqual( + container.afters?.map(x => x.name), + ); + + if (container.afters?.some(t => t.attachments)) { + wrapError(() => + // eslint-disable-next-line jest/no-conditional-expect + expect(actualAfters?.map(x => x.attachments)).toEqual( + container.afters?.map(x => x.attachments), + ), + ); + } + + if (container.afters?.some(t => t.steps)) { + const aftersSteps = actualAfters?.map(x => + mapSteps(x.steps, container.stepMap), + ); + + wrapError(() => + // eslint-disable-next-line jest/no-conditional-expect + expect(aftersSteps).toEqual( + container.afters?.map(x => x.steps), + ), + ); + } + }); + } + }); + }); + }); + }); + } + }); + }); +}; diff --git a/tests/test-folder/mocha-events/failures/before-all-hook/fail-one-test-before-all-fail.test.ts b/tests/test-folder/mocha-events/failures/before-all-hook/fail-one-test-before-all-fail.test.ts index 06f1ca42..43d6bcec 100644 --- a/tests/test-folder/mocha-events/failures/before-all-hook/fail-one-test-before-all-fail.test.ts +++ b/tests/test-folder/mocha-events/failures/before-all-hook/fail-one-test-before-all-fail.test.ts @@ -4,7 +4,7 @@ import { readWithRetry, whenCoverage, whenNoCoverage, -} from '../../../../cy-helper/utils'; +} from '@test-utils'; describe('before all hook from suite should be have correct events', () => { const res = createResTest2([ @@ -49,13 +49,13 @@ describe('hello suite', () => { ...whenNoCoverage('cypress: test:before:run: hello test'), 'cypress:screenshot:test:hello suite -- hello test -- before all hook (failed).png', 'mocha: fail: "before all" hook for "hello test"', + 'plugin test:ended', + 'plugin test:started', + 'plugin test:ended', 'mocha: suite end: hello suite', ...whenCoverage(...covergeAfterAllEvent), 'cypress: test:after:run: hello test', 'plugin test:ended', // doesn't do anything - - 'plugin test:started', - 'plugin test:ended', 'mocha: suite end: ', 'mocha: end', ]); diff --git a/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-after-fail-simple-04.ts b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-after-fail-simple-04.ts new file mode 100644 index 00000000..2f7358f2 --- /dev/null +++ b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-after-fail-simple-04.ts @@ -0,0 +1,310 @@ +import { TestData } from '@test-utils'; + +const rootSuite = 'Failed after hook in nested suite (simple)'; + +const data: TestData = { + name: rootSuite, + rootSuite, + fileName: __filename, + spec: ` + describe('${rootSuite}', () => { + describe('child suite', () => { + after('in sub suite', () => { + cy.log('hook pass'); + cy.wrap(null).then(() => { + throw new Error('Failure in hook'); + }); + }); + + it('test 1', () => { + cy.log('test 1'); + }); + + it('test 2', () => { + cy.log('test 2'); + }); + }); + }); + `, + + expect: { + testsNames: [ + `${rootSuite} child suite test 1`, + `${rootSuite} child suite test 2`, + ], + + testStatuses: [ + { + testName: 'test 1', + status: 'passed', + statusDetails: { message: undefined }, + }, + { + testName: 'test 2', + status: 'failed', + statusDetails: { + message: [ + 'Failure in hook', + '', + 'Because this error occurred during a `after all` hook we are skipping the remaining tests in the current suite: `child suite`', + ], + }, + }, + ], + + testAttachments: [ + { + expectMessage: 'should be no', + testName: 'test 1', + attachments: [], + }, + { + expectMessage: 'should be screenshot of failure', + testName: 'test 2', + attachments: [ + { + name: `${rootSuite} -- child suite -- test 2 -- after all hook in sub suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + ], + + testSteps: [ + { + testName: 'test 1', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [ + { + name: '"before each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: 'log: test 1', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: '"after each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + ], + }, + { + testName: 'test 2', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [ + { + name: '"before each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: 'log: test 2', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: '"after each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + ], + }, + ], + + testParents: [ + { + testName: 'test 1', + parents: [ + { name: 'child suite', parent: rootSuite }, + { name: rootSuite, parent: undefined }, + ], + }, + { + testName: 'test 2', + parents: [ + { name: 'child suite', parent: rootSuite }, + { name: rootSuite, parent: undefined }, + ], + }, + ], + + labels: { + filter: ['suite', 'parentSuite', 'subSuite'], + expected: [ + { + name: 'test 1', + labels: [ + { name: 'parentSuite', value: rootSuite }, + { name: 'suite', value: 'child suite' }, + ], + }, + { + name: 'test 2', + labels: [ + { name: 'parentSuite', value: rootSuite }, + { name: 'suite', value: 'child suite' }, + ], + }, + ], + }, + + parents: [ + { + testName: 'test 1', + containers: [ + { + name: rootSuite, + befores: [], + afters: [], + }, + { + name: 'child suite', + stepMap: x => ({ + name: x.name, + status: x.status, + attachments: x.attachments, + }), + befores: [ + { name: '"before all" hook', attachments: [], steps: [] }, + ], + afters: [ + { + name: '"after all" hook: in sub suite', + attachments: [], + steps: [ + { + name: 'log: hook pass', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: 'wrap', + status: 'passed', + steps: [], + attachments: [], + }, + ], + }, + { + name: 'video', + attachments: [ + { + name: 'test_3_number.cy.ts.mp4', + source: 'source.mp4', + type: 'video/mp4', + }, + ], + steps: [], + }, + ], + }, + ], + }, + { + testName: 'test 2', + containers: [ + { + name: rootSuite, + befores: [], + afters: [], + }, + { + name: 'child suite', + stepMap: x => ({ + name: x.name, + status: x.status, + attachments: x.attachments, + }), + befores: [ + { name: '"before all" hook', attachments: [], steps: [] }, + ], + afters: [ + { + name: '"after all" hook: in sub suite', + attachments: [], + steps: [ + { + name: 'log: hook pass', + steps: [], + status: 'passed', + attachments: [], + }, + { + name: 'wrap', + status: 'passed', + steps: [], + attachments: [], + }, + ], + }, + { + name: 'video', + attachments: [ + { + name: 'test_3_number.cy.ts.mp4', + source: 'source.mp4', + type: 'video/mp4', + }, + ], + steps: [], + }, + ], + }, + ], + }, + ], + + events: [ + 'mocha: start', + 'mocha: suite: , ', + 'mocha: hook: "before all" hook', + 'cypress: test:before:run: test 1', + 'mocha: hook end: "before all" hook', + `mocha: suite: ${rootSuite}, ${rootSuite}`, + `mocha: suite: child suite, ${rootSuite} child suite`, + 'mocha: test: test 1', + 'plugin test:started', + 'mocha: hook: "before each" hook', + 'mocha: hook end: "before each" hook', + 'mocha: pass: test 1', + 'mocha: test end: test 1', + 'mocha: hook: "after each" hook', + 'mocha: hook end: "after each" hook', + 'cypress: test:after:run: test 1', + 'plugin test:ended', + + 'mocha: test: test 2', + 'plugin test:started', + 'mocha: hook: "before each" hook', + 'cypress: test:before:run: test 2', + 'mocha: hook end: "before each" hook', + 'mocha: pass: test 2', + 'mocha: test end: test 2', + 'mocha: hook: "after each" hook', + 'mocha: hook end: "after each" hook', + 'mocha: hook: "after all" hook: in sub suite', + `cypress:screenshot:test:${rootSuite} -- child suite -- test 2 -- after all hook in sub suite (failed).png`, + 'mocha: fail: "after all" hook: in sub suite for "test 2"', + 'mocha: suite end: child suite', + `mocha: suite end: ${rootSuite}`, + 'cypress: test:after:run: test 2', + 'plugin test:ended', // does nothing + 'mocha: suite end: ', + 'mocha: end', + ], + }, +}; + +export default data; diff --git a/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-01.ts b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-01.ts new file mode 100644 index 00000000..c3057cd4 --- /dev/null +++ b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-01.ts @@ -0,0 +1,320 @@ +import { TestData } from '@test-utils'; + +const rootSuite = 'Failed before hook in nested suite (complex)'; + +const data: TestData = { + /** + * When hook in child suite fails + * - result should have proper suite structure + * - attachments + * - steps + * - video in tear down + */ + name: rootSuite, + rootSuite, + fileName: __filename, + spec: `describe('${rootSuite}', () => { + it('test 0', () => { + cy.log('test 1'); + }); + + describe('hooks test - child', () => { + describe('hooks test - sub child', () => { + before('in sub suite', () => { + throw new Error('Failure in hook'); + }); + + it('test 1', () => { + cy.log('test 1'); + }); + + it('test 2', () => { + cy.log('test 2'); + }); + }); + }); + }); + `, + + expect: { + testsNames: [ + `${rootSuite} hooks test - child hooks test - sub child test 1`, + `${rootSuite} hooks test - child hooks test - sub child test 2`, + `${rootSuite} test 0`, + ], + + testStatuses: [ + { + testName: 'test 0', + status: 'passed', + statusDetails: { + message: undefined, + }, + }, + { + testName: 'test 1', + status: 'failed', + statusDetails: { + message: [ + 'Failure in hook', + '', + 'Because this error occurred during a `before all` hook we are skipping the remaining tests in the current suite: `hooks test - sub child` (added by [cypress-allure-adapter])', + ], + }, + }, + { + testName: 'test 2', + status: 'unknown', + statusDetails: { + message: [ + 'Failure in hook', + '', + 'Because this error occurred during a `before all` hook we are skipping the remaining tests in the current suite: `hooks test - sub child` (added by [cypress-allure-adapter])', + ], + }, + }, + ], + + testAttachments: [ + { + expectMessage: 'should have no attachments', + testName: 'test 0', + attachments: [], + }, + { + expectMessage: 'todo check later', + testName: 'test 1', + attachments: [], + }, // todo check later + { expectMessage: '', testName: 'test 2', attachments: [] }, // todo check later + ], + + labels: { + filter: ['suite', 'parentSuite', 'subSuite'], + expected: [ + { + name: 'test 0', + labels: [ + { + name: 'parentSuite', + value: rootSuite, + }, + //{ name: 'suite', value: 'hooks test - child' }, + ], + }, + { + name: 'test 1', + labels: [ + { + name: 'parentSuite', + value: rootSuite, + }, + { name: 'suite', value: 'hooks test - child' }, + { name: 'subSuite', value: 'hooks test - sub child' }, + ], + }, + { + name: 'test 2', + labels: [ + { + name: 'parentSuite', + value: rootSuite, + }, + { name: 'suite', value: 'hooks test - child' }, + { name: 'subSuite', value: 'hooks test - sub child' }, + ], + }, + ], + }, + + testSteps: [ + { + testName: 'test 1', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [], + }, + { + testName: 'test 2', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [], + }, + ], + + parents: [ + { + testName: 'test 0', + containers: [ + { + name: rootSuite, + befores: [], + afters: [ + { + name: 'video', + attachments: [ + { + name: 'test_0_number.cy.ts.mp4', + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + { + testName: 'test 1', + containers: [ + { + name: rootSuite, + befores: [], + afters: [ + { + name: 'video', + attachments: [ + { + name: 'test_0_number.cy.ts.mp4', // video check + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + { + name: 'hooks test - child', + befores: [{ name: '"before all" hook', attachments: [] }], + afters: [], + }, + { + name: 'hooks test - sub child', + befores: [ + { + name: '"before all" hook', + attachments: [], + }, + { + name: '"before all" hook: in sub suite', + attachments: [ + { + name: `${rootSuite} -- hooks test - child -- hooks test - sub child -- test 1 -- before all hook in sub suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + ], + afters: [ + { + name: 'video', + attachments: [ + { + name: 'test_0_number.cy.ts.mp4', // video check + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + { + testName: 'test 2', + containers: [ + { + name: rootSuite, + befores: [], + afters: [ + { + name: 'video', + attachments: [ + { + name: 'test_0_number.cy.ts.mp4', // change + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + { + name: 'hooks test - child', + befores: [{ name: '"before all" hook', attachments: [] }], + afters: [], + }, + { + name: 'hooks test - sub child', + befores: [ + { + name: '"before all" hook', + attachments: [], + }, + { + name: '"before all" hook: in sub suite', + attachments: [ + { + name: `${rootSuite} -- hooks test - child -- hooks test - sub child -- test 1 -- before all hook in sub suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + ], + afters: [ + { + name: 'video', + attachments: [ + { + name: 'test_0_number.cy.ts.mp4', // video check + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + ], + + events: [ + 'mocha: start', + 'mocha: suite: , ', + 'mocha: hook: "before all" hook', + 'cypress: test:before:run: test 0', + 'mocha: hook end: "before all" hook', + `mocha: suite: ${rootSuite}, ${rootSuite}`, + 'mocha: test: test 0', + 'plugin test:started', + 'mocha: hook: "before each" hook', + 'mocha: hook end: "before each" hook', + 'mocha: pass: test 0', + 'mocha: test end: test 0', + 'mocha: hook: "after each" hook', + 'mocha: hook end: "after each" hook', + 'cypress: test:after:run: test 0', + 'plugin test:ended', + `mocha: suite: hooks test - child, ${rootSuite} hooks test - child`, + `mocha: suite: hooks test - sub child, ${rootSuite} hooks test - child hooks test - sub child`, + 'mocha: hook: "before all" hook: in sub suite', + 'cypress: test:before:run: test 1', + `cypress:screenshot:test:${rootSuite} -- hooks test - child -- hooks test - sub child -- test 1 -- before all hook in sub suite (failed).png`, + 'mocha: fail: "before all" hook: in sub suite for "test 1"', + 'plugin test:ended', + 'plugin test:started', + 'plugin test:ended', + 'plugin test:started', + 'plugin test:ended', + 'mocha: suite end: hooks test - sub child', + 'mocha: suite end: hooks test - child', + `mocha: suite end: ${rootSuite}`, + 'cypress: test:after:run: test 1', + 'plugin test:ended', // does nothing + 'mocha: suite end: ', + 'mocha: end', + ], + }, +}; + +export default data; diff --git a/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-simple-03.ts b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-simple-03.ts new file mode 100644 index 00000000..62f936b5 --- /dev/null +++ b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-fail-simple-03.ts @@ -0,0 +1,273 @@ +import { TestData } from '@test-utils'; + +const rootSuite = 'Failed before hook in nested suite (simple)'; + +const data: TestData = { + name: rootSuite, + rootSuite, + fileName: __filename, + spec: ` + describe('${rootSuite}', () => { + describe('child suite', () => { + before('in sub suite', () => { + cy.log('hook pass'); + cy.wrap(null).then(() => { + throw new Error('Failure in hook'); + }); + }); + + it('test 1', () => { + cy.log('test 1'); + }); + + it('test 2', () => { + cy.log('test 2'); + }); + }); + }); + `, + + expect: { + testsNames: [ + `${rootSuite} child suite test 1`, + `${rootSuite} child suite test 2`, + ], + + testStatuses: [ + { + testName: 'test 1', + status: 'failed', + statusDetails: { + message: [ + 'Failure in hook', + '', + 'Because this error occurred during a `before all` hook we are skipping the remaining tests in the current suite: `child suite` (added by [cypress-allure-adapter])', + ], + }, + }, + { + testName: 'test 2', + status: 'unknown', + statusDetails: { + message: [ + 'Failure in hook', + '', + 'Because this error occurred during a `before all` hook we are skipping the remaining tests in the current suite: `child suite` (added by [cypress-allure-adapter])', + ], + }, + }, + ], + + testAttachments: [ + { + expectMessage: 'should be no', + testName: 'test 1', + attachments: [], + }, + { expectMessage: 'should be no', testName: 'test 2', attachments: [] }, + ], + + testParents: [ + { + testName: 'test 1', + parents: [ + { name: 'child suite', parent: rootSuite }, + { name: rootSuite, parent: undefined }, + ], + }, + { + testName: 'test 2', + parents: [ + { name: 'child suite', parent: rootSuite }, + { name: rootSuite, parent: undefined }, + ], + }, + ], + + labels: { + filter: ['suite', 'parentSuite', 'subSuite'], + expected: [ + { + name: 'test 1', + labels: [ + { name: 'parentSuite', value: rootSuite }, + { name: 'suite', value: 'child suite' }, + ], + }, + { + name: 'test 2', + labels: [ + { name: 'parentSuite', value: rootSuite }, + { name: 'suite', value: 'child suite' }, + ], + }, + ], + }, + + testSteps: [ + { + testName: 'test 1', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [], + }, + { + testName: 'test 2', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [], + }, + ], + + parents: [ + { + testName: 'test 1', + containers: [ + { + name: rootSuite, + befores: [], + afters: [], + }, + { + name: 'child suite', + stepMap: x => ({ + name: x.name, + status: x.status, + attachments: x.attachments, + }), + befores: [ + { + name: '"before all" hook', + attachments: [], + steps: [], + }, + { + name: '"before all" hook: in sub suite', + attachments: [ + { + name: `${rootSuite} -- child suite -- test 1 -- before all hook in sub suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + steps: [ + { + attachments: [], + name: 'log: hook pass', + status: 'passed', + steps: [], + }, + { + attachments: [], + name: 'wrap', + status: 'passed', + steps: [], + }, + ], + }, + ], + afters: [ + { + name: 'video', + steps: [], + attachments: [ + { + name: 'test_2_number.cy.ts.mp4', + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + { + testName: 'test 2', + containers: [ + { + name: rootSuite, + befores: [], + afters: [], + }, + { + name: 'child suite', + stepMap: x => ({ + name: x.name, + status: x.status, + attachments: x.attachments, + }), + befores: [ + { + name: '"before all" hook', + attachments: [], + steps: [], + }, + { + name: '"before all" hook: in sub suite', + steps: [ + { + attachments: [], + name: 'log: hook pass', + status: 'passed', + steps: [], + }, + { + attachments: [], + name: 'wrap', + status: 'passed', + steps: [], + }, + ], + attachments: [ + { + name: `${rootSuite} -- child suite -- test 1 -- before all hook in sub suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + ], + afters: [ + { + name: 'video', + steps: [], + attachments: [ + { + name: 'test_2_number.cy.ts.mp4', + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + ], + + events: [ + 'mocha: start', + 'mocha: suite: , ', + 'mocha: hook: "before all" hook', + 'cypress: test:before:run: test 1', + 'mocha: hook end: "before all" hook', + `mocha: suite: ${rootSuite}, ${rootSuite}`, + `mocha: suite: child suite, ${rootSuite} child suite`, + 'mocha: hook: "before all" hook: in sub suite', + `cypress:screenshot:test:${rootSuite} -- child suite -- test 1 -- before all hook in sub suite (failed).png`, + 'mocha: fail: "before all" hook: in sub suite for "test 1"', + 'plugin test:ended', + 'plugin test:started', + 'plugin test:ended', + 'plugin test:started', + 'plugin test:ended', + 'mocha: suite end: child suite', + `mocha: suite end: ${rootSuite}`, + 'cypress: test:after:run: test 1', + 'plugin test:ended', // does nothing + 'mocha: suite end: ', + 'mocha: end', + ], + }, +}; + +export default data; diff --git a/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-pass-02.ts b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-pass-02.ts new file mode 100644 index 00000000..f2d24a52 --- /dev/null +++ b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suite-before-pass-02.ts @@ -0,0 +1,235 @@ +import { TestData } from '@test-utils'; + +const rootSuite = 'Passed before hook in nested suite'; + +const data: TestData = { + name: rootSuite, + rootSuite, + fileName: __filename, + spec: ` + describe('${rootSuite}', () => { + describe('child suite', () => { + before('in sub suite', () => { + cy.log('hook pass'); + }); + + it('test 1', () => { + cy.log('test 1'); + }); + + it('test 2', () => { + cy.log('test 2'); + }); + }); + }); + `, + + expect: { + testsNames: [ + `${rootSuite} child suite test 1`, + `${rootSuite} child suite test 2`, + ], + + testStatuses: [ + { + testName: 'test 1', + status: 'passed', + statusDetails: { message: undefined }, + }, + { + testName: 'test 2', + status: 'passed', + statusDetails: { message: undefined }, + }, + ], + + testSteps: [ + { + testName: 'test 1', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [ + { + name: '"before each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: 'log: test 1', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: '"after each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + ], + }, + { + testName: 'test 2', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [ + { + name: '"before each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: 'log: test 2', + status: 'passed', + steps: [], + attachments: [], + }, + { + name: '"after each" hook', + status: 'passed', + steps: [], + attachments: [], + }, + ], + }, + ], + + testAttachments: [ + { + expectMessage: 'should be no', + testName: 'test 1', + attachments: [], + }, + { expectMessage: 'should be no', testName: 'test 2', attachments: [] }, + ], + + testParents: [ + { + testName: 'test 1', + parents: [ + { name: 'child suite', parent: rootSuite }, + { name: rootSuite, parent: undefined }, + ], + }, + { + testName: 'test 2', + parents: [ + { name: 'child suite', parent: rootSuite }, + { name: rootSuite, parent: undefined }, + ], + }, + ], + + labels: { + filter: ['suite', 'parentSuite', 'subSuite'], + expected: [ + { + name: 'test 1', + labels: [ + { name: 'parentSuite', value: rootSuite }, + { name: 'suite', value: 'child suite' }, + ], + }, + { + name: 'test 2', + labels: [ + { name: 'parentSuite', value: rootSuite }, + { name: 'suite', value: 'child suite' }, + ], + }, + ], + }, + + parents: [ + { + testName: 'test 1', + containers: [ + { name: rootSuite, befores: [], afters: [] }, + { + name: 'child suite', + befores: [ + { name: '"before all" hook', attachments: [] }, + { name: '"before all" hook: in sub suite', attachments: [] }, + ], + afters: [ + { + name: 'video', + attachments: [ + { + name: 'test_1_number.cy.ts.mp4', + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + { + testName: 'test 2', + containers: [ + { name: rootSuite, befores: [], afters: [] }, + { + name: 'child suite', + befores: [ + { name: '"before all" hook', attachments: [] }, + { name: '"before all" hook: in sub suite', attachments: [] }, + ], + afters: [ + { + name: 'video', + attachments: [ + { + name: 'test_1_number.cy.ts.mp4', + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + ], + + events: [ + 'mocha: start', + 'mocha: suite: , ', + 'mocha: hook: "before all" hook', + 'cypress: test:before:run: test 1', + 'mocha: hook end: "before all" hook', + `mocha: suite: ${rootSuite}, ${rootSuite}`, + `mocha: suite: child suite, ${rootSuite} child suite`, + 'mocha: hook: "before all" hook: in sub suite', + 'mocha: hook end: "before all" hook: in sub suite', + 'mocha: test: test 1', + 'plugin test:started', + 'mocha: hook: "before each" hook', + 'mocha: hook end: "before each" hook', + 'mocha: pass: test 1', + 'mocha: test end: test 1', + 'mocha: hook: "after each" hook', + 'mocha: hook end: "after each" hook', + 'cypress: test:after:run: test 1', + 'plugin test:ended', + 'mocha: test: test 2', + 'plugin test:started', + 'mocha: hook: "before each" hook', + 'cypress: test:before:run: test 2', + 'mocha: hook end: "before each" hook', + 'mocha: pass: test 2', + 'mocha: test end: test 2', + 'mocha: hook: "after each" hook', + 'mocha: hook end: "after each" hook', + 'mocha: suite end: child suite', + `mocha: suite end: ${rootSuite}`, + 'cypress: test:after:run: test 2', + 'plugin test:ended', + 'mocha: suite end: ', + 'mocha: end', + ], + }, +}; + +export default data; diff --git a/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suites.test.ts b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suites.test.ts new file mode 100644 index 00000000..3f384c9a --- /dev/null +++ b/tests/test-folder/mocha-events/hooks/nested-suites-cy/nested-suites.test.ts @@ -0,0 +1,18 @@ +import { createResTest2, generateChecksTests, TestData } from '@test-utils'; + +describe('nested suites', () => { + // test + const testsForOneCyRun: TestData[] = [ + 'nested-suite-before-fail-01.ts', + 'nested-suite-before-pass-02.ts', + 'nested-suite-before-fail-simple-03.ts', + 'nested-suite-after-fail-simple-04.ts', + ].map(x => require(`${__dirname}/${x}`).default); + + const res = createResTest2( + testsForOneCyRun.map(x => x.spec), + { allureAddVideoOnPass: 'true' /* DEBUG: 'true'*/ }, + ); + + generateChecksTests(res, testsForOneCyRun); +}); diff --git a/tests/test-folder/mocha-events/hooks/suites/before-and-after-failure.ts b/tests/test-folder/mocha-events/hooks/suites/before-and-after-failure.ts new file mode 100644 index 00000000..4e393c26 --- /dev/null +++ b/tests/test-folder/mocha-events/hooks/suites/before-and-after-failure.ts @@ -0,0 +1,231 @@ +import { TestData } from '@test-utils'; + +const rootSuite = 'Failed before and after hook'; + +const data: TestData = { + name: rootSuite, + rootSuite, + fileName: __filename, + spec: ` + describe('${rootSuite}', () => { + before('in suite', () => { + throw new Error('Failure in before hook'); + }); + + after('after in suite', () => { + throw new Error('Failure in after hook'); + }); + + it('test 1', () => { + cy.log('test 1'); + }); + + it('test 2', () => { + cy.log('test 2'); + }); + }); + `, + + expect: { + testsNames: [`${rootSuite} test 1`, `${rootSuite} test 2`], + + testStatuses: [ + { + testName: 'test 1', + status: 'failed', + statusDetails: { + message: [ + 'Failure in before hook', + '', + `Because this error occurred during a \`before all\` hook we are skipping the remaining tests in the current suite: \`${rootSuite}\` (added by [cypress-allure-adapter])`, + ], + }, + }, + { + testName: 'test 2', + status: 'unknown', + statusDetails: { + message: [ + 'Failure in before hook', + '', + `Because this error occurred during a \`before all\` hook we are skipping the remaining tests in the current suite: \`${rootSuite}\` (added by [cypress-allure-adapter])`, + ], + }, + }, + ], + + testAttachments: [ + { + expectMessage: 'todo check later', + testName: 'test 1', + attachments: [], + }, + { expectMessage: '', testName: 'test 2', attachments: [] }, + ], + + labels: { + filter: ['suite', 'parentSuite', 'subSuite'], + expected: [ + { + name: 'test 1', + labels: [ + { + name: 'parentSuite', + value: rootSuite, + }, + ], + }, + { + name: 'test 2', + labels: [ + { + name: 'parentSuite', + value: rootSuite, + }, + ], + }, + ], + }, + + testSteps: [ + { + testName: 'test 1', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [], + }, + { + testName: 'test 2', + mapStep: m => ({ status: m.status, attachments: m.attachments }), + expected: [], + }, + ], + + parents: [ + { + testName: 'test 1', + containers: [ + { + name: rootSuite, + stepMap: x => ({ + name: x.name, + status: x.status, + attachments: x.attachments, + }), + befores: [ + { + name: '"before all" hook: in suite', + steps: [], + attachments: [ + { + name: `${rootSuite} -- test 1 -- before all hook in suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + ], + afters: [ + { + name: '"after all" hook: after in suite', + steps: [], + attachments: [ + { + name: `${rootSuite} -- test 1 -- after all hook after in suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + { + name: 'video', + steps: [], + attachments: [ + { + name: 'test_0_number.cy.ts.mp4', // video check + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + { + testName: 'test 2', + containers: [ + { + name: rootSuite, + stepMap: x => ({ + name: x.name, + status: x.status, + attachments: x.attachments, + }), + befores: [ + { + name: '"before all" hook: in suite', + steps: [], + attachments: [ + { + name: `${rootSuite} -- test 1 -- before all hook in suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + ], + afters: [ + { + name: '"after all" hook: after in suite', + steps: [], + attachments: [ + { + name: `${rootSuite} -- test 1 -- after all hook after in suite (failed).png`, + source: 'source.png', + type: 'image/png', + }, + ], + }, + { + name: 'video', + steps: [], + attachments: [ + { + name: 'test_0_number.cy.ts.mp4', // change + source: 'source.mp4', + type: 'video/mp4', + }, + ], + }, + ], + }, + ], + }, + ], + + events: [ + 'mocha: start', + 'mocha: suite: , ', + 'mocha: hook: "before all" hook', + 'cypress: test:before:run: test 1', + 'mocha: hook end: "before all" hook', + `mocha: suite: ${rootSuite}, ${rootSuite}`, + 'mocha: hook: "before all" hook: in suite', + `cypress:screenshot:test:${rootSuite} -- test 1 -- before all hook in suite (failed).png`, + 'mocha: fail: "before all" hook: in suite for "test 1"', + 'plugin test:ended', + 'plugin test:started', + 'plugin test:ended', + 'plugin test:started', + 'plugin test:ended', + 'mocha: hook: "after all" hook: after in suite', + `cypress:screenshot:test:${rootSuite} -- test 1 -- after all hook after in suite (failed).png`, + 'mocha: fail: "after all" hook: after in suite for "test 1"', + `mocha: suite end: ${rootSuite}`, + 'mocha: suite end: ', + 'mocha: end', + ], + }, +}; + +export default data; diff --git a/tests/test-folder/mocha-events/hooks/suites/suites.test.ts b/tests/test-folder/mocha-events/hooks/suites/suites.test.ts new file mode 100644 index 00000000..475b3ef4 --- /dev/null +++ b/tests/test-folder/mocha-events/hooks/suites/suites.test.ts @@ -0,0 +1,15 @@ +import { createResTest2, generateChecksTests, TestData } from '@test-utils'; + +describe('suites diff tests', () => { + // test + const testsForOneCyRun: TestData[] = ['before-and-after-failure.ts'].map( + x => require(`${__dirname}/${x}`).default, + ); + + const res = createResTest2( + testsForOneCyRun.map(x => x.spec), + { allureAddVideoOnPass: 'false' /* DEBUG: 'true'*/ }, + ); + + generateChecksTests(res, testsForOneCyRun); +}); diff --git a/tests/test-folder/mocha-events/suites/suites-nested-with-global-hooks-parent.test.ts b/tests/test-folder/mocha-events/suites/suites-nested-with-global-hooks-parent.test.ts index 313f344f..30832331 100644 --- a/tests/test-folder/mocha-events/suites/suites-nested-with-global-hooks-parent.test.ts +++ b/tests/test-folder/mocha-events/suites/suites-nested-with-global-hooks-parent.test.ts @@ -1,10 +1,7 @@ -import { - createResTest2, - fixResult, - readWithRetry, -} from '../../../cy-helper/utils'; +import { createResTest2, fixResult, readWithRetry } from '@test-utils'; import { getParentsArray, parseAllure } from 'allure-js-parser'; import { extname } from '../../../../src/common'; +import { AllureHook } from 'allure-js-parser/types'; // issue https://github.com/mmisty/cypress-allure-adapter/issues/95 describe('several nested suites with global hook - hook should be added to all children', () => { @@ -41,9 +38,10 @@ describe('hello suite', () => { describe('check results', () => { let resFixed; + let results; beforeAll(() => { - const results = parseAllure(res.watch); + results = parseAllure(res.watch); resFixed = fixResult(results); }); @@ -60,14 +58,14 @@ describe('hello suite', () => { it('suites parents', () => { expect( - resFixed + results .sort((a, b) => (a.name < b.name ? -1 : 1)) .map(t => ({ name: t.name, status: t.status, parents: getParentsArray(t).map(t => ({ name: t.name, - befores: t.befores + befores: (t.befores as AllureHook[]) ?.filter(x => (x as any).name !== '"before all" hook') .map(x => ({ name: (x as any).name, @@ -77,7 +75,7 @@ describe('hello suite', () => { ...t, source: `source${extname(t.source)}`, sourceContentMoreThanZero: - readWithRetry(`${res.watch}/${t.source}`).toString() + readWithRetry(`${res.watch}/${t.source}`)?.toString() .length > 0, })), })), @@ -92,6 +90,7 @@ describe('hello suite', () => { { name: '"before all" hook: glob hook', status: 'passed', + statusDetails: {}, attachments: [], }, { @@ -105,11 +104,13 @@ describe('hello suite', () => { ], name: '"before all" hook: parent hook', status: 'passed', + statusDetails: {}, }, { attachments: [], name: '"before all" hook: child hook', status: 'passed', + statusDetails: {}, }, ], name: 'sub sub suite', @@ -180,6 +181,7 @@ describe('hello suite', () => { attachments: [], name: '"before all" hook: glob hook', status: 'passed', + statusDetails: {}, }, { attachments: [ @@ -192,6 +194,7 @@ describe('hello suite', () => { ], name: '"before all" hook: parent hook', status: 'passed', + statusDetails: {}, }, ], name: 'hello suite', diff --git a/tests/test-folder/mocha-events/suites/suites-nested-with-hooks-parent.test.ts b/tests/test-folder/mocha-events/suites/suites-nested-with-hooks-parent.test.ts index 9ca08cbf..28d1233b 100644 --- a/tests/test-folder/mocha-events/suites/suites-nested-with-hooks-parent.test.ts +++ b/tests/test-folder/mocha-events/suites/suites-nested-with-hooks-parent.test.ts @@ -1,8 +1,4 @@ -import { - createResTest2, - fixResult, - readWithRetry, -} from '../../../cy-helper/utils'; +import { createResTest2, fixResult, readWithRetry } from '@test-utils'; import { getParentsArray, parseAllure } from 'allure-js-parser'; import { extname } from '../../../../src/common'; import { AllureHook, Parent } from 'allure-js-parser/types'; @@ -44,9 +40,10 @@ describe('hello suite', () => { describe('check results', () => { let resFixed; + let results; beforeAll(() => { - const results = parseAllure(res.watch); + results = parseAllure(res.watch); resFixed = fixResult(results); }); @@ -62,7 +59,7 @@ describe('hello suite', () => { it('suites parents', () => { expect( - resFixed.map(t => ({ + results.map(t => ({ name: t.name, status: t.status, parents: getParentsArray(t).map((y: Parent) => ({ @@ -76,8 +73,8 @@ describe('hello suite', () => { ...z, source: `source${extname(z.source)}`, sourceContentMoreThanZero: - readWithRetry(`${res.watch}/${z.source}`).toString() - .length > 0, + readWithRetry(`${res.watch}/${z.source}`)?.toString() + ?.length > 0, })), })), afters: (y.afters as AllureHook[]) diff --git a/tests/tsconfig.json b/tests/tsconfig.json index aed55f3e..30e83576 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -6,9 +6,11 @@ "baseUrl": "../src", "paths": { "@src": ["./index.ts"], - "@src/*": ["./*"] + "@src/*": ["./*"], + + "@test-utils": ["../tests/cy-helper/utils.ts"], } }, - "include": ["./", "../jest.setup.ts"], + "include": ["./", "../tests", "../jest.setup.ts"], }