From e56b333dd513cb8d03f97679737b05df4b19d1d0 Mon Sep 17 00:00:00 2001 From: Taisia Pitko Date: Wed, 26 Jun 2024 13:47:48 +0300 Subject: [PATCH] [patch] More test fixes (#148) --- package-lock.json | 11 +++ package.json | 1 + src/plugins/server.ts | 76 +++++++++++++++++-- tests/cy-helper/utils.ts | 41 ++++++++++ tests/test-folder/common/utils.test.ts | 2 +- .../plugin-events-test-no-allure.test.ts | 1 + .../fail-one-test-before-each-retry.test.ts | 2 +- .../mocha-events/interface/no-allure.test.ts | 1 + 8 files changed, 126 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3380afd4..6a53d45f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "debug": "4.3.5", "events": "3.3.0", "fast-glob": "3.3.2", + "net": "^1.0.2", "uuid": "10.0.0", "uuid-by-string": "4.0.0", "ws": "8.17.1" @@ -13088,6 +13089,11 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/net": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz", + "integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ==" + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -26353,6 +26359,11 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "net": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz", + "integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ==" + }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", diff --git a/package.json b/package.json index 89bf2e5c..1be7bccb 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "debug": "4.3.5", "events": "3.3.0", "fast-glob": "3.3.2", + "net": "^1.0.2", "uuid": "10.0.0", "uuid-by-string": "4.0.0", "ws": "8.17.1" diff --git a/src/plugins/server.ts b/src/plugins/server.ts index 89a0fbe3..fc9d73d7 100644 --- a/src/plugins/server.ts +++ b/src/plugins/server.ts @@ -1,5 +1,6 @@ import PluginConfigOptions = Cypress.PluginConfigOptions; import { RawData, WebSocketServer } from 'ws'; +import net from 'net'; import { ENV_WS, packageLog, wsPath } from '../common'; import Debug from 'debug'; import { AllureTasks, RequestTask } from '../plugins/allure-types'; @@ -18,11 +19,70 @@ const messageGot = (...args: unknown[]) => { logMessage(`${args}`); }; -function getRandomPortNumber(): number { - return 40000 + Math.round(Math.random() * 25000); +const checkPortSync = (port: number, timeoutMs = 2000): boolean => { + let isAvailable = true; + let server: net.Server | null = null; + let timeoutReached = false; + const startTime = Date.now(); + + try { + server = net.createServer(); + server.listen(port); + + server.on('error', (err: NodeJS.ErrnoException) => { + if (err.code === 'EADDRINUSE') { + isAvailable = false; + } + }); + + const checkTimeout = () => { + if (Date.now() - startTime >= timeoutMs) { + timeoutReached = true; + } + }; + + const waitForListening = () => { + if (!server?.listening && !timeoutReached) { + process.nextTick(waitForListening); // Yield to event loop + checkTimeout(); // Check if timeout has been reached + } + }; + + waitForListening(); + + if (timeoutReached) { + throw new Error(`Timeout waiting for port ${port} to become available.`); + } + } catch (error) { + isAvailable = false; + } finally { + if (server) { + server.close(); + } + } + + return isAvailable; +}; + +function retrieveRandomPortNumber(): number { + const getRandomPort = () => 40000 + Math.round(Math.random() * 25000); + let port = getRandomPort(); + + for (let i = 0; i < 30; i++) { + const result = checkPortSync(port); + + if (result) { + return port; + } + port = getRandomPort(); + } + + console.log(`${packageLog} could not find free port, will not report`); + + return port; } -const socketLogic = (port: number, sockserver: WebSocketServer | undefined, tasks: AllureTasks) => { +const socketLogic = (sockserver: WebSocketServer | undefined, tasks: AllureTasks) => { if (!sockserver) { log('Could not start reporting server'); @@ -77,19 +137,21 @@ const socketLogic = (port: number, sockserver: WebSocketServer | undefined, task }; export const startReporterServer = (configOptions: PluginConfigOptions, tasks: AllureTasks, attempt = 0) => { - const wsPort = getRandomPortNumber(); + const wsPort = retrieveRandomPortNumber(); - const sockserver: WebSocketServer | undefined = new WebSocketServer({ port: wsPort, path: wsPath }, () => { + let sockserver: WebSocketServer | undefined = new WebSocketServer({ port: wsPort, path: wsPath }, () => { configOptions.env[ENV_WS] = wsPort; const attemptMessage = attempt > 0 ? ` from ${attempt} attempt` : ''; console.log(`${packageLog} running on ${wsPort} port${attemptMessage}`); - socketLogic(wsPort, sockserver, tasks); + socketLogic(sockserver, tasks); }); sockserver.on('error', err => { if (err.message.indexOf('address already in use') !== -1) { if (attempt < 30) { - startReporterServer(configOptions, tasks, attempt + 1); + process.nextTick(() => { + sockserver = startReporterServer(configOptions, tasks, attempt + 1); + }); } else { console.error(`${packageLog} Could not find free port, will not report: ${err.message}`); } diff --git a/tests/cy-helper/utils.ts b/tests/cy-helper/utils.ts index d2e47869..aa9d0cfb 100644 --- a/tests/cy-helper/utils.ts +++ b/tests/cy-helper/utils.ts @@ -266,6 +266,7 @@ export const readWithRetry = (path: string, attempt = 0) => { export const createResTest2 = ( specTexts: string[], envConfig?: Record, + shouldBeResults?: boolean, ): { watch: string; specs: string[]; @@ -352,6 +353,31 @@ export const createResTest2 = ( process.env.DEBUG = envConfig?.DEBUG ? 'cypress-allure*' : ''; process.env.COVERAGE_REPORT_DIR = 'reports/coverage-cypress'; + const checkFilesExist = retries => { + return new Promise((resolve, reject) => { + const attempt = remainingRetries => { + if (!specs.every(p => existsSync(p))) { + console.log( + `Not all files were written: attempt ${retries - remainingRetries + 1}`, + ); + + if (remainingRetries > 0) { + return delay(1000) + .then(() => attempt(remainingRetries - 1)) + .catch(reject); + } else { + return reject( + new Error('Files are still missing after all retries'), + ); + } + } + resolve(true); + }; + + attempt(retries); + }); + }; + return cy .run({ spec, @@ -377,9 +403,24 @@ export const createResTest2 = ( return delay(1000); } + }) + .then(() => { + if (shouldBeResults) { + return checkFilesExist(10); + } }); }); + afterEach(() => { + // to investigate issue with missing + if (specs?.some(p => existsSync(p))) { + specs.forEach(s => { + const content = readFileSync(s); + console.log(content.toString()); + }); + } + }); + return { watch: env.allureResultsWatchPath ?? storeResDir, specs: specs, diff --git a/tests/test-folder/common/utils.test.ts b/tests/test-folder/common/utils.test.ts index 0178bfe6..d24fa3d3 100644 --- a/tests/test-folder/common/utils.test.ts +++ b/tests/test-folder/common/utils.test.ts @@ -63,7 +63,7 @@ describe('utils', () => { it('delay', async () => { const started = Date.now(); await delay(100); - expect(Date.now() - started).toBeGreaterThanOrEqual(100); + expect(Date.now() - started).toBeGreaterThanOrEqual(99); // sometime has 99 instead of 100 }); it('messages should be dequeued in the same order as added', async () => { diff --git a/tests/test-folder/mocha-events/events/plugin-events-test-no-allure.test.ts b/tests/test-folder/mocha-events/events/plugin-events-test-no-allure.test.ts index bd669b39..acb143f8 100644 --- a/tests/test-folder/mocha-events/events/plugin-events-test-no-allure.test.ts +++ b/tests/test-folder/mocha-events/events/plugin-events-test-no-allure.test.ts @@ -23,6 +23,7 @@ describe('hello suite', () => { `, ], { allure: 'false' }, + false, ); it('should be ok', () => { checkCyResults(res?.result?.res, { diff --git a/tests/test-folder/mocha-events/failures/test-retries/fail-one-test-before-each-retry.test.ts b/tests/test-folder/mocha-events/failures/test-retries/fail-one-test-before-each-retry.test.ts index 2c183873..4fa42c69 100644 --- a/tests/test-folder/mocha-events/failures/test-retries/fail-one-test-before-each-retry.test.ts +++ b/tests/test-folder/mocha-events/failures/test-retries/fail-one-test-before-each-retry.test.ts @@ -16,7 +16,7 @@ describe('mocha events - check failures @oneInconsistency', () => { const res = createResTest2([ ` describe('hello suite', { retries: 1 }, () => { - beforeEach(()=> { + beforeEach(() => { cy.wrap(null).then(() => { throw new Error('Test FAIL on purpose'); }); diff --git a/tests/test-folder/mocha-events/interface/no-allure.test.ts b/tests/test-folder/mocha-events/interface/no-allure.test.ts index 4278ae11..9c32b083 100644 --- a/tests/test-folder/mocha-events/interface/no-allure.test.ts +++ b/tests/test-folder/mocha-events/interface/no-allure.test.ts @@ -14,6 +14,7 @@ describe('should be no results when allure:false', () => { `, ], { allure: 'false' }, + false, ); describe('check results', () => {