sebastianbergmann/comparator · error · ComparisonFailure
Failed asserting that two DOM
Error message
Failed asserting that two DOM %s are equal.
What it means
ComparisonFailure thrown by DOMNodeComparator::assertEquals when the normalized text serialization of two DOM nodes differs. The message says 'two DOM documents' when the expected node is a DOMDocument, otherwise 'two DOM nodes'. Both nodes are converted to text (optionally lower-cased when ignoreCase=true) via nodeToText before comparison.
Solutions
- Diff the expectedAsString/actualAsString carried by the exception to see the first textual difference.
- Normalize whitespace: build documents without pretty printing or strip insignificant whitespace before comparing.
- Pass $ignoreCase=true when only casing of tags/text differs.
- Ensure both sides are the same kind of node (document vs element/fragment).
- Fix the producer (template/renderer) or the fixture so the serialized markup matches.
Example fix
// before $c->assertEquals($doc1, $doc2); // fails on attribute order/whitespace casing // after $c->assertEquals($doc1, $doc2, 0.0, false, true); // ignoreCase=true when only case differs
Defensive patterns
Strategy: validation
Validate before calling
// normalize before comparing: strip whitespace-only text nodes
$xp = new DOMXPath($doc);
foreach ($xp->query('//text()[normalize-space(.)=""]') as $t) { $t->parentNode->removeChild($t); } Type guard
function isDomNodeLike(mixed $v): bool { return $v instanceof DOMNode; } Try / catch
try {
$c->assertEquals($expectedDoc, $actualDoc);
} catch (ComparisonFailure $e) {
// compare $e->getExpectedAsString() vs $e->getActualAsString()
} Prevention
- Generate markup with deterministic formatting (no pretty printing) on both sides.
- Ensure both operands are the same node type (document vs element).
- Use ignoreCase=true when casing is irrelevant.
- Compare canonicalized XML (DOMDocument::C14N()) when semantic equality is the goal.
When it happens
Trigger: assertEquals on two DOMDocument/DOMNode objects whose serialized text differs — different elements, attributes, attribute order-sensitive content, whitespace/indentation differences, or casing (when ignoreCase=false).
Common situations: Testing generated HTML/XML output against fixtures; XML produced with different pretty-printing or whitespace than the fixture; missing or differently-ordered attributes; text content casing differences; comparing a fragment with a full document.
Related errors
- Failed asserting that two arrays are equal.
- Failed asserting that closure declared at
- Failed asserting that two DateInterval objects are equal.
- Failed asserting that two DateTime objects are equal.
- Failed asserting that two values of enumeration
AI-assisted analysis of sebastianbergmann/comparator@00837a9d22 (2026-09-15).
Data as JSON: /api/errors/05933ece1728a948.
Report an issue: GitHub.
Appendix: source
Thrown at src/DOMNodeComparator.php:51
}
/**
* @param array<mixed> $processed
*
* @throws ComparisonFailure
*/
public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void
{
assert($expected instanceof DOMNode);
assert($actual instanceof DOMNode);
$expectedAsString = $this->nodeToText($expected, $ignoreCase);
$actualAsString = $this->nodeToText($actual, $ignoreCase);
if ($expectedAsString !== $actualAsString) {
$type = $expected instanceof DOMDocument ? 'documents' : 'nodes';
throw new ComparisonFailure(
$expected,
$actual,
$expectedAsString,
$actualAsString,
sprintf("Failed asserting that two DOM %s are equal.\n", $type),
$this->contextLines(),
);
}
}
/**
* Canonicalizes nodes, removes empty text nodes and merges adjacent text nodes,
* and optionally ignores case.
*
* @see https://github.com/sebastianbergmann/phpunit/pull/1236#issuecomment-41765023
*/
private function nodeToText(DOMNode $node, bool $ignoreCase): string
{View on GitHub (pinned to 00837a9d22)