mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Cite
synced 2024-11-23 14:36:51 +00:00
Add ReferencePreviews config checks to Cite extension
PHP classes and test are somewhat copies from the Popups codebase. Some refactoring was applied. More could be done. Not to sure if this should happen more in follow ups though. Could also reduce the complexity of checks on the JS side. Most of these things can only change on page load. The only dynamic part left is the anon user setting managed by the Popups extension. Note, that I needed to add a new PHP config for here although the other still exists and is needed in the Popups extension. This will change, when the user settings code also moves. I guess it's okay for now though. Both settings default to true and are not overridden in the config repos. Also needed to add the Gadget extension as phan dependency. Bug: T362771 Depends-On: Ia028c41f8aaa1c522dfc7c372e1ce51e40933a5e Change-Id: Ie6e8bc706235724494036c7f0d873f5c996c46e6
This commit is contained in:
parent
646f167a2b
commit
179d402344
|
@ -2,6 +2,20 @@
|
|||
|
||||
$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
|
||||
|
||||
$cfg['directory_list'] = array_merge(
|
||||
$cfg['directory_list'],
|
||||
[
|
||||
'../../extensions/Gadgets',
|
||||
]
|
||||
);
|
||||
|
||||
$cfg['exclude_analysis_directory_list'] = array_merge(
|
||||
$cfg['exclude_analysis_directory_list'],
|
||||
[
|
||||
'../../extensions/Gadgets',
|
||||
]
|
||||
);
|
||||
|
||||
/**
|
||||
* Quick implementation of a recursive directory list.
|
||||
* @param string $dir The directory to list
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
"ParserCloned": "parser",
|
||||
"ParserFirstCallInit": "parser",
|
||||
"EditPage::showEditForm:initial": "main",
|
||||
"MakeGlobalVariablesScript": "main",
|
||||
"ResourceLoaderGetConfigVars": "main",
|
||||
"ResourceLoaderRegisterModules": "main"
|
||||
},
|
||||
|
@ -251,8 +252,7 @@
|
|||
"tests/qunit/ve-cite/ve.ui.MWWikitextStringTransferHandler.test.js",
|
||||
"tests/qunit/ext.cite.referencePreviews/createReferenceGateway.test.js",
|
||||
"tests/qunit/ext.cite.referencePreviews/isReferencePreviewsEnabled.test.js",
|
||||
"tests/qunit/ext.cite.referencePreviews/renderer.test.js",
|
||||
"tests/qunit/ext.cite.referencePreviews/setUserConfigFlags.test.js"
|
||||
"tests/qunit/ext.cite.referencePreviews/renderer.test.js"
|
||||
],
|
||||
"dependencies": [
|
||||
"ext.cite.visualEditor",
|
||||
|
@ -299,6 +299,18 @@
|
|||
"description": "If long <references /> lists with more than 10 references should behave responsive by default and be displayed in two or more columns. This can also be toggled individually with <references responsive /> to enable and <references responsive=\"0\" /> to disable it.",
|
||||
"public": true,
|
||||
"value": true
|
||||
},
|
||||
"CiteReferencePreviews": {
|
||||
"description": "Feature flag to enable or disable the popups provided by the Popups extension for <ref> tags.",
|
||||
"value": true
|
||||
},
|
||||
"CiteReferencePreviewsConflictingNavPopupsGadgetName": {
|
||||
"description": "@var string: Name of a gadget that would cause duplicate reference preview popups. Should usually be identical to wgPopupsConflictingNavPopupsGadgetName in the Popups extension.",
|
||||
"value": "Navigation_popups"
|
||||
},
|
||||
"CiteReferencePreviewsConflictingRefTooltipsGadgetName": {
|
||||
"description": "@var string: Name of a gadget that would cause duplicate reference preview popups. Known conflicting gadgets include \"ReferenceTooltips\", \"CiteTooltip\" alias \"RefTooltip\", \"ReferencePopups\", and \"tooltipRef\" (see T274353).",
|
||||
"value": "ReferenceTooltips"
|
||||
}
|
||||
},
|
||||
"AutoloadNamespaces": {
|
||||
|
|
|
@ -3,9 +3,7 @@ const { initReferencePreviewsInstrumentation, LOGGING_SCHEMA } = require( './ref
|
|||
const createReferenceGateway = require( './createReferenceGateway.js' );
|
||||
const renderFn = require( './createReferencePreview.js' );
|
||||
const { TYPE_REFERENCE, FETCH_DELAY_REFERENCE_TYPE } = require( './constants.js' );
|
||||
const setUserConfigFlags = require( './setUserConfigFlags.js' );
|
||||
|
||||
setUserConfigFlags( mw.config );
|
||||
const referencePreviewsState = isReferencePreviewsEnabled(
|
||||
mw.user,
|
||||
mw.popups.isEnabled,
|
||||
|
@ -40,7 +38,6 @@ if ( typeof QUnit !== 'undefined' ) {
|
|||
module.exports = { private: {
|
||||
createReferenceGateway: require( './createReferenceGateway.js' ),
|
||||
createReferencePreview: require( './createReferencePreview.js' ),
|
||||
isReferencePreviewsEnabled: require( './isReferencePreviewsEnabled.js' ),
|
||||
setUserConfigFlags: require( './setUserConfigFlags.js' )
|
||||
isReferencePreviewsEnabled: require( './isReferencePreviewsEnabled.js' )
|
||||
} };
|
||||
}
|
||||
|
|
|
@ -15,27 +15,15 @@ const { TYPE_REFERENCE } = require( './constants.js' );
|
|||
* @return {boolean|null} Null when there is no way the popup type can be enabled at run-time.
|
||||
*/
|
||||
function isReferencePreviewsEnabled( user, isPreviewTypeEnabled, config ) {
|
||||
// TODO: This and the final `mw.user.options` check are currently redundant. Only this here
|
||||
// should be removed when the wgCiteReferencePreviews feature flag is not needed any more.
|
||||
if ( !config.get( 'wgCiteReferencePreviews' ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// T265872: Unavailable when in conflict with (one of the) reference tooltips gadgets.
|
||||
if ( config.get( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget' ) ||
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' ) ||
|
||||
// T243822: Temporarily disabled in the mobile skin
|
||||
config.get( 'skin' ) === 'minerva'
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( user.isAnon() ) {
|
||||
return isPreviewTypeEnabled( TYPE_REFERENCE );
|
||||
}
|
||||
|
||||
// Registered users never can enable popup types at run-time.
|
||||
return user.options.get( 'popups-reference-previews' ) === '1' ? true : null;
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = isReferencePreviewsEnabled;
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* @module setUserConfigFlags
|
||||
*/
|
||||
|
||||
/**
|
||||
* Same as in includes/PopupsContext.php
|
||||
*/
|
||||
const REF_TOOLTIPS_ENABLED = 2,
|
||||
REFERENCE_PREVIEWS_ENABLED = 4;
|
||||
|
||||
/**
|
||||
* Decodes the bitmask that represents preferences to the related config options.
|
||||
*
|
||||
* @param {mw.Map} config
|
||||
*/
|
||||
module.exports = function setUserConfigFlags( config ) {
|
||||
const popupsFlags = parseInt( config.get( 'wgPopupsFlags' ), 10 );
|
||||
|
||||
/* eslint-disable no-bitwise */
|
||||
config.set(
|
||||
'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget',
|
||||
!!( popupsFlags & REF_TOOLTIPS_ENABLED )
|
||||
);
|
||||
config.set(
|
||||
'wgCiteReferencePreviews',
|
||||
!!( popupsFlags & REFERENCE_PREVIEWS_ENABLED )
|
||||
);
|
||||
/* eslint-enable no-bitwise */
|
||||
};
|
|
@ -7,11 +7,13 @@
|
|||
namespace Cite\Hooks;
|
||||
|
||||
use ApiQuerySiteinfo;
|
||||
use Cite\ReferencePreviews\ReferencePreviewsContext;
|
||||
use ExtensionRegistry;
|
||||
use MediaWiki\Api\Hook\APIQuerySiteInfoGeneralInfoHook;
|
||||
use MediaWiki\Config\Config;
|
||||
use MediaWiki\EditPage\EditPage;
|
||||
use MediaWiki\Hook\EditPage__showEditForm_initialHook;
|
||||
use MediaWiki\Output\Hook\MakeGlobalVariablesScriptHook;
|
||||
use MediaWiki\Output\OutputPage;
|
||||
use MediaWiki\ResourceLoader\Hook\ResourceLoaderGetConfigVarsHook;
|
||||
use MediaWiki\ResourceLoader\Hook\ResourceLoaderRegisterModulesHook;
|
||||
|
@ -26,6 +28,7 @@ use MediaWiki\User\Options\UserOptionsLookup;
|
|||
*/
|
||||
class CiteHooks implements
|
||||
ContentHandlerDefaultModelForHook,
|
||||
MakeGlobalVariablesScriptHook,
|
||||
ResourceLoaderGetConfigVarsHook,
|
||||
ResourceLoaderRegisterModulesHook,
|
||||
APIQuerySiteInfoGeneralInfoHook,
|
||||
|
@ -58,6 +61,21 @@ class CiteHooks implements
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array &$vars
|
||||
* @param OutputPage $out
|
||||
*/
|
||||
public function onMakeGlobalVariablesScript( &$vars, $out ): void {
|
||||
$referencePreviewsContext = new ReferencePreviewsContext(
|
||||
$out->getConfig(),
|
||||
$this->userOptionsLookup
|
||||
);
|
||||
$vars['wgCiteReferencePreviews'] = $referencePreviewsContext->isReferencePreviewsEnabled(
|
||||
$out->getUser(),
|
||||
$out->getSkin()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds extra variables to the global config
|
||||
* @param array &$vars `[ variable name => value ]`
|
||||
|
@ -92,8 +110,7 @@ class CiteHooks implements
|
|||
'createReferenceGateway.js',
|
||||
'createReferencePreview.js',
|
||||
'isReferencePreviewsEnabled.js',
|
||||
'referencePreviewsInstrumentation.js',
|
||||
'setUserConfigFlags.js'
|
||||
'referencePreviewsInstrumentation.js'
|
||||
]
|
||||
]
|
||||
] );
|
||||
|
|
52
src/ReferencePreviews/ReferencePreviewsContext.php
Normal file
52
src/ReferencePreviews/ReferencePreviewsContext.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Cite\ReferencePreviews;
|
||||
|
||||
use MediaWiki\Config\Config;
|
||||
use MediaWiki\User\Options\UserOptionsLookup;
|
||||
use MediaWiki\User\User;
|
||||
use Skin;
|
||||
|
||||
/**
|
||||
* @license GPL-2.0-or-later
|
||||
*/
|
||||
class ReferencePreviewsContext {
|
||||
|
||||
private Config $config;
|
||||
|
||||
private ReferencePreviewsGadgetsIntegration $gadgetsIntegration;
|
||||
|
||||
private UserOptionsLookup $userOptionsLookup;
|
||||
|
||||
public function __construct(
|
||||
Config $config,
|
||||
UserOptionsLookup $userOptionsLookup
|
||||
) {
|
||||
$this->gadgetsIntegration = new ReferencePreviewsGadgetsIntegration( $config );
|
||||
$this->userOptionsLookup = $userOptionsLookup;
|
||||
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* User preference key to enable/disable Reference Previews. Named
|
||||
* "mwe-popups-referencePreviews-enabled" in localStorage for anonymous users.
|
||||
*/
|
||||
public const REFERENCE_PREVIEWS_PREFERENCE_NAME = 'popups-reference-previews';
|
||||
|
||||
public function isReferencePreviewsEnabled( User $user, Skin $skin ): bool {
|
||||
if (
|
||||
// T243822: Temporarily disabled in the mobile skin
|
||||
$skin->getSkinName() === 'minerva' ||
|
||||
!$this->config->get( 'CiteReferencePreviews' ) ||
|
||||
$this->gadgetsIntegration->isRefToolTipsGadgetEnabled( $user ) ||
|
||||
$this->gadgetsIntegration->isNavPopupsGadgetEnabled( $user )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$user->isNamed() || $this->userOptionsLookup->getBoolOption(
|
||||
$user, self::REFERENCE_PREVIEWS_PREFERENCE_NAME
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace Cite\ReferencePreviews;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use MediaWiki\Config\Config;
|
||||
use MediaWiki\Extension\Gadgets\GadgetRepo;
|
||||
use MediaWiki\MediaWikiServices;
|
||||
use MediaWiki\User\User;
|
||||
use MediaWiki\User\UserIdentity;
|
||||
use Wikimedia\Services\NoSuchServiceException;
|
||||
|
||||
/**
|
||||
* Gadgets integration
|
||||
*
|
||||
* @package ReferencePreviews
|
||||
* @license GPL-2.0-or-later
|
||||
*/
|
||||
class ReferencePreviewsGadgetsIntegration {
|
||||
|
||||
public const CONFIG_NAVIGATION_POPUPS_NAME = 'CiteReferencePreviewsConflictingNavPopupsGadgetName';
|
||||
|
||||
public const CONFIG_REFERENCE_TOOLTIPS_NAME = 'CiteReferencePreviewsConflictingRefTooltipsGadgetName';
|
||||
|
||||
private ?GadgetRepo $gadgetRepo;
|
||||
|
||||
private string $navPopupsGadgetName;
|
||||
|
||||
private string $refTooltipsGadgetName;
|
||||
|
||||
public function __construct( Config $config ) {
|
||||
$this->navPopupsGadgetName = $this->sanitizeGadgetName(
|
||||
$config->get( self::CONFIG_NAVIGATION_POPUPS_NAME ) );
|
||||
$this->refTooltipsGadgetName = $this->sanitizeGadgetName(
|
||||
$config->get( self::CONFIG_REFERENCE_TOOLTIPS_NAME ) );
|
||||
|
||||
try {
|
||||
$this->gadgetRepo = MediaWikiServices::getInstance()->getService( 'GadgetsRepo' );
|
||||
} catch ( NoSuchServiceException $e ) {
|
||||
$this->gadgetRepo = null;
|
||||
}
|
||||
}
|
||||
|
||||
private function sanitizeGadgetName( string $gadgetName ): string {
|
||||
return str_replace( ' ', '_', trim( $gadgetName ) );
|
||||
}
|
||||
|
||||
private function isGadgetEnabled( UserIdentity $user, string $gadgetName ): bool {
|
||||
if ( $this->gadgetRepo ) {
|
||||
if ( in_array( $gadgetName, $this->gadgetRepo->getGadgetIds() ) ) {
|
||||
try {
|
||||
return $this->gadgetRepo->getGadget( $gadgetName )
|
||||
->isEnabled( $user );
|
||||
} catch ( InvalidArgumentException $e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isNavPopupsGadgetEnabled( User $user ): bool {
|
||||
return $this->isGadgetEnabled( $user, $this->navPopupsGadgetName );
|
||||
}
|
||||
|
||||
public function isRefTooltipsGadgetEnabled( User $user ): bool {
|
||||
return $this->isGadgetEnabled( $user, $this->refTooltipsGadgetName );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Cite\Tests\Integration\ReferencePreviews;
|
||||
|
||||
use Cite\ReferencePreviews\ReferencePreviewsContext;
|
||||
use MediaWiki\Config\HashConfig;
|
||||
use MediaWiki\User\Options\UserOptionsLookup;
|
||||
use MediaWiki\User\User;
|
||||
use MediaWikiIntegrationTestCase;
|
||||
use Skin;
|
||||
|
||||
/**
|
||||
* @group Popups
|
||||
* @coversDefaultClass \Cite\ReferencePreviews\ReferencePreviewsContext
|
||||
* @license GPL-2.0-or-later
|
||||
*/
|
||||
class ReferencePreviewsContextTest extends MediaWikiIntegrationTestCase {
|
||||
|
||||
/**
|
||||
* Tests #shouldSendModuleToUser when the user is logged in and the reference previews feature
|
||||
* is disabled.
|
||||
*
|
||||
* @covers ::isReferencePreviewsEnabled
|
||||
* @dataProvider provideIsReferencePreviewsEnabled_requirements
|
||||
*/
|
||||
public function testIsReferencePreviewsEnabled_requirements( bool $setting, string $skinName, bool $expected ) {
|
||||
$config = new HashConfig( [
|
||||
'CiteReferencePreviews' => $setting,
|
||||
'CiteReferencePreviewsConflictingNavPopupsGadgetName' => '',
|
||||
'CiteReferencePreviewsConflictingRefTooltipsGadgetName' => '',
|
||||
] );
|
||||
$userOptLookup = $this->createNoOpMock( UserOptionsLookup::class );
|
||||
|
||||
$context = new ReferencePreviewsContext( $config, $userOptLookup );
|
||||
|
||||
$user = $this->createMock( User::class );
|
||||
$user->method( 'isNamed' )->willReturn( false );
|
||||
|
||||
$skin = $this->createMock( Skin::class );
|
||||
$skin->method( 'getSkinName' )->willReturn( $skinName );
|
||||
|
||||
$this->assertSame( $expected,
|
||||
$context->isReferencePreviewsEnabled( $user, $skin ),
|
||||
( $expected ? 'A' : 'No' ) . ' module is sent to the user.' );
|
||||
}
|
||||
|
||||
public static function provideIsReferencePreviewsEnabled_requirements() {
|
||||
yield [ true, 'minerva', false ];
|
||||
yield [ false, 'minerva', false ];
|
||||
yield [ true, 'vector', true ];
|
||||
yield [ false, 'vector', false ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests #shouldSendModuleToUser when the user is logged in and the reference previews feature
|
||||
* is disabled.
|
||||
*
|
||||
* @covers ::isReferencePreviewsEnabled
|
||||
* @dataProvider provideIsReferencePreviewsEnabled_userOptions
|
||||
*/
|
||||
public function testIsReferencePreviewsEnabled_userOptions( bool $isNamed, bool $option, bool $expected ) {
|
||||
$user = $this->createMock( User::class );
|
||||
$user->method( 'isNamed' )->willReturn( $isNamed );
|
||||
|
||||
$userOptLookup = $this->createMock( UserOptionsLookup::class );
|
||||
$userOptLookup->method( 'getBoolOption' )
|
||||
->with( $user, ReferencePreviewsContext::REFERENCE_PREVIEWS_PREFERENCE_NAME )
|
||||
->willReturn( $option );
|
||||
|
||||
$config = new HashConfig( [
|
||||
'CiteReferencePreviews' => true,
|
||||
'CiteReferencePreviewsConflictingNavPopupsGadgetName' => '',
|
||||
'CiteReferencePreviewsConflictingRefTooltipsGadgetName' => '',
|
||||
] );
|
||||
|
||||
$context = new ReferencePreviewsContext( $config, $userOptLookup );
|
||||
|
||||
$skin = $this->createMock( Skin::class );
|
||||
|
||||
$this->assertSame( $expected,
|
||||
$context->isReferencePreviewsEnabled( $user, $skin ),
|
||||
( $expected ? 'A' : 'No' ) . ' module is sent to the user.' );
|
||||
}
|
||||
|
||||
public static function provideIsReferencePreviewsEnabled_userOptions() {
|
||||
yield [ true, true, true ];
|
||||
yield [ true, false, false ];
|
||||
yield [ false, false, true ];
|
||||
yield [ false, true, true ];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
namespace Cite\Tests\Integration\ReferencePreviews;
|
||||
|
||||
use Cite\ReferencePreviews\ReferencePreviewsGadgetsIntegration;
|
||||
use InvalidArgumentException;
|
||||
use MediaWiki\Config\Config;
|
||||
use MediaWiki\Extension\Gadgets\Gadget;
|
||||
use MediaWiki\Extension\Gadgets\GadgetRepo;
|
||||
use MediaWiki\User\User;
|
||||
use MediaWikiIntegrationTestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Cite\ReferencePreviews\ReferencePreviewsGadgetsIntegration
|
||||
* @license GPL-2.0-or-later
|
||||
*/
|
||||
class ReferencePreviewsGadgetsIntegrationTest extends MediaWikiIntegrationTestCase {
|
||||
/**
|
||||
* Gadget name for testing
|
||||
*/
|
||||
private const NAV_POPUPS_GADGET_NAME = 'navigation-test';
|
||||
|
||||
/**
|
||||
* Helper constants for easier reading
|
||||
*/
|
||||
private const GADGET_ENABLED = true;
|
||||
|
||||
/**
|
||||
* Helper constants for easier reading
|
||||
*/
|
||||
private const GADGET_DISABLED = false;
|
||||
|
||||
/**
|
||||
* @return MockObject|Config
|
||||
*/
|
||||
private function getConfigMock() {
|
||||
$mock = $this->createMock( Config::class );
|
||||
$mock->expects( $this->atLeastOnce() )
|
||||
->method( 'get' )
|
||||
->willReturnMap( [
|
||||
[ ReferencePreviewsGadgetsIntegration::CONFIG_NAVIGATION_POPUPS_NAME, self::NAV_POPUPS_GADGET_NAME ],
|
||||
[ ReferencePreviewsGadgetsIntegration::CONFIG_REFERENCE_TOOLTIPS_NAME, self::NAV_POPUPS_GADGET_NAME ],
|
||||
] );
|
||||
return $mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isNavPopupsGadgetEnabled
|
||||
* @covers ::__construct
|
||||
* @covers ::sanitizeGadgetName
|
||||
*/
|
||||
public function testConflictsWithNavPopupsGadgetIfGadgetsExtensionIsNotLoaded() {
|
||||
$user = $this->createMock( User::class );
|
||||
$integration = new ReferencePreviewsGadgetsIntegration( $this->getConfigMock() );
|
||||
$this->assertFalse(
|
||||
$integration->isNavPopupsGadgetEnabled( $user ),
|
||||
'No conflict is identified.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isNavPopupsGadgetEnabled
|
||||
*/
|
||||
public function testConflictsWithNavPopupsGadgetIfGadgetNotExists() {
|
||||
$user = $this->createMock( User::class );
|
||||
|
||||
$gadgetRepoMock = $this->createMock( GadgetRepo::class );
|
||||
$gadgetRepoMock->expects( $this->once() )
|
||||
->method( 'getGadgetIds' )
|
||||
->willReturn( [] );
|
||||
|
||||
$this->executeConflictsWithNavPopupsGadgetSafeCheck( $user, $this->getConfigMock(),
|
||||
$gadgetRepoMock, self::GADGET_DISABLED );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::isNavPopupsGadgetEnabled
|
||||
*/
|
||||
public function testConflictsWithNavPopupsGadgetIfGadgetExists() {
|
||||
$user = $this->createMock( User::class );
|
||||
|
||||
$gadgetMock = $this->createMock( Gadget::class );
|
||||
$gadgetMock->expects( $this->once() )
|
||||
->method( 'isEnabled' )
|
||||
->with( $user )
|
||||
->willReturn( self::GADGET_ENABLED );
|
||||
|
||||
$gadgetRepoMock = $this->createMock( GadgetRepo::class );
|
||||
$gadgetRepoMock->expects( $this->once() )
|
||||
->method( 'getGadgetIds' )
|
||||
->willReturn( [ self::NAV_POPUPS_GADGET_NAME ] );
|
||||
$gadgetRepoMock->expects( $this->once() )
|
||||
->method( 'getGadget' )
|
||||
->with( self::NAV_POPUPS_GADGET_NAME )
|
||||
->willReturn( $gadgetMock );
|
||||
|
||||
$this->executeConflictsWithNavPopupsGadgetSafeCheck( $user, $this->getConfigMock(),
|
||||
$gadgetRepoMock, self::GADGET_ENABLED );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the edge case when GadgetsRepo::getGadget throws an exception
|
||||
* @covers ::isNavPopupsGadgetEnabled
|
||||
*/
|
||||
public function testConflictsWithNavPopupsGadgetWhenGadgetNotExists() {
|
||||
$user = $this->createMock( User::class );
|
||||
|
||||
$gadgetRepoMock = $this->createMock( GadgetRepo::class );
|
||||
$gadgetRepoMock->expects( $this->once() )
|
||||
->method( 'getGadgetIds' )
|
||||
->willReturn( [ self::NAV_POPUPS_GADGET_NAME ] );
|
||||
$gadgetRepoMock->expects( $this->once() )
|
||||
->method( 'getGadget' )
|
||||
->with( self::NAV_POPUPS_GADGET_NAME )
|
||||
->willThrowException( new InvalidArgumentException() );
|
||||
|
||||
$this->executeConflictsWithNavPopupsGadgetSafeCheck( $user, $this->getConfigMock(),
|
||||
$gadgetRepoMock, self::GADGET_DISABLED );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::sanitizeGadgetName
|
||||
* @dataProvider provideGadgetNamesWithSanitizedVersion
|
||||
*/
|
||||
public function testConflictsWithNavPopupsGadgetNameSanitization( $name, $sanitized ) {
|
||||
$user = $this->createMock( User::class );
|
||||
|
||||
$configMock = $this->createMock( Config::class );
|
||||
$configMock->expects( $this->atLeastOnce() )
|
||||
->method( 'get' )
|
||||
->willReturnMap( [
|
||||
[ ReferencePreviewsGadgetsIntegration::CONFIG_NAVIGATION_POPUPS_NAME, $name ],
|
||||
[ ReferencePreviewsGadgetsIntegration::CONFIG_REFERENCE_TOOLTIPS_NAME, $name ]
|
||||
] );
|
||||
|
||||
$gadgetMock = $this->createMock( Gadget::class );
|
||||
$gadgetMock->expects( $this->once() )
|
||||
->method( 'isEnabled' )
|
||||
->willReturn( self::GADGET_ENABLED );
|
||||
|
||||
$gadgetRepoMock = $this->createMock( GadgetRepo::class );
|
||||
$gadgetRepoMock->expects( $this->once() )
|
||||
->method( 'getGadgetIds' )
|
||||
->willReturn( [ $sanitized ] );
|
||||
$gadgetRepoMock->expects( $this->once() )
|
||||
->method( 'getGadget' )
|
||||
->with( $sanitized )
|
||||
->willReturn( $gadgetMock );
|
||||
|
||||
$this->executeConflictsWithNavPopupsGadgetSafeCheck( $user, $configMock, $gadgetRepoMock,
|
||||
self::GADGET_ENABLED );
|
||||
}
|
||||
|
||||
public static function provideGadgetNamesWithSanitizedVersion() {
|
||||
return [
|
||||
[ ' Popups ', 'Popups' ],
|
||||
[ 'Navigation_popups-API', 'Navigation_popups-API' ],
|
||||
[ 'Navigation popups ', 'Navigation_popups' ]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute test and restore GadgetRepo
|
||||
*
|
||||
* @param User $user
|
||||
* @param Config $config
|
||||
* @param GadgetRepo $repoMock
|
||||
* @param bool $expected
|
||||
*/
|
||||
private function executeConflictsWithNavPopupsGadgetSafeCheck(
|
||||
User $user,
|
||||
Config $config,
|
||||
GadgetRepo $repoMock,
|
||||
$expected
|
||||
) {
|
||||
$this->setService( 'GadgetsRepo', $repoMock );
|
||||
|
||||
$integration = new ReferencePreviewsGadgetsIntegration( $config );
|
||||
$this->assertSame( $expected,
|
||||
$integration->isNavPopupsGadgetEnabled( $user ),
|
||||
( $expected ? 'A' : 'No' ) . ' conflict is identified.' );
|
||||
}
|
||||
}
|
|
@ -24,109 +24,28 @@ const options = { get: () => '1' };
|
|||
QUnit.module :
|
||||
QUnit.module.skip )( 'ext.cite.referencePreviews#isReferencePreviewsEnabled' );
|
||||
|
||||
QUnit.test( 'all relevant combinations of flags', ( assert ) => {
|
||||
QUnit.test( 'relevant combinations of anonymous flags', ( assert ) => {
|
||||
[
|
||||
{
|
||||
testCase: 'enabled for an anonymous user',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: false,
|
||||
isAnon: true,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: false,
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
testCase: 'turned off via the feature flag (anonymous user)',
|
||||
wgCiteReferencePreviews: false,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: false,
|
||||
isAnon: true,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: true,
|
||||
expected: null
|
||||
},
|
||||
{
|
||||
testCase: 'not available because of a conflicting gadget (anonymous user)',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: true,
|
||||
isMobile: false,
|
||||
isAnon: true,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: true,
|
||||
expected: null
|
||||
},
|
||||
{
|
||||
testCase: 'not available in the mobile skin (anonymous user)',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: true,
|
||||
isAnon: true,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: true,
|
||||
expected: null
|
||||
},
|
||||
{
|
||||
testCase: 'manually disabled by the anonymous user',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: false,
|
||||
isAnon: true,
|
||||
enabledByAnon: false,
|
||||
enabledByRegistered: true,
|
||||
expected: false
|
||||
},
|
||||
{
|
||||
testCase: 'enabled for a registered user',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: false,
|
||||
isAnon: false,
|
||||
enabledByAnon: false,
|
||||
enabledByRegistered: true,
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
testCase: 'turned off via the feature flag (registered user)',
|
||||
wgCiteReferencePreviews: false,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: false,
|
||||
isAnon: false,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: true,
|
||||
expected: null
|
||||
},
|
||||
{
|
||||
testCase: 'not available because of a conflicting gadget (registered user)',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: true,
|
||||
isMobile: false,
|
||||
isAnon: false,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: true,
|
||||
expected: null
|
||||
},
|
||||
{
|
||||
testCase: 'not available in the mobile skin (registered user)',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: true,
|
||||
isAnon: false,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: true,
|
||||
expected: null
|
||||
},
|
||||
{
|
||||
// TODO: This combination will make much more sense when the server-side
|
||||
// wgCiteReferencePreviews flag doesn't include the user's setting any more
|
||||
testCase: 'manually disabled by the registered user',
|
||||
wgCiteReferencePreviews: true,
|
||||
wgCiteReferencePreviewsConflictsWithRefTooltipsGadget: false,
|
||||
isMobile: false,
|
||||
isAnon: false,
|
||||
enabledByAnon: true,
|
||||
enabledByRegistered: false,
|
||||
expected: null
|
||||
}
|
||||
].forEach( ( data ) => {
|
||||
const user = {
|
||||
|
@ -142,9 +61,8 @@ QUnit.test( 'all relevant combinations of flags', ( assert ) => {
|
|||
}
|
||||
return data.enabledByAnon;
|
||||
},
|
||||
config = {
|
||||
get: ( key ) => key === 'skin' && data.isMobile ? 'minerva' : data[ key ]
|
||||
};
|
||||
config = new Map();
|
||||
config.set( 'wgCiteReferencePreviews', data.wgCiteReferencePreviews );
|
||||
|
||||
if ( data.isAnon ) {
|
||||
user.options.get = () => assert.true( false, 'not expected to be called 2' );
|
||||
|
@ -166,7 +84,6 @@ QUnit.test( 'it should display reference previews when conditions are fulfilled'
|
|||
config = new Map();
|
||||
|
||||
config.set( 'wgCiteReferencePreviews', true );
|
||||
config.set( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget', false );
|
||||
|
||||
assert.true(
|
||||
require( 'ext.cite.referencePreviews' ).private.isReferencePreviewsEnabled( user, userSettings, config ),
|
||||
|
@ -174,44 +91,12 @@ QUnit.test( 'it should display reference previews when conditions are fulfilled'
|
|||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'it should handle the conflict with the Reference Tooltips Gadget', ( assert ) => {
|
||||
const user = createStubUser( false ),
|
||||
userSettings = createStubUserSettings( false ),
|
||||
config = new Map();
|
||||
|
||||
config.set( 'wgCiteReferencePreviews', true );
|
||||
config.set( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget', true );
|
||||
|
||||
assert.strictEqual(
|
||||
require( 'ext.cite.referencePreviews' ).private.isReferencePreviewsEnabled( user, userSettings, config ),
|
||||
null,
|
||||
'Reference Previews is disabled.'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'it should not be enabled when the global is disabling it', ( assert ) => {
|
||||
const user = createStubUser( false ),
|
||||
userSettings = createStubUserSettings( false ),
|
||||
config = new Map();
|
||||
|
||||
config.set( 'wgCiteReferencePreviews', false );
|
||||
config.set( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget', false );
|
||||
|
||||
assert.strictEqual(
|
||||
require( 'ext.cite.referencePreviews' ).private.isReferencePreviewsEnabled( user, userSettings, config ),
|
||||
null,
|
||||
'Reference Previews is disabled.'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'it should not be enabled when minerva skin used', ( assert ) => {
|
||||
const user = createStubUser( false ),
|
||||
userSettings = createStubUserSettings( false ),
|
||||
config = new Map();
|
||||
|
||||
config.set( 'wgCiteReferencePreviews', true );
|
||||
config.set( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget', false );
|
||||
config.set( 'skin', 'minerva' );
|
||||
|
||||
assert.strictEqual(
|
||||
require( 'ext.cite.referencePreviews' ).private.isReferencePreviewsEnabled( user, userSettings, config ),
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
( mw.loader.getModuleNames().indexOf( 'ext.popups.main' ) !== -1 ?
|
||||
QUnit.module :
|
||||
QUnit.module.skip )( 'ext.cite.referencePreviews#setUserConfigFlags' );
|
||||
|
||||
QUnit.test( 'reference preview config settings are successfully set from bitmask', ( assert ) => {
|
||||
const config = new Map();
|
||||
|
||||
config.set( 'wgPopupsFlags', '7' );
|
||||
require( 'ext.cite.referencePreviews' ).private.setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgCiteReferencePreviews' )
|
||||
],
|
||||
[ true, true ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '2' );
|
||||
require( 'ext.cite.referencePreviews' ).private.setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgCiteReferencePreviews' )
|
||||
],
|
||||
[ true, false ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '5' );
|
||||
require( 'ext.cite.referencePreviews' ).private.setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgCiteReferencePreviews' )
|
||||
],
|
||||
[ false, true ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '0' );
|
||||
require( 'ext.cite.referencePreviews' ).private.setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgCiteReferencePreviewsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgCiteReferencePreviews' )
|
||||
],
|
||||
[ false, false ]
|
||||
);
|
||||
} );
|
Loading…
Reference in a new issue