2021-10-26 23:37:56 +00:00
|
|
|
/**
|
|
|
|
* Example A/B test configuration for sticky header:
|
|
|
|
*
|
|
|
|
* $wgVectorABTestEnrollment = [
|
2021-12-09 19:34:44 +00:00
|
|
|
* 'name' => 'vector.sticky_header',
|
2021-10-26 23:37:56 +00:00
|
|
|
* 'enabled' => true,
|
|
|
|
* 'buckets' => [
|
|
|
|
* 'unsampled' => [
|
|
|
|
* 'samplingRate' => 0.1,
|
|
|
|
* ],
|
|
|
|
* 'control' => [
|
|
|
|
* 'samplingRate' => 0.3,
|
|
|
|
* ],
|
|
|
|
* 'stickyHeaderDisabled' => [
|
|
|
|
* 'samplingRate' => 0.3,
|
|
|
|
* ],
|
|
|
|
* 'stickyHeaderEnabled' => [
|
|
|
|
* 'samplingRate' => 0.3,
|
|
|
|
* ],
|
|
|
|
* ],
|
|
|
|
* ];
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Functions and variables to implement A/B testing.
|
|
|
|
*/
|
|
|
|
const ABTestConfig = require( /** @type {string} */ ( './config.json' ) ).wgVectorWebABTestEnrollment || {};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the name of the bucket the user is assigned to for A/B testing.
|
|
|
|
*
|
|
|
|
* @return {string} the name of the bucket the user is assigned.
|
|
|
|
*/
|
|
|
|
function getBucketName() {
|
|
|
|
/**
|
|
|
|
* Provided config should contain the keys:
|
|
|
|
* name: the name of the experiment prefixed with the skin name.
|
|
|
|
* enabled: must be true or all users are assigned to control.
|
|
|
|
* buckets: dict with bucket name as key and test config as value.
|
|
|
|
*
|
|
|
|
* Bucket test config can contain the keys:
|
|
|
|
* samplingRate: sampling rates will be summed up and each bucket will receive a proportion
|
|
|
|
* equal to its value.
|
|
|
|
*/
|
|
|
|
return mw.experiments.getBucket( {
|
|
|
|
name: ABTestConfig.name,
|
|
|
|
enabled: ABTestConfig.enabled,
|
|
|
|
buckets: {
|
|
|
|
// @ts-ignore
|
|
|
|
unsampled: ABTestConfig.buckets.unsampled.samplingRate,
|
|
|
|
control: ABTestConfig.buckets.control.samplingRate,
|
|
|
|
stickyHeaderDisabled: ABTestConfig.buckets.stickyHeaderDisabled.samplingRate,
|
|
|
|
stickyHeaderEnabled: ABTestConfig.buckets.stickyHeaderEnabled.samplingRate
|
|
|
|
}
|
|
|
|
}, mw.user.getId().toString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the group and experiment name for an A/B test.
|
|
|
|
*
|
|
|
|
* @return {Object} data to pass to event logging
|
|
|
|
*/
|
|
|
|
function getABTestGroupExperimentName() {
|
|
|
|
return {
|
|
|
|
group: getBucketName(),
|
|
|
|
experimentName: ABTestConfig.name
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Provides A/B test config for the current user.
|
|
|
|
*
|
|
|
|
* @return {Object} A/B test config data
|
|
|
|
*/
|
|
|
|
function getEnabledExperiment() {
|
|
|
|
const mergedConfig = {};
|
|
|
|
|
|
|
|
if ( ABTestConfig.enabled ) {
|
|
|
|
// Merge all the A/B config to return.
|
|
|
|
Object.assign( mergedConfig, getABTestGroupExperimentName(), ABTestConfig );
|
|
|
|
}
|
|
|
|
return mergedConfig;
|
|
|
|
}
|
|
|
|
|
2021-12-03 19:19:27 +00:00
|
|
|
/**
|
|
|
|
* Determine if user is in test group to experience feature.
|
|
|
|
*
|
|
|
|
* @param {string} bucket the bucket name the user is assigned
|
|
|
|
* @param {string} targetGroup the target test group to experience feature
|
|
|
|
* @return {boolean} true if the user should experience feature
|
|
|
|
*/
|
|
|
|
function isInTestGroup( bucket, targetGroup ) {
|
|
|
|
return bucket === targetGroup;
|
|
|
|
}
|
|
|
|
|
2021-10-26 23:37:56 +00:00
|
|
|
/**
|
|
|
|
* Fire hook to register A/B test enrollment.
|
|
|
|
*
|
|
|
|
* @param {string} bucket the bucket user is assigned to
|
|
|
|
*/
|
|
|
|
function initAB( bucket ) {
|
|
|
|
// Send data to WikimediaEvents to log A/B test initialization if experiment is enabled
|
|
|
|
// and if the user is logged in.
|
2021-12-14 00:31:17 +00:00
|
|
|
if ( ABTestConfig.enabled && !mw.user.isAnon() && bucket !== 'unsampled' ) {
|
2021-10-26 23:37:56 +00:00
|
|
|
// @ts-ignore
|
|
|
|
mw.hook( 'mediawiki.web_AB_test_enrollment' ).fire( getABTestGroupExperimentName() );
|
|
|
|
|
|
|
|
// Remove class if present on the html element so that scroll padding isn't undesirably
|
|
|
|
// applied to users who don't experience the new treatment.
|
|
|
|
if ( bucket !== 'stickyHeaderEnabled' ) {
|
|
|
|
document.documentElement.classList.remove( 'vector-sticky-header-enabled' );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
2021-12-03 19:19:27 +00:00
|
|
|
isInTestGroup,
|
2021-10-26 23:37:56 +00:00
|
|
|
getEnabledExperiment,
|
2022-01-26 22:10:35 +00:00
|
|
|
initAB,
|
|
|
|
test: {
|
|
|
|
getBucketName,
|
|
|
|
getABTestGroupExperimentName
|
|
|
|
}
|
2021-10-26 23:37:56 +00:00
|
|
|
};
|