constructor (QUnit, options) {
    // Don't init the HTML Reporter in non-browser environments
    if (!window || !document || !document.querySelector || options.element === null) {
      return;
    }
    this.stats = {
      failedTests: [],
      defined: 0,
      completed: 0
    };
    this.urlParams = options.urlParams;
    this.config = options.config;
    this.abort = options.abort;
    this.hiddenTests = [];
    // Keep state for our hidepassed toggle, which can change without a reload.
    // null indicates we use the config/urlParams. Otherwise this will be
    // true/undefined based on checkbox changes. We don't use false here since
    // that would serialize in makeUrl() as "false".
    this.hidepassed = null;
    this.collapseNext = false;
    this.unfilteredUrl = this.makeUrl({
      filter: undefined,
      module: undefined,
      moduleId: undefined,
      testId: undefined
    });
    this.dropdownData = null;

    // We must not fallback to creating `<div id="qunit">` ourselves if it
    // does not exist, because not having `<div id="qunit">` is how projects
    // indicate that they wish to run QUnit headless, and do their own reporter.
    //
    // If options.element was set to HTMLElement, or if `<div id="qunit">` already
    // exists (i.e. qunit.js script is placed at end of `<body>`), then we render
    // an initial layout now (which is mostly inert).
    // Otherwise, we wait until QUnit.start and the onRunStart event, which by
    // default is called from window.onload.
    //
    // If no element is found now, leave this.element as undefined (unchanged).
    // We will try again at onRunStart().
    this.element = options.element || document.querySelector('#qunit') || undefined;
    this.elementBanner = null;
    this.elementDisplay = null;
    this.elementTests = null;
    if (this.element) {
      this.appendInterface();
    }

    // NOTE: Only listen for "runStart" now.
    // Other event handlers are added via listen() from onRunStart,
    // after we know that the element exists. This reduces overhead and avoids
    // potential internal errors when the HTML Reporter is disabled.
    this.listen = function () {
      this.listen = null;
      // It's important that we're in the callback queue before any user-defined
      // "QUnit.begin()", because, if those may throw, ours wouldn't run and
      // the UI would remain blank or incomplete.
      // https://github.com/qunitjs/qunit/issues/1792
      QUnit.begin(this.onBegin.bind(this), prioritySymbol);
      // Use prioritySignal for testStart() to increase availability
      // of the HTML API for TESTID elements toward other event listeners.
      QUnit.testStart(this.onTestStart.bind(this), prioritySymbol);
      QUnit.log(this.onLog.bind(this), prioritySymbol);
      QUnit.testDone(this.onTestDone.bind(this));
      QUnit.on('runEnd', this.onRunEnd.bind(this));

      // It's important that we don't listen for onError until after
      // this.element is found and populated by appendInterface(), as
      // otherwise it will fail in appendTest() to display error details.
      // We've given on() a memory for "error" events to accomodate
      // late listening.
      QUnit.on('error', this.onError.bind(this), prioritySymbol);
    };
    QUnit.on('runStart', this.onRunStart.bind(this), prioritySymbol);
  }
@internal Use QUnit.reporters.html.init() instead.

@param {QUnit} QUnit
@param {Object} options
@param {Object} options.urlParams
@param {Object} options.config
- `boolean` options.config.hidepassed
- `boolean` options.config.collapse For test result
- `string` options.config.filter
- `?string` options.config.moduleId For module selector
- `?string` options.config.testId For test result, rerun link
- `number` options.config.maxDepth For test result, error message
@param {Function} options.abort
@param {HTMLElement|undefined|null} options.element Output element
If set to HTMLElement, the report will be written to this element.
If set to undefined, then at `QUnit.on('runStart')` we look for `#qunit`
and use that if it exists.
If set to null, the reporter is disabled.