Take a screenshot after failed steps or save the HTML for non js drivers.

@AfterStep
349039
public function takeScreenshotAfterFailedStep(AfterStepScope $event) {
    if ($event->getTestResult()->isPassed()) {
      // Not a failed step.
      return;
    }
    try {
      $step = $event->getStep();
      if (function_exists('transliteration_clean_filename')) {
        $file_name = transliteration_clean_filename($step->getKeyword() . '_' . $step->getText());
      }
      else {
        $file_name = str_replace(' ', '_', $step->getKeyword() . '_' . $step->getText());
        $file_name = preg_replace('![^0-9A-Za-z_.-]!', '', $file_name);
      }
      $file_name = substr($file_name, 0, 30);
      $file_name = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat-failed__' . $file_name;
      $message = "Screenshot for failed step created in @file_name";
      $this->createScreenshot($file_name, $message);
    }
    catch (DriverException $e) {

    }
  }
1112510
def _render_after(self, element):
        ''''''
        if element.inline_content:
            return "</%s>%s" % (element.tag, self.render_newlines())
        elif element.self_close:
            return self.render_newlines()
        elif self.children:
            return "%s</%s>\n" % (self.spaces, element.tag)
        else:
            return "</%s>\n" % (element.tag)
1035896
function done(err) {
            if (err != null) {
                process.exitCode = 1
                console.error(`  ERROR: ${err.message}`)
            }
            if (options.verbose && err == null) {
                console.log("  Done.")
            }

            next()

            if (callback != null) {
                callback(err)
            }
        }
215456
function() {
            if ( consoleWindow ) {

                // Set notes to next steps notes.
                var newNotes = document.querySelector( '.active' ).querySelector( '.notes' );
                if ( newNotes ) {
                    newNotes = newNotes.innerHTML;
                } else {
                    newNotes = lang.noNotes;
                }
                consoleWindow.document.getElementById( 'notes' ).innerHTML = newNotes;

                // Set the views
                var baseURL = document.URL.substring( 0, document.URL.search( '#/' ) );
                var slideSrc = baseURL + '#' + document.querySelector( '.active' ).id;
                var preSrc = baseURL + '#' + nextStep().id;
                var slideView = consoleWindow.document.getElementById( 'slideView' );

                // Setting them when they are already set causes glithes in Firefox, so check first:
                if ( slideView.src !== slideSrc ) {
                    slideView.src = slideSrc;
                }
                var preView = consoleWindow.document.getElementById( 'preView' );
                if ( preView.src !== preSrc ) {
                    preView.src = preSrc;
                }

                consoleWindow.document.getElementById( 'status' ).innerHTML =
                    '<span class="moving">' + lang.moving + '</span>';
            }
        }
1237916
function(st) {
			this._clickToDisMiss = true;
			this.statusMessage = st;
			this._init();
			//could be: responseText from xhrGet, deferred error object, or plain string
			var _status = st.responseText || st.message || st;
			//accept either a string or a JSON representation of an IStatus
			if (typeof _status === "string") {
				try {
					_status = JSON.parse(_status);
				} catch(error) {
					//it is not JSON, just continue;
				}
			}
			var message = _status.DetailedMessage || _status.Message || _status;
			var color = "#DF0000"; //$NON-NLS-0$
			if (_status.Severity) {
				switch (_status.Severity) {
				case SEV_WARNING:
					color = "#FFCC00"; //$NON-NLS-0$
					break;
				case SEV_ERROR:
					color = "#DF0000"; //$NON-NLS-0$
					break;
				case SEV_INFO:
				case SEV_OK:
					color = "green"; //$NON-NLS-0$
					break;
				}
			}
			var span = document.createElement("span");
			span.style.color = color;
			span.appendChild(document.createTextNode(message));
			var node = lib.node(this.domId);
			lib.empty(node);
			node.appendChild(span);
			this._takeDownSplash();
		}
