{"record":{"id":"05933ece1728a948","repo":"sebastianbergmann/comparator","slug":"failed-asserting-that-two-dom-s-are-equal","errorCode":null,"errorMessage":"Failed asserting that two DOM %s are equal.\n","messagePattern":"Failed asserting that two DOM (.+?) are equal\\.\n","errorType":"exception","errorClass":"ComparisonFailure","httpStatus":null,"severity":"error","filePath":"src/DOMNodeComparator.php","lineNumber":51,"sourceCode":"    }\n\n    /**\n     * @param array<mixed> $processed\n     *\n     * @throws ComparisonFailure\n     */\n    public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void\n    {\n        assert($expected instanceof DOMNode);\n        assert($actual instanceof DOMNode);\n\n        $expectedAsString = $this->nodeToText($expected, $ignoreCase);\n        $actualAsString   = $this->nodeToText($actual, $ignoreCase);\n\n        if ($expectedAsString !== $actualAsString) {\n            $type = $expected instanceof DOMDocument ? 'documents' : 'nodes';\n\n            throw new ComparisonFailure(\n                $expected,\n                $actual,\n                $expectedAsString,\n                $actualAsString,\n                sprintf(\"Failed asserting that two DOM %s are equal.\\n\", $type),\n                $this->contextLines(),\n            );\n        }\n    }\n\n    /**\n     * Canonicalizes nodes, removes empty text nodes and merges adjacent text nodes,\n     * and optionally ignores case.\n     *\n     * @see https://github.com/sebastianbergmann/phpunit/pull/1236#issuecomment-41765023\n     */\n    private function nodeToText(DOMNode $node, bool $ignoreCase): string\n    {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/sebastianbergmann/comparator/blob/00837a9d227b4e123b0b42a91736960f6b0b3583/src/DOMNodeComparator.php#L33-L69","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n$c->assertEquals($doc1, $doc2); // fails on attribute order/whitespace casing\n// after\n$c->assertEquals($doc1, $doc2, 0.0, false, true); // ignoreCase=true when only case differs","handlingStrategy":"validation","validationCode":"// normalize before comparing: strip whitespace-only text nodes\n$xp = new DOMXPath($doc);\nforeach ($xp->query('//text()[normalize-space(.)=\"\"]') as $t) { $t->parentNode->removeChild($t); }","typeGuard":"function isDomNodeLike(mixed $v): bool { return $v instanceof DOMNode; }","tryCatchPattern":"try {\n    $c->assertEquals($expectedDoc, $actualDoc);\n} catch (ComparisonFailure $e) {\n    // compare $e->getExpectedAsString() vs $e->getActualAsString()\n}","preventionTips":["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."],"tags":["phpunit","dom","xml","comparison"],"backgroundTag":"unexpected-response-shape","analyzedSha":"00837a9d227b4e123b0b42a91736960f6b0b3583","analyzedAt":"2026-09-15T03:36:55.154Z","contentChangedAt":"2026-09-15T03:36:55.154Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}