Include user's preview count in BOOT action

Action changes:
* Include the user's preview count in the user property of the action.

Reducer changes:
* Make the eventLogging reducer add the bucketed user's preview count to
  the state tree.

Changes:
* Extract mw.popups.UserSettings#getPreviewCount and #setPreviewCount
  and associated tests from the ext.popups.core module.

Bug: T152225
Change-Id: I6b7afef31311be8fede685deb536f577845cb9cf
This commit is contained in:
Sam Smith 2016-12-01 14:56:46 +00:00
parent 4b74f72926
commit b7effdc000
9 changed files with 190 additions and 24 deletions

View file

@ -39,12 +39,20 @@
*
* @param {Function} isUserInCondition See `mw.popups.createExperiment`
* @param {mw.user} user
* @param {ext.popups.UserSettings} userSettings
* @param {Function} generateToken
* @param {mw.Map} config The config of the MediaWiki client-side application,
* i.e. `mw.config`
*/
actions.boot = function ( isUserInCondition, user, generateToken, config ) {
var editCount = config.get( 'wgUserEditCount' );
actions.boot = function (
isUserInCondition,
user,
userSettings,
generateToken,
config
) {
var editCount = config.get( 'wgUserEditCount' ),
previewCount = userSettings.getPreviewCount();
return {
type: types.BOOT,
@ -58,7 +66,8 @@
user: {
isInCondition: isUserInCondition(),
isAnon: user.isAnon(),
editCount: editCount
editCount: editCount,
previewCount: previewCount
}
};
};

View file

@ -107,6 +107,7 @@
actions.boot(
isUserInCondition,
mw.user,
userSettings,
generateToken,
mw.config
);

View file

@ -31,4 +31,38 @@
return bucket + ' edits';
};
/**
* Return count bucket for the number of previews a user has seen.
*
* If local storage isn't available - because the user has disabled it
* or the browser doesn't support it - then then "unknown" is returned.
*
* The buckets are defined as part of
* [the Popups schema](https://meta.wikimedia.org/wiki/Schema:Popups).
*
* Extracted from `mw.popups.getPreviewCountBucket`.
*
* @param {Number} count
* @return {String}
*/
mw.popups.counts.getPreviewCountBucket = function ( count ) {
var bucket;
if ( count === -1 ) {
return 'unknown';
}
if ( count === 0 ) {
bucket = '0';
} else if ( count >= 1 && count <= 4 ) {
bucket = '1-4';
} else if ( count >= 5 && count <= 20 ) {
bucket = '5-20';
} else if ( count >= 21 ) {
bucket = '21+';
}
return bucket + ' previews';
};
}( mediaWiki ) );

View file

