From 161fb73e2548369abd3ba0b953d1d6aa8b1034b8 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 15:17:17 -0700 Subject: [PATCH 01/27] refactor: more constants, improved types --- package-lock.json | 4 +- src/collector/LogCollectBrowserConsole.ts | 6 +- src/collector/LogCollectControlBase.ts | 16 ++- src/collector/LogCollectControlExtended.ts | 40 +++---- src/collector/LogCollectControlSimple.ts | 2 +- .../LogCollectCypressBrowserNetwork.ts | 7 +- src/collector/LogCollectCypressCommand.ts | 4 +- src/collector/LogCollectCypressIntercept.ts | 5 +- src/collector/LogCollectCypressLog.ts | 2 - src/collector/LogCollectCypressRequest.ts | 9 +- src/collector/LogCollectorState.ts | 2 +- src/constants.ts | 56 ++++++++-- src/installLogsCollector.schema.ts | 22 ++-- src/installLogsCollector.ts | 8 +- src/installLogsCollector.types.ts | 4 +- src/installLogsPrinter.schema.ts | 7 +- src/installLogsPrinter.types.ts | 8 +- src/jsonPrune.ts | 8 +- src/outputProcessor/consoleProcessor.ts | 103 ++++++++---------- src/outputProcessor/logsTxtFormatter.ts | 4 +- src/types.ts | 34 +++--- 21 files changed, 188 insertions(+), 163 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b29c25..82ae5da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cypress-terminal-report", - "version": "7.0.2", + "version": "7.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cypress-terminal-report", - "version": "7.0.2", + "version": "7.0.4", "license": "MIT", "dependencies": { "chalk": "^4.0.0", diff --git a/src/collector/LogCollectBrowserConsole.ts b/src/collector/LogCollectBrowserConsole.ts index 1042d6a..4eabadc 100644 --- a/src/collector/LogCollectBrowserConsole.ts +++ b/src/collector/LogCollectBrowserConsole.ts @@ -1,8 +1,6 @@ import CONSTANTS from '../constants'; import utils from '../utils'; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; -import type {Severity} from "../types"; +import type {LogType, Severity} from "../types"; import LogCollectBase from "./LogCollectBase"; type Methods = 'warn' | 'error' | 'debug' | 'info' | 'log'; @@ -47,7 +45,7 @@ export default class LogCollectBrowserConsole extends LogCollectBase { const createWrapper = ( method: Methods, - logType: any, + logType: LogType, type: Severity = CONSTANTS.SEVERITY.SUCCESS ) => { oldConsoleMethods[method] = appWindow.console[method]; diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index 2d41fd6..c087714 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -1,7 +1,7 @@ import CtrError from '../CtrError'; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectorState from "./LogCollectorState"; -import type {MessageData, TestData} from "../types"; +import type {MessageData, State, TestData} from "../types"; export default abstract class LogCollectControlBase { protected abstract collectorState: LogCollectorState; @@ -11,7 +11,7 @@ export default abstract class LogCollectControlBase { logStackIndex: number, mochaRunnable: Mocha.Runnable, options: { - state?: string, + state?: State, title?: string, noQueue?: boolean, consoleTitle?: string, @@ -20,7 +20,11 @@ export default abstract class LogCollectControlBase { continuous?: boolean, } = {} ) { - let testState: MessageData['state'] = (options.state || mochaRunnable.state) as MessageData['state'] || 'running'; + let testState = options.state || mochaRunnable.state; + if (!testState) { + return; + } + let testTitle = options.title || mochaRunnable.title; let testLevel = 0; @@ -34,7 +38,7 @@ export default abstract class LogCollectControlBase { { let parent = mochaRunnable.parent; - while (parent && parent.title) { + while (parent?.title) { testTitle = `${parent.title} -> ${testTitle}` parent = parent.parent; ++testLevel; @@ -98,13 +102,13 @@ export default abstract class LogCollectControlBase { let invocationDetails = mochaRunnable.invocationDetails; let parent = mochaRunnable.parent; // always get top-most spec to determine the called .spec file - while (parent && parent.invocationDetails) { + while (parent?.invocationDetails) { invocationDetails = parent.invocationDetails parent = parent.parent; } return parent.file || // Support for cypress-grep. invocationDetails.relativeFile || - (invocationDetails.fileUrl && invocationDetails.fileUrl.replace(/^[^?]+\?p=/, '')); + invocationDetails.fileUrl?.replace(/^[^?]+\?p=/, ''); } } diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 63b65cd..b4489cf 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -157,7 +157,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs after all hook commands when a command fails in the hook. - Cypress.prependListener('fail', function(this: any, error: any) { + Cypress.prependListener('fail', function(this: any, error: Error) { const currentRunnable = this.mocha.getRunner().currentRunnable; if (currentRunnable.hookName === 'after all' && self.collectorState.hasLogsInCurrentStack()) { @@ -180,7 +180,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Have to wait for debounce on log updates to have correct state information. // Done state is used as callback and awaited in Cypress.fail. // @ts-ignore - Cypress.state('done', async (error: any) => { + Cypress.state('done', async (error: Error) => { await new Promise(resolve => setTimeout(resolve, 6)); throw error; }); @@ -195,7 +195,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { registerTests() { const self = this; - const sendLogsToPrinterForATest = (test: any) => { + const sendLogsToPrinterForATest = (test: Mocha.Test) => { // We take over logging the passing test titles since we need to control when it gets printed so // that our logs come after it is printed. if (test.state === 'passed') { @@ -206,25 +206,27 @@ export default class LogCollectControlExtended extends LogCollectControlBase { this.sendLogsToPrinter(this.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); }; - const testHasAfterEachHooks = (test: any) => { + const testHasAfterEachHooks = (test: Mocha.Test) => { do { - if (test.parent._afterEach.length > 0) { + const _afterEach = (test.parent as any)?._afterEach + if (_afterEach.length > 0) { return true; } - test = test.parent; + test = test.parent as any as Mocha.Test; } while(test.parent); return false; }; - const isLastAfterEachHookForTest = (test: any, hook: any) => { + const isLastAfterEachHookForTest = (test: Mocha.Test, hook: Mocha.Hook) => { let suite = test.parent; - do { - if (suite._afterEach.length === 0) { + while (suite) { + const _afterEach = (suite as any)._afterEach + if (_afterEach.length === 0) { suite = suite.parent; } else { - return suite._afterEach.indexOf(hook) === suite._afterEach.length - 1; + return _afterEach.indexOf(hook) === _afterEach.length - 1; } - } while (suite); + }; return false; }; @@ -240,7 +242,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs commands form each separate test when there is no after each hook. // @ts-ignore - Cypress.mocha.getRunner().on('test end', function (test: any) { + Cypress.mocha.getRunner().on('test end', function (test: Mocha.Test) { if (!testHasAfterEachHooks(test)) { self.debugLog('extended: sending logs for ended test, that has not after each hooks: ' + self.collectorState.getCurrentTest().title); sendLogsToPrinterForATest(self.collectorState.getCurrentTest()); @@ -248,7 +250,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs commands if test was manually skipped. // @ts-ignore - Cypress.mocha.getRunner().on('pending', function (test: any) { + Cypress.mocha.getRunner().on('pending', function (test: Mocha.Test) { if (self.collectorState.getCurrentTest() === test) { // In case of fully skipped tests we might not yet have a log stack. if (self.collectorState.hasLogsInCurrentStack()) { @@ -298,18 +300,18 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }; } - prependBeforeAllHookInAllSuites(rootSuites: any, hookCallback: (this: any) => void) { - const recursiveSuites = (suites: any) => { + prependBeforeAllHookInAllSuites(rootSuites: Mocha.Suite[], hookCallback: (this: any) => void) { + const recursiveSuites = (suites: Mocha.Suite[]) => { if (suites) { - suites.forEach((suite: any) => { + suites.forEach((suite) => { if (suite.isPending()) { return } suite.afterAll(hookCallback); // Make sure our hook is first so that other after all hook logs come after // the failed before all hooks logs. - const hook = suite._afterAll.pop(); - suite._afterAll.unshift(hook); + const hook = (suite as any)._afterAll.pop(); + (suite as any)._afterAll.unshift(hook); // Don't count this in the hook index and logs. hook._ctr_hook = true; @@ -352,7 +354,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }; } - debugLog(message: any) { + debugLog(message: string) { if (this.config.debug) { console.log(CONSTANTS.DEBUG_LOG_PREFIX + message); } diff --git a/src/collector/LogCollectControlSimple.ts b/src/collector/LogCollectControlSimple.ts index edfc1dd..6f889f9 100644 --- a/src/collector/LogCollectControlSimple.ts +++ b/src/collector/LogCollectControlSimple.ts @@ -75,7 +75,7 @@ export default class LogCollectControlSimple extends LogCollectControlBase { // @ts-ignore Cypress.mocha.getRunner().on('pending', function () { let test = self.collectorState.getCurrentTest(); - if (test && test.state === 'pending') { + if (test?.state === 'pending') { // In case of fully skipped tests we might not yet have a log stack. self.collectorState.ensureLogStack(); self.sendLogsToPrinter(self.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); diff --git a/src/collector/LogCollectCypressBrowserNetwork.ts b/src/collector/LogCollectCypressBrowserNetwork.ts index b600e5b..016d580 100644 --- a/src/collector/LogCollectCypressBrowserNetwork.ts +++ b/src/collector/LogCollectCypressBrowserNetwork.ts @@ -1,5 +1,4 @@ import CONSTANTS from '../constants'; -import LogFormat from "./LogFormat"; import LogCollectorState from "./LogCollectorState"; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; @@ -38,10 +37,10 @@ export default class LogCollectCypressBrowserNetwork extends LogCollectBase { register() { // In Cypress 13+ this is under an extra props key - const getConsoleProps = (options: any) => - options.consoleProps?.props ? options.consoleProps.props : options.consoleProps + const getConsoleProps = (options: Cypress.ObjectLike) => + options.consoleProps?.props || options.consoleProps - const formatXhr = (options: any, props: any) => + const formatXhr = (options: Cypress.ObjectLike, props: Cypress.ObjectLike) => (options.alias !== undefined ? '(' + options.alias + ') ' : '') + (options.renderProps.wentToOrigin || props["Request went to origin?"] === 'yes' ? '' : 'STUBBED ') + props.Method + ' ' + props.URL; diff --git a/src/collector/LogCollectCypressCommand.ts b/src/collector/LogCollectCypressCommand.ts index 5ae5e85..597379e 100644 --- a/src/collector/LogCollectCypressCommand.ts +++ b/src/collector/LogCollectCypressCommand.ts @@ -6,12 +6,12 @@ export default class LogCollectCypressCommand extends LogCollectBase { ignoredCommands = ['xhr', 'log', 'request']; register() { - const isOfInterest = (options: any) => options.instrument === 'command' && + const isOfInterest = (options: Cypress.ObjectLike) => options.instrument === 'command' && options.consoleProps && !this.ignoredCommands.includes(options.name) && !(options.name === 'task' && options.message.match(/ctrLogMessages/)); - const formatLogMessage = (options: any) => { + const formatLogMessage = (options: Cypress.ObjectLike) => { let message = options.name + '\t' + options.message; if (options.expected && options.actual) { diff --git a/src/collector/LogCollectCypressIntercept.ts b/src/collector/LogCollectCypressIntercept.ts index e987105..6141167 100644 --- a/src/collector/LogCollectCypressIntercept.ts +++ b/src/collector/LogCollectCypressIntercept.ts @@ -1,7 +1,4 @@ import CONSTANTS from '../constants'; -import LogFormat from "./LogFormat"; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; Object.defineProperty(RegExp.prototype, "toJSON", { @@ -13,7 +10,7 @@ export default class LogCollectCypressIntercept extends LogCollectBase { Cypress.Commands.overwrite('intercept', (originalFn, ...args) => { let message = ''; - if (typeof args[0] === "string" && CONSTANTS.HTTP_METHODS.includes(args[0].toUpperCase())) { + if (typeof args[0] === "string" && (CONSTANTS.HTTP_METHODS as readonly string[]).includes(args[0].toUpperCase())) { message += `Method: ${args[0]}\nMatcher: ${JSON.stringify(args[1])}`; if (args[2]) { message += `\nMocked Response: ${typeof args[2] === 'object' ? JSON.stringify(args[2]) : args[2]}`; diff --git a/src/collector/LogCollectCypressLog.ts b/src/collector/LogCollectCypressLog.ts index d607e4b..7d99fd0 100644 --- a/src/collector/LogCollectCypressLog.ts +++ b/src/collector/LogCollectCypressLog.ts @@ -1,6 +1,4 @@ import CONSTANTS from '../constants'; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; export default class LogCollectCypressLog extends LogCollectBase { diff --git a/src/collector/LogCollectCypressRequest.ts b/src/collector/LogCollectCypressRequest.ts index dd4b67f..1abcea7 100644 --- a/src/collector/LogCollectCypressRequest.ts +++ b/src/collector/LogCollectCypressRequest.ts @@ -1,16 +1,13 @@ import CONSTANTS from '../constants'; -import LogFormat from "./LogFormat"; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; export default class LogCollectCypressRequest extends LogCollectBase { register() { const isValidHttpMethod = (str: any) => typeof str === 'string' && CONSTANTS.HTTP_METHODS.some((s) => str.toUpperCase().includes(s)); - const isNetworkError = (e: any) => e.message && e.message.startsWith('`cy.request()` failed trying to load:'); + const isNetworkError = (e: Error) => e.message && e.message.startsWith('`cy.request()` failed trying to load:'); - const isStatusCodeFailure = (e: any) => e.message && e.message.startsWith('`cy.request()` failed on:'); + const isStatusCodeFailure = (e: Error) => e.message && e.message.startsWith('`cy.request()` failed on:'); const RESPONSE_START = '\n\nThe response we got was:\n\n'; const STATUS_START = 'Status: '; @@ -85,7 +82,7 @@ export default class LogCollectCypressRequest extends LogCollectBase { body: formattedRequestBody, }; - return originalFn(...args).catch(async (e: any) => { + return originalFn(...args).catch(async (e: Error) => { if (isNetworkError(e)) { log += `\n` + diff --git a/src/collector/LogCollectorState.ts b/src/collector/LogCollectorState.ts index 3d4414a..3aecc41 100644 --- a/src/collector/LogCollectorState.ts +++ b/src/collector/LogCollectorState.ts @@ -190,7 +190,7 @@ export default class LogCollectorState extends EventTarget { this.afterHookIndexes.shift(); } - startTest(test: any) { + startTest(test: Mocha.Runnable) { if (this.config.debug) { console.log(CONSTANTS.DEBUG_LOG_PREFIX + 'starting test: ' + test.title); } diff --git a/src/constants.ts b/src/constants.ts index e02bb94..ce0af7b 100755 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,5 +1,3 @@ -import type {LogType, Severity} from "./types"; - const CONSTANTS = { TASK_NAME: 'ctrLogMessages', TASK_NAME_OUTPUT: 'ctrLogFiles', @@ -18,14 +16,52 @@ const CONSTANTS = { CYPRESS_INTERCEPT: 'cy:intercept', CYPRESS_COMMAND: 'cy:command', - PLUGIN_LOG_TYPE: 'ctr:info', - } satisfies Record, + PLUGIN_LOG_TYPE: 'ctr:info' + }, SEVERITY: { SUCCESS: 'success', ERROR: 'error', WARNING: 'warning', - } satisfies Record, + }, + + LOG_SYMBOLS: { + ERROR: '✘', + WARNING: '❖', + SUCCESS: '✔', + INFO: '✱', + DEBUG: '⚈', + ROUTE: '➟' + }, + LOG_SYMBOLS_CONSOLE: { + ERROR: 'x', + WARNING: '!', + SUCCESS: '+', + INFO: 'i', + DEBUG: '%', + ROUTE: '~' + }, + + LOG_OCCURRENCE: { + ON_FAIL: 'onFail', + ALWAYS: 'always', + NEVER: 'never' + }, + + COLORS: { + WHITE: 'white', + YELLOW: 'yellow', + RED: 'red', + BLUE: 'blue', + GREEN: 'green', + GREY: 'grey', + }, + + STATE: { + FAILED: 'failed', + PASSED: 'passed', + RUNNING: 'running' + }, HOOK_TITLES: { BEFORE: '[[ before all {index} ]]', @@ -52,7 +88,13 @@ const CONSTANTS = { 'SOURCE', 'SUBSCRIBE', 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE' - ] -} + ], + + COMMAND_TIMINGS: { + TIMESTAMP: 'timestamp', + SECONDS: 'seconds' + } +} as const + export default CONSTANTS; diff --git a/src/installLogsCollector.schema.ts b/src/installLogsCollector.schema.ts index 1ad3330..58ff038 100644 --- a/src/installLogsCollector.schema.ts +++ b/src/installLogsCollector.schema.ts @@ -1,19 +1,13 @@ +import CONSTANTS from "./constants"; import {array, boolean, enums, func, object, optional} from "superstruct"; const InstallLogsCollectorSchema = object({ - collectTypes: optional(array(enums([ - "cons:log", - "cons:info", - "cons:warn", - "cons:error", - "cons:debug", - "cy:log", - "cy:xhr", - "cy:fetch", - "cy:request", - "cy:intercept", - "cy:command" - ]))), + collectTypes: optional(array(enums( + Object.values(CONSTANTS.LOG_TYPES).filter( + (t) => t !== CONSTANTS.LOG_TYPES.PLUGIN_LOG_TYPE + ) + )) + ), filterLog: optional(func()), processLog: optional(func()), collectTestLogs: optional(func()), @@ -24,7 +18,7 @@ const InstallLogsCollectorSchema = object({ })), enableExtendedCollector: optional(boolean()), enableContinuousLogging: optional(boolean()), - commandTimings: optional(enums(["timestamp", "seconds"])), + commandTimings: optional(enums(Object.values(CONSTANTS.COMMAND_TIMINGS))), debug: optional(boolean()), }); diff --git a/src/installLogsCollector.ts b/src/installLogsCollector.ts index 4eb8f98..56cd7e5 100755 --- a/src/installLogsCollector.ts +++ b/src/installLogsCollector.ts @@ -26,9 +26,9 @@ function installLogsCollector(config: SupportOptions = {}) { const extendedConfig: ExtendedSupportOptions = { ...config, collectTypes: config.collectTypes || Object.values(CONSTANTS.LOG_TYPES) as LogType[], - collectBody: config.xhr && config.xhr.printBody !== undefined ? config.xhr.printBody : true, - collectRequestData: config.xhr && config.xhr.printRequestData, - collectHeaderData: config.xhr && config.xhr.printHeaderData, + collectBody: config.xhr?.printBody ?? true, + collectRequestData: config.xhr?.printRequestData, + collectHeaderData: config.xhr?.printHeaderData, }; let logCollectorState = new LogCollectorState(extendedConfig); @@ -43,7 +43,7 @@ function installLogsCollector(config: SupportOptions = {}) { registerGlobalApi(logCollectorState); } -function registerLogCollectorTypes(logCollectorState: any, config: ExtendedSupportOptions) { +function registerLogCollectorTypes(logCollectorState: LogCollectorState, config: ExtendedSupportOptions) { (new LogCollectBrowserConsole(logCollectorState, config)).register() if (config.collectTypes.includes(CONSTANTS.LOG_TYPES.CYPRESS_LOG)) { diff --git a/src/installLogsCollector.types.ts b/src/installLogsCollector.types.ts index b48cc1b..125b68f 100644 --- a/src/installLogsCollector.types.ts +++ b/src/installLogsCollector.types.ts @@ -1,4 +1,4 @@ -import type {Log, LogType, TestData} from "./types"; +import type {CommandTimings, Log, LogType, TestData} from "./types"; export interface SupportOptions { /** @@ -71,7 +71,7 @@ export interface SupportOptions { * Adds time information to logs. * @default null */ - commandTimings?: null | 'timestamp' | 'seconds' + commandTimings?: null | CommandTimings /** * Enabled debug logging. diff --git a/src/installLogsPrinter.schema.ts b/src/installLogsPrinter.schema.ts index fc03d29..7dab44f 100644 --- a/src/installLogsPrinter.schema.ts +++ b/src/installLogsPrinter.schema.ts @@ -1,8 +1,11 @@ +import CONSTANTS from "./constants"; import {boolean, enums, func, min, number, object, optional, record, string, union} from "superstruct"; +const LOG_OCCURRENCE = Object.values(CONSTANTS.LOG_OCCURRENCE) + const InstallLogsPrinterSchema = object({ - printLogsToConsole: optional(enums(['onFail', 'always', 'never'])), - printLogsToFile: optional(enums(['onFail', 'always', 'never'])), + printLogsToConsole: optional(enums(LOG_OCCURRENCE)), + printLogsToFile: optional(enums(LOG_OCCURRENCE)), includeSuccessfulHookLogs: optional(boolean()), defaultTrimLength: optional(number()), commandTrimLength: optional(number()), diff --git a/src/installLogsPrinter.types.ts b/src/installLogsPrinter.types.ts index 1410352..f6757b4 100644 --- a/src/installLogsPrinter.types.ts +++ b/src/installLogsPrinter.types.ts @@ -1,6 +1,6 @@ /// import type CustomOutputProcessor from "./outputProcessor/CustomOutputProcessor"; -import type {Log} from "./types"; +import type {Log, LogOccurrence, State} from "./types"; export type AllMessages = { [specPath: string]: { @@ -83,13 +83,13 @@ export interface PluginOptions { * When set to always logs will be printed for console for successful test as well as failing ones. * @default 'onFail' */ - printLogsToConsole?: 'onFail' | 'always' | 'never'; + printLogsToConsole?: LogOccurrence; /** * When set to always logs will be printed to file for successful test as well as failing ones. * @default 'onFail' */ - printLogsToFile?: 'onFail' | 'always' | 'never'; + printLogsToFile?: LogOccurrence; /** * Whether to log commands from hooks that passed. @@ -109,5 +109,5 @@ export interface PluginOptions { * Callback to collect each test case's logs after its run. * @default undefined */ - collectTestLogs?: (context: {spec: string, test: string, state: string}, messages: Log[]) => void; + collectTestLogs?: (context: {spec: string, test: string, state: State}, messages: Log[]) => void; } diff --git a/src/jsonPrune.ts b/src/jsonPrune.ts index c1dfdd7..acf7978 100644 --- a/src/jsonPrune.ts +++ b/src/jsonPrune.ts @@ -8,18 +8,18 @@ var seen: any; // Same variable used for all stringifications var iterator: any; // either forEachEnumerableOwnProperty, forEachEnumerableProperty or forEachProperty // iterates on enumerable own properties (default behavior) -var forEachEnumerableOwnProperty = function(obj: any, callback: any) { +var forEachEnumerableOwnProperty = function(obj: Record, callback: (arg:any)=>void) { for (var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) callback(k); } } // iterates on enumerable properties -var forEachEnumerableProperty = function(obj: any, callback: any) { +var forEachEnumerableProperty = function(obj: Record, callback: (arg:any)=>void) { for (var k in obj) callback(k); } // iterates on properties, even non enumerable and inherited ones // This is dangerous -var forEachProperty = function(obj: any, callback: any, excluded: any) { +var forEachProperty = function(obj: Record, callback: (arg:any)=>void, excluded: Record) { if (obj==null) return; excluded = excluded || {}; Object.getOwnPropertyNames(obj).forEach(function(k){ @@ -57,7 +57,7 @@ function quote(string: any) { } -const jsonPrune = function (value: any, depthDecr: any, arrayMaxLength: any) { +const jsonPrune = function (value: any, depthDecr: any, arrayMaxLength: number) { var prunedString = DEFAULT_PRUNED_VALUE; var replacer: any; if (typeof depthDecr == "object") { diff --git a/src/outputProcessor/consoleProcessor.ts b/src/outputProcessor/consoleProcessor.ts index f692382..802a267 100644 --- a/src/outputProcessor/consoleProcessor.ts +++ b/src/outputProcessor/consoleProcessor.ts @@ -1,87 +1,73 @@ import CONSTANTS from "../constants"; -import type {Log, LogType, MessageData} from "../types"; +import type {Colors, Log, LogSymbols, LogType, MessageData} from "../types"; import type {PluginOptions} from "../installLogsPrinter.types"; import chalk from "chalk"; -const LOG_TYPES = CONSTANTS.LOG_TYPES; -const KNOWN_TYPES = Object.values(CONSTANTS.LOG_TYPES); - -const LOG_SYMBOLS = (() => { - if (process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color') { - return { - error: '✘', - warning: '❖', - success: '✔', - info: '✱', - debug: '⚈', - route: '➟' - } - } else { - return { - error: 'x', - warning: '!', - success: '+', - info: 'i', - debug: '%', - route: '~' - } - } -})(); +const {LOG_TYPES, COLORS} = CONSTANTS; +const KNOWN_LOG_TYPES = Object.values(LOG_TYPES); + +const LOG_SYMBOLS = (() => + process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color' + ? CONSTANTS.LOG_SYMBOLS : CONSTANTS.LOG_SYMBOLS_CONSOLE)(); -const BOLD_COLORS = ['red', 'yellow']; +const BOLD_COLORS: Colors[] = [COLORS.RED, COLORS.YELLOW]; -const TYPE_COMPUTE: {[key in typeof LOG_TYPES[keyof typeof LOG_TYPES]]: (options: PluginOptions) => {icon: string, color: string, trim?: number}} = { +const TYPE_COMPUTE: Record { + icon: LogSymbols, + color: Colors, + trim?: number +}> = { [LOG_TYPES.PLUGIN_LOG_TYPE]: () => ({ - color: 'white', + color: COLORS.WHITE, icon: '-', }), [LOG_TYPES.BROWSER_CONSOLE_WARN]: () => ({ - color: 'yellow', - icon: LOG_SYMBOLS.warning, + color: COLORS.YELLOW, + icon: LOG_SYMBOLS.WARNING, }), [LOG_TYPES.BROWSER_CONSOLE_ERROR]: () => ({ - color: 'red', - icon: LOG_SYMBOLS.warning, + color: COLORS.RED, + icon: LOG_SYMBOLS.WARNING, }), [LOG_TYPES.BROWSER_CONSOLE_DEBUG]: () => ({ - color: 'blue', - icon: LOG_SYMBOLS.debug, + color: COLORS.BLUE, + icon: LOG_SYMBOLS.DEBUG, }), [LOG_TYPES.BROWSER_CONSOLE_LOG]: () => ({ - color: 'white', - icon: LOG_SYMBOLS.info, + color: COLORS.WHITE, + icon: LOG_SYMBOLS.INFO, }), [LOG_TYPES.BROWSER_CONSOLE_INFO]: () => ({ - color: 'white', - icon: LOG_SYMBOLS.info, + color: COLORS.WHITE, + icon: LOG_SYMBOLS.INFO, }), [LOG_TYPES.CYPRESS_LOG]: () => ({ - color: 'green', - icon: LOG_SYMBOLS.info, + color: COLORS.GREEN, + icon: LOG_SYMBOLS.INFO, }), [LOG_TYPES.CYPRESS_XHR]: (options) => ({ - color: 'green', - icon: LOG_SYMBOLS.route, + color: COLORS.GREEN, + icon: LOG_SYMBOLS.ROUTE, trim: options.routeTrimLength || 5000, }), [LOG_TYPES.CYPRESS_FETCH]: (options) => ({ - color: 'green', - icon: LOG_SYMBOLS.route, + color: COLORS.GREEN, + icon: LOG_SYMBOLS.ROUTE, trim: options.routeTrimLength || 5000, }), [LOG_TYPES.CYPRESS_INTERCEPT]: (options) => ({ - color: 'green', - icon: LOG_SYMBOLS.route, + color: COLORS.GREEN, + icon: LOG_SYMBOLS.ROUTE, trim: options.routeTrimLength || 5000, }), [LOG_TYPES.CYPRESS_REQUEST]: (options) => ({ - color: 'green', - icon: LOG_SYMBOLS.success, + color: COLORS.GREEN, + icon: LOG_SYMBOLS.SUCCESS, trim: options.routeTrimLength || 5000, }), [LOG_TYPES.CYPRESS_COMMAND]: (options) => ({ - color: 'green', - icon: LOG_SYMBOLS.success, + color: COLORS.GREEN, + icon: LOG_SYMBOLS.SUCCESS, trim: options.routeTrimLength || 5000, }), } @@ -91,17 +77,18 @@ const TYPE_STRING_CACHE: Record = {}; const padType = (type: string, padding: string) => ' '.repeat(Math.max(padding.length - type.length - 4, 0)) + type + ' '; -const getTypeString = (type: LogType, icon: string, color: string, padding: string) => { +const getTypeString = (type: LogType, icon: LogSymbols, color: Colors, padding: string) => { const key = `${type}:${icon}:${color}:${padding}`; if (TYPE_STRING_CACHE[key]) { return TYPE_STRING_CACHE[key]; } - const typeString = KNOWN_TYPES.includes(type) ? padType(type, padding) : padType('[unknown]', padding) + const typeString = padType(KNOWN_LOG_TYPES.includes(type) ? type : '[unknown]', padding) + const fullString = typeString + icon + ' ' const coloredTypeString = BOLD_COLORS.includes(color) ? - (chalk as any)[color].bold(typeString + icon + ' ') : - (chalk as any)[color](typeString + icon + ' '); + chalk[color].bold(fullString) : + chalk[color](fullString); TYPE_STRING_CACHE[key] = coloredTypeString; return coloredTypeString; @@ -133,11 +120,11 @@ function consoleProcessor( trim = trim || options.defaultTrimLength || 800; if (severity === CONSTANTS.SEVERITY.ERROR) { - color = 'red'; - icon = LOG_SYMBOLS.error; + color = COLORS.RED; + icon = LOG_SYMBOLS.ERROR; } else if (severity === CONSTANTS.SEVERITY.WARNING) { - color = 'yellow'; - icon = LOG_SYMBOLS.warning; + color = COLORS.YELLOW; + icon = LOG_SYMBOLS.WARNING; } if (message.length > trim) { diff --git a/src/outputProcessor/logsTxtFormatter.ts b/src/outputProcessor/logsTxtFormatter.ts index 2687e66..347518b 100644 --- a/src/outputProcessor/logsTxtFormatter.ts +++ b/src/outputProcessor/logsTxtFormatter.ts @@ -1,5 +1,5 @@ import CONSTANTS from "../constants"; -import type {Log} from "../types"; +import type {Log, Severity} from "../types"; const PADDING = ' '; const PADDING_LOGS = `${PADDING}`.repeat(6); @@ -7,7 +7,7 @@ const SEVERITY_ICON = { [CONSTANTS.SEVERITY.ERROR]: 'X', [CONSTANTS.SEVERITY.WARNING]: '!', [CONSTANTS.SEVERITY.SUCCESS]: 'K', -} +} satisfies Record const padTypeText = (text: string) => { return ' '.repeat(Math.max(PADDING_LOGS.length - text.length, 0)) + text; diff --git a/src/types.ts b/src/types.ts index ebb71a0..7d44f70 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,17 +1,21 @@ -export type Severity = 'success' | 'error' | 'warning'; - -export type LogType = 'cons:log' | - 'cons:info' | - 'cons:warn' | - 'cons:error' | - 'cons:debug' | - 'cy:log' | - 'cy:xhr' | - 'cy:fetch' | - 'cy:request' | - 'cy:intercept' | - 'cy:command' | - 'ctr:info'; +import CONSTANTS from "./constants"; + +type ValueOf = T[keyof T]; + +export type Severity = ValueOf + +export type LogType = ValueOf + +export type LogSymbols = ValueOf | + ValueOf | '-' + +export type LogOccurrence = ValueOf + +export type Colors = ValueOf + +export type State = ValueOf + +export type CommandTimings = ValueOf export type Log = { type: LogType, @@ -23,7 +27,7 @@ export type Log = { export type MessageData = { spec: string, test: string, - state: 'failed' | 'passed' | 'running', + state: State, messages: Log[], consoleTitle?: string; level?: number, From f74cc73c4d23efbeaeb17ec2db9f80830a3d820d Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 15:40:14 -0700 Subject: [PATCH 02/27] more types --- src/collector/LogCollectControlExtended.ts | 15 ++++++++------- src/collector/LogCollectControlSimple.ts | 2 +- src/collector/LogCollectorState.ts | 3 ++- src/constants.ts | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index b4489cf..3c4f852 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -55,7 +55,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { } }); // @ts-ignore - Cypress.mocha.getRunner().on('test', (test) => { + Cypress.mocha.getRunner().on('test', (test: Mocha.Runnable) => { this.collectorState.startTest(test); }); // @ts-ignore @@ -195,7 +195,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { registerTests() { const self = this; - const sendLogsToPrinterForATest = (test: Mocha.Test) => { + const sendLogsToPrinterForATest = (test: Mocha.Runnable) => { // We take over logging the passing test titles since we need to control when it gets printed so // that our logs come after it is printed. if (test.state === 'passed') { @@ -206,18 +206,19 @@ export default class LogCollectControlExtended extends LogCollectControlBase { this.sendLogsToPrinter(this.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); }; - const testHasAfterEachHooks = (test: Mocha.Test) => { + const testHasAfterEachHooks = (test: Mocha.Runnable) => { do { const _afterEach = (test.parent as any)?._afterEach if (_afterEach.length > 0) { return true; } - test = test.parent as any as Mocha.Test; + // @ts-ignore + test = test.parent; } while(test.parent); return false; }; - const isLastAfterEachHookForTest = (test: Mocha.Test, hook: Mocha.Hook) => { + const isLastAfterEachHookForTest = (test: Mocha.Runnable, hook: Mocha.Hook) => { let suite = test.parent; while (suite) { const _afterEach = (suite as any)._afterEach @@ -242,7 +243,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs commands form each separate test when there is no after each hook. // @ts-ignore - Cypress.mocha.getRunner().on('test end', function (test: Mocha.Test) { + Cypress.mocha.getRunner().on('test end', function (test: Mocha.Runnable) { if (!testHasAfterEachHooks(test)) { self.debugLog('extended: sending logs for ended test, that has not after each hooks: ' + self.collectorState.getCurrentTest().title); sendLogsToPrinterForATest(self.collectorState.getCurrentTest()); @@ -250,7 +251,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs commands if test was manually skipped. // @ts-ignore - Cypress.mocha.getRunner().on('pending', function (test: Mocha.Test) { + Cypress.mocha.getRunner().on('pending', function (test: Mocha.Runnable) { if (self.collectorState.getCurrentTest() === test) { // In case of fully skipped tests we might not yet have a log stack. if (self.collectorState.hasLogsInCurrentStack()) { diff --git a/src/collector/LogCollectControlSimple.ts b/src/collector/LogCollectControlSimple.ts index 6f889f9..46640d4 100644 --- a/src/collector/LogCollectControlSimple.ts +++ b/src/collector/LogCollectControlSimple.ts @@ -75,7 +75,7 @@ export default class LogCollectControlSimple extends LogCollectControlBase { // @ts-ignore Cypress.mocha.getRunner().on('pending', function () { let test = self.collectorState.getCurrentTest(); - if (test?.state === 'pending') { + if ((test?.state as string) === 'pending') { // In case of fully skipped tests we might not yet have a log stack. self.collectorState.ensureLogStack(); self.sendLogsToPrinter(self.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); diff --git a/src/collector/LogCollectorState.ts b/src/collector/LogCollectorState.ts index 3aecc41..dd55003 100644 --- a/src/collector/LogCollectorState.ts +++ b/src/collector/LogCollectorState.ts @@ -14,7 +14,7 @@ export type StackLogArray = StackLog[] & { _ctr_before_each?: number } export default class LogCollectorState extends EventTarget { afterHookIndexes: number[]; beforeHookIndexes: number[]; - currentTest: any; + currentTest: Mocha.Runnable; isStrict: boolean; listeners: Record; logStacks: Array; @@ -25,6 +25,7 @@ export default class LogCollectorState extends EventTarget { super(); this.listeners = {}; + // @ts-ignore this.currentTest = null; this.logStacks = []; this.beforeHookIndexes = []; diff --git a/src/constants.ts b/src/constants.ts index ce0af7b..3451ad3 100755 --- a/src/constants.ts +++ b/src/constants.ts @@ -60,7 +60,7 @@ const CONSTANTS = { STATE: { FAILED: 'failed', PASSED: 'passed', - RUNNING: 'running' + RUNNING: 'running', }, HOOK_TITLES: { From e7a43abd8011b78f47a67b76969a65d9bfc926fb Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 15:46:26 -0700 Subject: [PATCH 03/27] refactor function --- src/collector/LogCollectControlExtended.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 3c4f852..bd749b3 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -207,14 +207,14 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }; const testHasAfterEachHooks = (test: Mocha.Runnable) => { - do { - const _afterEach = (test.parent as any)?._afterEach + let suite = test.parent + while (suite) { + const _afterEach = (suite as any)._afterEach if (_afterEach.length > 0) { return true; } - // @ts-ignore - test = test.parent; - } while(test.parent); + suite = suite.parent; + }; return false; }; From 1b3f74a41b90c148d9555883c53e2ece96c21c40 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 15:47:30 -0700 Subject: [PATCH 04/27] more type --- src/collector/LogCollectControlExtended.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index bd749b3..e5a2c73 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -209,7 +209,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const testHasAfterEachHooks = (test: Mocha.Runnable) => { let suite = test.parent while (suite) { - const _afterEach = (suite as any)._afterEach + const _afterEach: any[] = (suite as any)._afterEach if (_afterEach.length > 0) { return true; } @@ -221,7 +221,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const isLastAfterEachHookForTest = (test: Mocha.Runnable, hook: Mocha.Hook) => { let suite = test.parent; while (suite) { - const _afterEach = (suite as any)._afterEach + const _afterEach: any[] = (suite as any)._afterEach if (_afterEach.length === 0) { suite = suite.parent; } else { From 47215228b256cbe83df02eead3d77c2fc7a79cd6 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 16:24:11 -0700 Subject: [PATCH 05/27] revert type change --- src/collector/LogCollectControlExtended.ts | 11 +++++++---- src/jsonPrune.ts | 8 ++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index e5a2c73..3beff21 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -5,6 +5,8 @@ import LogCollectorState from "./LogCollectorState"; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import type {MessageData} from "../types"; +type MochaHook = Mocha.Hook & {hookName:string; _ctr_hook: boolean} + /** * Collects and dispatches all logs from all tests and hooks. */ @@ -69,7 +71,8 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Keeps track of before and after all hook indexes. // @ts-ignore - Cypress.mocha.getRunner().on('hook', function (hook: any) { + Cypress.mocha.getRunner().on('hook', function (hook: MochaHook) { + // @ts-ignore if (!hook._ctr_hook && !hook.fn._ctr_hook) { // After each hooks get merged with the test. if (hook.hookName !== "after each") { @@ -95,7 +98,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Logs commands from before all hook if the hook passed. // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function(this: any, hook: any) { + Cypress.mocha.getRunner().on('hook end', function(this: any, hook: MochaHook) { if (hook.hookName === "before all" && self.collectorState.hasLogsInCurrentStack() && !hook._ctr_hook) { self.debugLog('extended: sending logs of passed before all hook'); self.sendLogsToPrinter( @@ -139,7 +142,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Logs commands from after all hooks that passed. // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function (hook: any) { + Cypress.mocha.getRunner().on('hook end', function (hook: MochaHook) { if (hook.hookName === "after all" && self.collectorState.hasLogsInCurrentStack() && !hook._ctr_hook) { self.debugLog('extended: sending logs of passed after all hook'); self.sendLogsToPrinter( @@ -233,7 +236,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Logs commands form each separate test when after each hooks are present. // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function (hook: any) { + Cypress.mocha.getRunner().on('hook end', function (hook: MochaHook) { if (hook.hookName === 'after each') { if (isLastAfterEachHookForTest(self.collectorState.getCurrentTest(), hook)) { self.debugLog('extended: sending logs for ended test, just after the last after each hook: ' + self.collectorState.getCurrentTest().title); diff --git a/src/jsonPrune.ts b/src/jsonPrune.ts index acf7978..c1dfdd7 100644 --- a/src/jsonPrune.ts +++ b/src/jsonPrune.ts @@ -8,18 +8,18 @@ var seen: any; // Same variable used for all stringifications var iterator: any; // either forEachEnumerableOwnProperty, forEachEnumerableProperty or forEachProperty // iterates on enumerable own properties (default behavior) -var forEachEnumerableOwnProperty = function(obj: Record, callback: (arg:any)=>void) { +var forEachEnumerableOwnProperty = function(obj: any, callback: any) { for (var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) callback(k); } } // iterates on enumerable properties -var forEachEnumerableProperty = function(obj: Record, callback: (arg:any)=>void) { +var forEachEnumerableProperty = function(obj: any, callback: any) { for (var k in obj) callback(k); } // iterates on properties, even non enumerable and inherited ones // This is dangerous -var forEachProperty = function(obj: Record, callback: (arg:any)=>void, excluded: Record) { +var forEachProperty = function(obj: any, callback: any, excluded: any) { if (obj==null) return; excluded = excluded || {}; Object.getOwnPropertyNames(obj).forEach(function(k){ @@ -57,7 +57,7 @@ function quote(string: any) { } -const jsonPrune = function (value: any, depthDecr: any, arrayMaxLength: number) { +const jsonPrune = function (value: any, depthDecr: any, arrayMaxLength: any) { var prunedString = DEFAULT_PRUNED_VALUE; var replacer: any; if (typeof depthDecr == "object") { From 67c32ed713382d4f05ba210a5e35b771cb4e9392 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 16:58:32 -0700 Subject: [PATCH 06/27] arrow function returns --- src/collector/LogCollectControlBase.ts | 5 ++--- src/collector/LogCollectCypressRequest.ts | 11 ++++++---- src/collector/LogFormat.ts | 2 +- src/installLogsPrinter.ts | 6 +++--- src/jsonPrune.ts | 26 +++++++++++------------ src/utils.ts | 7 ++---- 6 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index c087714..f611781 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -49,9 +49,8 @@ export default abstract class LogCollectControlBase { testTitle += ` (Attempt ${mochaRunnable && (mochaRunnable as any)._currentRetry + 1})` } - const prepareLogs = () => { - return this.prepareLogs(logStackIndex, {mochaRunnable, testState, testTitle, testLevel}); - }; + const prepareLogs = () => + this.prepareLogs(logStackIndex, {mochaRunnable, testState, testTitle, testLevel}); const buildDataMessage = () => ({ spec: spec, diff --git a/src/collector/LogCollectCypressRequest.ts b/src/collector/LogCollectCypressRequest.ts index 1abcea7..4711e40 100644 --- a/src/collector/LogCollectCypressRequest.ts +++ b/src/collector/LogCollectCypressRequest.ts @@ -50,7 +50,8 @@ export default class LogCollectCypressRequest extends LogCollectBase { return errorPart.trim(); }; - Cypress.Commands.overwrite('request', (originalFn: any, ...args: any[]) => { + // @ts-ignore + Cypress.Commands.overwrite('request', (originalFn, ...args) => { if (typeof args === 'object' && args !== null && args[0]['log'] === false){ return originalFn(...args); } @@ -66,7 +67,9 @@ export default class LogCollectCypressRequest extends LogCollectBase { requestBody = args[0].body; requestHeaders = args[0].headers; } else if (isValidHttpMethod(args[0])) { + // @ts-ignore there are more than 1 cy.request types, but .overwrite only infers one. log = `${args[0]} ${args[1]}`; + // @ts-ignore there are more than 1 cy.request types, but .overwrite only infers one. requestBody = args[3]; } else { log = `${args[0]}`; @@ -82,7 +85,8 @@ export default class LogCollectCypressRequest extends LogCollectBase { body: formattedRequestBody, }; - return originalFn(...args).catch(async (e: Error) => { + // cy.request is a Cypress.Chainable, so originalFn doesn't have a "catch" + return ((originalFn(...args) as any as Promise).catch(async (e: Error) => { if (isNetworkError(e)) { log += `\n` + @@ -110,8 +114,7 @@ export default class LogCollectCypressRequest extends LogCollectBase { this.collectorState.addLog([CONSTANTS.LOG_TYPES.CYPRESS_REQUEST, log, CONSTANTS.SEVERITY.ERROR]); throw e; - }) - .then((response: any) => { + }) as any as ReturnType).then((response) => { return Promise.all([ this.format.formatXhrData(response.headers), this.format.formatXhrData(response.body) diff --git a/src/collector/LogFormat.ts b/src/collector/LogFormat.ts index 2ac97a0..ee3b31c 100644 --- a/src/collector/LogFormat.ts +++ b/src/collector/LogFormat.ts @@ -30,7 +30,7 @@ export default class LogFormat { return logMessage.trimEnd(); } - formatXhrData(body: any) { + formatXhrData(body: any): Promise { if (!body) { return Promise.resolve(''); } diff --git a/src/installLogsPrinter.ts b/src/installLogsPrinter.ts index 904c0e8..d667e9f 100755 --- a/src/installLogsPrinter.ts +++ b/src/installLogsPrinter.ts @@ -174,9 +174,9 @@ function installOutputProcessors(on: Cypress.PluginEvents, options: PluginOption const parts = file.split('|'); const root = parts[0]; const ext = parts[1]; - outputProcessors.push(new NestedOutputProcessorDecorator(root, options.specRoot || '', ext, (nestedFile: string) => { - return createProcessorFromType(nestedFile, type); - })); + outputProcessors.push(new NestedOutputProcessorDecorator(root, options.specRoot || '', ext, (nestedFile: string) => + createProcessorFromType(nestedFile, type) + )); } else { outputProcessors.push(createProcessorFromType(file, type)); } diff --git a/src/jsonPrune.ts b/src/jsonPrune.ts index c1dfdd7..119a481 100644 --- a/src/jsonPrune.ts +++ b/src/jsonPrune.ts @@ -1,25 +1,26 @@ // From https://github.com/Canop/JSON.prune/blob/master/JSON.prune.js +// @ts-nocheck - Copied from js file, so don't need to add types. var DEFAULT_MAX_DEPTH = 6; var DEFAULT_ARRAY_MAX_LENGTH = 50; var DEFAULT_PRUNED_VALUE = '"[DepthPruned]"'; var DEFAULT_CIRCULAR_VALUE = '"[Circular]"'; -var seen: any; // Same variable used for all stringifications -var iterator: any; // either forEachEnumerableOwnProperty, forEachEnumerableProperty or forEachProperty +var seen; // Same variable used for all stringifications +var iterator; // either forEachEnumerableOwnProperty, forEachEnumerableProperty or forEachProperty // iterates on enumerable own properties (default behavior) -var forEachEnumerableOwnProperty = function(obj: any, callback: any) { +var forEachEnumerableOwnProperty = function(obj, callback) { for (var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) callback(k); } } // iterates on enumerable properties -var forEachEnumerableProperty = function(obj: any, callback: any) { +var forEachEnumerableProperty = function(obj, callback) { for (var k in obj) callback(k); } // iterates on properties, even non enumerable and inherited ones // This is dangerous -var forEachProperty = function(obj: any, callback: any, excluded: any) { +var forEachProperty = function(obj, callback, excluded) { if (obj==null) return; excluded = excluded || {}; Object.getOwnPropertyNames(obj).forEach(function(k){ @@ -45,10 +46,9 @@ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f '\\': '\\\\' }; -function quote(string: any) { +function quote(string) { escapable.lastIndex = 0; - return escapable.test(string) ? '"' + string.replace(escapable, function (a: any) { - // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c @@ -57,9 +57,9 @@ function quote(string: any) { } -const jsonPrune = function (value: any, depthDecr: any, arrayMaxLength: any) { +const jsonPrune = function (value, depthDecr, arrayMaxLength) { var prunedString = DEFAULT_PRUNED_VALUE; - var replacer: any; + var replacer; if (typeof depthDecr == "object") { var options = depthDecr; depthDecr = options.depthDecr; @@ -79,8 +79,8 @@ const jsonPrune = function (value: any, depthDecr: any, arrayMaxLength: any) { seen = []; depthDecr = depthDecr || DEFAULT_MAX_DEPTH; arrayMaxLength = arrayMaxLength || DEFAULT_ARRAY_MAX_LENGTH; - function str(key: any, holder: any, depthDecr: any) { - var i, k, v, length, partial: any, value = holder[key]; + function str(key, holder, depthDecr) { + var i, k, v, length, partial, value = holder[key]; if (value && typeof value === 'object' && typeof value.toPrunedJSON === 'function') { value = value.toPrunedJSON(key); @@ -123,7 +123,7 @@ const jsonPrune = function (value: any, depthDecr: any, arrayMaxLength: any) { if (value instanceof RegExp) { return quote(value.toString()); } - iterator(value, function(k: any) { + iterator(value, function(k) { try { v = str(k, value, depthDecr-1); if (v) partial.push(quote(k) + ':' + v); diff --git a/src/utils.ts b/src/utils.ts index 31b8b8d..7785b14 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -82,11 +82,8 @@ const utils = { return json; }, - validatorErrToStr: function (errorList: Failure[]) { - return '\n' + errorList.map((error) => { - return ` => ${error.path.join('.')}: ${error.message}`; - }).join('\n') + '\n'; - } + validatorErrToStr: (errorList: Failure[]) => + '\n' + errorList.map((error) => ` => ${error.path.join('.')}: ${error.message}`).join('\n') + '\n' } export default utils; From a2ef92618a4061d7f1f2777cffb10a2e5b68e667 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 19:11:42 -0700 Subject: [PATCH 07/27] attempt fix --- src/collector/LogCollectControlBase.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index f611781..442875a 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -20,11 +20,7 @@ export default abstract class LogCollectControlBase { continuous?: boolean, } = {} ) { - let testState = options.state || mochaRunnable.state; - if (!testState) { - return; - } - + let testState = options.state || mochaRunnable.state as State; let testTitle = options.title || mochaRunnable.title; let testLevel = 0; From ed04a0784fcd58e9d66014a3bc14ff4402370092 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 19:40:33 -0700 Subject: [PATCH 08/27] better types --- index.d.ts | 8 +++----- .../LogCollectCypressBrowserNetwork.ts | 5 ++--- src/installLogsCollector.ts | 18 ++++++++++-------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/index.d.ts b/index.d.ts index 614e34f..b8f05c5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -3,11 +3,9 @@ declare namespace Cypress { interface Cypress { TerminalReport: { - getLogs(format?: T): { - txt: string, - json: string, - none: CtrLog[], - }[T]; + getLogs(format: 'txt'): string | null; + getLogs(format: 'json'): string | null; + getLogs(format?: 'none' = 'none'): CtrLog[] | null; } } } diff --git a/src/collector/LogCollectCypressBrowserNetwork.ts b/src/collector/LogCollectCypressBrowserNetwork.ts index 016d580..78577aa 100644 --- a/src/collector/LogCollectCypressBrowserNetwork.ts +++ b/src/collector/LogCollectCypressBrowserNetwork.ts @@ -75,11 +75,10 @@ export default class LogCollectCypressBrowserNetwork extends LogCollectBase { if (statusCode) { log += `\nStatus: ${statusCode}`; } - if (options.err) { + if (options.err?.message) { if (options.err.message.match(/abort/)) { log += ' - ABORTED'; - } - else if (options.err.message) { + } else { log += ' - ' + options.err.message; } } diff --git a/src/installLogsCollector.ts b/src/installLogsCollector.ts index 56cd7e5..3260714 100755 --- a/src/installLogsCollector.ts +++ b/src/installLogsCollector.ts @@ -70,21 +70,23 @@ function registerLogCollectorTypes(logCollectorState: LogCollectorState, config: } function registerGlobalApi(logCollectorState: LogCollectorState) { - (Cypress as any).TerminalReport = { - getLogs: (format: string) => { + Cypress.TerminalReport = { + //@ts-ignore there is no error, this works correctly. + getLogs: (format = 'none') => { const logs = logCollectorState.getCurrentLogStack(); if (!logs) { return null; } - if (format === 'txt') { - return logsTxtFormatter(logs); - } else if (format === 'json') { - return JSON.stringify(logs, null, 2); + switch (format) { + case "txt": + return logsTxtFormatter(logs); + case "json": + return JSON.stringify(logs, null, 2); + default: + return logs; } - - return logs; }, }; } From 1bcbb077140bd4380c1dc84e1800b91dc041aa37 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 19:58:16 -0700 Subject: [PATCH 09/27] REVERTS --- src/collector/LogCollectBrowserConsole.ts | 2 + src/collector/LogCollectControlBase.ts | 6 +-- src/collector/LogCollectControlExtended.ts | 49 +++++++++---------- src/collector/LogCollectControlSimple.ts | 4 +- .../LogCollectCypressBrowserNetwork.ts | 3 +- src/collector/LogCollectCypressIntercept.ts | 3 ++ src/collector/LogCollectCypressLog.ts | 2 + src/collector/LogCollectCypressRequest.ts | 3 ++ src/installLogsCollector.ts | 8 +-- src/installLogsPrinter.ts | 6 +-- src/utils.ts | 7 ++- 11 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/collector/LogCollectBrowserConsole.ts b/src/collector/LogCollectBrowserConsole.ts index 4eabadc..ea588f7 100644 --- a/src/collector/LogCollectBrowserConsole.ts +++ b/src/collector/LogCollectBrowserConsole.ts @@ -1,5 +1,7 @@ import CONSTANTS from '../constants'; import utils from '../utils'; +import LogCollectorState from "./LogCollectorState"; +import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import type {LogType, Severity} from "../types"; import LogCollectBase from "./LogCollectBase"; diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index 442875a..703121e 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -34,7 +34,7 @@ export default abstract class LogCollectControlBase { { let parent = mochaRunnable.parent; - while (parent?.title) { + while (parent && parent.title) { testTitle = `${parent.title} -> ${testTitle}` parent = parent.parent; ++testLevel; @@ -97,13 +97,13 @@ export default abstract class LogCollectControlBase { let invocationDetails = mochaRunnable.invocationDetails; let parent = mochaRunnable.parent; // always get top-most spec to determine the called .spec file - while (parent?.invocationDetails) { + while (parent && parent.invocationDetails) { invocationDetails = parent.invocationDetails parent = parent.parent; } return parent.file || // Support for cypress-grep. invocationDetails.relativeFile || - invocationDetails.fileUrl?.replace(/^[^?]+\?p=/, ''); + (invocationDetails.fileUrl && invocationDetails.fileUrl?.replace(/^[^?]+\?p=/, '')); } } diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 3beff21..4a8967b 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -2,10 +2,10 @@ import CONSTANTS from '../constants'; import LogCollectControlBase from './LogCollectControlBase'; import utils from "../utils"; import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; -import type {MessageData} from "../types"; +import type { ExtendedSupportOptions } from "../installLogsCollector.types"; +import type { MessageData } from "../types"; -type MochaHook = Mocha.Hook & {hookName:string; _ctr_hook: boolean} +type MochaHook = Mocha.Hook & { hookName: string; _ctr_hook: boolean } /** * Collects and dispatches all logs from all tests and hooks. @@ -41,9 +41,9 @@ export default class LogCollectControlExtended extends LogCollectControlBase { ); } else { // Need to wait for command log update debounce. - cy.wait(wait, {log: false}) + cy.wait(wait, { log: false }) .then(() => { - cy.task(CONSTANTS.TASK_NAME, buildDataMessage(), {log: false}); + cy.task(CONSTANTS.TASK_NAME, buildDataMessage(), { log: false }); }); } } @@ -98,7 +98,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Logs commands from before all hook if the hook passed. // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function(this: any, hook: MochaHook) { + Cypress.mocha.getRunner().on('hook end', function (this: any, hook: MochaHook) { if (hook.hookName === "before all" && self.collectorState.hasLogsInCurrentStack() && !hook._ctr_hook) { self.debugLog('extended: sending logs of passed before all hook'); self.sendLogsToPrinter( @@ -115,7 +115,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs commands from before all hooks that failed. - Cypress.on('before:mocha:hooks:seal', function(this: any) { + Cypress.on('before:mocha:hooks:seal', function (this: any) { self.prependBeforeAllHookInAllSuites(this.mocha.getRootSuite().suites, function ctrAfterAllPerSuite(this: any) { if ( this.test.parent === this.currentTest.parent // Since we have after all in each suite we need this for nested suites case. @@ -160,7 +160,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs after all hook commands when a command fails in the hook. - Cypress.prependListener('fail', function(this: any, error: Error) { + Cypress.prependListener('fail', function (this: any, error: Error) { const currentRunnable = this.mocha.getRunner().currentRunnable; if (currentRunnable.hookName === 'after all' && self.collectorState.hasLogsInCurrentStack()) { @@ -206,31 +206,28 @@ export default class LogCollectControlExtended extends LogCollectControlBase { this.preventNextMochaPassEmit(); } - this.sendLogsToPrinter(this.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); + this.sendLogsToPrinter(this.collectorState.getCurrentLogStackIndex(), test, { noQueue: true }); }; - const testHasAfterEachHooks = (test: Mocha.Runnable) => { - let suite = test.parent - while (suite) { - const _afterEach: any[] = (suite as any)._afterEach - if (_afterEach.length > 0) { + const testHasAfterEachHooks = (test: any) => { + do { + if (test.parent._afterEach.length > 0) { return true; } - suite = suite.parent; - }; + test = test.parent; + } while(test.parent); return false; }; - - const isLastAfterEachHookForTest = (test: Mocha.Runnable, hook: Mocha.Hook) => { + + const isLastAfterEachHookForTest = (test: any, hook: any) => { let suite = test.parent; - while (suite) { - const _afterEach: any[] = (suite as any)._afterEach - if (_afterEach.length === 0) { + do { + if (suite._afterEach.length === 0) { suite = suite.parent; } else { - return _afterEach.indexOf(hook) === _afterEach.length - 1; + return suite._afterEach.indexOf(hook) === suite._afterEach.length - 1; } - }; + } while (suite); return false; }; @@ -267,8 +264,8 @@ export default class LogCollectControlExtended extends LogCollectControlBase { registerLogToFiles() { after(function () { - cy.wait(50, {log: false}); - cy.task(CONSTANTS.TASK_NAME_OUTPUT, null, {log: false}); + cy.wait(50, { log: false }); + cy.task(CONSTANTS.TASK_NAME_OUTPUT, null, { log: false }); }); } @@ -283,7 +280,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const originalRunSuite = runner.runSuite; runner.runSuite = function (...args: any[]) { promise - .catch(() => {/* noop */}) + .catch(() => {/* noop */ }) // We need to wait here as for some reason the next suite title will be displayed to soon. .then(() => new Promise(resolve => setTimeout(resolve, 6))) .then(() => { diff --git a/src/collector/LogCollectControlSimple.ts b/src/collector/LogCollectControlSimple.ts index 46640d4..15c0163 100644 --- a/src/collector/LogCollectControlSimple.ts +++ b/src/collector/LogCollectControlSimple.ts @@ -3,7 +3,7 @@ import LogCollectControlBase from './LogCollectControlBase'; import utils from "../utils"; import type LogCollectorState from "./LogCollectorState"; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; -import type {MessageData} from "../types"; +import type {MessageData, State} from "../types"; /** * Collects and dispatches all logs from all tests and hooks. @@ -75,7 +75,7 @@ export default class LogCollectControlSimple extends LogCollectControlBase { // @ts-ignore Cypress.mocha.getRunner().on('pending', function () { let test = self.collectorState.getCurrentTest(); - if ((test?.state as string) === 'pending') { + if (test && test.state === ('pending' as State)) { // In case of fully skipped tests we might not yet have a log stack. self.collectorState.ensureLogStack(); self.sendLogsToPrinter(self.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); diff --git a/src/collector/LogCollectCypressBrowserNetwork.ts b/src/collector/LogCollectCypressBrowserNetwork.ts index 78577aa..b7a47f9 100644 --- a/src/collector/LogCollectCypressBrowserNetwork.ts +++ b/src/collector/LogCollectCypressBrowserNetwork.ts @@ -1,4 +1,5 @@ import CONSTANTS from '../constants'; +import LogFormat from "./LogFormat"; import LogCollectorState from "./LogCollectorState"; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; @@ -38,7 +39,7 @@ export default class LogCollectCypressBrowserNetwork extends LogCollectBase { register() { // In Cypress 13+ this is under an extra props key const getConsoleProps = (options: Cypress.ObjectLike) => - options.consoleProps?.props || options.consoleProps + options.consoleProps?.props ? options.consoleProps.props : options.consoleProps const formatXhr = (options: Cypress.ObjectLike, props: Cypress.ObjectLike) => (options.alias !== undefined ? '(' + options.alias + ') ' : '') + diff --git a/src/collector/LogCollectCypressIntercept.ts b/src/collector/LogCollectCypressIntercept.ts index 6141167..c2396f2 100644 --- a/src/collector/LogCollectCypressIntercept.ts +++ b/src/collector/LogCollectCypressIntercept.ts @@ -1,4 +1,7 @@ import CONSTANTS from '../constants'; +import LogFormat from "./LogFormat"; +import LogCollectorState from "./LogCollectorState"; +import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; Object.defineProperty(RegExp.prototype, "toJSON", { diff --git a/src/collector/LogCollectCypressLog.ts b/src/collector/LogCollectCypressLog.ts index 7d99fd0..d607e4b 100644 --- a/src/collector/LogCollectCypressLog.ts +++ b/src/collector/LogCollectCypressLog.ts @@ -1,4 +1,6 @@ import CONSTANTS from '../constants'; +import LogCollectorState from "./LogCollectorState"; +import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; export default class LogCollectCypressLog extends LogCollectBase { diff --git a/src/collector/LogCollectCypressRequest.ts b/src/collector/LogCollectCypressRequest.ts index 4711e40..338a296 100644 --- a/src/collector/LogCollectCypressRequest.ts +++ b/src/collector/LogCollectCypressRequest.ts @@ -1,4 +1,7 @@ import CONSTANTS from '../constants'; +import LogFormat from "./LogFormat"; +import LogCollectorState from "./LogCollectorState"; +import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; export default class LogCollectCypressRequest extends LogCollectBase { diff --git a/src/installLogsCollector.ts b/src/installLogsCollector.ts index 3260714..412092a 100755 --- a/src/installLogsCollector.ts +++ b/src/installLogsCollector.ts @@ -25,10 +25,10 @@ function installLogsCollector(config: SupportOptions = {}) { const extendedConfig: ExtendedSupportOptions = { ...config, - collectTypes: config.collectTypes || Object.values(CONSTANTS.LOG_TYPES) as LogType[], - collectBody: config.xhr?.printBody ?? true, - collectRequestData: config.xhr?.printRequestData, - collectHeaderData: config.xhr?.printHeaderData, + collectTypes: config.collectTypes || Object.values(CONSTANTS.LOG_TYPES), + collectBody: config.xhr && config.xhr.printBody !== undefined ? config.xhr.printBody : true, + collectRequestData: config.xhr && config.xhr.printRequestData, + collectHeaderData: config.xhr && config.xhr.printHeaderData, }; let logCollectorState = new LogCollectorState(extendedConfig); diff --git a/src/installLogsPrinter.ts b/src/installLogsPrinter.ts index d667e9f..904c0e8 100755 --- a/src/installLogsPrinter.ts +++ b/src/installLogsPrinter.ts @@ -174,9 +174,9 @@ function installOutputProcessors(on: Cypress.PluginEvents, options: PluginOption const parts = file.split('|'); const root = parts[0]; const ext = parts[1]; - outputProcessors.push(new NestedOutputProcessorDecorator(root, options.specRoot || '', ext, (nestedFile: string) => - createProcessorFromType(nestedFile, type) - )); + outputProcessors.push(new NestedOutputProcessorDecorator(root, options.specRoot || '', ext, (nestedFile: string) => { + return createProcessorFromType(nestedFile, type); + })); } else { outputProcessors.push(createProcessorFromType(file, type)); } diff --git a/src/utils.ts b/src/utils.ts index 7785b14..31b8b8d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -82,8 +82,11 @@ const utils = { return json; }, - validatorErrToStr: (errorList: Failure[]) => - '\n' + errorList.map((error) => ` => ${error.path.join('.')}: ${error.message}`).join('\n') + '\n' + validatorErrToStr: function (errorList: Failure[]) { + return '\n' + errorList.map((error) => { + return ` => ${error.path.join('.')}: ${error.message}`; + }).join('\n') + '\n'; + } } export default utils; From 0751727c8d5977700b0f93b0c38542daec7ab02a Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 20:04:55 -0700 Subject: [PATCH 10/27] style: whitespace --- src/collector/LogCollectControlExtended.ts | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 4a8967b..64266b3 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -2,10 +2,10 @@ import CONSTANTS from '../constants'; import LogCollectControlBase from './LogCollectControlBase'; import utils from "../utils"; import LogCollectorState from "./LogCollectorState"; -import type { ExtendedSupportOptions } from "../installLogsCollector.types"; -import type { MessageData } from "../types"; +import type {ExtendedSupportOptions} from "../installLogsCollector.types"; +import type {MessageData} from "../types"; -type MochaHook = Mocha.Hook & { hookName: string; _ctr_hook: boolean } +type MochaHook = Mocha.Hook & {hookName: string; _ctr_hook: boolean} /** * Collects and dispatches all logs from all tests and hooks. @@ -41,9 +41,9 @@ export default class LogCollectControlExtended extends LogCollectControlBase { ); } else { // Need to wait for command log update debounce. - cy.wait(wait, { log: false }) + cy.wait(wait, {log: false}) .then(() => { - cy.task(CONSTANTS.TASK_NAME, buildDataMessage(), { log: false }); + cy.task(CONSTANTS.TASK_NAME, buildDataMessage(), {log: false}); }); } } @@ -98,7 +98,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Logs commands from before all hook if the hook passed. // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function (this: any, hook: MochaHook) { + Cypress.mocha.getRunner().on('hook end', function(this: any, hook: MochaHook) { if (hook.hookName === "before all" && self.collectorState.hasLogsInCurrentStack() && !hook._ctr_hook) { self.debugLog('extended: sending logs of passed before all hook'); self.sendLogsToPrinter( @@ -115,7 +115,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs commands from before all hooks that failed. - Cypress.on('before:mocha:hooks:seal', function (this: any) { + Cypress.on('before:mocha:hooks:seal', function(this: any) { self.prependBeforeAllHookInAllSuites(this.mocha.getRootSuite().suites, function ctrAfterAllPerSuite(this: any) { if ( this.test.parent === this.currentTest.parent // Since we have after all in each suite we need this for nested suites case. @@ -160,7 +160,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs after all hook commands when a command fails in the hook. - Cypress.prependListener('fail', function (this: any, error: Error) { + Cypress.prependListener('fail', function(this: any, error: Error) { const currentRunnable = this.mocha.getRunner().currentRunnable; if (currentRunnable.hookName === 'after all' && self.collectorState.hasLogsInCurrentStack()) { @@ -206,7 +206,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { this.preventNextMochaPassEmit(); } - this.sendLogsToPrinter(this.collectorState.getCurrentLogStackIndex(), test, { noQueue: true }); + this.sendLogsToPrinter(this.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); }; const testHasAfterEachHooks = (test: any) => { @@ -218,7 +218,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { } while(test.parent); return false; }; - + const isLastAfterEachHookForTest = (test: any, hook: any) => { let suite = test.parent; do { @@ -264,8 +264,8 @@ export default class LogCollectControlExtended extends LogCollectControlBase { registerLogToFiles() { after(function () { - cy.wait(50, { log: false }); - cy.task(CONSTANTS.TASK_NAME_OUTPUT, null, { log: false }); + cy.wait(50, {log: false}); + cy.task(CONSTANTS.TASK_NAME_OUTPUT, null, {log: false}); }); } @@ -280,7 +280,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const originalRunSuite = runner.runSuite; runner.runSuite = function (...args: any[]) { promise - .catch(() => {/* noop */ }) + .catch(() => {/* noop */}) // We need to wait here as for some reason the next suite title will be displayed to soon. .then(() => new Promise(resolve => setTimeout(resolve, 6))) .then(() => { From 7aefc55bb25a7a7de5130312c2d82b8cb51db3d6 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 20:08:17 -0700 Subject: [PATCH 11/27] add some back --- src/collector/LogCollectControlBase.ts | 9 ++++----- src/installLogsPrinter.ts | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index 703121e..54244f1 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -20,15 +20,14 @@ export default abstract class LogCollectControlBase { continuous?: boolean, } = {} ) { - let testState = options.state || mochaRunnable.state as State; + let testState = options.state || mochaRunnable.state; + if (!testState) return; + let testTitle = options.title || mochaRunnable.title; let testLevel = 0; let spec = this.getSpecFilePath(mochaRunnable); - - if (!spec) { - return; - } + if (!spec) return; let wait = typeof options.wait === 'number' ? options.wait : 5; diff --git a/src/installLogsPrinter.ts b/src/installLogsPrinter.ts index 904c0e8..2e51085 100755 --- a/src/installLogsPrinter.ts +++ b/src/installLogsPrinter.ts @@ -174,9 +174,9 @@ function installOutputProcessors(on: Cypress.PluginEvents, options: PluginOption const parts = file.split('|'); const root = parts[0]; const ext = parts[1]; - outputProcessors.push(new NestedOutputProcessorDecorator(root, options.specRoot || '', ext, (nestedFile: string) => { - return createProcessorFromType(nestedFile, type); - })); + outputProcessors.push(new NestedOutputProcessorDecorator(root, options.specRoot || '', ext, (nestedFile: string) => + createProcessorFromType(nestedFile, type) + )); } else { outputProcessors.push(createProcessorFromType(file, type)); } From 07a9d5ce3e1065eb8a11e59bd31ac964c1e0a3b6 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 20:15:41 -0700 Subject: [PATCH 12/27] attempt fix --- src/collector/LogCollectControlBase.ts | 5 ++--- src/types.ts | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index 54244f1..91e2b5d 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -1,7 +1,7 @@ import CtrError from '../CtrError'; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectorState from "./LogCollectorState"; -import type {MessageData, State, TestData} from "../types"; +import type {MessageData, SetOptional, State, TestData} from "../types"; export default abstract class LogCollectControlBase { protected abstract collectorState: LogCollectorState; @@ -21,7 +21,6 @@ export default abstract class LogCollectControlBase { } = {} ) { let testState = options.state || mochaRunnable.state; - if (!testState) return; let testTitle = options.title || mochaRunnable.title; let testLevel = 0; @@ -61,7 +60,7 @@ export default abstract class LogCollectControlBase { this.triggerSendTask(buildDataMessage, options.noQueue || false, wait); } - protected abstract triggerSendTask(buildDataMessage: (continuous?: boolean) => MessageData, noQueue: boolean, wait: number): void; + protected abstract triggerSendTask(buildDataMessage: (continuous?: boolean) => SetOptional, noQueue: boolean, wait: number): void; prepareLogs(logStackIndex: number, testData: TestData) { let logsCopy = this.collectorState.consumeLogStacks(logStackIndex); diff --git a/src/types.ts b/src/types.ts index 7d44f70..ed5131e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,16 @@ import CONSTANTS from "./constants"; -type ValueOf = T[keyof T]; +// ***************************************************************************** +// Type operations +// ***************************************************************************** + +export type ValueOf = T[keyof T]; + +export type SetOptional = Omit & Partial>; + +// ***************************************************************************** +// String unions +// ***************************************************************************** export type Severity = ValueOf @@ -17,6 +27,10 @@ export type State = ValueOf export type CommandTimings = ValueOf +// ***************************************************************************** +// Objects +// ***************************************************************************** + export type Log = { type: LogType, message: string, From 714d0e68c5e302a4809f3f506727f31550efe900 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 20:36:38 -0700 Subject: [PATCH 13/27] undo some reverts --- index.d.ts | 2 ++ src/collector/LogCollectBrowserConsole.ts | 6 ++-- src/collector/LogCollectControlBase.ts | 4 +-- src/collector/LogCollectControlExtended.ts | 34 ++++++++++++---------- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/index.d.ts b/index.d.ts index b8f05c5..685fa5a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,5 +7,7 @@ declare namespace Cypress { getLogs(format: 'json'): string | null; getLogs(format?: 'none' = 'none'): CtrLog[] | null; } + + onSpecReady(...args: any[]): void; } } diff --git a/src/collector/LogCollectBrowserConsole.ts b/src/collector/LogCollectBrowserConsole.ts index ea588f7..01e829c 100644 --- a/src/collector/LogCollectBrowserConsole.ts +++ b/src/collector/LogCollectBrowserConsole.ts @@ -17,13 +17,13 @@ export default class LogCollectBrowserConsole extends LogCollectBase { Cypress.on(event, () => { const docIframe = (window.parent.document.querySelector("[id*='Your project: ']") || window.parent.document.querySelector("[id*='Your App']")) as HTMLIFrameElement; - const appWindow = docIframe.contentWindow as Window & typeof globalThis; + const appWindow = docIframe.contentWindow as Window & typeof globalThis & {_ctr_registered: boolean}; // In case of component tests the even will be called multiple times. Prevent registering multiple times. - if (!appWindow || (appWindow as any)._ctr_registered) { + if (!appWindow || appWindow._ctr_registered) { return; } - (appWindow as any)._ctr_registered = true; + appWindow._ctr_registered = true; const stringableTypes = ['string', 'number', 'undefined', 'function']; const processArg = (arg: any) => { diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index 91e2b5d..e61f405 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -39,8 +39,8 @@ export default abstract class LogCollectControlBase { } } - if (testState === 'failed' && mochaRunnable && (mochaRunnable as any)._retries > 0) { - testTitle += ` (Attempt ${mochaRunnable && (mochaRunnable as any)._currentRetry + 1})` + if (testState === 'failed' && mochaRunnable && mochaRunnable["_retries"] > 0) { + testTitle += ` (Attempt ${mochaRunnable && mochaRunnable["_currentRetry"] + 1})` } const prepareLogs = () => diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 64266b3..39ec6ea 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -209,25 +209,27 @@ export default class LogCollectControlExtended extends LogCollectControlBase { this.sendLogsToPrinter(this.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); }; - const testHasAfterEachHooks = (test: any) => { - do { - if (test.parent._afterEach.length > 0) { + const testHasAfterEachHooks = (test: Mocha.Runnable) => { + let suite = test.parent + while (suite) { + const _afterEach: any[] = suite['_afterEach'] + if (_afterEach.length > 0) { return true; } - test = test.parent; - } while(test.parent); + suite = suite.parent; + }; return false; }; - const isLastAfterEachHookForTest = (test: any, hook: any) => { + const isLastAfterEachHookForTest = (test: Mocha.Runnable, hook: Mocha.Hook) => { let suite = test.parent; - do { - if (suite._afterEach.length === 0) { - suite = suite.parent; - } else { - return suite._afterEach.indexOf(hook) === suite._afterEach.length - 1; + while (suite) { + const _afterEach: any[] = suite['_afterEach'] + if (_afterEach.length > 0) { + return _afterEach.indexOf(hook) === _afterEach.length - 1; } - } while (suite); + suite = suite.parent; + }; return false; }; @@ -294,8 +296,8 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Hack to have dynamic after hook per suite. // The onSpecReady in cypress is called before the hooks are 'condensed', or so // to say sealed and thus in this phase we can register dynamically hooks. - const oldOnSpecReady = (Cypress as any).onSpecReady; - (Cypress as any).onSpecReady = function () { + const oldOnSpecReady = Cypress.onSpecReady; + Cypress.onSpecReady = function () { Cypress.emit('before:mocha:hooks:seal'); oldOnSpecReady(...arguments); }; @@ -311,8 +313,8 @@ export default class LogCollectControlExtended extends LogCollectControlBase { suite.afterAll(hookCallback); // Make sure our hook is first so that other after all hook logs come after // the failed before all hooks logs. - const hook = (suite as any)._afterAll.pop(); - (suite as any)._afterAll.unshift(hook); + const hook = suite["_afterAll"].pop(); + suite["_afterAll"].unshift(hook); // Don't count this in the hook index and logs. hook._ctr_hook = true; From 690a8b10d2349703202bfdf584857ec583c1728e Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 20:56:52 -0700 Subject: [PATCH 14/27] revert all, improve types --- index.d.ts | 15 ++++++++ src/collector/LogCollectBrowserConsole.ts | 2 - src/collector/LogCollectControlBase.ts | 6 +-- src/collector/LogCollectControlExtended.ts | 38 +++++++------------ src/collector/LogCollectControlSimple.ts | 7 +--- .../LogCollectCypressBrowserNetwork.ts | 3 +- src/collector/LogCollectCypressIntercept.ts | 3 -- src/collector/LogCollectCypressLog.ts | 2 - src/collector/LogCollectCypressRequest.ts | 3 -- src/collector/LogCollectorState.ts | 2 +- src/installLogsCollector.ts | 6 +-- src/utils.ts | 9 ++--- 12 files changed, 42 insertions(+), 54 deletions(-) diff --git a/index.d.ts b/index.d.ts index 685fa5a..40406a8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -9,5 +9,20 @@ declare namespace Cypress { } onSpecReady(...args: any[]): void; + + mocha: { + getRunner(): Mocha.Runner + } + } +} + +declare namespace Mocha { + interface Hook { + hookName: string + _ctr_hook: boolean + } + + interface Runnable { + hookName: string } } diff --git a/src/collector/LogCollectBrowserConsole.ts b/src/collector/LogCollectBrowserConsole.ts index 01e829c..86ddefc 100644 --- a/src/collector/LogCollectBrowserConsole.ts +++ b/src/collector/LogCollectBrowserConsole.ts @@ -1,7 +1,5 @@ import CONSTANTS from '../constants'; import utils from '../utils'; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import type {LogType, Severity} from "../types"; import LogCollectBase from "./LogCollectBase"; diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index e61f405..514bb6f 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -32,7 +32,7 @@ export default abstract class LogCollectControlBase { { let parent = mochaRunnable.parent; - while (parent && parent.title) { + while (parent?.title) { testTitle = `${parent.title} -> ${testTitle}` parent = parent.parent; ++testLevel; @@ -95,13 +95,13 @@ export default abstract class LogCollectControlBase { let invocationDetails = mochaRunnable.invocationDetails; let parent = mochaRunnable.parent; // always get top-most spec to determine the called .spec file - while (parent && parent.invocationDetails) { + while (parent?.invocationDetails) { invocationDetails = parent.invocationDetails parent = parent.parent; } return parent.file || // Support for cypress-grep. invocationDetails.relativeFile || - (invocationDetails.fileUrl && invocationDetails.fileUrl?.replace(/^[^?]+\?p=/, '')); + invocationDetails.fileUrl?.replace(/^[^?]+\?p=/, ''); } } diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 39ec6ea..3367c1c 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -5,8 +5,6 @@ import LogCollectorState from "./LogCollectorState"; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import type {MessageData} from "../types"; -type MochaHook = Mocha.Hook & {hookName: string; _ctr_hook: boolean} - /** * Collects and dispatches all logs from all tests and hooks. */ @@ -56,22 +54,18 @@ export default class LogCollectControlExtended extends LogCollectControlBase { this.collectorState.updateLogStatus(options.id); } }); - // @ts-ignore - Cypress.mocha.getRunner().on('test', (test: Mocha.Runnable) => { + Cypress.mocha.getRunner().on('test', (test) => { this.collectorState.startTest(test); }); - // @ts-ignore Cypress.mocha.getRunner().on('suite', () => { this.collectorState.startSuite(); }); - // @ts-ignore Cypress.mocha.getRunner().on('suite end', () => { this.collectorState.endSuite(); }); // Keeps track of before and after all hook indexes. - // @ts-ignore - Cypress.mocha.getRunner().on('hook', function (hook: MochaHook) { + Cypress.mocha.getRunner().on('hook', function (hook) { // @ts-ignore if (!hook._ctr_hook && !hook.fn._ctr_hook) { // After each hooks get merged with the test. @@ -97,13 +91,12 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const self = this; // Logs commands from before all hook if the hook passed. - // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function(this: any, hook: MochaHook) { + Cypress.mocha.getRunner().on('hook end', function(this: Mocha.Runner, hook) { if (hook.hookName === "before all" && self.collectorState.hasLogsInCurrentStack() && !hook._ctr_hook) { self.debugLog('extended: sending logs of passed before all hook'); self.sendLogsToPrinter( self.collectorState.getCurrentLogStackIndex(), - this.currentRunnable, + this.currentRunnable!, { state: 'passed', isHook: true, @@ -141,8 +134,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const self = this; // Logs commands from after all hooks that passed. - // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function (hook: MochaHook) { + Cypress.mocha.getRunner().on('hook end', function (hook) { if (hook.hookName === "after all" && self.collectorState.hasLogsInCurrentStack() && !hook._ctr_hook) { self.debugLog('extended: sending logs of passed after all hook'); self.sendLogsToPrinter( @@ -160,8 +152,8 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs after all hook commands when a command fails in the hook. - Cypress.prependListener('fail', function(this: any, error: Error) { - const currentRunnable = this.mocha.getRunner().currentRunnable; + Cypress.prependListener('fail', function(this: Cypress.Cypress, error: Error) { + const currentRunnable = this.mocha.getRunner().currentRunnable!; if (currentRunnable.hookName === 'after all' && self.collectorState.hasLogsInCurrentStack()) { // We only have the full list of commands when the suite ends. @@ -234,8 +226,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }; // Logs commands form each separate test when after each hooks are present. - // @ts-ignore - Cypress.mocha.getRunner().on('hook end', function (hook: MochaHook) { + Cypress.mocha.getRunner().on('hook end', function (hook) { if (hook.hookName === 'after each') { if (isLastAfterEachHookForTest(self.collectorState.getCurrentTest(), hook)) { self.debugLog('extended: sending logs for ended test, just after the last after each hook: ' + self.collectorState.getCurrentTest().title); @@ -244,16 +235,14 @@ export default class LogCollectControlExtended extends LogCollectControlBase { } }); // Logs commands form each separate test when there is no after each hook. - // @ts-ignore - Cypress.mocha.getRunner().on('test end', function (test: Mocha.Runnable) { + Cypress.mocha.getRunner().on('test end', function (test) { if (!testHasAfterEachHooks(test)) { self.debugLog('extended: sending logs for ended test, that has not after each hooks: ' + self.collectorState.getCurrentTest().title); sendLogsToPrinterForATest(self.collectorState.getCurrentTest()); } }); // Logs commands if test was manually skipped. - // @ts-ignore - Cypress.mocha.getRunner().on('pending', function (test: Mocha.Runnable) { + Cypress.mocha.getRunner().on('pending', function (test) { if (self.collectorState.getCurrentTest() === test) { // In case of fully skipped tests we might not yet have a log stack. if (self.collectorState.hasLogsInCurrentStack()) { @@ -272,22 +261,21 @@ export default class LogCollectControlExtended extends LogCollectControlBase { } debounceNextMochaSuite(promise: Promise) { - // @ts-ignore const runner = Cypress.mocha.getRunner(); // Hack to make mocha wait for our logs to be written to console before // going to the next suite. This is because 'fail' and 'suite begin' both // fire synchronously and thus we wouldn't get a window to display the // logs between the failed hook title and next suite title. - const originalRunSuite = runner.runSuite; - runner.runSuite = function (...args: any[]) { + const originalRunSuite = runner['runSuite']; + runner['runSuite'] = function (...args: Parameters) { promise .catch(() => {/* noop */}) // We need to wait here as for some reason the next suite title will be displayed to soon. .then(() => new Promise(resolve => setTimeout(resolve, 6))) .then(() => { originalRunSuite.apply(runner, args); - runner.runSuite = originalRunSuite; + runner['runSuite'] = originalRunSuite; }); } } diff --git a/src/collector/LogCollectControlSimple.ts b/src/collector/LogCollectControlSimple.ts index 15c0163..8652afe 100644 --- a/src/collector/LogCollectControlSimple.ts +++ b/src/collector/LogCollectControlSimple.ts @@ -48,17 +48,14 @@ export default class LogCollectControlSimple extends LogCollectControlBase { } }); - // @ts-ignore - Cypress.mocha.getRunner().on('test', (test: Mocha.Runnable) => { + Cypress.mocha.getRunner().on('test', (test) => { this.collectorState.startTest(test); }); - // @ts-ignore Cypress.mocha.getRunner().on('suite', () => { this.collectorState.startSuite(); }); - // @ts-ignore Cypress.mocha.getRunner().on('suite end', () => { this.collectorState.endSuite(); }); @@ -75,7 +72,7 @@ export default class LogCollectControlSimple extends LogCollectControlBase { // @ts-ignore Cypress.mocha.getRunner().on('pending', function () { let test = self.collectorState.getCurrentTest(); - if (test && test.state === ('pending' as State)) { + if (test?.state === ('pending' as State)) { // In case of fully skipped tests we might not yet have a log stack. self.collectorState.ensureLogStack(); self.sendLogsToPrinter(self.collectorState.getCurrentLogStackIndex(), test, {noQueue: true}); diff --git a/src/collector/LogCollectCypressBrowserNetwork.ts b/src/collector/LogCollectCypressBrowserNetwork.ts index b7a47f9..78577aa 100644 --- a/src/collector/LogCollectCypressBrowserNetwork.ts +++ b/src/collector/LogCollectCypressBrowserNetwork.ts @@ -1,5 +1,4 @@ import CONSTANTS from '../constants'; -import LogFormat from "./LogFormat"; import LogCollectorState from "./LogCollectorState"; import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; @@ -39,7 +38,7 @@ export default class LogCollectCypressBrowserNetwork extends LogCollectBase { register() { // In Cypress 13+ this is under an extra props key const getConsoleProps = (options: Cypress.ObjectLike) => - options.consoleProps?.props ? options.consoleProps.props : options.consoleProps + options.consoleProps?.props || options.consoleProps const formatXhr = (options: Cypress.ObjectLike, props: Cypress.ObjectLike) => (options.alias !== undefined ? '(' + options.alias + ') ' : '') + diff --git a/src/collector/LogCollectCypressIntercept.ts b/src/collector/LogCollectCypressIntercept.ts index c2396f2..6141167 100644 --- a/src/collector/LogCollectCypressIntercept.ts +++ b/src/collector/LogCollectCypressIntercept.ts @@ -1,7 +1,4 @@ import CONSTANTS from '../constants'; -import LogFormat from "./LogFormat"; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; Object.defineProperty(RegExp.prototype, "toJSON", { diff --git a/src/collector/LogCollectCypressLog.ts b/src/collector/LogCollectCypressLog.ts index d607e4b..7d99fd0 100644 --- a/src/collector/LogCollectCypressLog.ts +++ b/src/collector/LogCollectCypressLog.ts @@ -1,6 +1,4 @@ import CONSTANTS from '../constants'; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; export default class LogCollectCypressLog extends LogCollectBase { diff --git a/src/collector/LogCollectCypressRequest.ts b/src/collector/LogCollectCypressRequest.ts index 338a296..4711e40 100644 --- a/src/collector/LogCollectCypressRequest.ts +++ b/src/collector/LogCollectCypressRequest.ts @@ -1,7 +1,4 @@ import CONSTANTS from '../constants'; -import LogFormat from "./LogFormat"; -import LogCollectorState from "./LogCollectorState"; -import type {ExtendedSupportOptions} from "../installLogsCollector.types"; import LogCollectBase from "./LogCollectBase"; export default class LogCollectCypressRequest extends LogCollectBase { diff --git a/src/collector/LogCollectorState.ts b/src/collector/LogCollectorState.ts index dd55003..8c3f631 100644 --- a/src/collector/LogCollectorState.ts +++ b/src/collector/LogCollectorState.ts @@ -191,7 +191,7 @@ export default class LogCollectorState extends EventTarget { this.afterHookIndexes.shift(); } - startTest(test: Mocha.Runnable) { + startTest(test: Mocha.Test) { if (this.config.debug) { console.log(CONSTANTS.DEBUG_LOG_PREFIX + 'starting test: ' + test.title); } diff --git a/src/installLogsCollector.ts b/src/installLogsCollector.ts index 412092a..59c3858 100755 --- a/src/installLogsCollector.ts +++ b/src/installLogsCollector.ts @@ -26,9 +26,9 @@ function installLogsCollector(config: SupportOptions = {}) { const extendedConfig: ExtendedSupportOptions = { ...config, collectTypes: config.collectTypes || Object.values(CONSTANTS.LOG_TYPES), - collectBody: config.xhr && config.xhr.printBody !== undefined ? config.xhr.printBody : true, - collectRequestData: config.xhr && config.xhr.printRequestData, - collectHeaderData: config.xhr && config.xhr.printHeaderData, + collectBody: config.xhr?.printBody ?? true, + collectRequestData: config.xhr?.printRequestData, + collectHeaderData: config.xhr?.printHeaderData, }; let logCollectorState = new LogCollectorState(extendedConfig); diff --git a/src/utils.ts b/src/utils.ts index 31b8b8d..67e864d 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -82,11 +82,10 @@ const utils = { return json; }, - validatorErrToStr: function (errorList: Failure[]) { - return '\n' + errorList.map((error) => { - return ` => ${error.path.join('.')}: ${error.message}`; - }).join('\n') + '\n'; - } + validatorErrToStr: (errorList: Failure[]) => + '\n' + + errorList.map((error) => ` => ${error.path.join('.')}: ${error.message}`).join('\n') + + '\n' } export default utils; From 6d138c9e08f8da20ea9ae2489d7297f10387cf55 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 21:13:54 -0700 Subject: [PATCH 15/27] add more types --- index.d.ts | 28 ++++++++++++++++++++-- src/collector/LogCollectControlBase.ts | 11 ++++----- src/collector/LogCollectControlExtended.ts | 14 +++++------ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/index.d.ts b/index.d.ts index 40406a8..6125cd6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,22 +1,33 @@ +/** + * This file used for adding types to package interfaces that are not included + * in the package's types. + */ + declare namespace Cypress { - import {Log as CtrLog} from "./src/installLogsCollector"; + import { Log } from "./src/installLogsCollector"; interface Cypress { TerminalReport: { getLogs(format: 'txt'): string | null; getLogs(format: 'json'): string | null; - getLogs(format?: 'none' = 'none'): CtrLog[] | null; + getLogs(format?: 'none' = 'none'): Log[] | null; } onSpecReady(...args: any[]): void; mocha: { getRunner(): Mocha.Runner + getRootSuite(): Mocha.Suite } } } declare namespace Mocha { + interface InvocationDetails { + relativeFile?: string + fileUrl?: string + } + interface Hook { hookName: string _ctr_hook: boolean @@ -24,5 +35,18 @@ declare namespace Mocha { interface Runnable { hookName: string + invocationDetails: InvocationDetails + id: string + order: unknown + wallClockStartedAt: unknown + timings: unknown + } + + interface Suite { + invocationDetails: InvocationDetails + } + + interface Test { + failedFromHookId?: unknown } } diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index 514bb6f..a8a7b8c 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -84,12 +84,9 @@ export default abstract class LogCollectControlBase { return logsCopy; } - getSpecFilePath(mochaRunnable: any) { - if (!mochaRunnable.invocationDetails && !mochaRunnable.parent.invocationDetails) { - if (mochaRunnable.parent.file) { - return mochaRunnable.parent.file; - } - return null; + getSpecFilePath(mochaRunnable: Mocha.Runnable) { + if (!mochaRunnable.invocationDetails && !mochaRunnable.parent?.invocationDetails) { + return mochaRunnable.parent?.file ?? null; } let invocationDetails = mochaRunnable.invocationDetails; @@ -100,7 +97,7 @@ export default abstract class LogCollectControlBase { parent = parent.parent; } - return parent.file || // Support for cypress-grep. + return parent?.file || // Support for cypress-grep. invocationDetails.relativeFile || invocationDetails.fileUrl?.replace(/^[^?]+\?p=/, ''); } diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 3367c1c..e30ab5f 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -108,11 +108,11 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }); // Logs commands from before all hooks that failed. - Cypress.on('before:mocha:hooks:seal', function(this: any) { - self.prependBeforeAllHookInAllSuites(this.mocha.getRootSuite().suites, function ctrAfterAllPerSuite(this: any) { + Cypress.on('before:mocha:hooks:seal', function(this: Cypress.Cypress) { + self.prependBeforeAllHookInAllSuites(this.mocha.getRootSuite().suites, function ctrAfterAllPerSuite(this: Mocha.Context) { if ( - this.test.parent === this.currentTest.parent // Since we have after all in each suite we need this for nested suites case. - && this.currentTest.failedFromHookId // This is how we know a hook failed the suite. + this.test?.parent === this.currentTest?.parent // Since we have after all in each suite we need this for nested suites case. + && this.currentTest?.failedFromHookId // This is how we know a hook failed the suite. && self.collectorState.hasLogsInCurrentStack() ) { self.debugLog('extended: sending logs of failed before all hook'); @@ -291,7 +291,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { }; } - prependBeforeAllHookInAllSuites(rootSuites: Mocha.Suite[], hookCallback: (this: any) => void) { + prependBeforeAllHookInAllSuites(rootSuites: Mocha.Suite[], hookCallback: Mocha.Func) { const recursiveSuites = (suites: Mocha.Suite[]) => { if (suites) { suites.forEach((suite) => { @@ -313,7 +313,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { recursiveSuites(rootSuites); } - printPassingMochaTestTitle(test: any) { + printPassingMochaTestTitle(test: Mocha.Runnable) { if (Cypress.config('isTextTerminal')) { Cypress.emit('mocha', 'pass', { "id": test.id, @@ -327,7 +327,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { "file": null, "invocationDetails": test.invocationDetails, "final": true, - "currentRetry": test.currentRetry(), + "currentRetry": test["currentRetry"](), "retries": test.retries(), }) } From b22b7f17700120068097d1284fa8e10c94e7e88f Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 21:17:55 -0700 Subject: [PATCH 16/27] whitespace --- src/collector/LogCollectControlBase.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/collector/LogCollectControlBase.ts b/src/collector/LogCollectControlBase.ts index a8a7b8c..3b609d6 100644 --- a/src/collector/LogCollectControlBase.ts +++ b/src/collector/LogCollectControlBase.ts @@ -21,7 +21,6 @@ export default abstract class LogCollectControlBase { } = {} ) { let testState = options.state || mochaRunnable.state; - let testTitle = options.title || mochaRunnable.title; let testLevel = 0; From 67694d5c87186f456a77b937b2a2e91b0e0d610d Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 21:20:33 -0700 Subject: [PATCH 17/27] remove type --- src/collector/LogCollectControlExtended.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index e30ab5f..0896dc0 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -268,7 +268,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // fire synchronously and thus we wouldn't get a window to display the // logs between the failed hook title and next suite title. const originalRunSuite = runner['runSuite']; - runner['runSuite'] = function (...args: Parameters) { + runner['runSuite'] = function (...args) { promise .catch(() => {/* noop */}) // We need to wait here as for some reason the next suite title will be displayed to soon. From 954dfa9f97bbe92c868118ce27d23310cab24587 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 21:34:46 -0700 Subject: [PATCH 18/27] more typings --- index.d.ts | 10 +++-- src/collector/LogCollectCypressRequest.ts | 50 +++++++++++------------ 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/index.d.ts b/index.d.ts index 6125cd6..c4fb115 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,10 +1,10 @@ /** - * This file used for adding types to package interfaces that are not included - * in the package's types. + * This file used for adding types to package interfaces that are not documented + * by the package (not included in the package's types). */ declare namespace Cypress { - import { Log } from "./src/installLogsCollector"; + import {Log} from "./src/installLogsCollector"; interface Cypress { TerminalReport: { @@ -20,6 +20,10 @@ declare namespace Cypress { getRootSuite(): Mocha.Suite } } + + interface Chainable { + catch: Promise['catch'] + } } declare namespace Mocha { diff --git a/src/collector/LogCollectCypressRequest.ts b/src/collector/LogCollectCypressRequest.ts index 4711e40..0f36e93 100644 --- a/src/collector/LogCollectCypressRequest.ts +++ b/src/collector/LogCollectCypressRequest.ts @@ -50,9 +50,8 @@ export default class LogCollectCypressRequest extends LogCollectBase { return errorPart.trim(); }; - // @ts-ignore Cypress.Commands.overwrite('request', (originalFn, ...args) => { - if (typeof args === 'object' && args !== null && args[0]['log'] === false){ + if (typeof args === 'object' && args !== null && args[0]['log'] === false) { return originalFn(...args); } @@ -84,9 +83,8 @@ export default class LogCollectCypressRequest extends LogCollectBase { headers: formattedRequestHeaders, body: formattedRequestBody, }; - - // cy.request is a Cypress.Chainable, so originalFn doesn't have a "catch" - return ((originalFn(...args) as any as Promise).catch(async (e: Error) => { + + return originalFn(...args).catch(async (e: Error) => { if (isNetworkError(e)) { log += `\n` + @@ -114,28 +112,28 @@ export default class LogCollectCypressRequest extends LogCollectBase { this.collectorState.addLog([CONSTANTS.LOG_TYPES.CYPRESS_REQUEST, log, CONSTANTS.SEVERITY.ERROR]); throw e; - }) as any as ReturnType).then((response) => { - return Promise.all([ - this.format.formatXhrData(response.headers), - this.format.formatXhrData(response.body) - ]) - .then(([formattedResponseHeaders, formattedResponseBody]) => { - log += - `\n` + - this.format.formatXhrLog({ - request: requestData, - response: { - status: response.status, - headers: formattedResponseHeaders, - body: formattedResponseBody, - }, - }); + }).then((response) => { + return Promise.all([ + this.format.formatXhrData(response.headers), + this.format.formatXhrData(response.body) + ]) + .then(([formattedResponseHeaders, formattedResponseBody]) => { + log += + `\n` + + this.format.formatXhrLog({ + request: requestData, + response: { + status: response.status, + headers: formattedResponseHeaders, + body: formattedResponseBody, + }, + }); - this.collectorState.addLog([CONSTANTS.LOG_TYPES.CYPRESS_REQUEST, log, CONSTANTS.SEVERITY.SUCCESS]); - return response; - }); - }); - }); + this.collectorState.addLog([CONSTANTS.LOG_TYPES.CYPRESS_REQUEST, log, CONSTANTS.SEVERITY.SUCCESS]); + return response; + }); + }); + }) as any as ReturnType; }); } } From 45a960d80da3db7dc43cb54d2521574095917961 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 21:54:35 -0700 Subject: [PATCH 19/27] more types --- src/installLogsPrinter.ts | 8 ++++---- src/installLogsPrinter.types.ts | 5 ++--- src/types.ts | 2 ++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/installLogsPrinter.ts b/src/installLogsPrinter.ts index 2e51085..8b5d241 100755 --- a/src/installLogsPrinter.ts +++ b/src/installLogsPrinter.ts @@ -6,14 +6,14 @@ import NestedOutputProcessorDecorator from './outputProcessor/NestedOutputProces import JsonOutputProcessor from "./outputProcessor/JsonOutputProcessor"; import TextOutputProcessor from "./outputProcessor/TextOutputProcessor"; import type {CustomOutputProcessorCallback, PluginOptions, AllMessages} from "./installLogsPrinter.types"; -import type {Log, LogType, MessageData, Severity} from "./types"; +import type {BuiltinOutputProcessorsTypes, Log, LogType, MessageData, Severity} from "./types"; import {IOutputProcecessor} from "./outputProcessor/BaseOutputProcessor"; import utils from "./utils"; import consoleProcessor from "./outputProcessor/consoleProcessor"; import {validate} from "superstruct"; import {InstallLogsPrinterSchema} from "./installLogsPrinter.schema"; -const OUTPUT_PROCESSOR_TYPE: Record = { +const OUTPUT_PROCESSOR_TYPE: Record = { 'json': JsonOutputProcessor, 'txt': TextOutputProcessor, } @@ -129,7 +129,7 @@ function logToFiles(options: PluginOptions) { function logOutputTarget(processor: IOutputProcecessor) { let message; - let standardOutputType = Object.keys(OUTPUT_PROCESSOR_TYPE).find( + let standardOutputType = (Object.keys(OUTPUT_PROCESSOR_TYPE) as BuiltinOutputProcessorsTypes[]).find( (type) => processor instanceof OUTPUT_PROCESSOR_TYPE[type] ); if (standardOutputType) { @@ -148,7 +148,7 @@ function installOutputProcessors(on: Cypress.PluginEvents, options: PluginOption throw new CtrError(`Missing outputRoot configuration.`); } - const createProcessorFromType = (file: string, type: string | CustomOutputProcessorCallback) => { + const createProcessorFromType = (file: string, type: BuiltinOutputProcessorsTypes | CustomOutputProcessorCallback) => { if (typeof type === 'string') { return new OUTPUT_PROCESSOR_TYPE[type](path.join(options.outputRoot || '', file)); } diff --git a/src/installLogsPrinter.types.ts b/src/installLogsPrinter.types.ts index f6757b4..7145412 100644 --- a/src/installLogsPrinter.types.ts +++ b/src/installLogsPrinter.types.ts @@ -1,6 +1,6 @@ /// import type CustomOutputProcessor from "./outputProcessor/CustomOutputProcessor"; -import type {Log, LogOccurrence, State} from "./types"; +import type {BuiltinOutputProcessorsTypes, Log, LogOccurrence, State} from "./types"; export type AllMessages = { [specPath: string]: { @@ -56,8 +56,7 @@ export interface PluginOptions { */ outputTarget?: Record< string, - | 'json' - | 'txt' + | BuiltinOutputProcessorsTypes | CustomOutputProcessorCallback >; diff --git a/src/types.ts b/src/types.ts index ed5131e..bbd1c5a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -27,6 +27,8 @@ export type State = ValueOf export type CommandTimings = ValueOf +export type BuiltinOutputProcessorsTypes = 'txt' | 'json' + // ***************************************************************************** // Objects // ***************************************************************************** From 6650ec49af55e806e243299218b128b10820d91d Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 21:56:41 -0700 Subject: [PATCH 20/27] refac --- index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index c4fb115..94fff60 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,11 +5,11 @@ declare namespace Cypress { import {Log} from "./src/installLogsCollector"; + import {BuiltinOutputProcessorsTypes} from "./src/types"; interface Cypress { TerminalReport: { - getLogs(format: 'txt'): string | null; - getLogs(format: 'json'): string | null; + getLogs(format: BuiltinOutputProcessorsTypes): string | null; getLogs(format?: 'none' = 'none'): Log[] | null; } From 01fff6844f1b2e2ac758df9ad6b01625be1f9d4c Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 22:33:09 -0700 Subject: [PATCH 21/27] rename const --- src/constants.ts | 8 +++++++- src/outputProcessor/consoleProcessor.ts | 2 +- src/types.ts | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 3451ad3..57c32c1 100755 --- a/src/constants.ts +++ b/src/constants.ts @@ -25,6 +25,9 @@ const CONSTANTS = { WARNING: 'warning', }, + /** + * Unicode log symbols + */ LOG_SYMBOLS: { ERROR: '✘', WARNING: '❖', @@ -33,7 +36,10 @@ const CONSTANTS = { DEBUG: '⚈', ROUTE: '➟' }, - LOG_SYMBOLS_CONSOLE: { + /** + * Non-unicode log symbols + */ + LOG_SYMBOLS_BASIC: { ERROR: 'x', WARNING: '!', SUCCESS: '+', diff --git a/src/outputProcessor/consoleProcessor.ts b/src/outputProcessor/consoleProcessor.ts index 802a267..e56d0d8 100644 --- a/src/outputProcessor/consoleProcessor.ts +++ b/src/outputProcessor/consoleProcessor.ts @@ -8,7 +8,7 @@ const KNOWN_LOG_TYPES = Object.values(LOG_TYPES); const LOG_SYMBOLS = (() => process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color' - ? CONSTANTS.LOG_SYMBOLS : CONSTANTS.LOG_SYMBOLS_CONSOLE)(); + ? CONSTANTS.LOG_SYMBOLS : CONSTANTS.LOG_SYMBOLS_BASIC)(); const BOLD_COLORS: Colors[] = [COLORS.RED, COLORS.YELLOW]; diff --git a/src/types.ts b/src/types.ts index bbd1c5a..d3414ff 100644 --- a/src/types.ts +++ b/src/types.ts @@ -17,7 +17,7 @@ export type Severity = ValueOf export type LogType = ValueOf export type LogSymbols = ValueOf | - ValueOf | '-' + ValueOf | '-' export type LogOccurrence = ValueOf From 883fdbd191dd0d0483a4799d82b829ec35e6de75 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 23:10:29 -0700 Subject: [PATCH 22/27] more types --- src/collector/LogCollectControlExtended.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index 0896dc0..e924342 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -204,7 +204,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const testHasAfterEachHooks = (test: Mocha.Runnable) => { let suite = test.parent while (suite) { - const _afterEach: any[] = suite['_afterEach'] + const _afterEach: Mocha.Hook[] = suite['_afterEach'] if (_afterEach.length > 0) { return true; } @@ -216,7 +216,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { const isLastAfterEachHookForTest = (test: Mocha.Runnable, hook: Mocha.Hook) => { let suite = test.parent; while (suite) { - const _afterEach: any[] = suite['_afterEach'] + const _afterEach: Mocha.Hook[] = suite['_afterEach'] if (_afterEach.length > 0) { return _afterEach.indexOf(hook) === _afterEach.length - 1; } @@ -301,7 +301,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { suite.afterAll(hookCallback); // Make sure our hook is first so that other after all hook logs come after // the failed before all hooks logs. - const hook = suite["_afterAll"].pop(); + const hook: Mocha.Hook = suite["_afterAll"].pop(); suite["_afterAll"].unshift(hook); // Don't count this in the hook index and logs. hook._ctr_hook = true; From 8de78984e6f10b77ab45ebbe7ec1de3a40554c80 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 5 Nov 2024 23:30:14 -0700 Subject: [PATCH 23/27] refactor into loop --- src/collector/LogCollectBrowserConsole.ts | 24 ++++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/collector/LogCollectBrowserConsole.ts b/src/collector/LogCollectBrowserConsole.ts index 86ddefc..c953ab2 100644 --- a/src/collector/LogCollectBrowserConsole.ts +++ b/src/collector/LogCollectBrowserConsole.ts @@ -58,20 +58,16 @@ export default class LogCollectBrowserConsole extends LogCollectBase { }; }; - if (this.config.collectTypes.includes(CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_WARN)) { - createWrapper('warn', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_WARN, CONSTANTS.SEVERITY.WARNING); - } - if (this.config.collectTypes.includes(CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_ERROR)) { - createWrapper('error', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_ERROR, CONSTANTS.SEVERITY.ERROR); - } - if (this.config.collectTypes.includes(CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_INFO)) { - createWrapper('info', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_INFO); - } - if (this.config.collectTypes.includes(CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_DEBUG)) { - createWrapper('debug', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_DEBUG); - } - if (this.config.collectTypes.includes(CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_LOG)) { - createWrapper('log', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_LOG); + for (const [method, logType, severity] of [ + ['warn', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_WARN, CONSTANTS.SEVERITY.WARNING], + ['error', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_ERROR, CONSTANTS.SEVERITY.ERROR], + ['info', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_INFO], + ['debug', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_DEBUG], + ['log', CONSTANTS.LOG_TYPES.BROWSER_CONSOLE_LOG], + ] as const) { + if (this.config.collectTypes.includes(logType)) { + createWrapper(method, logType, severity); + } } }); } From 755d3670c9b77a5d019d5cca3622dd0c765ba66c Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Wed, 6 Nov 2024 00:06:47 -0700 Subject: [PATCH 24/27] more types --- index.d.ts | 5 ++++- src/collector/LogCollectControlExtended.ts | 5 +---- src/collector/LogCollectControlSimple.ts | 1 - src/collector/LogCollectorState.ts | 2 +- src/installLogsCollector.ts | 4 ++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/index.d.ts b/index.d.ts index 94fff60..3fbcfc0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -19,10 +19,13 @@ declare namespace Cypress { getRunner(): Mocha.Runner getRootSuite(): Mocha.Suite } + + state(key: 'done', callback: (error: Error) => Promise): void + state(key: 'error', error: Error): void } interface Chainable { - catch: Promise['catch'] + catch: Promise['catch'] } } diff --git a/src/collector/LogCollectControlExtended.ts b/src/collector/LogCollectControlExtended.ts index e924342..e577e1c 100644 --- a/src/collector/LogCollectControlExtended.ts +++ b/src/collector/LogCollectControlExtended.ts @@ -66,8 +66,7 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Keeps track of before and after all hook indexes. Cypress.mocha.getRunner().on('hook', function (hook) { - // @ts-ignore - if (!hook._ctr_hook && !hook.fn._ctr_hook) { + if (!hook._ctr_hook && !(hook.fn as any)._ctr_hook) { // After each hooks get merged with the test. if (hook.hookName !== "after each") { self.collectorState.addNewLogStack(); @@ -174,14 +173,12 @@ export default class LogCollectControlExtended extends LogCollectControlBase { // Have to wait for debounce on log updates to have correct state information. // Done state is used as callback and awaited in Cypress.fail. - // @ts-ignore Cypress.state('done', async (error: Error) => { await new Promise(resolve => setTimeout(resolve, 6)); throw error; }); } - // @ts-ignore Cypress.state('error', error); throw error; }); diff --git a/src/collector/LogCollectControlSimple.ts b/src/collector/LogCollectControlSimple.ts index 8652afe..28b809a 100644 --- a/src/collector/LogCollectControlSimple.ts +++ b/src/collector/LogCollectControlSimple.ts @@ -69,7 +69,6 @@ export default class LogCollectControlSimple extends LogCollectControlBase { }); // Logs commands if test was manually skipped. - // @ts-ignore Cypress.mocha.getRunner().on('pending', function () { let test = self.collectorState.getCurrentTest(); if (test?.state === ('pending' as State)) { diff --git a/src/collector/LogCollectorState.ts b/src/collector/LogCollectorState.ts index 8c3f631..1b08de3 100644 --- a/src/collector/LogCollectorState.ts +++ b/src/collector/LogCollectorState.ts @@ -25,7 +25,7 @@ export default class LogCollectorState extends EventTarget { super(); this.listeners = {}; - // @ts-ignore + // @ts-ignore gets initialized to the correct state anyways this.currentTest = null; this.logStacks = []; this.beforeHookIndexes = []; diff --git a/src/installLogsCollector.ts b/src/installLogsCollector.ts index 59c3858..95a1363 100755 --- a/src/installLogsCollector.ts +++ b/src/installLogsCollector.ts @@ -11,7 +11,7 @@ import LogCollectControlSimple from "./collector/LogCollectControlSimple"; import logsTxtFormatter from "./outputProcessor/logsTxtFormatter"; import CONSTANTS from "./constants"; import type {ExtendedSupportOptions, SupportOptions} from "./installLogsCollector.types"; -import type {LogType, Log, Severity} from "./types"; +import type {LogType, Log, Severity, BuiltinOutputProcessorsTypes} from "./types"; import utils from "./utils"; import {validate} from "superstruct"; import {InstallLogsCollectorSchema} from "./installLogsCollector.schema"; @@ -72,7 +72,7 @@ function registerLogCollectorTypes(logCollectorState: LogCollectorState, config: function registerGlobalApi(logCollectorState: LogCollectorState) { Cypress.TerminalReport = { //@ts-ignore there is no error, this works correctly. - getLogs: (format = 'none') => { + getLogs: (format: BuiltinOutputProcessorsTypes | "none" = "none") => { const logs = logCollectorState.getCurrentLogStack(); if (!logs) { From 2162795a01c583b15cc9d1e32e36af3b23e53afa Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Wed, 6 Nov 2024 00:16:24 -0700 Subject: [PATCH 25/27] Chainable --- index.d.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 3fbcfc0..532e839 100644 --- a/index.d.ts +++ b/index.d.ts @@ -24,8 +24,7 @@ declare namespace Cypress { state(key: 'error', error: Error): void } - interface Chainable { - catch: Promise['catch'] + interface Chainable extends Pick, 'catch'> { } } From bf84798fc0245fa0e58d57fecd992cc2429ab1ee Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 12 Nov 2024 18:05:39 -0700 Subject: [PATCH 26/27] create internal global types file --- .npmignore | 1 + index.d.ts | 47 ------------------------------------------ index.internal.d.ts | 50 +++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 2 +- 4 files changed, 52 insertions(+), 48 deletions(-) create mode 100644 index.internal.d.ts diff --git a/.npmignore b/.npmignore index f4122e2..c419f1e 100755 --- a/.npmignore +++ b/.npmignore @@ -5,4 +5,5 @@ test *.png src/**/*.ts !src/**/*.d.ts +*.internal.* tsconfig.json diff --git a/index.d.ts b/index.d.ts index 532e839..ac7e8ee 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,8 +1,3 @@ -/** - * This file used for adding types to package interfaces that are not documented - * by the package (not included in the package's types). - */ - declare namespace Cypress { import {Log} from "./src/installLogsCollector"; import {BuiltinOutputProcessorsTypes} from "./src/types"; @@ -12,47 +7,5 @@ declare namespace Cypress { getLogs(format: BuiltinOutputProcessorsTypes): string | null; getLogs(format?: 'none' = 'none'): Log[] | null; } - - onSpecReady(...args: any[]): void; - - mocha: { - getRunner(): Mocha.Runner - getRootSuite(): Mocha.Suite - } - - state(key: 'done', callback: (error: Error) => Promise): void - state(key: 'error', error: Error): void - } - - interface Chainable extends Pick, 'catch'> { - } -} - -declare namespace Mocha { - interface InvocationDetails { - relativeFile?: string - fileUrl?: string - } - - interface Hook { - hookName: string - _ctr_hook: boolean - } - - interface Runnable { - hookName: string - invocationDetails: InvocationDetails - id: string - order: unknown - wallClockStartedAt: unknown - timings: unknown - } - - interface Suite { - invocationDetails: InvocationDetails - } - - interface Test { - failedFromHookId?: unknown } } diff --git a/index.internal.d.ts b/index.internal.d.ts new file mode 100644 index 0000000..d91624c --- /dev/null +++ b/index.internal.d.ts @@ -0,0 +1,50 @@ +/** + * This file used for internally adding types to package interfaces that are not + * documented by the package (not included in the package's types). + */ + +declare namespace Cypress { + interface Cypress { + onSpecReady(...args: any[]): void; + + mocha: { + getRunner(): Mocha.Runner + getRootSuite(): Mocha.Suite + } + + state(key: 'done', callback: (error: Error) => Promise): void + state(key: 'error', error: Error): void + } + + interface Chainable extends Pick, 'catch'> { + } +} + +declare namespace Mocha { + interface InvocationDetails { + relativeFile?: string + fileUrl?: string + } + + interface Hook { + hookName: string + _ctr_hook: boolean + } + + interface Runnable { + hookName: string + invocationDetails: InvocationDetails + id: string + order: unknown + wallClockStartedAt: unknown + timings: unknown + } + + interface Suite { + invocationDetails: InvocationDetails + } + + interface Test { + failedFromHookId?: unknown + } +} diff --git a/tsconfig.json b/tsconfig.json index 1822cb5..579014e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,7 +32,7 @@ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - "types": ["cypress", "mocha", "node", "./index.d.ts"], /* Specify type package names to be included without being referenced in a source file. */ + "types": ["cypress", "mocha", "node", "./index.d.ts", "./index.internal.d.ts"], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ From 911541a3438b5577940daa017be5b5f12c237357 Mon Sep 17 00:00:00 2001 From: Blake Vandercar Date: Tue, 12 Nov 2024 18:09:24 -0700 Subject: [PATCH 27/27] chore: import type --- index.d.ts | 4 ++-- src/installLogsPrinter.ts | 2 +- src/outputProcessor/NestedOutputProcessorDecorator.ts | 2 +- src/utils.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index ac7e8ee..0b6e2b5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,6 +1,6 @@ declare namespace Cypress { - import {Log} from "./src/installLogsCollector"; - import {BuiltinOutputProcessorsTypes} from "./src/types"; + import type {Log} from "./src/installLogsCollector"; + import type {BuiltinOutputProcessorsTypes} from "./src/types"; interface Cypress { TerminalReport: { diff --git a/src/installLogsPrinter.ts b/src/installLogsPrinter.ts index 8b5d241..c4f655e 100755 --- a/src/installLogsPrinter.ts +++ b/src/installLogsPrinter.ts @@ -7,7 +7,7 @@ import JsonOutputProcessor from "./outputProcessor/JsonOutputProcessor"; import TextOutputProcessor from "./outputProcessor/TextOutputProcessor"; import type {CustomOutputProcessorCallback, PluginOptions, AllMessages} from "./installLogsPrinter.types"; import type {BuiltinOutputProcessorsTypes, Log, LogType, MessageData, Severity} from "./types"; -import {IOutputProcecessor} from "./outputProcessor/BaseOutputProcessor"; +import type {IOutputProcecessor} from "./outputProcessor/BaseOutputProcessor"; import utils from "./utils"; import consoleProcessor from "./outputProcessor/consoleProcessor"; import {validate} from "superstruct"; diff --git a/src/outputProcessor/NestedOutputProcessorDecorator.ts b/src/outputProcessor/NestedOutputProcessorDecorator.ts index 023d4d7..e92eb56 100755 --- a/src/outputProcessor/NestedOutputProcessorDecorator.ts +++ b/src/outputProcessor/NestedOutputProcessorDecorator.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import {IOutputProcecessor} from "./BaseOutputProcessor"; +import type {IOutputProcecessor} from "./BaseOutputProcessor"; import type {AllMessages} from "../installLogsPrinter.types"; export default class NestedOutputProcessorDecorator implements IOutputProcecessor { diff --git a/src/utils.ts b/src/utils.ts index 67e864d..818d8f4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,6 @@ import jsonPrune from "./jsonPrune"; import {compare} from "compare-versions"; -import {Failure} from "superstruct"; +import type {Failure} from "superstruct"; const utils = { nonQueueTask: async (name: string, data: Record) => {