static expectToEqualElementRecursive_(actual, expected) {
    const prospectiveDiff = 'The difference was in ' +
        (actual.outerHTML || actual.textContent) + ' vs ' +
        (expected['outerHTML'] || expected.textContent) + ': ';
    const getAttr = (obj, attr) => {
      if (attr.namespaceURI) {
        return shaka.util.TXml.getAttributeNS(
            obj, attr.namespaceURI, attr.localName);
      } else {
        return obj.getAttribute(attr.localName);
      }
    };

    if (!(actual instanceof Element) && !(expected instanceof Element)) {
      // Compare them as nodes.
      if (actual.textContent != expected.textContent) {
        return prospectiveDiff + 'Nodes are different.';
      }
    } else if (!(actual instanceof Element) || !(expected instanceof Element)) {
      return prospectiveDiff + 'One is element, one isn\'t.';
    } else {
      // Compare them as elements.
      if (actual.tagName != expected.tagName) {
        return prospectiveDiff + 'Different tagName.';
      }

      if (actual.attributes.length != expected.attributes.length) {
        return prospectiveDiff + 'Different attribute list length.';
      }
      for (const attr of Array.from(actual.attributes)) {
        const valueA = getAttr(actual, attr);
        const valueB = getAttr(expected, attr);
        if (valueA != valueB) {
          const name = (attr.prefix ? attr.prefix + ':' : '') + attr.localName;
          return `${prospectiveDiff} Attribute ${name} was different ` +
                 `(${valueA} vs ${valueB})`;
        }
      }

      if (actual.childNodes.length != expected.childNodes.length) {
        return prospectiveDiff + 'Different child node list length.';
      }
      for (let i = 0; i < actual.childNodes.length; i++) {
        const aNode = actual.childNodes[i];
        const eNode = expected.childNodes[i];
        const diff =
            shaka.test.Util.expectToEqualElementRecursive_(aNode, eNode);
        if (diff) {
          return diff;
        }
      }
    }

    return null;
  }
@param {?} actual
@param {!Node} expected
@return {?string} failureReason
@private