969182
function() {
      if (dest) {
        // Restore console.log to original and write the output
        console.log = consoleLog;

        if (!grunt.file.exists(dest)) {
            // Write only if our reporter ignored our `output` option
            grunt.file.write(dest, output.join('\n'));
        }
      }
      var stats = helpers.reduceStats(testStats);

      if (stats.failures === 0) {
        var okMsg = stats.tests + ' passed!' + ' (' + stats.duration + 's)';

        if (options.growlOnSuccess) {
          growl(okMsg, {
            image: asset('growl/ok.png'),
            title: okMsg,
            priority: 3
          });
        }

        grunt.log.ok(okMsg);

        // Async test pass
        done(true);

      } else {
        var failMsg = stats.failures + '/' + stats.tests + ' tests failed (' +
          stats.duration + 's)';

        // Show Growl notice, if avail
        growl(failMsg, {
          image: asset('growl/error.png'),
          title: failMsg,
          priority: 3
        });

        // Bail tests if bail option is true
        if (options.bail) {
          grunt.warn(failMsg);
        } else {
          grunt.log.error(failMsg);
        }

        // Async test fail
        done(false);
      }
    }
192087
function saveScreenshotIfExists(testResults) {
        var deferred = Q.defer();

        if (testResults.screenshotBuffer) {

            var screenshotFilePath = path.join(resultsDir, testResults.runId, resultScreenshotName);
            fs.writeFile(screenshotFilePath, testResults.screenshotBuffer);

            delete testResults.screenshotBuffer;

        } else {
            deferred.resolve();
        }

        return deferred;
    }
1059296
function (callback) {
            getData.takeSnapshot(page, ph, function (error, page, ph, dom) {
                if (error) {
                    callback (error);
                    return;
                }

                originalDom = dom;
                callback();
            });
        }
117940
function isAfterStepWithScreenshot(step) {
        return step.keyword.trim() === 'After' && step.embeddings && step.embeddings[0] && step.embeddings[0].mime_type === 'image/png';
    }
1105652
function screenshot(name, options) {
      var options  = options || {};
      var newPath = path;

      // options to override
      if(options.selector) { selector = options.selector; }
      if(options.path) { newPath = path + '/' + options.path; }
      if(Array.isArray(options.exclude)) { exclude = exclude.concat(options.exclude); }

      // Check if in phantomjs browser and PhantomScreenshot exists
      if(window.callPhantom && window.PhantomScreenshot) {
        asyncScreenshot(name, newPath);
      }
    }
1323120
function saveImage(rect) {
        if (DEBUG && rect && !rect.bottom) inspectArgs("saveImage: ", rect);

        if (rect && typeof rect.bottom === "number") {
            phPage.property("clipRect", rect);
        }

        // Set a timeout to give the page a chance to render.
        setTimeout(function () {
            phPage.render(option.output)
                  .then(function () {
                      phInstance.exit();
                      // process.removeListener("uncaughtException", onUncaughtException);
                      process.nextTick(callback);
                  });
        }, option.renderdelay || 250);
    }
415830
private function shouldSaveScreenshot(AfterTested $event)
    {
        $hasScreenshot = $this->screenshotTaker->hasScreenshot();
        $isScenarioFailed = $event->getTestResult()->getResultCode() === TestResult::FAILED;
        $shouldRecordAllScenarios = $this->config->shouldRecordAllScenarios();

        return $hasScreenshot && ($isScenarioFailed || $shouldRecordAllScenarios);
    }
