Override mw.experiments.getBucket() via body classes

When AB bucketing via ABRequirements.php in Vector,
the browser has no awareness of this bucketing and buckets users
once more via mw.experiments.getBucket() in AB.js.

mw.experiments uses a different algorithm than ABRequirements.php,
causing a mismatch between the server-side bucketing
and the client-side bucketing.

This patch overrides that client-side bucketing by
adding classes to the HTML element that are recognized
by AB.js

Bug: T335972
Change-Id: I0549a8dee23ebe7cd68465f8403e4f7aac76633e
This commit is contained in:
Jan Drewniak 2023-05-24 18:21:30 -04:00
parent a38229cc7f
commit b599da4153
2 changed files with 15 additions and 1 deletions

View file

@ -236,6 +236,8 @@ class SkinVector22 extends SkinMustache {
* @inheritDoc
*/
public function getHtmlElementAttributes() {
$aBTest = $this->getConfig()->get( 'VectorWebABTestEnrollment' );
$zebraEnabled = VectorServices::getFeatureManager()->isFeatureEnabled( Constants::FEATURE_ZEBRA_DESIGN );
$original = parent::getHtmlElementAttributes();
$featureManager = VectorServices::getFeatureManager();
$original['class'] .= ' ' . implode( ' ', $featureManager->getFeatureBodyClass() );
@ -254,6 +256,15 @@ class SkinVector22 extends SkinMustache {
// possibly others). It must instead be applied to the html tag.
$original['class'] = implode( ' ', [ $original['class'] ?? '', self::STICKY_HEADER_ENABLED_CLASS ] );
}
if ( $aBTest[ 'enabled' ] ) {
if ( $zebraEnabled ) {
$original['class'] .= ' ' . $aBTest[ 'name' ] . '-treatment ';
} else {
$original['class'] .= ' ' . $aBTest[ 'name' ] . '-control ';
}
}
$original['class'] = trim( $original['class'] );
return $original;

View file

@ -90,7 +90,10 @@ module.exports = function webABTest( props, token, forceInit ) {
*/
function getBucketFromHTML() {
for ( const bucketName of getBucketNames() ) {
if ( document.body.classList.contains( `${props.name}-${bucketName}` ) ) {
if (
document.body.classList.contains( `${props.name}-${bucketName}` ) ||
document.documentElement.classList.contains( `${props.name}-${bucketName}` )
) {
return bucketName;
}
}