@ -155,6 +155,7 @@
switch ( action.type ) {
case mw.popups.actionTypes.BOOT:
return nextState( state, {
previewCount: action.user.previewCount,
baseData: {
pageTitleSource: action.page.title,
namespaceIdSource: action.page.namespaceID,
@ -163,7 +164,8 @@
popupEnabled: action.user.isInCondition,
pageToken: action.pageToken,
sessionToken: action.sessionToken,
editCountBucket: counts.getEditCountBucket( action.user.editCount )
editCountBucket: counts.getEditCountBucket( action.user.editCount ),
previewCountBucket: counts.getPreviewCountBucket( action.user.previewCount )
},
event: {
action: 'pageLoaded'

View file

@ -1,10 +1,11 @@
( function ( mw ) {
/**
* @typedef {Object} mw.popups.UserSettings
* @typedef {Object} ext.popups.UserSettings
*/
var IS_ENABLED_KEY = 'mwe-popups-enabled';
var IS_ENABLED_KEY = 'mwe-popups-enabled',
PREVIEW_COUNT_KEY = 'ext.popups.core.previewCount';
/**
* Given the global state of the application, creates an object whose methods
@ -13,7 +14,7 @@
* @param {mw.storage} storage The `mw.storage` singleton instance
* @param {mw.user} user The `mw.user` singleton instance
*
* @return {mw.popups.UserSettings}
* @return {ext.popups.UserSettings}
*/
mw.popups.createUserSettings = function ( storage, user ) {
return {
@ -69,6 +70,34 @@
}
return id;
},
/**
* Gets the number of Page Previews that the user has seen.
*
* If the storage isn't available, then -1 is returned.
*
* @return {Number}
*/
getPreviewCount: function () {
var result = storage.get( PREVIEW_COUNT_KEY );
if ( result === false ) {
return -1;
} else if ( result === null ) {
return 0;
}
return parseInt( result, 10 );
},
/**
* Sets the number of Page Previews that the user has seen.
*
* @param {Number} count
*/
setPreviewCount: function ( count ) {
storage.set( PREVIEW_COUNT_KEY, count.toString() );
}
};
};

View file

@ -10,7 +10,9 @@
return '9876543210';
},
config = new mw.Map(),
stubUser = mw.popups.tests.stubs.createStubUser( /* isAnon = */ true );
stubUser = mw.popups.tests.stubs.createStubUser( /* isAnon = */ true ),
stubUserSettings,
action;
config.set( {
wgTitle: 'Foo',
@ -19,10 +21,24 @@
wgUserEditCount: 3
} );
stubUserSettings = {
getPreviewCount: function () {
return 22;
}
};
assert.expect( 1 );
action = mw.popups.actions.boot(
isUserInCondition,
stubUser,
stubUserSettings,
generateToken,
config
);
assert.deepEqual(
mw.popups.actions.boot( isUserInCondition, stubUser, generateToken, config ),
action,
{
type: 'BOOT',
sessionToken: '0123456789',
@ -35,7 +51,8 @@
user: {
isInCondition: false,
isAnon: true,
editCount: 3
editCount: 3,
previewCount: 22
}
}
);

View file

@ -34,4 +34,33 @@
}
} );
QUnit.test( '#getPreviewCountBucket', function ( assert ) {
var i, count, bucket,
cases = [
[ -1, 'unknown' ],
[ 0, '0 previews' ],
[ 1, '1-4 previews' ],
[ 2, '1-4 previews' ],
[ 4, '1-4 previews' ],
[ 5, '5-20 previews' ],
[ 10, '5-20 previews' ],
[ 20, '5-20 previews' ],
[ 21, '21+ previews' ],
[ 100, '21+ previews' ],
[ 1000, '21+ previews' ]
];
QUnit.expect( cases.length );
for ( i = 0; i < cases.length; i++ ) {
count = cases[ i ][ 0 ];
bucket = mw.popups.counts.getPreviewCountBucket( count );
assert.equal(
bucket,
cases[ i ][ 1 ],
'Preview count bucket is "' + bucket + '" when preview count is ' + count + '.'
);
}
} );
}( mediaWiki ) );

View file

@ -12,24 +12,31 @@
QUnit.test( 'BOOT', function ( assert ) {
var action = {
type: 'BOOT',
sessionToken: '0123456789',
pageToken: '9876543210',
page: {
title: 'Foo',
namespaceID: 1,
id: 2
type: 'BOOT',
sessionToken: '0123456789',
pageToken: '9876543210',
page: {
title: 'Foo',
namespaceID: 1,
id: 2
},
user: {
isInCondition: true,
isAnon: false,
editCount: 11,
previewCount: 22
}
},
user: {
isInCondition: true,
isAnon: false,
editCount: 11
}
};
expectedEditCountBucket,
expectedPreviewCountBucket;
expectedEditCountBucket = counts.getEditCountBucket( action.user.editCount );
expectedPreviewCountBucket = counts.getPreviewCountBucket( action.user.previewCount );
assert.deepEqual(
mw.popups.reducers.eventLogging( this.initialState, action ),
{
previewCount: action.user.previewCount,
baseData: {
pageTitleSource: action.page.title,
namespaceIdSource: action.page.namespaceID,
@ -38,7 +45,8 @@
popupEnabled: action.user.isInCondition,
pageToken: action.pageToken,
sessionToken: action.sessionToken,
editCountBucket: counts.getEditCountBucket( action.user.editCount )
editCountBucket: expectedEditCountBucket,
previewCountBucket: expectedPreviewCountBucket
},
event: {
action: 'pageLoaded'

View file

@ -60,4 +60,41 @@
assert.equal( this.userSettings.getToken(), this.userSettings.getToken() );
} );
QUnit.test( '#getPreviewCount should return the count as a number', function ( assert ) {
assert.expect( 3 );
assert.strictEqual(
this.userSettings.getPreviewCount(),
0,
'#getPreviewCount returns 0 when the storage is empty.'
);
// ---
this.storage.set( 'ext.popups.core.previewCount', false );
assert.strictEqual(
this.userSettings.getPreviewCount(),
-1,
'#getPreviewCount returns -1 when the storage isn\'t available.'
);
// ---
this.storage.set( 'ext.popups.core.previewCount', '111' );
assert.strictEqual(
this.userSettings.getPreviewCount(),
111
);
} );
QUnit.test( '#setPreviewCount should store the count as a string', function ( assert ) {
assert.expect( 1 );
this.userSettings.setPreviewCount( 222 );
assert.strictEqual( this.storage.get( 'ext.popups.core.previewCount' ), '222' );
} );
}( mediaWiki ) );