@wdio/reporter
Advanced tools
Comparing version 9.0.0-alpha.426 to 9.0.0
@@ -6,3 +6,3 @@ import type { WriteStream } from 'node:fs'; | ||
import HookStats from './stats/hook.js'; | ||
import TestStats, { Test } from './stats/test.js'; | ||
import TestStats, { type Test } from './stats/test.js'; | ||
import RunnerStats from './stats/runner.js'; | ||
@@ -9,0 +9,0 @@ import type { AfterCommandArgs, BeforeCommandArgs, CommandArgs, Tag, Argument } from './types.js'; |
@@ -1,261 +0,713 @@ | ||
import fs from 'node:fs'; | ||
import { EventEmitter } from 'node:events'; | ||
import { getErrorsFromEvent } from './utils.js'; | ||
import SuiteStats from './stats/suite.js'; | ||
import HookStats from './stats/hook.js'; | ||
import TestStats from './stats/test.js'; | ||
import RunnerStats from './stats/runner.js'; | ||
export default class WDIOReporter extends EventEmitter { | ||
options; | ||
outputStream; | ||
failures = 0; | ||
suites = {}; | ||
hooks = {}; | ||
tests = {}; | ||
currentSuites = []; | ||
counts = { | ||
suites: 0, | ||
tests: 0, | ||
hooks: 0, | ||
passes: 0, | ||
skipping: 0, | ||
failures: 0 | ||
}; | ||
retries = 0; | ||
runnerStat; | ||
isContentPresent = false; | ||
specs = []; | ||
currentSpec; | ||
constructor(options) { | ||
super(); | ||
this.options = options; | ||
// ensure the report directory exists | ||
if (this.options.outputDir) { | ||
try { | ||
fs.mkdirSync(this.options.outputDir, { recursive: true }); | ||
} | ||
catch (err) { | ||
throw new Error(`Couldn't create output directory at "${this.options.outputDir}": ${err.stack}`); | ||
} | ||
} | ||
this.outputStream = (this.options.stdout || !this.options.logFile) && this.options.writeStream | ||
? this.options.writeStream | ||
: fs.createWriteStream(this.options.logFile); | ||
let currentTest; | ||
const rootSuite = new SuiteStats({ | ||
title: '(root)', | ||
fullTitle: '(root)', | ||
file: '' | ||
}); | ||
this.currentSuites.push(rootSuite); | ||
this.on('client:beforeCommand', this.onBeforeCommand.bind(this)); | ||
this.on('client:afterCommand', this.onAfterCommand.bind(this)); | ||
this.on('client:beforeAssertion', this.onBeforeAssertion.bind(this)); | ||
this.on('client:afterAssertion', this.onAfterAssertion.bind(this)); | ||
this.on('runner:start', /* istanbul ignore next */ (runner) => { | ||
rootSuite.cid = runner.cid; | ||
this.specs.push(...runner.specs); | ||
this.runnerStat = new RunnerStats(runner); | ||
this.onRunnerStart(this.runnerStat); | ||
}); | ||
this.on('suite:start', /* istanbul ignore next */ (params) => { | ||
/** | ||
* the jasmine framework doesn't give us information about the file | ||
* therefore we need to propagate these information into params | ||
*/ | ||
if (!params.file) { | ||
params.file = !params.parent | ||
? this.specs.shift() || 'unknown spec file' | ||
: this.currentSpec; | ||
this.currentSpec = params.file; | ||
} | ||
const suite = new SuiteStats(params); | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentSuite.suites.push(suite); | ||
this.currentSuites.push(suite); | ||
this.suites[suite.uid] = suite; | ||
this.onSuiteStart(suite); | ||
}); | ||
this.on('hook:start', /* istanbul ignore next */ (hook) => { | ||
const hookStats = new HookStats(hook); | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentSuite.hooks.push(hookStats); | ||
currentSuite.hooksAndTests.push(hookStats); | ||
this.hooks[hook.uid] = hookStats; | ||
this.onHookStart(hookStats); | ||
}); | ||
this.on('hook:end', /* istanbul ignore next */ (hook) => { | ||
const hookStats = this.hooks[hook.uid]; | ||
hookStats.complete(getErrorsFromEvent(hook)); | ||
this.counts.hooks++; | ||
this.onHookEnd(hookStats); | ||
}); | ||
this.on('test:start', /* istanbul ignore next */ (test) => { | ||
test.retries = this.retries; | ||
currentTest = new TestStats(test); | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentSuite.tests.push(currentTest); | ||
currentSuite.hooksAndTests.push(currentTest); | ||
this.tests[test.uid] = currentTest; | ||
this.onTestStart(currentTest); | ||
}); | ||
this.on('test:pass', /* istanbul ignore next */ (test) => { | ||
const testStat = this.tests[test.uid]; | ||
testStat.pass(); | ||
this.counts.passes++; | ||
this.counts.tests++; | ||
this.onTestPass(testStat); | ||
}); | ||
this.on('test:skip', (test) => { | ||
const testStat = this.tests[test.uid]; | ||
currentTest.skip(test.pendingReason); | ||
this.counts.skipping++; | ||
this.counts.tests++; | ||
this.onTestSkip(testStat); | ||
}); | ||
this.on('test:fail', /* istanbul ignore next */ (test) => { | ||
const testStat = this.tests[test.uid]; | ||
testStat.fail(getErrorsFromEvent(test)); | ||
this.counts.failures++; | ||
this.counts.tests++; | ||
this.onTestFail(testStat); | ||
}); | ||
this.on('test:retry', (test) => { | ||
const testStat = this.tests[test.uid]; | ||
testStat.fail(getErrorsFromEvent(test)); | ||
this.onTestRetry(testStat); | ||
this.retries++; | ||
}); | ||
this.on('test:pending', (test) => { | ||
test.retries = this.retries; | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentTest = new TestStats(test); | ||
/** | ||
* In Mocha: tests that are skipped don't have a start event but a test end. | ||
* In Jasmine: tests have a start event, therefore we need to replace the | ||
* test instance with the pending test here | ||
*/ | ||
if (test.uid in this.tests && this.tests[test.uid].state !== 'pending') { | ||
currentTest.uid = test.uid in this.tests ? 'skipped-' + this.counts.skipping : currentTest.uid; | ||
} | ||
const suiteTests = currentSuite.tests; | ||
if (!suiteTests.length || currentTest.uid !== suiteTests[suiteTests.length - 1].uid) { | ||
currentSuite.tests.push(currentTest); | ||
currentSuite.hooksAndTests.push(currentTest); | ||
} | ||
else { | ||
suiteTests[suiteTests.length - 1] = currentTest; | ||
currentSuite.hooksAndTests[currentSuite.hooksAndTests.length - 1] = currentTest; | ||
} | ||
this.tests[currentTest.uid] = currentTest; | ||
currentTest.skip(test.pendingReason); | ||
this.counts.skipping++; | ||
this.counts.tests++; | ||
this.onTestSkip(currentTest); | ||
}); | ||
this.on('test:end', /* istanbul ignore next */ (test) => { | ||
const testStat = this.tests[test.uid]; | ||
this.retries = 0; | ||
this.onTestEnd(testStat); | ||
}); | ||
this.on('suite:end', /* istanbul ignore next */ (suite) => { | ||
const suiteStat = this.suites[suite.uid]; | ||
suiteStat.complete(); | ||
this.currentSuites.pop(); | ||
this.onSuiteEnd(suiteStat); | ||
}); | ||
this.on('runner:end', /* istanbul ignore next */ (runner) => { | ||
rootSuite.complete(); | ||
if (this.runnerStat) { | ||
this.runnerStat.failures = runner.failures; | ||
this.runnerStat.retries = runner.retries; | ||
this.runnerStat.complete(); | ||
this.onRunnerEnd(this.runnerStat); | ||
} | ||
const logFile = this.options.logFile; | ||
if (!this.isContentPresent && logFile && fs.existsSync(logFile)) { | ||
fs.unlinkSync(logFile); | ||
} | ||
}); | ||
/** | ||
* browser client event handlers | ||
*/ | ||
this.on('client:beforeCommand', /* istanbul ignore next */ (payload) => { | ||
if (!currentTest) { | ||
return; | ||
} | ||
currentTest.output.push(Object.assign(payload, { type: 'command' })); | ||
}); | ||
this.on('client:afterCommand', /* istanbul ignore next */ (payload) => { | ||
if (!currentTest) { | ||
return; | ||
} | ||
currentTest.output.push(Object.assign(payload, { type: 'result' })); | ||
}); | ||
// src/index.ts | ||
import fs from "node:fs"; | ||
import { EventEmitter } from "node:events"; | ||
// src/supportsColor.ts | ||
import process from "node:process"; | ||
import os from "node:os"; | ||
import tty from "node:tty"; | ||
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) { | ||
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; | ||
const position = argv.indexOf(prefix + flag); | ||
const terminatorPosition = argv.indexOf("--"); | ||
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); | ||
} | ||
var { env } = process; | ||
var flagForceColor; | ||
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { | ||
flagForceColor = 0; | ||
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { | ||
flagForceColor = 1; | ||
} | ||
function envForceColor() { | ||
if ("FORCE_COLOR" in env) { | ||
if (env.FORCE_COLOR === "true") { | ||
return 1; | ||
} | ||
/** | ||
* allows reporter to stale process shutdown process until required sync work | ||
* is done (e.g. when having to send data to some server or any other async work) | ||
*/ | ||
get isSynchronised() { | ||
return true; | ||
if (env.FORCE_COLOR === "false") { | ||
return 0; | ||
} | ||
/** | ||
* function to write to reporters output stream | ||
*/ | ||
write(content) { | ||
if (content) { | ||
this.isContentPresent = true; | ||
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); | ||
} | ||
} | ||
function translateLevel(level) { | ||
if (level === 0) { | ||
return false; | ||
} | ||
return { | ||
level, | ||
hasBasic: true, | ||
has256: level >= 2, | ||
has16m: level >= 3 | ||
}; | ||
} | ||
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) { | ||
const noFlagForceColor = envForceColor(); | ||
if (noFlagForceColor !== void 0) { | ||
flagForceColor = noFlagForceColor; | ||
} | ||
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; | ||
if (forceColor === 0) { | ||
return 0; | ||
} | ||
if (sniffFlags) { | ||
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) { | ||
return 3; | ||
} | ||
if (hasFlag("color=256")) { | ||
return 2; | ||
} | ||
} | ||
if ("TF_BUILD" in env && "AGENT_NAME" in env) { | ||
return 1; | ||
} | ||
if (haveStream && !streamIsTTY && forceColor === void 0) { | ||
return 0; | ||
} | ||
const min = forceColor || 0; | ||
if (env.TERM === "dumb") { | ||
return min; | ||
} | ||
if (process.platform === "win32") { | ||
const osRelease = os.release().split("."); | ||
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { | ||
return Number(osRelease[2]) >= 14931 ? 3 : 2; | ||
} | ||
return 1; | ||
} | ||
if ("CI" in env) { | ||
if ("GITHUB_ACTIONS" in env || "GITEA_ACTIONS" in env) { | ||
return 3; | ||
} | ||
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") { | ||
return 1; | ||
} | ||
return min; | ||
} | ||
if ("TEAMCITY_VERSION" in env) { | ||
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; | ||
} | ||
if (env.COLORTERM === "truecolor") { | ||
return 3; | ||
} | ||
if (env.TERM === "xterm-kitty") { | ||
return 3; | ||
} | ||
if ("TERM_PROGRAM" in env) { | ||
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10); | ||
switch (env.TERM_PROGRAM) { | ||
case "iTerm.app": { | ||
return version >= 3 ? 3 : 2; | ||
} | ||
case "Apple_Terminal": { | ||
return 2; | ||
} | ||
} | ||
} | ||
if (env.TERM && /-256(color)?$/i.test(env.TERM)) { | ||
return 2; | ||
} | ||
if (env.TERM && /^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { | ||
return 1; | ||
} | ||
if ("COLORTERM" in env) { | ||
return 1; | ||
} | ||
return min; | ||
} | ||
function createSupportsColor(stream, options = {}) { | ||
const level = _supportsColor(stream, { | ||
streamIsTTY: stream && stream.isTTY, | ||
...options | ||
}); | ||
return translateLevel(level); | ||
} | ||
var supportsColor = { | ||
stdout: createSupportsColor({ isTTY: tty.isatty(1) }), | ||
stderr: createSupportsColor({ isTTY: tty.isatty(2) }) | ||
}; | ||
var supportsColor_default = supportsColor; | ||
// src/constants.ts | ||
var COLORS = { | ||
pass: 90, | ||
fail: 31, | ||
"bright pass": 92, | ||
"bright fail": 91, | ||
"bright yellow": 93, | ||
pending: 36, | ||
suite: 0, | ||
"error title": 0, | ||
"error message": 31, | ||
"error stack": 90, | ||
checkmark: 32, | ||
fast: 90, | ||
medium: 33, | ||
slow: 31, | ||
green: 32, | ||
light: 90, | ||
"diff gutter": 90, | ||
"diff added": 32, | ||
"diff removed": 31, | ||
"diff added inline": "30;42", | ||
"diff removed inline": "30;41" | ||
}; | ||
// src/utils.ts | ||
function sanitizeString(str) { | ||
if (!str) { | ||
return ""; | ||
} | ||
return String(str).replace(/^.*\/([^/]+)\/?$/, "$1").replace(/\./g, "_").replace(/\s/g, "").toLowerCase(); | ||
} | ||
function sanitizeCaps(caps) { | ||
if (!caps) { | ||
return ""; | ||
} | ||
let result; | ||
result = caps["appium:deviceName"] || caps.deviceName ? [ | ||
sanitizeString(caps.platformName), | ||
// @ts-expect-error outdated JSONWP capabilities | ||
sanitizeString(caps["appium:deviceName"] || caps.deviceName), | ||
sanitizeString(caps["appium:platformVersion"]), | ||
sanitizeString(caps["appium:app"]) | ||
] : [ | ||
sanitizeString(caps.browserName), | ||
// @ts-expect-error outdated JSONWP capabilities | ||
sanitizeString(caps.version || caps.browserVersion), | ||
// @ts-expect-error outdated JSONWP capabilities | ||
sanitizeString(caps.platform || caps.platformName), | ||
sanitizeString(caps["appium:app"]) | ||
]; | ||
result = result.filter((n) => n !== void 0 && n !== ""); | ||
return result.join("."); | ||
} | ||
function getErrorsFromEvent(e) { | ||
if (e.errors) { | ||
return e.errors; | ||
} | ||
if (e.error) { | ||
return [e.error]; | ||
} | ||
return []; | ||
} | ||
function pad(str, len) { | ||
return Array(len - str.length + 1).join(" ") + str; | ||
} | ||
function color(type, content) { | ||
if (!supportsColor_default.stdout) { | ||
return String(content); | ||
} | ||
return `\x1B[${COLORS[type]}m${content}\x1B[0m`; | ||
} | ||
function colorLines(name, str) { | ||
return str.split("\n").map((str2) => color(name, str2)).join("\n"); | ||
} | ||
// src/stats/runnable.ts | ||
var RunnableStats = class { | ||
constructor(type) { | ||
this.type = type; | ||
} | ||
start = /* @__PURE__ */ new Date(); | ||
end; | ||
_duration = 0; | ||
complete() { | ||
this.end = /* @__PURE__ */ new Date(); | ||
this._duration = this.end.getTime() - this.start.getTime(); | ||
} | ||
get duration() { | ||
if (this.end) { | ||
return this._duration; | ||
} | ||
return (/* @__PURE__ */ new Date()).getTime() - this.start.getTime(); | ||
} | ||
/** | ||
* ToDo: we should always rely on uid | ||
*/ | ||
static getIdentifier(runner) { | ||
return runner.uid || runner.title; | ||
} | ||
}; | ||
// src/stats/suite.ts | ||
var SuiteStats = class extends RunnableStats { | ||
uid; | ||
cid; | ||
file; | ||
title; | ||
fullTitle; | ||
tags; | ||
tests = []; | ||
hooks = []; | ||
suites = []; | ||
parent; | ||
/** | ||
* an array of hooks and tests stored in order as they happen | ||
*/ | ||
hooksAndTests = []; | ||
description; | ||
rule; | ||
constructor(suite) { | ||
super(suite.type || "suite"); | ||
this.uid = RunnableStats.getIdentifier(suite); | ||
this.cid = suite.cid; | ||
this.file = suite.file; | ||
this.title = suite.title; | ||
this.fullTitle = suite.fullTitle; | ||
this.tags = suite.tags; | ||
this.parent = suite.parent; | ||
this.description = suite.description; | ||
this.rule = suite.rule; | ||
} | ||
}; | ||
// src/stats/hook.ts | ||
var HookStats = class extends RunnableStats { | ||
uid; | ||
cid; | ||
title; | ||
parent; | ||
// Mocha only | ||
body; | ||
errors; | ||
error; | ||
state; | ||
currentTest; | ||
constructor(runner) { | ||
super("hook"); | ||
this.uid = RunnableStats.getIdentifier(runner); | ||
this.cid = runner.cid; | ||
this.title = runner.title; | ||
this.parent = runner.parent; | ||
this.currentTest = runner.currentTest; | ||
this.body = runner.body; | ||
} | ||
complete(errors) { | ||
this.errors = errors; | ||
if (errors && errors.length) { | ||
this.error = errors[0]; | ||
this.state = "failed"; | ||
} | ||
super.complete(); | ||
} | ||
}; | ||
// src/stats/test.ts | ||
import { types as nodeUtilTypes } from "node:util"; | ||
import { diffWordsWithSpace } from "diff"; | ||
import objectInspect from "object-inspect"; | ||
var maxStringLength = 2048; | ||
var TestStats = class extends RunnableStats { | ||
uid; | ||
cid; | ||
title; | ||
currentTest; | ||
fullTitle; | ||
output; | ||
argument; | ||
retries; | ||
parent; | ||
/** | ||
* initial test state is pending | ||
* the state can change to the following: passed, skipped, failed | ||
*/ | ||
state; | ||
pendingReason; | ||
errors; | ||
error; | ||
body; | ||
constructor(test) { | ||
super("test"); | ||
this.uid = RunnableStats.getIdentifier(test); | ||
this.cid = test.cid; | ||
this.title = test.title; | ||
this.fullTitle = test.fullTitle; | ||
this.output = []; | ||
this.argument = test.argument; | ||
this.retries = test.retries; | ||
this.parent = test.parent; | ||
this.body = test.body; | ||
this.state = "pending"; | ||
} | ||
pass() { | ||
this.complete(); | ||
this.state = "passed"; | ||
} | ||
skip(reason) { | ||
this.pendingReason = reason; | ||
this.state = "skipped"; | ||
} | ||
fail(errors) { | ||
this.complete(); | ||
this.state = "failed"; | ||
const formattedErrors = errors?.map((err) => ( | ||
/** | ||
* only format if error object has either an "expected" or "actual" property set | ||
*/ | ||
(err.expected || err.actual) && !nodeUtilTypes.isProxy(err.actual) && /** | ||
* and if they aren't already formated, e.g. in Jasmine | ||
*/ | ||
(err.message && !err.message.includes("Expected: ") && !err.message.includes("Received: ")) ? this._stringifyDiffObjs(err) : err | ||
)); | ||
this.errors = formattedErrors; | ||
if (formattedErrors && formattedErrors.length) { | ||
this.error = formattedErrors[0]; | ||
} | ||
} | ||
_stringifyDiffObjs(err) { | ||
const inspectOpts = { maxStringLength }; | ||
const expected = objectInspect(err.expected, inspectOpts); | ||
const actual = objectInspect(err.actual, inspectOpts); | ||
let msg = diffWordsWithSpace(actual, expected).map((str) => str.added ? colorLines("diff added inline", str.value) : str.removed ? colorLines("diff removed inline", str.value) : str.value).join(""); | ||
const lines = msg.split("\n"); | ||
if (lines.length > 4) { | ||
const width = String(lines.length).length; | ||
msg = lines.map(function(str, i) { | ||
return pad(String(++i), width) + " | " + str; | ||
}).join("\n"); | ||
} | ||
msg = ` | ||
${color("diff removed inline", "actual")} ${color("diff added inline", "expected")} | ||
${msg} | ||
`; | ||
msg = msg.replace(/^/gm, " "); | ||
const newError = new Error(err.message + msg); | ||
newError.stack = err.stack; | ||
return newError; | ||
} | ||
}; | ||
// src/stats/runner.ts | ||
var RunnerStats = class extends RunnableStats { | ||
cid; | ||
capabilities; | ||
sanitizedCapabilities; | ||
config; | ||
specs; | ||
sessionId; | ||
isMultiremote; | ||
instanceOptions; | ||
retry; | ||
failures; | ||
retries; | ||
constructor(runner) { | ||
super("runner"); | ||
this.cid = runner.cid; | ||
this.capabilities = runner.capabilities; | ||
this.sanitizedCapabilities = sanitizeCaps(runner.capabilities); | ||
this.config = runner.config; | ||
this.specs = runner.specs; | ||
this.sessionId = runner.sessionId; | ||
this.isMultiremote = runner.isMultiremote; | ||
this.instanceOptions = runner.instanceOptions; | ||
this.retry = runner.retry; | ||
} | ||
}; | ||
// src/index.ts | ||
var WDIOReporter = class extends EventEmitter { | ||
constructor(options) { | ||
super(); | ||
this.options = options; | ||
if (this.options.outputDir) { | ||
try { | ||
fs.mkdirSync(this.options.outputDir, { recursive: true }); | ||
} catch (err) { | ||
throw new Error(`Couldn't create output directory at "${this.options.outputDir}": ${err.stack}`); | ||
} | ||
} | ||
this.outputStream = (this.options.stdout || !this.options.logFile) && this.options.writeStream ? this.options.writeStream : fs.createWriteStream(this.options.logFile); | ||
let currentTest; | ||
const rootSuite = new SuiteStats({ | ||
title: "(root)", | ||
fullTitle: "(root)", | ||
file: "" | ||
}); | ||
this.currentSuites.push(rootSuite); | ||
this.on("client:beforeCommand", this.onBeforeCommand.bind(this)); | ||
this.on("client:afterCommand", this.onAfterCommand.bind(this)); | ||
this.on("client:beforeAssertion", this.onBeforeAssertion.bind(this)); | ||
this.on("client:afterAssertion", this.onAfterAssertion.bind(this)); | ||
this.on( | ||
"runner:start", | ||
/* istanbul ignore next */ | ||
(runner) => { | ||
rootSuite.cid = runner.cid; | ||
this.specs.push(...runner.specs); | ||
this.runnerStat = new RunnerStats(runner); | ||
this.onRunnerStart(this.runnerStat); | ||
} | ||
); | ||
this.on( | ||
"suite:start", | ||
/* istanbul ignore next */ | ||
(params) => { | ||
if (!params.file) { | ||
params.file = !params.parent ? this.specs.shift() || "unknown spec file" : this.currentSpec; | ||
this.currentSpec = params.file; | ||
} | ||
this.outputStream.write(content); | ||
const suite = new SuiteStats(params); | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentSuite.suites.push(suite); | ||
this.currentSuites.push(suite); | ||
this.suites[suite.uid] = suite; | ||
this.onSuiteStart(suite); | ||
} | ||
); | ||
this.on( | ||
"hook:start", | ||
/* istanbul ignore next */ | ||
(hook) => { | ||
const hookStats = new HookStats(hook); | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentSuite.hooks.push(hookStats); | ||
currentSuite.hooksAndTests.push(hookStats); | ||
this.hooks[hook.uid] = hookStats; | ||
this.onHookStart(hookStats); | ||
} | ||
); | ||
this.on( | ||
"hook:end", | ||
/* istanbul ignore next */ | ||
(hook) => { | ||
const hookStats = this.hooks[hook.uid]; | ||
hookStats.complete(getErrorsFromEvent(hook)); | ||
this.counts.hooks++; | ||
this.onHookEnd(hookStats); | ||
} | ||
); | ||
this.on( | ||
"test:start", | ||
/* istanbul ignore next */ | ||
(test) => { | ||
test.retries = this.retries; | ||
currentTest = new TestStats(test); | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentSuite.tests.push(currentTest); | ||
currentSuite.hooksAndTests.push(currentTest); | ||
this.tests[test.uid] = currentTest; | ||
this.onTestStart(currentTest); | ||
} | ||
); | ||
this.on( | ||
"test:pass", | ||
/* istanbul ignore next */ | ||
(test) => { | ||
const testStat = this.tests[test.uid]; | ||
testStat.pass(); | ||
this.counts.passes++; | ||
this.counts.tests++; | ||
this.onTestPass(testStat); | ||
} | ||
); | ||
this.on("test:skip", (test) => { | ||
const testStat = this.tests[test.uid]; | ||
currentTest.skip(test.pendingReason); | ||
this.counts.skipping++; | ||
this.counts.tests++; | ||
this.onTestSkip(testStat); | ||
}); | ||
this.on( | ||
"test:fail", | ||
/* istanbul ignore next */ | ||
(test) => { | ||
const testStat = this.tests[test.uid]; | ||
testStat.fail(getErrorsFromEvent(test)); | ||
this.counts.failures++; | ||
this.counts.tests++; | ||
this.onTestFail(testStat); | ||
} | ||
); | ||
this.on("test:retry", (test) => { | ||
const testStat = this.tests[test.uid]; | ||
testStat.fail(getErrorsFromEvent(test)); | ||
this.onTestRetry(testStat); | ||
this.retries++; | ||
}); | ||
this.on("test:pending", (test) => { | ||
test.retries = this.retries; | ||
const currentSuite = this.currentSuites[this.currentSuites.length - 1]; | ||
currentTest = new TestStats(test); | ||
if (test.uid in this.tests && this.tests[test.uid].state !== "pending") { | ||
currentTest.uid = test.uid in this.tests ? "skipped-" + this.counts.skipping : currentTest.uid; | ||
} | ||
const suiteTests = currentSuite.tests; | ||
if (!suiteTests.length || currentTest.uid !== suiteTests[suiteTests.length - 1].uid) { | ||
currentSuite.tests.push(currentTest); | ||
currentSuite.hooksAndTests.push(currentTest); | ||
} else { | ||
suiteTests[suiteTests.length - 1] = currentTest; | ||
currentSuite.hooksAndTests[currentSuite.hooksAndTests.length - 1] = currentTest; | ||
} | ||
this.tests[currentTest.uid] = currentTest; | ||
currentTest.skip(test.pendingReason); | ||
this.counts.skipping++; | ||
this.counts.tests++; | ||
this.onTestSkip(currentTest); | ||
}); | ||
this.on( | ||
"test:end", | ||
/* istanbul ignore next */ | ||
(test) => { | ||
const testStat = this.tests[test.uid]; | ||
this.retries = 0; | ||
this.onTestEnd(testStat); | ||
} | ||
); | ||
this.on( | ||
"suite:end", | ||
/* istanbul ignore next */ | ||
(suite) => { | ||
const suiteStat = this.suites[suite.uid]; | ||
suiteStat.complete(); | ||
this.currentSuites.pop(); | ||
this.onSuiteEnd(suiteStat); | ||
} | ||
); | ||
this.on( | ||
"runner:end", | ||
/* istanbul ignore next */ | ||
(runner) => { | ||
rootSuite.complete(); | ||
if (this.runnerStat) { | ||
this.runnerStat.failures = runner.failures; | ||
this.runnerStat.retries = runner.retries; | ||
this.runnerStat.complete(); | ||
this.onRunnerEnd(this.runnerStat); | ||
} | ||
const logFile = this.options.logFile; | ||
if (!this.isContentPresent && logFile && fs.existsSync(logFile)) { | ||
fs.unlinkSync(logFile); | ||
} | ||
} | ||
); | ||
this.on( | ||
"client:beforeCommand", | ||
/* istanbul ignore next */ | ||
(payload) => { | ||
if (!currentTest) { | ||
return; | ||
} | ||
currentTest.output.push(Object.assign(payload, { type: "command" })); | ||
} | ||
); | ||
this.on( | ||
"client:afterCommand", | ||
/* istanbul ignore next */ | ||
(payload) => { | ||
if (!currentTest) { | ||
return; | ||
} | ||
currentTest.output.push(Object.assign(payload, { type: "result" })); | ||
} | ||
); | ||
} | ||
outputStream; | ||
failures = 0; | ||
suites = {}; | ||
hooks = {}; | ||
tests = {}; | ||
currentSuites = []; | ||
counts = { | ||
suites: 0, | ||
tests: 0, | ||
hooks: 0, | ||
passes: 0, | ||
skipping: 0, | ||
failures: 0 | ||
}; | ||
retries = 0; | ||
runnerStat; | ||
isContentPresent = false; | ||
specs = []; | ||
currentSpec; | ||
/** | ||
* allows reporter to stale process shutdown process until required sync work | ||
* is done (e.g. when having to send data to some server or any other async work) | ||
*/ | ||
get isSynchronised() { | ||
return true; | ||
} | ||
/** | ||
* function to write to reporters output stream | ||
*/ | ||
write(content) { | ||
if (content) { | ||
this.isContentPresent = true; | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onRunnerStart(runnerStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onBeforeCommand(commandArgs) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onAfterCommand(commandArgs) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onBeforeAssertion(assertionArgs) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onAfterAssertion(assertionArgs) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onSuiteStart(suiteStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onHookStart(hookStat) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onHookEnd(hookStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestStart(testStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestPass(testStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestFail(testStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestRetry(testStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestSkip(testStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestEnd(testStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onSuiteEnd(suiteStats) { } | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onRunnerEnd(runnerStats) { } | ||
} | ||
export { SuiteStats, HookStats, TestStats, RunnerStats }; | ||
this.outputStream.write(content); | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onRunnerStart(runnerStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onBeforeCommand(commandArgs) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onAfterCommand(commandArgs) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onBeforeAssertion(assertionArgs) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onAfterAssertion(assertionArgs) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onSuiteStart(suiteStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onHookStart(hookStat) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onHookEnd(hookStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestStart(testStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestPass(testStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestFail(testStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestRetry(testStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestSkip(testStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onTestEnd(testStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onSuiteEnd(suiteStats) { | ||
} | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
onRunnerEnd(runnerStats) { | ||
} | ||
}; | ||
export { | ||
HookStats, | ||
RunnerStats, | ||
SuiteStats, | ||
TestStats, | ||
WDIOReporter as default | ||
}; |
{ | ||
"name": "@wdio/reporter", | ||
"version": "9.0.0-alpha.426+d760644c4", | ||
"version": "9.0.0", | ||
"description": "A WebdriverIO utility to help reporting all events", | ||
@@ -28,15 +28,11 @@ "author": "Christian Bromann <mail@bromann.dev>", | ||
"type": "module", | ||
"main": "./cjs/index.js", | ||
"main": "./build/index.cjs", | ||
"module": "./build/index.js", | ||
"types": "./build/index.d.ts", | ||
"exports": { | ||
"./package.json": "./package.json", | ||
".": [ | ||
{ | ||
"types": "./build/index.d.ts", | ||
"import": "./build/index.js", | ||
"require": "./cjs/index.js" | ||
}, | ||
"./cjs/index.js" | ||
] | ||
".": { | ||
"types": "./build/index.d.ts", | ||
"import": "./build/index.js", | ||
"require": "./build/index.cjs" | ||
} | ||
}, | ||
@@ -46,4 +42,4 @@ "typeScriptVersion": "3.8.3", | ||
"@types/node": "^20.1.0", | ||
"@wdio/logger": "9.0.0-alpha.426+d760644c4", | ||
"@wdio/types": "9.0.0-alpha.426+d760644c4", | ||
"@wdio/logger": "9.0.0", | ||
"@wdio/types": "9.0.0", | ||
"diff": "^5.0.0", | ||
@@ -59,3 +55,3 @@ "object-inspect": "^1.12.0" | ||
}, | ||
"gitHead": "d760644c4c6e1ef910c0bee120cb422e25dbbe06" | ||
"gitHead": "957693463371a4cb329395dcdbce8fb0c930ab93" | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
5
74546
25
1815
+ Added@wdio/logger@9.0.0(transitive)
+ Added@wdio/types@9.0.0(transitive)
+ Addedansi-regex@6.1.0(transitive)
+ Addedchalk@5.3.0(transitive)
+ Addedloglevel@1.9.2(transitive)
+ Addedloglevel-plugin-prefix@0.8.4(transitive)
+ Addedstrip-ansi@7.1.0(transitive)
Updated@wdio/logger@9.0.0
Updated@wdio/types@9.0.0