From a31f2dc5b112472e035c70ce0121cf4d49d80059 Mon Sep 17 00:00:00 2001 From: shadowusr Date: Mon, 20 Nov 2023 15:42:27 +0300 Subject: [PATCH 1/5] chore: rename gui/app to typescript --- lib/gui/{app.js => app.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/gui/{app.js => app.ts} (100%) diff --git a/lib/gui/app.js b/lib/gui/app.ts similarity index 100% rename from lib/gui/app.js rename to lib/gui/app.ts From 1465864945382016e2730e168152487ad528918d Mon Sep 17 00:00:00 2001 From: shadowusr Date: Mon, 20 Nov 2023 17:47:07 +0300 Subject: [PATCH 2/5] chore: rewrite gui/app to typescript --- lib/gui/app.ts | 66 +++++++++++++++++++++--------------- lib/gui/server.js | 2 +- lib/gui/tool-runner/index.ts | 2 +- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/lib/gui/app.ts b/lib/gui/app.ts index ae546c869..b642682aa 100644 --- a/lib/gui/app.ts +++ b/lib/gui/app.ts @@ -1,38 +1,52 @@ -'use strict'; +import {Response} from 'express'; +import _ from 'lodash'; -const _ = require('lodash'); -const {ToolRunner} = require('./tool-runner'); +import {ToolRunner, ToolRunnerTree, UndoAcceptImagesResult} from './tool-runner'; +import {HtmlReporterApi} from '../types'; +import Hermione, {Config} from 'hermione'; +import {GuiConfigs} from './index'; +import {TestSpec} from './tool-runner/runner/runner'; +import {TestBranch, TestEqualDiffsData, TestRefUpdateData} from '../tests-tree-builder/gui'; -module.exports = class App { - static create(paths, hermione, configs) { - return new this(paths, hermione, configs); - } +type BrowserConfig = ReturnType; + +type AppArgs = [paths: string[], hermione: Hermione & HtmlReporterApi, configs: GuiConfigs]; - constructor(paths, hermione, configs) { - const {pluginConfig} = configs; +export class App { + private _toolRunner: ToolRunner; + private _browserConfigs: BrowserConfig[]; + private _retryCache: Record; + static create(this: new (...args: AppArgs) => T, ...args: AppArgs): T { + return new this(...args); + } + + constructor(...[paths, hermione, configs]: AppArgs) { this._toolRunner = ToolRunner.create(paths, hermione, configs); - this._pluginConfig = pluginConfig; this._browserConfigs = []; this._retryCache = {}; } - async initialize() { + get data(): ToolRunnerTree | null { + return this._toolRunner.tree; + } + + async initialize(): Promise { return await this._toolRunner.initialize(); } - finalize() { - this._toolRunner.finalize(); + async finalize(): Promise { + return this._toolRunner.finalize(); } - run(tests) { + async run(tests: TestSpec[]): Promise { return _.isEmpty(tests) ? this._toolRunner.run() : this._runWithoutRetries(tests); } - _runWithoutRetries(tests) { + private async _runWithoutRetries(tests: TestSpec[]): Promise { if (_.isEmpty(this._browserConfigs)) { this._browserConfigs = _.map(this._toolRunner.config.getBrowserIds(), (id) => this._toolRunner.config.forBrowser(id)); } @@ -43,44 +57,40 @@ module.exports = class App { .finally(() => this._restoreRetries()); } - getTestsDataToUpdateRefs(imageIds = []) { + getTestsDataToUpdateRefs(imageIds: string[] = []): TestRefUpdateData[] { return this._toolRunner.getTestsDataToUpdateRefs(imageIds); } - getImageDataToFindEqualDiffs(imageIds = []) { + getImageDataToFindEqualDiffs(imageIds: string[] = []): TestEqualDiffsData[] { return this._toolRunner.getImageDataToFindEqualDiffs(imageIds); } - updateReferenceImage(failedTests = []) { + async updateReferenceImage(failedTests: TestRefUpdateData[] = []): Promise { return this._toolRunner.updateReferenceImage(failedTests); } - undoAcceptImages(imageIds) { + async undoAcceptImages(imageIds: TestRefUpdateData[]): Promise { return this._toolRunner.undoAcceptImages(imageIds); } - async findEqualDiffs(data) { + async findEqualDiffs(data: TestEqualDiffsData[]): Promise { return this._toolRunner.findEqualDiffs(data); } - addClient(connection) { + addClient(connection: Response): void { this._toolRunner.addClient(connection); } - get data() { - return this._toolRunner.tree; - } - - _disableRetries() { + private _disableRetries(): void { this._browserConfigs.forEach((broConfig) => { this._retryCache[broConfig.id] = broConfig.retry; broConfig.retry = 0; }); } - _restoreRetries() { + private _restoreRetries(): void { this._browserConfigs.forEach((broConfig) => { broConfig.retry = this._retryCache[broConfig.id]; }); } -}; +} diff --git a/lib/gui/server.js b/lib/gui/server.js index 84e795216..e58f04bef 100644 --- a/lib/gui/server.js +++ b/lib/gui/server.js @@ -7,7 +7,7 @@ const Promise = require('bluebird'); const bodyParser = require('body-parser'); const {INTERNAL_SERVER_ERROR, OK} = require('http-codes'); -const App = require('./app'); +const {App} = require('./app'); const {MAX_REQUEST_SIZE, KEEP_ALIVE_TIMEOUT, HEADERS_TIMEOUT} = require('./constants'); const {initializeCustomGui, runCustomGuiAction} = require('../server-utils'); const {logger} = require('../common-utils'); diff --git a/lib/gui/tool-runner/index.ts b/lib/gui/tool-runner/index.ts index 1b0d5756f..6769e3e65 100644 --- a/lib/gui/tool-runner/index.ts +++ b/lib/gui/tool-runner/index.ts @@ -36,7 +36,7 @@ import {ImagesInfoFormatter} from '../../image-handler'; type ToolRunnerArgs = [paths: string[], hermione: Hermione & HtmlReporterApi, configs: GuiConfigs]; -type ToolRunnerTree = GuiReportBuilderResult & Pick; +export type ToolRunnerTree = GuiReportBuilderResult & Pick; interface HermioneTestExtended extends HermioneTest { assertViewResults: {stateName: string, refImg: ImageData, currImg: ImageData}; From 3dd39599b588d0cee1970eac979ae09f85c7b59b Mon Sep 17 00:00:00 2001 From: shadowusr Date: Mon, 20 Nov 2023 17:57:38 +0300 Subject: [PATCH 3/5] chore: rewrite gui/routes/plugins to typescript --- lib/gui/routes/{plugins.js => plugins.ts} | 21 ++++++++++----------- lib/gui/server.js | 2 +- lib/server-utils.ts | 7 ++++++- package-lock.json | 13 +++++++++++++ package.json | 1 + 5 files changed, 31 insertions(+), 13 deletions(-) rename lib/gui/routes/{plugins.js => plugins.ts} (70%) diff --git a/lib/gui/routes/plugins.js b/lib/gui/routes/plugins.ts similarity index 70% rename from lib/gui/routes/plugins.js rename to lib/gui/routes/plugins.ts index be5ce6eee..bad32f4df 100644 --- a/lib/gui/routes/plugins.js +++ b/lib/gui/routes/plugins.ts @@ -1,22 +1,21 @@ -'use strict'; +import {Router} from 'express'; +import {INTERNAL_SERVER_ERROR, BAD_REQUEST} from 'http-codes'; -const {Router} = require('express'); -const {INTERNAL_SERVER_ERROR, BAD_REQUEST} = require('http-codes'); - -const { +import { isUnexpectedPlugin, getPluginClientScriptPath, getPluginMiddleware, forEachPlugin, logError -} = require('../../server-utils'); +} from '../../server-utils'; +import {ReporterConfig} from '../../types'; -module.exports = function(router, pluginConfig) { +export const initPluginsRoutes = (router: Router, pluginConfig: ReporterConfig): Router =>{ if (!pluginConfig.pluginsEnabled) { return router; } - router.get(`/plugins/:pluginName/plugin.js`, (req, res) => { + router.get<{pluginName: string}>(`/plugins/:pluginName/plugin.js`, (req, res) => { if (isUnexpectedPlugin(pluginConfig.plugins, req.params.pluginName)) { res.status(BAD_REQUEST).send({error: `Unexpected plugin "${req.params.pluginName}" requested.`}); return; @@ -42,12 +41,12 @@ module.exports = function(router, pluginConfig) { initPluginMiddleware(pluginRouter); router.use(`/plugin-routes/${pluginName}`, pluginRouter); - } catch (err) { - logError(err); + } catch (err: unknown) { + logError(err as Error); } }); - router.use('/plugin-routes/:pluginName', (req, res) => { + router.use<{pluginName: string}>('/plugin-routes/:pluginName', (req, res) => { res.status(BAD_REQUEST).send({error: `No middleware is registered for "${req.params.pluginName}".`}); }); diff --git a/lib/gui/server.js b/lib/gui/server.js index e58f04bef..502ab2bf7 100644 --- a/lib/gui/server.js +++ b/lib/gui/server.js @@ -11,7 +11,7 @@ const {App} = require('./app'); const {MAX_REQUEST_SIZE, KEEP_ALIVE_TIMEOUT, HEADERS_TIMEOUT} = require('./constants'); const {initializeCustomGui, runCustomGuiAction} = require('../server-utils'); const {logger} = require('../common-utils'); -const initPluginsRoutes = require('./routes/plugins'); +const {initPluginsRoutes} = require('./routes/plugins'); exports.start = async ({paths, hermione, guiApi, configs}) => { const {options, pluginConfig} = configs; diff --git a/lib/server-utils.ts b/lib/server-utils.ts index 94f3b09f2..cf60419a2 100644 --- a/lib/server-utils.ts +++ b/lib/server-utils.ts @@ -12,6 +12,7 @@ import type Hermione from 'hermione'; import crypto from 'crypto'; import {ImageHandler, ImagesInfoFormatter} from './image-handler'; import {HermioneTestAdapter} from './test-adapter'; +import {Router} from 'express'; const DATA_FILE_NAME = 'data.js'; @@ -270,7 +271,11 @@ export function getPluginClientScriptPath(pluginName: string): string | null { } } -export function getPluginMiddleware(pluginName: string): unknown | null { +interface PluginMiddleware { + (pluginRouter: Router): unknown; +} + +export function getPluginMiddleware(pluginName: string): PluginMiddleware | null { try { return require(`${pluginName}/middleware.js`); } catch (e: any) { // eslint-disable-line @typescript-eslint/no-explicit-any diff --git a/package-lock.json b/package-lock.json index 471f03cae..ed81647dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "@types/enzyme": "^3.10.13", "@types/express": "4.16", "@types/fs-extra": "^7.0.0", + "@types/http-codes": "^1.0.4", "@types/json-stringify-safe": "^5.0.2", "@types/lodash": "^4.14.195", "@types/nested-error-stacks": "^2.1.0", @@ -4355,6 +4356,12 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, + "node_modules/@types/http-codes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/http-codes/-/http-codes-1.0.4.tgz", + "integrity": "sha512-LGWkImWfjqxGYPXa+uHNuugnpG2bvjkWfPCpm1E9xb6Te/N3E8vr7dIUuC82JgCny+dl3lQ5domuXkdyHyUvsQ==", + "dev": true + }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -34978,6 +34985,12 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", "dev": true }, + "@types/http-codes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/http-codes/-/http-codes-1.0.4.tgz", + "integrity": "sha512-LGWkImWfjqxGYPXa+uHNuugnpG2bvjkWfPCpm1E9xb6Te/N3E8vr7dIUuC82JgCny+dl3lQ5domuXkdyHyUvsQ==", + "dev": true + }, "@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", diff --git a/package.json b/package.json index 8b10631dd..e2b55a62e 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "@types/enzyme": "^3.10.13", "@types/express": "4.16", "@types/fs-extra": "^7.0.0", + "@types/http-codes": "^1.0.4", "@types/json-stringify-safe": "^5.0.2", "@types/lodash": "^4.14.195", "@types/nested-error-stacks": "^2.1.0", From 6477f537a8f5d63fcbbe8ea6bfe99ebbc0a4af03 Mon Sep 17 00:00:00 2001 From: shadowusr Date: Tue, 21 Nov 2023 00:43:39 +0300 Subject: [PATCH 4/5] chore: rewrite gui server to typescript --- lib/gui/api/facade.js | 16 --- lib/gui/api/facade.ts | 16 +++ lib/gui/api/index.js | 21 ---- lib/gui/api/index.ts | 31 ++++++ lib/gui/index.ts | 14 ++- lib/gui/{server.js => server.ts} | 86 ++++++++------- package-lock.json | 182 +++++++++++++++++++------------ package.json | 2 +- 8 files changed, 218 insertions(+), 150 deletions(-) delete mode 100644 lib/gui/api/facade.js create mode 100644 lib/gui/api/facade.ts delete mode 100644 lib/gui/api/index.js create mode 100644 lib/gui/api/index.ts rename lib/gui/{server.js => server.ts} (60%) diff --git a/lib/gui/api/facade.js b/lib/gui/api/facade.js deleted file mode 100644 index 2856e22f3..000000000 --- a/lib/gui/api/facade.js +++ /dev/null @@ -1,16 +0,0 @@ -'use strict'; - -const EventEmitter2 = require('eventemitter2'); -const {GuiEvents} = require('../constants/gui-events'); - -module.exports = class ApiFacade extends EventEmitter2 { - static create() { - return new ApiFacade(); - } - - constructor() { - super(); - - this.events = GuiEvents; - } -}; diff --git a/lib/gui/api/facade.ts b/lib/gui/api/facade.ts new file mode 100644 index 000000000..4250a558b --- /dev/null +++ b/lib/gui/api/facade.ts @@ -0,0 +1,16 @@ +import EventEmitter2 from 'eventemitter2'; +import {GuiEvents} from '../constants'; + +export class ApiFacade extends EventEmitter2 { + events: GuiEvents; + + static create(this: new () => T): T { + return new this(); + } + + constructor() { + super(); + + this.events = GuiEvents; + } +} diff --git a/lib/gui/api/index.js b/lib/gui/api/index.js deleted file mode 100644 index 178a9f79c..000000000 --- a/lib/gui/api/index.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const ApiFacade = require('./facade'); - -module.exports = class Api { - static create(hermione) { - return new Api(hermione); - } - - constructor(hermione) { - this._gui = hermione.gui = ApiFacade.create(); - } - - async initServer(server) { - await this._gui.emitAsync(this._gui.events.SERVER_INIT, server); - } - - async serverReady(data) { - await this._gui.emitAsync(this._gui.events.SERVER_READY, data); - } -}; diff --git a/lib/gui/api/index.ts b/lib/gui/api/index.ts new file mode 100644 index 000000000..6a8ca29a5 --- /dev/null +++ b/lib/gui/api/index.ts @@ -0,0 +1,31 @@ +import {ApiFacade} from './facade'; +import Hermione from 'hermione'; +import {Express} from 'express'; + +interface GuiFacade { + gui: ApiFacade; +} + +export interface ServerReadyData { + url: string; +} + +export class Api { + private _gui: ApiFacade; + + static create(this: new (hermione: Hermione & GuiFacade) => T, hermione: Hermione & GuiFacade): T { + return new this(hermione); + } + + constructor(hermione: Hermione & GuiFacade) { + this._gui = hermione.gui = ApiFacade.create(); + } + + async initServer(server: Express): Promise { + await this._gui.emitAsync(this._gui.events.SERVER_INIT, server); + } + + async serverReady(data: ServerReadyData): Promise { + await this._gui.emitAsync(this._gui.events.SERVER_READY, data); + } +} diff --git a/lib/gui/index.ts b/lib/gui/index.ts index 31ab42468..cae5f8a49 100644 --- a/lib/gui/index.ts +++ b/lib/gui/index.ts @@ -2,16 +2,20 @@ import type {CommanderStatic} from '@gemini-testing/commander'; import chalk from 'chalk'; import opener from 'opener'; -import server from './server'; +import * as server from './server'; import {logger} from '../common-utils'; import * as utils from '../server-utils'; -import {ReporterConfig} from '../types'; +import {HtmlReporterApi, ReporterConfig} from '../types'; +import Hermione from 'hermione'; +import {Api} from './api'; const {logError} = utils; export interface GuiCliOptions { autoRun: boolean; open: unknown; + port: number; + hostname: string; } export interface GuiConfigs { @@ -20,10 +24,10 @@ export interface GuiConfigs { pluginConfig: ReporterConfig; } -interface ServerArgs { +export interface ServerArgs { paths: string[]; - hermione: unknown; - guiApi: unknown; + hermione: Hermione & HtmlReporterApi; + guiApi: Api; configs: GuiConfigs; } diff --git a/lib/gui/server.js b/lib/gui/server.ts similarity index 60% rename from lib/gui/server.js rename to lib/gui/server.ts index 502ab2bf7..63eb0fd85 100644 --- a/lib/gui/server.js +++ b/lib/gui/server.ts @@ -1,19 +1,19 @@ -'use strict'; - -const path = require('path'); -const express = require('express'); -const onExit = require('signal-exit'); -const Promise = require('bluebird'); -const bodyParser = require('body-parser'); -const {INTERNAL_SERVER_ERROR, OK} = require('http-codes'); - -const {App} = require('./app'); -const {MAX_REQUEST_SIZE, KEEP_ALIVE_TIMEOUT, HEADERS_TIMEOUT} = require('./constants'); -const {initializeCustomGui, runCustomGuiAction} = require('../server-utils'); -const {logger} = require('../common-utils'); -const {initPluginsRoutes} = require('./routes/plugins'); - -exports.start = async ({paths, hermione, guiApi, configs}) => { +import path from 'path'; +import express from 'express'; +import {onExit} from 'signal-exit'; +import BluebirdPromise from 'bluebird'; +import bodyParser from 'body-parser'; +import {INTERNAL_SERVER_ERROR, OK} from 'http-codes'; + +import {App} from './app'; +import {MAX_REQUEST_SIZE, KEEP_ALIVE_TIMEOUT, HEADERS_TIMEOUT} from './constants'; +import {initializeCustomGui, runCustomGuiAction} from '../server-utils'; +import {logger} from '../common-utils'; +import {initPluginsRoutes} from './routes/plugins'; +import {ServerArgs} from './index'; +import {ServerReadyData} from './api'; + +export const start = async ({paths, hermione, guiApi, configs}: ServerArgs): Promise => { const {options, pluginConfig} = configs; const app = App.create(paths, hermione, configs); const server = express(); @@ -28,31 +28,37 @@ exports.start = async ({paths, hermione, guiApi, configs}) => { server.use(express.static(path.join(__dirname, '../static'), {index: 'gui.html'})); server.use(express.static(path.join(process.cwd(), pluginConfig.path))); - server.get('/', (req, res) => res.sendFile(path.join(__dirname, '../static', 'gui.html'))); + server.get('/', (_req, res) => res.sendFile(path.join(__dirname, '../static', 'gui.html'))); - server.get('/events', (req, res) => { + server.get('/events', (_req, res) => { res.writeHead(OK, {'Content-Type': 'text/event-stream'}); app.addClient(res); }); - server.set('json replacer', (key, val) => { + server.set('json replacer', (_key: string, val: unknown) => { return typeof val === 'function' ? val.toString() : val; }); - server.get('/init', async (req, res) => { + server.get('/init', async (_req, res) => { try { await initializeCustomGui(hermione, pluginConfig); - } catch (e) { - app.data.customGuiError = { - response: { - status: INTERNAL_SERVER_ERROR, - data: `Error while trying to initialize custom GUI: ${e.message}` + res.json(app.data); + } catch (e: unknown) { + const error = e as Error; + if (!app.data) { + throw new Error(`Failed to initialize custom GUI ${error.message}`); + } + res.json({ + ...app.data, + customGuiError: { + response: { + status: INTERNAL_SERVER_ERROR, + data: `Error while trying to initialize custom GUI: ${error.message}` + } } - }; + }); } - - res.json(app.data); }); server.post('/run', (req, res) => { @@ -61,7 +67,7 @@ exports.start = async ({paths, hermione, guiApi, configs}) => { app.run(req.body); res.sendStatus(OK); } catch (e) { - res.status(INTERNAL_SERVER_ERROR).send(`Error while trying to run tests: ${e.message}`); + res.status(INTERNAL_SERVER_ERROR).send(`Error while trying to run tests: ${(e as Error).message}`); } }); @@ -70,7 +76,7 @@ exports.start = async ({paths, hermione, guiApi, configs}) => { await runCustomGuiAction(hermione, pluginConfig, payload); res.sendStatus(OK); } catch (e) { - res.status(INTERNAL_SERVER_ERROR).send(`Error while running custom gui action: ${e.message}`); + res.status(INTERNAL_SERVER_ERROR).send(`Error while running custom gui action: ${(e as Error).message}`); } }); @@ -79,7 +85,7 @@ exports.start = async ({paths, hermione, guiApi, configs}) => { const data = app.getTestsDataToUpdateRefs(req.body); res.json(data); } catch (error) { - res.status(INTERNAL_SERVER_ERROR).send({error: error.message}); + res.status(INTERNAL_SERVER_ERROR).send({error: (error as Error).message}); } }); @@ -99,8 +105,8 @@ exports.start = async ({paths, hermione, guiApi, configs}) => { try { const data = app.getImageDataToFindEqualDiffs(req.body); res.json(data); - } catch (error) { - res.status(INTERNAL_SERVER_ERROR).send({error: error.message}); + } catch (e) { + res.status(INTERNAL_SERVER_ERROR).send({error: (e as Error).message}); } }); @@ -108,8 +114,8 @@ exports.start = async ({paths, hermione, guiApi, configs}) => { try { const result = await app.findEqualDiffs(req.body); res.json(result); - } catch ({message}) { - res.status(INTERNAL_SERVER_ERROR).send({error: message}); + } catch (e) { + res.status(INTERNAL_SERVER_ERROR).send({error: (e as Error).message}); } }); @@ -118,21 +124,21 @@ exports.start = async ({paths, hermione, guiApi, configs}) => { logger.log('server shutting down'); }); - server.post('/stop', (req, res) => { + server.post('/stop', (_req, res) => { try { // pass 0 to prevent terminating hermione process - hermione.halt('Tests were stopped by the user', 0); + hermione.halt(new Error('Tests were stopped by the user'), 0); res.sendStatus(OK); } catch (e) { - res.status(INTERNAL_SERVER_ERROR).send(`Error while stopping tests: ${e.message}`); + res.status(INTERNAL_SERVER_ERROR).send(`Error while stopping tests: ${(e as Error).message}`); } }); await app.initialize(); const {port, hostname} = options; - await Promise.fromCallback((callback) => { - const httpServer = server.listen(port, hostname, callback); + await BluebirdPromise.fromCallback((callback) => { + const httpServer = server.listen(port, hostname, callback as () => void); httpServer.keepAliveTimeout = KEEP_ALIVE_TIMEOUT; httpServer.headersTimeout = HEADERS_TIMEOUT; }); diff --git a/package-lock.json b/package-lock.json index ed81647dc..aad6de3c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "ora": "^5.4.1", "p-queue": "^5.0.0", "qs": "^6.9.1", - "signal-exit": "^3.0.2", + "signal-exit": "^4.1.0", "strip-ansi": "^6.0.1", "tmp": "^0.1.0", "worker-farm": "^1.7.0" @@ -5391,19 +5391,6 @@ "node": ">=8" } }, - "node_modules/@wdio/config/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@wdio/config/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -11230,6 +11217,12 @@ "node": ">=6" } }, + "node_modules/default-gateway/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/default-require-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", @@ -12855,20 +12848,6 @@ "node": ">=8" } }, - "node_modules/devtools/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/devtools/node_modules/socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", @@ -14744,6 +14723,12 @@ "yallist": "^2.1.2" } }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/execa/node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -15465,6 +15450,12 @@ "yallist": "^2.1.2" } }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/foreground-child/node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -18227,18 +18218,6 @@ "node": ">=8" } }, - "node_modules/hermione/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/hermione/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -21396,6 +21375,12 @@ "node": ">=0.10.0" } }, + "node_modules/loud-rejection/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -22860,6 +22845,12 @@ "node": ">=4" } }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -25836,6 +25827,11 @@ "node": ">=8" } }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "node_modules/ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -26489,9 +26485,15 @@ } }, "node_modules/signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/simple-concat": { "version": "1.0.1", @@ -26954,6 +26956,12 @@ "which": "^1.3.0" } }, + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -31495,6 +31503,12 @@ "signal-exit": "^3.0.2" } }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", @@ -35767,13 +35781,6 @@ "dev": true, "optional": true }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "optional": true - }, "strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -40337,6 +40344,12 @@ "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true } } }, @@ -41557,14 +41570,6 @@ "optional": true, "peer": true }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "optional": true, - "peer": true - }, "socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", @@ -43015,6 +43020,12 @@ "yallist": "^2.1.2" } }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -43629,6 +43640,12 @@ "yallist": "^2.1.2" } }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -45640,12 +45657,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -48093,6 +48104,14 @@ "requires": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.0" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + } } }, "lower-case": { @@ -49259,6 +49278,12 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true } } }, @@ -51606,6 +51631,13 @@ "requires": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + } } }, "ret": { @@ -52148,9 +52180,9 @@ } }, "signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" }, "simple-concat": { "version": "1.0.1", @@ -52520,6 +52552,14 @@ "rimraf": "^2.6.2", "signal-exit": "^3.0.2", "which": "^1.3.0" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + } } }, "spdx-correct": { @@ -56001,6 +56041,14 @@ "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", "signal-exit": "^3.0.2" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + } } }, "ws": { diff --git a/package.json b/package.json index e2b55a62e..97a059029 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "ora": "^5.4.1", "p-queue": "^5.0.0", "qs": "^6.9.1", - "signal-exit": "^3.0.2", + "signal-exit": "^4.1.0", "strip-ansi": "^6.0.1", "tmp": "^0.1.0", "worker-farm": "^1.7.0" From 0988ef6d4b8ca183b2fa3c38393a42466c38fc71 Mon Sep 17 00:00:00 2001 From: shadowusr Date: Tue, 21 Nov 2023 13:52:15 +0300 Subject: [PATCH 5/5] test: fix unit and e2e tests --- lib/cli-commands/gui.js | 2 +- lib/gui/api/index.ts | 10 +++---- lib/gui/routes/plugins.ts | 2 +- test/unit/lib/gui/api/index.js | 2 +- test/unit/lib/gui/app.js | 2 +- test/unit/lib/gui/routes/plugins.js | 2 +- test/unit/lib/gui/server.js | 46 +++++++++++++++-------------- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lib/cli-commands/gui.js b/lib/cli-commands/gui.js index 155489e5b..fb7e0d59d 100644 --- a/lib/cli-commands/gui.js +++ b/lib/cli-commands/gui.js @@ -2,7 +2,7 @@ const {cliCommands} = require('.'); const runGui = require('../gui').default; -const Api = require('../gui/api'); +const {Api} = require('../gui/api'); const {GUI: commandName} = cliCommands; diff --git a/lib/gui/api/index.ts b/lib/gui/api/index.ts index 6a8ca29a5..06ae26609 100644 --- a/lib/gui/api/index.ts +++ b/lib/gui/api/index.ts @@ -2,22 +2,20 @@ import {ApiFacade} from './facade'; import Hermione from 'hermione'; import {Express} from 'express'; -interface GuiFacade { - gui: ApiFacade; -} - export interface ServerReadyData { url: string; } +type HermioneWithGui = Hermione & { gui: ApiFacade }; + export class Api { private _gui: ApiFacade; - static create(this: new (hermione: Hermione & GuiFacade) => T, hermione: Hermione & GuiFacade): T { + static create(this: new (hermione: HermioneWithGui) => T, hermione: HermioneWithGui): T { return new this(hermione); } - constructor(hermione: Hermione & GuiFacade) { + constructor(hermione: HermioneWithGui) { this._gui = hermione.gui = ApiFacade.create(); } diff --git a/lib/gui/routes/plugins.ts b/lib/gui/routes/plugins.ts index bad32f4df..38eac1c23 100644 --- a/lib/gui/routes/plugins.ts +++ b/lib/gui/routes/plugins.ts @@ -10,7 +10,7 @@ import { } from '../../server-utils'; import {ReporterConfig} from '../../types'; -export const initPluginsRoutes = (router: Router, pluginConfig: ReporterConfig): Router =>{ +export const initPluginsRoutes = (router: Router, pluginConfig: ReporterConfig): Router => { if (!pluginConfig.pluginsEnabled) { return router; } diff --git a/test/unit/lib/gui/api/index.js b/test/unit/lib/gui/api/index.js index 8ba58af75..87e5ee07a 100644 --- a/test/unit/lib/gui/api/index.js +++ b/test/unit/lib/gui/api/index.js @@ -2,7 +2,7 @@ const EventEmitter2 = require('eventemitter2'); const {GuiEvents} = require('lib/gui/constants/gui-events'); -const Api = require('lib/gui/api'); +const {Api} = require('lib/gui/api'); const {stubTool} = require('../../../utils'); describe('lig/gui/api', () => { diff --git a/test/unit/lib/gui/app.js b/test/unit/lib/gui/app.js index 86079422f..61218fca3 100644 --- a/test/unit/lib/gui/app.js +++ b/test/unit/lib/gui/app.js @@ -48,7 +48,7 @@ describe('lib/gui/app', () => { App = proxyquire('lib/gui/app', { 'looks-same': looksSame - }); + }).App; sandbox.stub(ToolRunner, 'create').returns(toolRunner); }); diff --git a/test/unit/lib/gui/routes/plugins.js b/test/unit/lib/gui/routes/plugins.js index 4fe400b17..5f77b6fea 100644 --- a/test/unit/lib/gui/routes/plugins.js +++ b/test/unit/lib/gui/routes/plugins.js @@ -32,7 +32,7 @@ describe('lib/gui/routes/plugins', () => { return router; } } - }); + }).initPluginsRoutes; }); afterEach(() => sandbox.restore()); diff --git a/test/unit/lib/gui/server.js b/test/unit/lib/gui/server.js index 46f249848..7050f1f6e 100644 --- a/test/unit/lib/gui/server.js +++ b/test/unit/lib/gui/server.js @@ -2,7 +2,7 @@ const _ = require('lodash'); const proxyquire = require('proxyquire'); -const App = require('lib/gui/app'); +const {App} = require('lib/gui/app'); const {stubTool} = require('../../utils'); describe('lib/gui/server', () => { @@ -60,47 +60,49 @@ describe('lib/gui/server', () => { Router: () => RouterStub }), 'body-parser': bodyParserStub, - 'signal-exit': sandbox.stub().yields(), + 'signal-exit': {onExit: sandbox.stub().yields()}, '../common-utils': {logger: {log: sandbox.stub()}}, - './routes/plugins': initPluginRoutesStub + './routes/plugins': {initPluginsRoutes: initPluginRoutesStub} }); }); - afterEach(() => sandbox.restore()); + afterEach(() => { + sandbox.restore(); + }); - it('should init server from api', () => { + it('should init server from api', async () => { const guiApi = mkApi_(); - return startServer({guiApi}) - .then(() => { - assert.calledOnceWith(guiApi.initServer, expressStub); - assert.calledOnceWith(guiApi.serverReady, {url: 'http://localhost:4444'}); - }); + await startServer({guiApi}); + + assert.calledOnceWith(guiApi.initServer, expressStub); + assert.calledOnceWith(guiApi.serverReady, {url: 'http://localhost:4444'}); }); - it('should init server only after body is parsed', () => { + it('should init server only after body is parsed', async () => { const guiApi = mkApi_(); - return startServer({guiApi}) - .then(() => assert.callOrder(bodyParserStub.json, guiApi.initServer, guiApi.serverReady)); + await startServer({guiApi}); + + assert.callOrder(bodyParserStub.json, guiApi.initServer, guiApi.serverReady); }); - it('should init server before any static middleware starts', () => { + it('should init server before any static middleware starts', async () => { const guiApi = mkApi_(); - return startServer({guiApi}) - .then(() => assert.callOrder(guiApi.initServer, staticMiddleware, guiApi.serverReady)); + await startServer({guiApi}); + + assert.callOrder(guiApi.initServer, staticMiddleware, guiApi.serverReady); }); - it('should properly complete app working', () => { + it('should properly complete app working', async () => { sandbox.stub(process, 'kill'); - return startServer() - .then(() => { - process.emit('SIGTERM'); + await startServer(); + + process.emit('SIGTERM'); - assert.calledOnce(App.prototype.finalize); - }); + assert.calledOnce(App.prototype.finalize); }); it('should correctly set json replacer', async () => {