diff --git a/__mocks__/@wdio/reporter.ts b/__mocks__/@wdio/reporter.ts index c1829fea6..13de770fe 100644 --- a/__mocks__/@wdio/reporter.ts +++ b/__mocks__/@wdio/reporter.ts @@ -1,10 +1,11 @@ import { vi } from 'vitest' import { EventEmitter } from 'node:events' -import HookStats from '../../packages/wdio-reporter/src/stats/hook' -import RunnerStats from '../../packages/wdio-reporter/src/stats/runner' -import SuiteStats from '../../packages/wdio-reporter/src/stats/suite' -import TestStats from '../../packages/wdio-reporter/src/stats/test' +import HookStats from '../../packages/wdio-reporter/src/stats/hook.ts' +import RunnerStats from '../../packages/wdio-reporter/src/stats/runner.ts' +import SuiteStats from '../../packages/wdio-reporter/src/stats/suite.ts' +import TestStats from '../../packages/wdio-reporter/src/stats/test.ts' +import { Chalk } from '../chalk.ts' export default class WDIOReporter extends EventEmitter { outputStream: { write: Function } @@ -22,6 +23,7 @@ export default class WDIOReporter extends EventEmitter { failures: number } retries: number + _chalk: Chalk runnerStat?: RunnerStats constructor (public options: any) { super() @@ -41,6 +43,7 @@ export default class WDIOReporter extends EventEmitter { failures: 0 } this.retries = 0 + this._chalk = new Chalk(!options.color ? { level : 0 } : {}) } get isSynchronised () { @@ -79,4 +82,4 @@ export default class WDIOReporter extends EventEmitter { onRunnerEnd () {} } -export { HookStats, RunnerStats, SuiteStats, TestStats } \ No newline at end of file +export { HookStats, RunnerStats, SuiteStats, TestStats } diff --git a/__mocks__/chalk.ts b/__mocks__/chalk.ts index c212fd8f6..c7b3e5186 100644 --- a/__mocks__/chalk.ts +++ b/__mocks__/chalk.ts @@ -1,26 +1,33 @@ import { vi } from 'vitest' -const chalkMock: any = {} -chalkMock.cyanBright = vi.fn().mockImplementation((msg) => `cyanBright ${msg}`) -chalkMock.greenBright = vi.fn().mockImplementation((msg) => `greenBright ${msg}`) -chalkMock.whiteBright = vi.fn().mockImplementation((msg) => `whiteBright ${msg}`) -chalkMock.redBright = vi.fn().mockImplementation((msg) => `redBright ${msg}`) -chalkMock.cyan = vi.fn().mockImplementation((msg) => `cyan ${msg}`) -chalkMock.blue = vi.fn().mockImplementation((msg) => `blue ${msg}`) -chalkMock.grey = vi.fn().mockImplementation((msg) => `grey ${msg}`) -chalkMock.green = vi.fn().mockImplementation((msg) => `green ${msg}`) -chalkMock.red = vi.fn().mockImplementation((...msg: string[]) => `red ${msg.join(' ')}`) -chalkMock.gray = vi.fn().mockImplementation((...msg: string[]) => `gray ${msg.join(' ')}`) -chalkMock.black = vi.fn().mockImplementation((msg) => `black ${msg}`) -chalkMock.white = chalkMock -chalkMock.yellow = vi.fn().mockImplementation((...msg: string[]) => `yellow ${msg.join(' ')}`) -chalkMock.magenta = vi.fn().mockImplementation((msg) => `magenta ${msg}`) -chalkMock.bgGreen = vi.fn().mockImplementation((msg) => `bgGreen ${msg}`) -chalkMock.dim = vi.fn().mockImplementation((msg) => `dim ${msg}`) -chalkMock.supportsColor = { hasBasic: true } -chalkMock.bgYellow = chalkMock -chalkMock.bgRed = chalkMock -chalkMock.bold = function (msg: string) { return `bold ${msg}` } -chalkMock.bold.__proto__ = chalkMock +class Chalk { + supportsColor = { hasBasic: true } -export default chalkMock + private color = true + constructor(options:{level?:number}){ + this.color = options.level === 0 ? false : this.color + } + + bold(msg: string) { return `bold ${msg}` } + bgYellow(msg: string) { return `bgYellow ${msg}` } + bgRed(msg: string) { return `bgRed ${msg}` } + cyanBright = vi.fn().mockImplementation((msg) => this.color ? `cyanBright ${msg}` : msg) + greenBright = vi.fn().mockImplementation((msg) => this.color ? `greenBright ${msg}` : msg) + whiteBright = vi.fn().mockImplementation((msg) => this.color ? `whiteBright ${msg}` : msg) + redBright = vi.fn().mockImplementation((msg) => this.color ? `redBright ${msg}` : msg) + cyan = vi.fn().mockImplementation((msg) => this.color ? `cyan ${msg}` : msg) + white = vi.fn().mockImplementation((msg) => this.color ? `white ${msg}` : msg) + blue = vi.fn().mockImplementation((msg) => this.color ? `blue ${msg}` : msg) + grey = vi.fn().mockImplementation((msg) => this.color ? `grey ${msg}` : msg) + green = vi.fn().mockImplementation((msg) => this.color ? `green ${msg}` : msg) + red = vi.fn().mockImplementation((...msg: string[]) => this.color ? `red ${msg.join(' ')}` : msg.join(' ')) + gray = vi.fn().mockImplementation((...msg: string[]) => this.color ? `gray ${msg.join(' ')}` : msg.join(' ')) + black = vi.fn().mockImplementation((msg) => this.color ? `black ${msg}` : msg) + yellow = vi.fn().mockImplementation((...msg: string[]) => this.color ? `yellow ${msg.join(' ')}` : msg.join(' ')) + magenta = vi.fn().mockImplementation((msg) => this.color ? `magenta ${msg}` : msg) + bgGreen = vi.fn().mockImplementation((msg) => this.color ? `bgGreen ${msg}` : msg) + dim = vi.fn().mockImplementation((msg) => this.color ? `dim ${msg}` : msg) +} + +export default new Chalk({}) +export { Chalk } diff --git a/packages/wdio-cli/src/interface.ts b/packages/wdio-cli/src/interface.ts index 603ee7821..8d3a767a6 100644 --- a/packages/wdio-cli/src/interface.ts +++ b/packages/wdio-cli/src/interface.ts @@ -112,16 +112,16 @@ export default class WDIOCLInterface extends EventEmitter { : '' this.log(chalk.bold(`\nExecution of ${chalk.blue(this.totalWorkerCnt)} workers${shardNote} started at`), this._start.toISOString()) if (this._inDebugMode) { - this.log(chalk.bgYellow.black('DEBUG mode enabled!')) + this.log(chalk.bgYellow(chalk.black('DEBUG mode enabled!'))) } if (this._isWatchMode) { - this.log(chalk.bgYellow.black('WATCH mode enabled!')) + this.log(chalk.bgYellow(chalk.black('WATCH mode enabled!'))) } this.log('') } onSpecRunning (rid: string) { - this.onJobComplete(rid, this._jobs.get(rid), 0, chalk.bold.cyan('RUNNING')) + this.onJobComplete(rid, this._jobs.get(rid), 0, chalk.bold(chalk.cyan('RUNNING'))) } onSpecRetry (rid: string, job?: Workers.Job, retries = 0) { @@ -130,11 +130,11 @@ export default class WDIOCLInterface extends EventEmitter { } onSpecPass (rid: string, job?: Workers.Job, retries = 0) { - this.onJobComplete(rid, job, retries, chalk.bold.green('PASSED')) + this.onJobComplete(rid, job, retries, chalk.bold(chalk.green('PASSED'))) } onSpecFailure (rid: string, job?: Workers.Job, retries = 0) { - this.onJobComplete(rid, job, retries, chalk.bold.red('FAILED')) + this.onJobComplete(rid, job, retries, chalk.bold(chalk.red('FAILED'))) } onSpecSkip (rid: string, job?: Workers.Job) { @@ -261,7 +261,7 @@ export default class WDIOCLInterface extends EventEmitter { if (event.name === 'error') { return this.log( `[${event.cid}]`, - chalk.white.bgRed.bold(' Error: '), + chalk.white(chalk.bgRed(chalk.bold(' Error: '))), event.content ? (event.content.message || event.content.stack || event.content) : '' ) } @@ -310,7 +310,7 @@ export default class WDIOCLInterface extends EventEmitter { const reporter = this._messages.reporter this._messages.reporter = {} for (const [reporterName, messages] of Object.entries(reporter)) { - this.log('\n', chalk.bold.magenta(`"${reporterName}" Reporter:`)) + this.log('\n', chalk.bold(chalk.magenta(`"${reporterName}" Reporter:`))) this.log(messages.join('')) } } diff --git a/packages/wdio-cli/src/utils.ts b/packages/wdio-cli/src/utils.ts index e57ef1c86..4922e797c 100644 --- a/packages/wdio-cli/src/utils.ts +++ b/packages/wdio-cli/src/utils.ts @@ -718,7 +718,7 @@ export async function createPackageJSON(parsedAnswers: ParsedAnswers) { dependencies: {}, devDependencies: {} }, null, 2)) - console.log(chalk.green.bold('✔ Success!\n')) + console.log(chalk.green(chalk.bold('✔ Success!\n'))) } } @@ -808,7 +808,7 @@ export async function npmInstall(parsedAnswers: ParsedAnswers, npmTag: string) { console.log(`Installing packages using ${pm}:${SEP}${parsedAnswers.packagesToInstall.join(SEP)}`) const success = await installPackages(cwd, parsedAnswers.packagesToInstall, true) if (success) { - console.log(chalk.green.bold('✔ Success!\n')) + console.log(chalk.green(chalk.bold('✔ Success!\n'))) } } else { const installationCommand = getInstallCommand(pm, parsedAnswers.packagesToInstall, true) @@ -936,7 +936,7 @@ export async function setupTypeScript(parsedAnswers: ParsedAnswers) { JSON.stringify(config, null, 4) ) - console.log(chalk.green.bold('✔ Success!\n')) + console.log(chalk.green(chalk.bold('✔ Success!\n'))) } function getPreset (parsedAnswers: ParsedAnswers) { @@ -989,7 +989,7 @@ export async function setupBabel(parsedAnswers: ParsedAnswers) { ] }, null, 4)}` ) - console.log(chalk.green.bold('✔ Success!\n')) + console.log(chalk.green(chalk.bold('✔ Success!\n'))) } } @@ -1002,12 +1002,12 @@ export async function createWDIOConfig(parsedAnswers: ParsedAnswers) { _: new EjsHelpers({ useEsm: parsedAnswers.esmSupport, useTypeScript: parsedAnswers.isUsingTypeScript }) }) await fs.writeFile(parsedAnswers.wdioConfigPath, renderedTpl) - console.log(chalk.green.bold('✔ Success!\n')) + console.log(chalk.green(chalk.bold('✔ Success!\n'))) if (parsedAnswers.generateTestFiles) { console.log('Autogenerating test files...') await generateTestFiles(parsedAnswers) - console.log(chalk.green.bold('✔ Success!\n')) + console.log(chalk.green(chalk.bold('✔ Success!\n'))) } } catch (err: any) { throw new Error(`⚠️ Couldn't write config file: ${err.stack}`) @@ -1065,7 +1065,7 @@ export async function createWDIOScript(parsedAnswers: ParsedAnswers) { return false } } - console.log(chalk.green.bold('✔ Success!')) + console.log(chalk.green(chalk.bold('✔ Success!'))) return true } diff --git a/packages/wdio-cli/tests/interface.test.ts b/packages/wdio-cli/tests/interface.test.ts index 9803b596c..6e82d0876 100644 --- a/packages/wdio-cli/tests/interface.test.ts +++ b/packages/wdio-cli/tests/interface.test.ts @@ -147,7 +147,7 @@ describe('cli interface', () => { }) expect(wdioClInterface.log).toBeCalledTimes(1) - expect(wdioClInterface.log).toBeCalledWith('[0-0]', 'bold Error: ', 'foo') + expect(wdioClInterface.log).toBeCalledWith('[0-0]', 'white bgRed bold Error: ', 'foo') }) it('should print message on worker error', () => { @@ -160,7 +160,7 @@ describe('cli interface', () => { }) expect(wdioClInterface.log).toBeCalledTimes(1) - expect(wdioClInterface.log).toBeCalledWith('[0-0]', 'bold Error: ', 'bar') + expect(wdioClInterface.log).toBeCalledWith('[0-0]', 'white bgRed bold Error: ', 'bar') }) it('should ignore messages that do not contain a proper origin', () => { @@ -280,7 +280,7 @@ describe('cli interface', () => { cid, job, retries: 0, - message: chalk.bold.cyan('RUNNING') + message: chalk.bold(chalk.cyan('RUNNING')) }, { method: 'onSpecRetry', cid, @@ -292,13 +292,13 @@ describe('cli interface', () => { cid, job, retries, - message: chalk.bold.green('PASSED') + message: chalk.bold(chalk.green('PASSED')) }, { method: 'onSpecFailure', cid, job, retries, - message: chalk.bold.red('FAILED') + message: chalk.bold(chalk.red('FAILED')) }] scenarios.forEach(scenario => { diff --git a/packages/wdio-spec-reporter/README.md b/packages/wdio-spec-reporter/README.md index 342cdd635..84cf4ba33 100644 --- a/packages/wdio-spec-reporter/README.md +++ b/packages/wdio-spec-reporter/README.md @@ -85,7 +85,7 @@ Default: `false` ``` ### addConsoleLogs -Set to true to show console logs from steps in final report +Set to `true` to show console logs from steps in final report Type: `boolean` Default: `false` @@ -100,7 +100,7 @@ Default: `false` ``` ### realtimeReporting -Set to true to display test status realtime than just at the end of the run +Set to `true` to display test status realtime than just at the end of the run Type: `boolean` Default: `false` @@ -115,7 +115,7 @@ Default: `false` ``` ### showPreface -Set to false to disable `[ MutliRemoteBrowser ... ]` preface in the reports. +Set to `false` to disable `[ MutliRemoteBrowser ... ]` preface in the reports. Type: `boolean` Default: `true` @@ -164,6 +164,21 @@ and with `true` (default) each line will be prefixed with the preface: [loremipsum 50 Windows 10 #0-0] ``` +### color +Set to `true` to display colored output in terminal + +Type: `boolean` +Default: `true` + +```js +[ + "spec", + { + color: true, + }, +] +``` + ## Environment Options There are certain options you can set through environment variables: diff --git a/packages/wdio-spec-reporter/src/index.ts b/packages/wdio-spec-reporter/src/index.ts index 2588d1305..79de2a4ae 100644 --- a/packages/wdio-spec-reporter/src/index.ts +++ b/packages/wdio-spec-reporter/src/index.ts @@ -1,12 +1,11 @@ -import { format } from 'node:util' -import chalk from 'chalk' import prettyMs from 'pretty-ms' -import type { SuiteStats, HookStats, RunnerStats, Argument } from '@wdio/reporter' -import WDIOReporter, { TestStats } from '@wdio/reporter' +import { format } from 'node:util' import type { Capabilities } from '@wdio/types' - +import { Chalk, type ChalkInstance } from 'chalk' +import WDIOReporter, { TestStats } from '@wdio/reporter' +import type { SuiteStats, HookStats, RunnerStats, Argument } from '@wdio/reporter' import { buildTableData, printTable, getFormattedRows, sauceAuthenticationToken } from './utils.js' -import type { StateCount, Symbols, SpecReporterOptions, TestLink } from './types.js' +import { ChalkColors, type SpecReporterOptions, type TestLink, type StateCount, type Symbols, State } from './types.js' const DEFAULT_INDENT = ' ' @@ -43,7 +42,7 @@ export default class SpecReporter extends WDIOReporter { pending: '?', failed: '✖' } - + private _chalk: ChalkInstance private _onlyFailures = false private _sauceLabsSharableLinks = true @@ -69,7 +68,16 @@ export default class SpecReporter extends WDIOReporter { return this._originalStdoutWrite(chunk, encoding, callback) } } + this._chalk = new Chalk(options.color === false ? { level:0 } : {}) + } + /** + * @param state state of test execution + * @param msg the message to print in terminal + * @returns colord value based on chalk to print in terminal + */ + setMessageColor(message:string, state?: State): string{ + return this._chalk[this.getColor(state)](message) } onRunnerStart (runner: RunnerStats) { @@ -134,7 +142,7 @@ export default class SpecReporter extends WDIOReporter { return } - const title = stat.title, state = (stat as TestStats).state + const title = stat.title, state = (stat as TestStats).state as State const divider = '------------------------------------------------------------------' const indent = (stat.type==='test') ? @@ -148,8 +156,8 @@ export default class SpecReporter extends WDIOReporter { const content = stat.type === 'test' ? `${this._preface} ${indent}` + - `${chalk[this.getColor(state)](this.getSymbol(state))} ${title}` + - ` » ${chalk[this.getColor(state)]('[')} ${this._suiteName} ${chalk[this.getColor(state)](']')}` + `${this.setMessageColor(this.getSymbol(state), state)} ${title}` + + ` » ${this.setMessageColor('[', state)} ${this._suiteName} ${this.setMessageColor(']', state)}` : stat.type !== 'hook' ? `${suiteStartBanner}${this._preface} ${title}` : title @@ -351,24 +359,24 @@ export default class SpecReporter extends WDIOReporter { // display suite description (Cucumber only) if (suite.description) { output.push(...suite.description.trim().split('\n') - .map((l) => `${suiteIndent}${chalk.grey(l.trim())}`)) + .map((l) => `${suiteIndent}${this.setMessageColor(l.trim())}`)) output.push('') // empty line } // display suite rule (Cucumber only) if (suite.rule) { output.push(...suite.rule.trim().split('\n') - .map((l) => `${suiteIndent}${chalk.grey(l.trim())}`)) + .map((l) => `${suiteIndent}${this.setMessageColor(l.trim())}`)) } const eventsToReport = this.getEventsToReport(suite) for (const test of eventsToReport) { const testTitle = `${test.title} ${(test instanceof TestStats && test.retries && test.retries > 0) ? `(${test.retries} retries)` : ''}` - const state = test.state + const state = test.state as State const testIndent = `${DEFAULT_INDENT}${suiteIndent}` // Output for a single test - output.push(`${testIndent}${chalk[this.getColor(state)](this.getSymbol(state))} ${testTitle.trim()}`) + output.push(`${testIndent}${this.setMessageColor(this.getSymbol(state), state)} ${testTitle.trim()}`) // print cucumber data table cells and docstring const arg = (test as TestStats).argument @@ -427,21 +435,21 @@ export default class SpecReporter extends WDIOReporter { // Get the passes if (this._stateCounts.passed > 0) { const text = `${this._stateCounts.passed} passing ${duration}` - output.push(chalk[this.getColor('passed')](text)) + output.push(this.setMessageColor(text, State.PASSED)) duration = '' } // Get the failures if (this._stateCounts.failed > 0) { const text = `${this._stateCounts.failed} failing ${duration}`.trim() - output.push(chalk[this.getColor('failed')](text)) + output.push(this.setMessageColor(text, State.FAILED)) duration = '' } // Get the skipped tests if (this._stateCounts.skipped > 0) { const text = `${this._stateCounts.skipped} skipped ${duration}`.trim() - output.push(chalk[this.getColor('skipped')](text)) + output.push(this.setMessageColor(text, State.SKIPPED)) } return output @@ -460,7 +468,7 @@ export default class SpecReporter extends WDIOReporter { const suiteTitle = suite.title const eventsToReport = this.getEventsToReport(suite) for (const test of eventsToReport) { - if (test.state !== 'failed') { + if (test.state !== State.FAILED) { continue } @@ -474,10 +482,10 @@ export default class SpecReporter extends WDIOReporter { ) for (const error of errors) { !error?.stack?.includes('new AssertionError') - ? output.push(chalk.red(error.message)) + ? output.push(this.setMessageColor(error.message, State.FAILED)) : output.push(...error.message.split('\n')) if (error.stack) { - output.push(...error.stack.split(/\n/g).map(value => chalk.gray(value))) + output.push(...error.stack.split(/\n/g).map(value => this.setMessageColor(value))) } } } @@ -557,20 +565,20 @@ export default class SpecReporter extends WDIOReporter { * @param {string} state Test state * @return {String} State color */ - getColor (state?: string) { + getColor (state?: string): ChalkColors { // In case of an unknown state - let color: keyof typeof chalk = 'gray' + let color = ChalkColors.GRAY switch (state) { - case 'passed': - color = 'green' + case State.PASSED: + color = ChalkColors.GREEN break - case 'pending': - case 'skipped': - color = 'cyan' + case State.PENDING: + case State.SKIPPED: + color = ChalkColors.CYAN break - case 'failed': - color = 'red' + case State.FAILED: + color = ChalkColors.RED break } @@ -579,11 +587,12 @@ export default class SpecReporter extends WDIOReporter { /** * Get information about the enviroment - * @param {Object} caps Enviroment details + * @param capability * @param {Boolean} verbose + * @param isMultiremote * @return {String} Enviroment string */ - getEnviromentCombo (capability: Capabilities.RemoteCapability, verbose = true, isMultiremote = false) { + getEnviromentCombo (capability: Capabilities.RemoteCapability, verbose = true, isMultiremote = false): string { if (isMultiremote) { const browserNames = Object.values(capability).map((c) => c.browserName) const browserName = browserNames.length > 1 diff --git a/packages/wdio-spec-reporter/src/types.ts b/packages/wdio-spec-reporter/src/types.ts index 733976074..ba5ce11d0 100644 --- a/packages/wdio-spec-reporter/src/types.ts +++ b/packages/wdio-spec-reporter/src/types.ts @@ -47,13 +47,39 @@ export interface SpecReporterOptions { * * @default: `false` */ - realtimeReporting?: boolean + realtimeReporting?: boolean /** * Ability to show or hide preface on each line of the report ('[MultiRemote ...]') * * @default: `true` */ - showPreface?: boolean + showPreface?: boolean + /** + * Ability to enable or disable colored output in terminal') + * + * @default: `true` + */ + color?: boolean +} + +export enum ChalkColors { + RED = 'red', + GREEN = 'green', + CYAN = 'cyan', + GRAY = 'gray', + GREY = 'grey', + BLACCK = 'black', + YELLOW = 'yellow', + BLUE = 'blue', + MAGENTA = 'magenta', + WHITE = 'white', +} + +export enum State { + FAILED = 'failed', + PASSED = 'passed', + PENDING = 'pending', + SKIPPED = 'skipped', } export interface TestLink { diff --git a/packages/wdio-spec-reporter/tests/__snapshots__/index.test.ts.snap b/packages/wdio-spec-reporter/tests/__snapshots__/index.test.ts.snap index cbff772d2..c8565e9d8 100644 --- a/packages/wdio-spec-reporter/tests/__snapshots__/index.test.ts.snap +++ b/packages/wdio-spec-reporter/tests/__snapshots__/index.test.ts.snap @@ -24,10 +24,10 @@ exports[`SpecReporter > getResultDisplay > should not print if argument is a sin [ "» /foo/bar/loo.e2e.js", "Foo test", - "grey Some important", - "grey description to read!", + "gray Some important", + "gray description to read!", "", - "grey Very important business rule", + "gray Very important business rule", " green ✓ foo", " """", " some different format", @@ -41,10 +41,10 @@ exports[`SpecReporter > getResultDisplay > should not print if data table is emp [ "» /foo/bar/loo.e2e.js", "Foo test", - "grey Some important", - "grey description to read!", + "gray Some important", + "gray description to read!", "", - "grey Very important business rule", + "gray Very important business rule", " green ✓ foo", " green ✓ bar", "", @@ -55,10 +55,10 @@ exports[`SpecReporter > getResultDisplay > should not print if the argument is u [ "» /foo/bar/loo.e2e.js", "Foo test", - "grey Some important", - "grey description to read!", + "gray Some important", + "gray description to read!", "", - "grey Very important business rule", + "gray Very important business rule", " green ✓ foo", " green ✓ bar", "", @@ -69,10 +69,10 @@ exports[`SpecReporter > getResultDisplay > should print data tables 1`] = ` [ "» /foo/bar/loo.e2e.js", "Foo test", - "grey Some important", - "grey description to read!", + "gray Some important", + "gray description to read!", "", - "grey Very important business rule", + "gray Very important business rule", " green ✓ foo", " │ Vegetable │ Rating │", " │ Apricot │ 5 │", @@ -87,10 +87,10 @@ exports[`SpecReporter > getResultDisplay > should print if the doc string is a b [ "» /foo/bar/loo.e2e.js", "Foo test", - "grey Some important", - "grey description to read!", + "gray Some important", + "gray description to read!", "", - "grey Very important business rule", + "gray Very important business rule", " green ✓ foo", " """", " """", @@ -105,10 +105,10 @@ exports[`SpecReporter > getResultDisplay > should print multiple lines doc strin [ "» /foo/bar/loo.e2e.js", "Foo test", - "grey Some important", - "grey description to read!", + "gray Some important", + "gray description to read!", "", - "grey Very important business rule", + "gray Very important business rule", " green ✓ foo", " """", " Docstring line 1", diff --git a/packages/wdio-spec-reporter/tests/index.test.ts b/packages/wdio-spec-reporter/tests/index.test.ts index fc26a288f..740d95ba8 100644 --- a/packages/wdio-spec-reporter/tests/index.test.ts +++ b/packages/wdio-spec-reporter/tests/index.test.ts @@ -1,18 +1,19 @@ import path from 'node:path' -import { describe, expect, it, vi, beforeEach, beforeAll } from 'vitest' -import { runnerEnd } from '../../wdio-allure-reporter/tests/__fixtures__/runner.js' -import SpecReporter from '../src/index.js' import { RUNNER, - SUITE_UIDS, SUITES, + SUITE_UIDS, SUITES_NO_TESTS, + SUITES_WITH_RETRY, SUITES_WITH_DATA_TABLE, - SUITES_NO_TESTS_WITH_HOOK_ERROR, SUITES_MULTIPLE_ERRORS, SUITES_WITH_DOC_STRING, - SUITES_WITH_RETRY + SUITES_NO_TESTS_WITH_HOOK_ERROR, } from './__fixtures__/testdata.js' +import { State } from '../src/types.js' +import SpecReporter from '../src/index.js' +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest' +import { runnerEnd } from '../../wdio-allure-reporter/tests/__fixtures__/runner.js' vi.mock('chalk') vi.mock('@wdio/reporter', () => import(path.join(process.cwd(), '__mocks__', '@wdio/reporter'))) @@ -94,7 +95,7 @@ describe('SpecReporter', () => { beforeAll(() => { reporter.onTestPass({ title:'test1', - state:'passed' + state:State.PASSED } as any) }) @@ -107,7 +108,7 @@ describe('SpecReporter', () => { beforeAll(() => { reporter.onTestFail({ title:'test1', - state:'failed' + state:State.FAILED } as any) }) @@ -120,7 +121,7 @@ describe('SpecReporter', () => { beforeAll(() => { reporter.onTestSkip({ title:'test1', - state:'skipped', + state:State.SKIPPED, pendingReason: 'some random reason' } as any) }) @@ -409,8 +410,7 @@ describe('SpecReporter', () => { it('should print multiple lines doc string', () => { tmpReporter.getOrderedSuites = vi.fn(() => { - const suites = Object.values(JSON.parse(JSON.stringify(SUITES_WITH_DOC_STRING))) as any[] - return suites + return Object.values(JSON.parse(JSON.stringify(SUITES_WITH_DOC_STRING))) as any[] }) const result = tmpReporter.getResultDisplay() expect(result).toMatchSnapshot() @@ -555,7 +555,7 @@ describe('SpecReporter', () => { hooks: [{ type: 'hook', title: '"before all" hook in "{root}"', - state: 'failed' + state: State.FAILED }, { type: 'hook', title: '"after all" hook in "{root}"', @@ -563,7 +563,7 @@ describe('SpecReporter', () => { }, { type: 'hook', title: '"after all" hook in "{root}"', - state: 'failed' + state: State.FAILED }] }] as any const result = tmpReporter.getOrderedSuites() @@ -593,15 +593,15 @@ describe('SpecReporter', () => { describe('getSymbol', () => { it('should get the checkbox symbol', () => { - expect(tmpReporter.getSymbol('passed')).toBe('✓') + expect(tmpReporter.getSymbol(State.PASSED)).toBe('✓') }) it('should get the x symbol', () => { - expect(tmpReporter.getSymbol('failed')).toBe('✖') + expect(tmpReporter.getSymbol(State.FAILED)).toBe('✖') }) it('should get the - symbol', () => { - expect(tmpReporter.getSymbol('skipped')).toBe('-') + expect(tmpReporter.getSymbol(State.SKIPPED)).toBe('-') }) it('should get the ? symbol', () => { @@ -616,15 +616,15 @@ describe('SpecReporter', () => { }) it('should get new passed symbol', () => { - expect(tmpReporter.getSymbol('passed')).toBe(options.symbols.passed) + expect(tmpReporter.getSymbol(State.PASSED)).toBe(options.symbols.passed) }) it('should get new failed symbol', () => { - expect(tmpReporter.getSymbol('failed')).toBe(options.symbols.failed) + expect(tmpReporter.getSymbol(State.FAILED)).toBe(options.symbols.failed) }) it('should get the skipped symbol that is not set', () => { - expect(tmpReporter.getSymbol('skipped')).toBe('-') + expect(tmpReporter.getSymbol(State.SKIPPED)).toBe('-') }) }) @@ -639,7 +639,7 @@ describe('SpecReporter', () => { tmpReporter['_consoleOutput']='Printing to console spec' tmpReporter.onTestPass({ title:'test1', - state:'passed' + state:State.PASSED } as any) expect(tmpReporter.getResultDisplay().toString()).toContain('Printing to console spec') tmpReporter.onSuiteEnd() @@ -654,7 +654,7 @@ describe('SpecReporter', () => { tmpReporter['_consoleOutput']='Printing to console spec' tmpReporter.onTestFail({ title:'test1', - state:'failed' + state:State.FAILED } as any) expect(tmpReporter.getResultDisplay().toString()).toContain('Printing to console spec') tmpReporter.onSuiteEnd() @@ -669,7 +669,7 @@ describe('SpecReporter', () => { tmpReporter['_consoleOutput']='Printing to console spec' tmpReporter.onTestSkip({ title:'test1', - state:'skipped' + state:State.SKIPPED } as any) expect(tmpReporter.getResultDisplay().toString()).toContain('Printing to console spec') tmpReporter.onSuiteEnd() @@ -683,7 +683,7 @@ describe('SpecReporter', () => { tmpReporter['_orderedSuites'] = Object.values(SUITES) as any tmpReporter.onTestSkip({ title:'test1', - state:'skipped', + state:State.SKIPPED, pendingReason:'some random Reasons' } as any) expect(tmpReporter.getResultDisplay().toString()).toContain('Pending Reasons') @@ -801,16 +801,16 @@ describe('SpecReporter', () => { describe('getColor', () => { it('should get green', () => { - expect(tmpReporter.getColor('passed')).toBe('green') + expect(tmpReporter.getColor(State.PASSED)).toBe('green') }) it('should get red', () => { - expect(tmpReporter.getColor('failed')).toBe('red') + expect(tmpReporter.getColor(State.FAILED)).toBe('red') }) it('should get cyan', () => { - expect(tmpReporter.getColor('skipped')).toBe('cyan') - expect(tmpReporter.getColor('pending')).toBe('cyan') + expect(tmpReporter.getColor(State.SKIPPED)).toBe('cyan') + expect(tmpReporter.getColor(State.PENDING)).toBe('cyan') }) it('should get null', () => { @@ -818,6 +818,22 @@ describe('SpecReporter', () => { }) }) + describe('colors in terminal', () => { + it('should give colors', () => { + const tmpReporter = new SpecReporter({}) + expect(tmpReporter.setMessageColor('test', State.PASSED)).toEqual('green test') + expect(tmpReporter.setMessageColor('test', State.FAILED)).toEqual('red test') + expect(tmpReporter.setMessageColor('test', State.SKIPPED)).toEqual('cyan test') + }) + + it('should not give any color', () => { + const tmpReporter = new SpecReporter({ color: false }) + expect(tmpReporter.setMessageColor('test', State.PASSED)).toEqual('test') + expect(tmpReporter.setMessageColor('test', State.FAILED)).toEqual('test') + expect(tmpReporter.setMessageColor('test', State.SKIPPED)).toEqual('test') + }) + }) + describe('getEnviromentCombo', () => { it('should return Multibrowser as capability if multiremote is used', () => { expect(tmpReporter.getEnviromentCombo({ @@ -997,11 +1013,11 @@ describe('SpecReporter', () => { tmpReporter['_consoleOutput']='Printing to console spec' tmpReporter.onTestPass({ title:'test1', - state:'passed' + state:State.PASSED } as any) expect(tmpReporter.printCurrentStats).toBeCalledWith({ title:'test1', - state:'passed' + state:State.PASSED }) tmpReporter.onSuiteEnd() tmpReporter.onRunnerEnd(runnerEnd()) @@ -1016,11 +1032,11 @@ describe('SpecReporter', () => { tmpReporter['_consoleOutput']='Printing to console spec' tmpReporter.onTestPass({ title:'test1', - state:'failed' + state:State.FAILED } as any) expect(tmpReporter.printCurrentStats).toBeCalledWith({ title:'test1', - state:'failed' + state:State.FAILED }) tmpReporter.onSuiteEnd() tmpReporter.onRunnerEnd(runnerEnd()) @@ -1035,11 +1051,11 @@ describe('SpecReporter', () => { tmpReporter['_consoleOutput']='Printing to console spec' tmpReporter.onTestPass({ title:'test1', - state:'skipped' + state:State.SKIPPED } as any) expect(tmpReporter.printCurrentStats).toBeCalledWith({ title:'test1', - state:'skipped' + state:State.SKIPPED }) tmpReporter.onSuiteEnd() tmpReporter.onRunnerEnd(runnerEnd()) @@ -1055,11 +1071,11 @@ describe('SpecReporter', () => { tmpReporter['_consoleOutput']='Printing to console spec' tmpReporter.onHookEnd({ title:'test1', - state:'failed' + state:State.FAILED } as any) expect(tmpReporter.printCurrentStats).toBeCalledWith({ title:'test1', - state:'failed' + state:State.FAILED }) tmpReporter.onSuiteEnd() tmpReporter.onRunnerEnd(runnerEnd())