129044
function(opts = {}) {
  if (opts.handleUncaughtExceptions == null) {
    opts.handleUncaughtExceptions = true;
  }
  if (opts.structuredStackTrace == null) {
    opts.structuredStackTrace = false;
  }
  if (opts.handleUncaughtExceptions) {
    process.on('uncaughtException', function(err) {
      prettyPrint(err, {
        colorize: process.stdout.isTTY
      });
      return process.exit(1);
    });
  }
  return Error.prepareStackTrace = function(err, stack) {
    var _stack, frame;
    _stack = (function() {
      var i, len, results;
      results = [];
      for (i = 0, len = stack.length; i < len; i++) {
        frame = stack[i];
        results.push(wrap(err, frame));
      }
      return results;
    })();
    if (opts.structuredStackTrace) {
      err.structuredStackTrace = structured(err, stack);
    }
    return err + ((function() {
      var i, len, results;
      results = [];
      for (i = 0, len = _stack.length; i < len; i++) {
        frame = _stack[i];
        results.push('\n    at ' + frame);
      }
      return results;
    })()).join('');
  };
}
225930
function asyncScreenshot(name, path) {
      var rect, offset, clientRect;
      var assert = QUnit.config.current.assert,
          done   = assert.async();

      // pause test for 300ms for rendering purposes
      window.setTimeout(function() {
        // Hide dom element specified by each item in exclude array
        excludeElements(exclude);

        // bubbling to phantomjs to trigger screenshot event
        window.PhantomScreenshot(name, {
          path: path,
          rect: getOffset(selector)
        });

        // Let QUnit know it's done
        done();
      }, 300);
    }
1106662
def render_error_debug(request, exception, is_html):
    '''
    '''
    error = Html('div', cn='well well-lg') if is_html else []
    for trace in format_traceback(exception):
        counter = 0
        for line in trace.split('\n'):
            if line.startswith('  '):
                counter += 1
                line = line[2:]
            if line:
                if is_html:
                    line = Html('p', escape(line), cn='text-danger')
                    if counter:
                        line.css({'margin-left': '%spx' % (20*counter)})
                error.append(line)
    if is_html:
        error = Html('div', Html('h1', request.response.status), error)
    return error
636481
protected function captureFailuresFor($browsers)
    {
        $browsers->each(function ($browser, $key) {
            $name = str_replace('\\', '_', get_class($this)).'_'.$this->getName(false);

            $browser->screenshot('failure-'.$name.'-'.$key);
        });
    }
174494
function captureScreenshot (chromy, filePath_, selector, selectorMap, config, selectors) {
  return new Promise(function (resolve, reject) {
    // VIEWPORT screenshot
    if (selector === VIEWPORT_SELECTOR || selector === BODY_SELECTOR) {
      chromy
        .screenshot()
        .result(buffer => {
          return saveViewport(buffer, selector);
        });
    // DOCUMENT screenshot
    } else if (selector === NOCLIP_SELECTOR || selector === DOCUMENT_SELECTOR) {
      chromy.screenshotMultipleSelectors(['body'], saveSelector);
    // OTHER-SELECTOR screenshot
    } else {
      chromy.screenshotMultipleSelectors(selectors, saveSelector);
    }

    chromy
      .end()
      .then(_ => {
        resolve();
      })
      .catch(e => {
        reject(e);
      });

    // result helpers

    // saveViewport: selectors will be `body` or `viewport` ONLY
    function saveViewport (buffer, selector) {
      const filePath = selectorMap[selector].filePath;

      ensureDirectoryPath(filePath);
      return fs.writeFile(filePath, buffer);
    }

    // saveSelector: selectorArr will contain any valid selector (not body or viewport).
    // If body *is* found in selector arr then it was originally DOCUMENT_SELECTOR -- and it will be reset back to DOCUMENT_SELECTOR -- this is because chromy takes a Document shot when BODY is used.
    function saveSelector (err, buffer, index, selectorArr) {
      let selector = selectorArr[index];
      if (selector === BODY_SELECTOR) {
        selector = DOCUMENT_SELECTOR;
      }
      const selectorProps = selectorMap[selector];
      const filePath = selectorProps.filePath;
      if (!selectorProps.exists) {
        return fs.copy(config.env.backstop + SELECTOR_NOT_FOUND_PATH, filePath);
      } else if (!selectorProps.isVisible) {
        return fs.copy(config.env.backstop + HIDDEN_SELECTOR_PATH, filePath);
      } else {
        if (err) {
          console.log('ChromyJS returned an unexpected error while attempting to capture a selector.', err);
          return new Error(err);
        }
        ensureDirectoryPath(filePath);
        return fs.writeFile(filePath, buffer);
      }
    }
  });
}