mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Popups
synced 2024-11-12 09:18:59 +00:00
Add ext.popups.experiment module
Changes: * Add the ext.popups.experiment module * Add the mw.popups.experiment.isUserInCondition function, which returns a promise that resolves with true if the user is in the experimental condition, otherwise false * If the experiment isn't configured, i.e. wgPopupsExperimentConfig is null or undefined, then the user isn't entered into the experiment, providing a kill switch Bug: T132604 Change-Id: I49597494273e3862711a32e4951c8598e6c8bf59
This commit is contained in:
parent
85b27d8de8
commit
3f03d681c9
|
@ -223,8 +223,12 @@ class PopupsHooks {
|
|||
'tests/qunit/ext.popups.renderer.article.test.js',
|
||||
'tests/qunit/ext.popups.core.test.js',
|
||||
'tests/qunit/ext.popups.settings.test.js',
|
||||
'tests/qunit/ext.popups.experiment.test.js',
|
||||
),
|
||||
'dependencies' => array(
|
||||
'ext.popups.desktop',
|
||||
'ext.popups.experiment'
|
||||
),
|
||||
'dependencies' => array( 'ext.popups.desktop' ),
|
||||
'localBasePath' => __DIR__,
|
||||
'remoteExtPath' => 'Popups',
|
||||
);
|
||||
|
|
|
@ -92,6 +92,21 @@
|
|||
"dependencies": [
|
||||
"ext.popups.core"
|
||||
]
|
||||
},
|
||||
"ext.popups.experiment": {
|
||||
"scripts": [
|
||||
"resources/ext.popups.experiment.js"
|
||||
],
|
||||
"dependencies": [
|
||||
"ext.popups.core",
|
||||
"jquery.jStorage",
|
||||
"mediawiki.user",
|
||||
"mediawiki.storage",
|
||||
"mediawiki.experiments"
|
||||
],
|
||||
"targets": [
|
||||
"desktop"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ResourceFileModulePaths": {
|
||||
|
|
79
resources/ext.popups.experiment.js
Normal file
79
resources/ext.popups.experiment.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
( function ( mw, $ ) {
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
function getToken() {
|
||||
var key = 'PopupsExperimentID',
|
||||
id = mw.storage.get( key );
|
||||
|
||||
if ( !id ) {
|
||||
id = mw.user.generateRandomSessionId();
|
||||
|
||||
mw.storage.set( key, id );
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the user previously enabled Popups by clicking "Enable previews" in the
|
||||
* footer menu?
|
||||
*
|
||||
* @return {boolean}
|
||||
* @ignore
|
||||
*/
|
||||
function hasUserEnabledFeature() {
|
||||
var value = $.jStorage.get( 'mwe-popups-enabled' );
|
||||
|
||||
return Boolean( value ) && value !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* @class mw.popups.experiment
|
||||
* @singleton
|
||||
*/
|
||||
mw.popups.experiment = {};
|
||||
|
||||
/**
|
||||
* Gets whether or not the user has Popups enabled, i.e. whether they are in the experiment
|
||||
* condition.
|
||||
*
|
||||
* The user is in the experiment condition if:
|
||||
* * they've enabled Popups by click "Enable previews" in the footer menu, or
|
||||
* * they've enabled Popups as a beta feature, or
|
||||
* * they aren't in the control bucket of the experiment
|
||||
*
|
||||
* N.B. that the user isn't entered into the experiment, i.e. they aren't assigned or a bucket,
|
||||
* if the experiment isn't configured.
|
||||
*
|
||||
* @return {jQuery.Promise}
|
||||
*/
|
||||
mw.popups.experiment.isUserInCondition = function isUserInCondition() {
|
||||
var deferred = $.Deferred(),
|
||||
config = mw.config.get( 'wgPopupsExperimentConfig' ),
|
||||
result;
|
||||
|
||||
if (
|
||||
hasUserEnabledFeature() ||
|
||||
|
||||
// Users with the beta feature enabled are already in the experimental condition.
|
||||
mw.config.get( 'wgPopupsExperimentIsBetaFeatureEnabled', false )
|
||||
) {
|
||||
deferred.resolve( true );
|
||||
} else if ( !config ) {
|
||||
deferred.resolve( false );
|
||||
} else {
|
||||
mw.requestIdleCallback( function () {
|
||||
// FIXME: mw.experiments should expose the CONTROL_BUCKET constant, e.g.
|
||||
// `mw.experiments.CONTROL_BUCKET`.
|
||||
result = mw.experiments.getBucket( config, getToken() ) !== 'control';
|
||||
|
||||
deferred.resolve( result );
|
||||
} );
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
}( mediaWiki, jQuery ) );
|
112
tests/qunit/ext.popups.experiment.test.js
Normal file
112
tests/qunit/ext.popups.experiment.test.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
( function ( mw, $ ) {
|
||||
|
||||
QUnit.module( 'ext.popups.experiment', QUnit.newMwEnvironment( {
|
||||
config: {
|
||||
wgPopupsExperimentConfig: {
|
||||
name: 'Popups A/B Test - May, 2016',
|
||||
enabled: true,
|
||||
buckets: {
|
||||
control: 0.5,
|
||||
A: 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
teardown: function () {
|
||||
mw.storage.remove( 'PopupsExperimentID' );
|
||||
}
|
||||
} ) );
|
||||
|
||||
QUnit.test( '#isUserInCondition: user has beta feature enabled', function ( assert ) {
|
||||
var done = assert.async();
|
||||
|
||||
mw.config.set( 'wgPopupsExperimentConfig', null );
|
||||
mw.config.set( 'wgPopupsExperimentIsBetaFeatureEnabled', true );
|
||||
|
||||
mw.popups.experiment.isUserInCondition().then( function ( result ) {
|
||||
assert.strictEqual(
|
||||
result,
|
||||
true,
|
||||
'If the user has the beta feature enabled, then they aren\'t in the condition.'
|
||||
);
|
||||
|
||||
done();
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( '#isUserInCondition', function ( assert ) {
|
||||
var getBucketSpy = this.sandbox.stub( mw.experiments, 'getBucket' ).returns( 'A' ),
|
||||
config = mw.config.get( 'wgPopupsExperimentConfig' ),
|
||||
done = assert.async();
|
||||
|
||||
mw.popups.experiment.isUserInCondition().then( function ( result ) {
|
||||
var fistCallArgs = getBucketSpy.firstCall.args;
|
||||
|
||||
assert.deepEqual(
|
||||
fistCallArgs[ 0 ],
|
||||
config,
|
||||
'The Popups experiment config is used when bucketing the user.'
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
result,
|
||||
true,
|
||||
'If the user isn\'t in the control bucket, then they are in the condition.'
|
||||
);
|
||||
|
||||
done();
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( '#isUserInCondition: token is persisted', function ( assert ) {
|
||||
var token = '1234567890',
|
||||
setSpy = this.sandbox.spy( mw.storage, 'set' ),
|
||||
done = assert.async();
|
||||
|
||||
this.sandbox.stub( mw.user, 'generateRandomSessionId' ).returns( token );
|
||||
|
||||
mw.popups.experiment.isUserInCondition().then( function () {
|
||||
assert.deepEqual(
|
||||
setSpy.firstCall.args[ 1 ],
|
||||
token,
|
||||
'The token is persisted transparently.'
|
||||
);
|
||||
|
||||
done();
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( '#isUserInCondition: experiment isn\'t configured', function ( assert ) {
|
||||
var done = assert.async();
|
||||
|
||||
mw.config.set( 'wgPopupsExperimentConfig', null );
|
||||
|
||||
mw.popups.experiment.isUserInCondition().then( function ( result ) {
|
||||
assert.strictEqual(
|
||||
result,
|
||||
false,
|
||||
'If the experiment isn\'t configured, then the user isn\'t in the condition.'
|
||||
);
|
||||
|
||||
done();
|
||||
} );
|
||||
} );
|
||||
|
||||
QUnit.test( '#isUserInCondition: user has enabled the feature', function ( assert ) {
|
||||
var done = assert.async();
|
||||
|
||||
$.jStorage.set( 'mwe-popups-enabled', 'true' );
|
||||
|
||||
mw.popups.experiment.isUserInCondition().then( function ( result ) {
|
||||
assert.strictEqual(
|
||||
result,
|
||||
true,
|
||||
'If the experiment has enabled the feature, then the user is in the condition.'
|
||||
);
|
||||
|
||||
$.jStorage.deleteKey( 'mwe-popups-enabled' );
|
||||
|
||||
done();
|
||||
} );
|
||||
} );
|
||||
|
||||
}( mediaWiki, jQuery ) );
|
Loading…
Reference in a new issue