/* * decaffeinate suggestions: * DS001: Remove Babel/TypeScript constructor workaround * DS103: Rewrite code to no longer use __guard__ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ import path from 'path'; import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; const formatStackTrace = function(spec, message, stackTrace, indent) { if (message == null) { message = ''; } if (indent == null) { indent = ''; } if (!stackTrace) { return stackTrace; } const jasminePattern = /^\s*at\s+.*\(?.*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/; const firstJasmineLinePattern = /^\s*at [/\\].*[/\\]jasmine(-[^/\\]*)?\.js:\d+:\d+\)?\s*$/; const convertedLines = []; for (var line of stackTrace.split('\n')) { if (!jasminePattern.test(line)) { convertedLines.push(line); } if (firstJasmineLinePattern.test(line)) { break; } } stackTrace = convertedLines.join('\n'); let lines = stackTrace.split('\n'); // Remove first line of stack when it is the same as the error message const errorMatch = lines[0] != null ? lines[0].match(/^Error: (.*)/) : undefined; if (errorMatch && message.trim() === errorMatch[1].trim()) { lines.shift(); } for (let index = 0; index < lines.length; index++) { // Remove prefix of lines matching: at [object Object]. (path:1:2) line = lines[index]; const prefixMatch = line.match(/at \[object Object\]\. \(([^)]+)\)/); if (prefixMatch) { line = `at ${prefixMatch[1]}`; } // Relativize locations to spec directory lines[index] = line.replace(`at ${spec.specDirectory}${path.sep}`, 'at '); } lines = lines.map(line => indent + line.trim()); return lines.join('\n'); }; function indentationString(suite, plus) { if (plus == null) { plus = 0; } let rootSuite = suite; let indentLevel = 0 + plus; while (rootSuite.parentSuite) { rootSuite = rootSuite.parentSuite; indentLevel += 1; } return __range__(0, indentLevel, false) .map(() => ' ') .join(''); } function suiteString(spec) { const descriptions = [spec.suite.description]; let rootSuite = spec.suite; while (rootSuite.parentSuite) { const indent = indentationString(rootSuite); descriptions.unshift(indent + rootSuite.description); rootSuite = rootSuite.parentSuite; } return descriptions.join('\n'); } class N1GuiReporter extends React.Component { render() { return (
Core
{this._renderSpecsOfType('core')}
Bundled
{this._renderSpecsOfType('bundled')}
User
{this._renderSpecsOfType('user')}
{this._renderStatus()}
{this._renderFailures()}
{this.props.plainTextOutput}
); } _renderSpecsOfType = type => { const items = []; this.props.specs.forEach((spec, idx) => { if (spec.specType !== type) { return; } let statusClass = 'pending'; let title = undefined; const results = spec.results(); if (results) { if (results.skipped) { statusClass = 'skipped'; } else if (results.failedCount > 0) { statusClass = 'failed'; title = spec.getFullName(); } else if (spec.endedAt) { statusClass = 'passed'; } } return items.push(
  • ); }); return items; }; _renderFailures = () => { // We have an array of specs with `suite` and potentially N `parentSuite` from there. // Create a tree instead. const topLevelSuites = []; const failedSpecs = this.props.specs.filter( spec => spec.endedAt && spec.results().failedCount > 0 ); for (let spec of failedSpecs) { let { suite } = spec; while (suite.parentSuite) { suite = suite.parentSuite; } if (topLevelSuites.indexOf(suite) === -1) { topLevelSuites.push(suite); } } return topLevelSuites.map((suite, idx) => ( )); }; _renderStatus = () => { let message, specCount; let failedCount = 0; let skippedCount = 0; let completeCount = 0; for (let spec of this.props.specs) { const results = spec.results(); if (!spec.endedAt) { continue; } if (results.failedCount > 0) { failedCount += 1; } if (results.skipped) { skippedCount += 1; } if (results.passedCount > 0 && results.failedCount === 0) { completeCount += 1; } } if (failedCount === 1) { message = `${failedCount} failure`; } else { message = `${failedCount} failures`; } if (skippedCount) { specCount = `${completeCount - skippedCount}/${this.props.specs.length - skippedCount} (${skippedCount} skipped)`; } else { specCount = `${completeCount}/${this.props.specs.length}`; } return (
    {specCount}
    {message}
    ); }; onReloadSpecs = () => { require('electron') .remote.getCurrentWindow() .reload(); }; } class SuiteResultView extends React.Component { static propTypes = { suite: PropTypes.object, allSpecs: PropTypes.array, }; render() { let items = []; let subsuites = []; this.props.allSpecs.forEach(spec => { if (spec.suite === this.props.suite) { return items.push(spec); } else { let { suite } = spec; while (suite.parentSuite) { if (suite.parentSuite === this.props.suite) { subsuites.push(suite); return; } suite = suite.parentSuite; } } }); items = items.map((spec, idx) => ); subsuites = subsuites.map((suite, idx) => ( )); return (
    {this.props.suite.description}
    {items} {subsuites}
    ); } } class SpecResultView extends React.Component { static propTypes = { spec: PropTypes.object, }; render() { let { description } = this.props.spec; const resultItems = this.props.spec.results().getItems(); if (description.indexOf('it ') !== 0) { description = `it ${description}`; } const failures = []; for (let idx = 0; idx < resultItems.length; idx++) { const result = resultItems[idx]; if (result.passed()) { continue; } const stackTrace = formatStackTrace(this.props.spec, result.message, result.trace.stack); failures.push(
    {result.message}
    {stackTrace}
    ); } return (
    {description}
    {failures}
    ); } } const el = document.createElement('div'); document.body.appendChild(el); let startedAt = null; let specs = []; let plainTextOutput = ''; const update = () => { const component = ; return ReactDOM.render(component, el); }; export function reportRunnerStarting(runner) { specs = runner.specs(); startedAt = Date.now(); update(); } export function reportRunnerResults(runner) { update(); } export function reportSuiteResults(suite) {} export function reportSpecResults(spec) { spec.endedAt = Date.now(); update(); } export function reportPlainTextSpecResult(spec) { let str = ''; if (spec.results().failedCount > 0) { str += suiteString(spec) + '\n'; const indent = indentationString(spec.suite, 1); const stackIndent = indentationString(spec.suite, 2); let { description } = spec; if (description.indexOf('it ') !== 0) { description = `it ${description}`; } str += indent + description + '\n'; for (let result of spec.results().getItems()) { if (result.passed()) { continue; } str += indent + result.message + '\n'; const stackTrace = formatStackTrace(spec, result.message, result.trace.stack, stackIndent); str += stackTrace + '\n'; } str += '\n\n'; } plainTextOutput = plainTextOutput + str; update(); } export function reportSpecStarting(spec) { update(); } function __range__(left, right, inclusive) { let range = []; let ascending = left < right; let end = !inclusive ? right : ascending ? right + 1 : right - 1; for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) { range.push(i); } return range; }