Skip to main content

One post tagged with "phpunit"

View All Tags

Review: Adopting assertEqualHTML() in WordPress Tests (Migration Patterns)

· 3 min read
Victor Jimenez
Software Engineer & AI Agent Builder

The Hook WordPress 6.9 added assertEqualHTML(), which removes a lot of brittle test failures caused by formatting-only HTML differences.

Why I Built It In plugin and theme suites, many HTML tests still use strict string equality and fail on whitespace, indentation, or equivalent tag formatting instead of real behavior regressions.

The Solution Adopt assertEqualHTML() for semantic HTML equivalence checks, keep assertSame() where byte-for-byte output matters, and phase migration by risk and signal quality.

The Code No standalone project repo for this task. This is migration guidance for WordPress/PHPUnit test suites.

Recommendation

  • Adopt now if your suite has frequent brittle failures from HTML formatting differences.
  • Use it for rendered markup assertions where DOM meaning matters more than exact serialization.
  • Do not replace assertions that intentionally verify exact escaping, spacing, or deterministic serialization.

Concrete Migration Patterns

1) Direct string comparison to semantic HTML comparison

Before:

$this->assertSame(
'<p class="notice">Saved</p>',
$actual_html
);

After:

$this->assertEqualHTML(
'<p class="notice">Saved</p>',
$actual_html
);

2) Remove ad-hoc whitespace normalization

Before:

$normalize = static fn( $html ) => preg_replace( '/\s+/', ' ', trim( $html ) );
$this->assertSame( $normalize( $expected ), $normalize( $actual ) );

After:

$this->assertEqualHTML( $expected, $actual );

3) Output-buffer render tests

Before:

ob_start();
render_banner_block( array( 'message' => 'Hi' ) );
$actual = ob_get_clean();

$this->assertSame(
'<section class="banner"><p>Hi</p></section>',
$actual
);

After:

ob_start();
render_banner_block( array( 'message' => 'Hi' ) );
$actual = ob_get_clean();

$this->assertEqualHTML(
'<section class="banner"><p>Hi</p></section>',
$actual
);

4) Attribute/order formatting noise

Before:

$expected = '<a class="btn primary" href="/docs">Docs</a>';
$actual = '<a href="/docs" class="btn primary">Docs</a>';
$this->assertSame( $expected, $actual );

After:

$this->assertEqualHTML( $expected, $actual );

5) Version-safe bridge for mixed core baselines

If your suite runs against WordPress versions older than 6.9:

private function assertHtmlEquivalent( string $expected, string $actual ): void {
if ( method_exists( $this, 'assertEqualHTML' ) ) {
$this->assertEqualHTML( $expected, $actual );
return;
}

$this->assertSame( trim( $expected ), trim( $actual ) );
}

Rollout Guidance

  • Start with render-heavy tests (render_callback, shortcode output, template helpers).
  • Convert only tests currently compensating for formatting differences.
  • Keep assertSame() for escaping/security assertions and exact output contracts.
  • Add a short team note: "Use assertEqualHTML() for semantic markup checks."

What I Learned

  • assertEqualHTML() landed in WordPress core test tools in 6.9 and is intended to compare HTML equivalence, not raw string identity.
  • Most migration wins come from deleting custom normalization code and reducing flaky failures.
  • A two-lane assertion policy (assertEqualHTML() for semantics, assertSame() for exactness) keeps intent explicit and avoids over-migration.

References