From d452bad57fcb1116361f969d16fc5033a9122d1a Mon Sep 17 00:00:00 2001 From: fabiodalez-dev Date: Tue, 6 Oct 2026 08:54:57 +0200 Subject: [PATCH] test(compact): cover the Do-Not-Sell row, the one compact rule nothing asserted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test-mobile-compact-css-php.php asserts every rule the compact phone layout emits — the flex basis, the 44px tap target, the wrapping, the order reset, the classic chevron padding — except the Do-Not-Sell control, which had no unit assertion at all. Only the E2E spec covered it, and that does not run in `npm run test:unit`. That control is the fourth item in the wrapper and the one the compared-pair rules do not describe, so each property is load-bearing: without a full basis it shares the row with accept and reject, and at 360px their 40% bases leave it almost nothing to grow into — it collapsed to a few pixels while its label spilled across Accept. It is reached in ordinary operation, not only by hand: Geo_Runtime turns donotSell on for a US visitor while applicableLaw stays 'gdpr', so for that visitor this row IS the opt-out. Six assertions per banner type (+36 overall, 61 -> 97): - the rule exists at all; - flex:1 1 100% and width:100%, so it takes a row instead of a share of one; - white-space:normal, because "Do Not Sell or Share My Personal Information" is statutory wording that cannot be shortened and does not fit one phone line; - display:block, which keeps the template's left-aligned link look rather than the centred flex box the compared buttons use; - the selector matches the data attribute and NOT the class, because the shortcode emits either `.faz-btn.faz-btn-do-not-sell` or a bare with no class, and narrowing it would silently drop the link variant; - the rule comes AFTER the generic `.faz-btn` rule it overrides. Both selectors are 1-1-0, so source order alone decides the winner — a reorder that changes no rule text would restore the collapse invisibly. Each one was control-run: a full basis swapped back to `flex:1 1 0`, the selector narrowed to the class, white-space dropped, and the rule moved above the generic one each turn the matching assertion red (4, 28, 4 and 4 respectively), and the source-order control turns red on that assertion alone. Two further fixes were examined and deliberately left untested, rather than covered with assertions that would pass regardless: - clearstatcache() in Geolocation::database_fingerprint(). Removing it keeps every test green because the premise does not reproduce here: on PHP 8.4 filesize() returns the new length after file_put_contents() and even after an external writer, so the stale-stat condition the line defends against is not observable. Worth knowing that the existing "database replaced -> different fingerprint" assertion does not prove that line either: it writes through a helper that clears the stat cache itself. - the `degraded` copy that distinguishes probe_failed from key_without_database. The reason code it branches on already has three unit assertions; reaching the state from the browser needs a fake MaxMind licence key and a deliberately broken database planted on the test site, which is a poor trade for one `if` on a string. --- tests/unit/test-mobile-compact-css-php.php | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/unit/test-mobile-compact-css-php.php b/tests/unit/test-mobile-compact-css-php.php index fcf2dd18d..d770f3003 100644 --- a/tests/unit/test-mobile-compact-css-php.php +++ b/tests/unit/test-mobile-compact-css-php.php @@ -154,6 +154,47 @@ function ( $value ) { // 360px: accept/reject paired, customise on a row of its own. faz_mcss_assert( false !== strpos( $m360, '.faz-btn-reject{flex:1 1 40%;}' ) && false !== strpos( $m360, '.faz-btn-customize{flex:1 1 100%;}' ), "{$type}: at 360px and below customise takes its own row and the pair stays together" ); + + // The Do-Not-Sell control. It is the fourth item in this wrapper and the + // one the compared-pair rules do not describe, so every property below + // is load-bearing rather than decorative. + // + // Reached in ordinary operation, not only by hand: Geo_Runtime turns + // donotSell on for a US visitor while applicableLaw stays 'gdpr', and + // class-template.php keeps the button precisely because its status is + // true. For that visitor this row IS the opt-out. + $dns = array(); + preg_match( '/#faz-consent \.faz-notice-btn-wrapper \[data-faz-tag="donotsell-button"\]\{([^}]*)\}/', $m440, $dns ); + faz_mcss_assert( ! empty( $dns ), "{$type}: compact describes the Do-Not-Sell control" ); + $dns_body = isset( $dns[1] ) ? $dns[1] : ''; + + // Without a full basis it shares the row with the pair, and at 360px + // their 40% bases leave it almost nothing to grow into: it collapsed to + // a few pixels wide. + faz_mcss_assert( false !== strpos( $dns_body, 'flex:1 1 100%' ), "{$type}: the Do-Not-Sell control takes a full row, not a share of the pair's" ); + faz_mcss_assert( false !== strpos( $dns_body, 'width:100%' ), "{$type}: the Do-Not-Sell row spans the wrapper" ); + // "Do Not Sell or Share My Personal Information" is statutory wording + // that cannot be shortened, and it does not fit one line on a phone. + faz_mcss_assert( false !== strpos( $dns_body, 'white-space:normal' ), "{$type}: the statutory Do-Not-Sell label is allowed to wrap" ); + // A link, not one of the compared buttons: the template draws it + // left-aligned and borderless, which the centred flex box would undo. + faz_mcss_assert( false !== strpos( $dns_body, 'display:block' ), "{$type}: the Do-Not-Sell control keeps its link look, not the button box" ); + + // Matched by data attribute on purpose. The shortcode emits either + // `.faz-btn.faz-btn-do-not-sell` or a bare with no class at all, and + // the attribute is the only thing both variants carry: narrowing this + // selector to the class would silently drop the link variant, which is a + // flex item just the same. + faz_mcss_assert( false === strpos( $m440, '.faz-btn-do-not-sell{' ), "{$type}: the Do-Not-Sell rule matches the attribute, so the variant is covered too" ); + + // Source order, not specificity, decides this one. Both selectors are + // 1-1-0 (#faz-consent + .faz-notice-btn-wrapper + one class/attribute), + // so the generic `.faz-btn{flex:1 1 0}` above wins unless the + // Do-Not-Sell rule comes after it. Reordering the block would restore + // the collapse with no visible change to either rule. + $generic_at = strpos( $m440, '#faz-consent .faz-notice-btn-wrapper .faz-btn{' ); + $dns_at = strpos( $m440, '#faz-consent .faz-notice-btn-wrapper [data-faz-tag="donotsell-button"]{' ); + faz_mcss_assert( false !== $generic_at && false !== $dns_at && $dns_at > $generic_at, "{$type}: the Do-Not-Sell rule comes after the generic button rule it overrides" ); } // The template does draw that chevron with an absolute ::after anchored to