[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
<?php
|
|
|
|
/*
|
|
|
|
* @file
|
|
|
|
* @ingroup skins
|
|
|
|
*/
|
|
|
|
|
2022-03-04 13:35:05 +00:00
|
|
|
namespace MediaWiki\Skins\Vector\Tests\Integration;
|
|
|
|
|
2022-10-20 18:37:10 +00:00
|
|
|
use FauxRequest;
|
2022-03-04 13:35:05 +00:00
|
|
|
use HashConfig;
|
2022-05-23 07:32:40 +00:00
|
|
|
use MediaWiki\Skins\Vector\Constants;
|
2022-10-21 17:39:16 +00:00
|
|
|
use MediaWiki\Skins\Vector\FeatureManagement\Requirements\LimitedWidthContentRequirement;
|
2022-05-23 07:32:40 +00:00
|
|
|
use MediaWiki\Skins\Vector\Hooks;
|
|
|
|
use MediaWiki\Skins\Vector\SkinVector22;
|
|
|
|
use MediaWiki\Skins\Vector\SkinVectorLegacy;
|
2021-03-30 21:50:11 +00:00
|
|
|
use MediaWiki\User\UserOptionsManager;
|
2022-03-04 13:35:05 +00:00
|
|
|
use MediaWikiIntegrationTestCase;
|
2022-03-04 15:45:45 +00:00
|
|
|
use ReflectionMethod;
|
2022-03-24 20:34:02 +00:00
|
|
|
use RequestContext;
|
2022-03-04 13:35:05 +00:00
|
|
|
use ResourceLoaderContext;
|
|
|
|
use RuntimeException;
|
|
|
|
use Title;
|
|
|
|
use User;
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Integration tests for Vector Hooks.
|
|
|
|
*
|
|
|
|
* @group Vector
|
2022-05-23 07:32:40 +00:00
|
|
|
* @coversDefaultClass \MediaWiki\Skins\Vector\Hooks
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
*/
|
2021-03-25 04:06:14 +00:00
|
|
|
class VectorHooksTest extends MediaWikiIntegrationTestCase {
|
2021-01-06 21:50:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param bool $excludeMainPage
|
|
|
|
* @param array $excludeNamespaces
|
|
|
|
* @param array $include
|
|
|
|
* @param array $querystring
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
private static function makeMaxWidthConfig(
|
|
|
|
$excludeMainPage,
|
|
|
|
$excludeNamespaces = [],
|
|
|
|
$include = [],
|
|
|
|
$querystring = []
|
|
|
|
) {
|
|
|
|
return [
|
|
|
|
'exclude' => [
|
|
|
|
'mainpage' => $excludeMainPage,
|
|
|
|
'namespaces' => $excludeNamespaces,
|
|
|
|
'querystring' => $querystring,
|
|
|
|
],
|
|
|
|
'include' => $include
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-04-10 18:56:19 +00:00
|
|
|
public function provideGetActiveABTest() {
|
2021-12-14 19:24:32 +00:00
|
|
|
return [
|
|
|
|
[
|
|
|
|
[
|
|
|
|
'VectorWebABTestEnrollment' => [],
|
|
|
|
],
|
2023-04-10 18:56:19 +00:00
|
|
|
[]
|
2021-12-14 19:24:32 +00:00
|
|
|
],
|
|
|
|
[
|
|
|
|
[
|
|
|
|
'VectorWebABTestEnrollment' => [
|
|
|
|
'name' => 'vector.sticky_header',
|
|
|
|
'enabled' => true,
|
|
|
|
'buckets' => [
|
|
|
|
'unsampled' => [
|
|
|
|
'samplingRate' => 1,
|
|
|
|
],
|
|
|
|
'control' => [
|
|
|
|
'samplingRate' => 0
|
|
|
|
],
|
|
|
|
'stickyHeaderEnabled' => [
|
|
|
|
'samplingRate' => 0
|
|
|
|
],
|
|
|
|
'stickyHeaderDisabled' => [
|
|
|
|
'samplingRate' => 0
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
[
|
2023-04-10 18:56:19 +00:00
|
|
|
'name' => 'vector.sticky_header',
|
|
|
|
'enabled' => true,
|
|
|
|
'buckets' => [
|
|
|
|
'unsampled' => [
|
|
|
|
'samplingRate' => 1,
|
|
|
|
],
|
|
|
|
'control' => [
|
|
|
|
'samplingRate' => 0
|
|
|
|
],
|
|
|
|
'stickyHeaderEnabled' => [
|
|
|
|
'samplingRate' => 0
|
|
|
|
],
|
|
|
|
'stickyHeaderDisabled' => [
|
|
|
|
'samplingRate' => 0
|
|
|
|
],
|
2021-12-14 19:24:32 +00:00
|
|
|
],
|
|
|
|
]
|
|
|
|
],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-04-10 18:56:19 +00:00
|
|
|
public function provideGetActiveABTestWithExceptions() {
|
2021-12-14 19:24:32 +00:00
|
|
|
return [
|
|
|
|
# Bad experiment (no buckets)
|
|
|
|
[
|
|
|
|
[
|
2022-10-06 00:38:38 +00:00
|
|
|
'VectorSearchApiUrl' => 'https://en.wikipedia.org/w/rest.php',
|
2021-12-14 19:24:32 +00:00
|
|
|
'VectorWebABTestEnrollment' => [
|
|
|
|
'name' => 'vector.sticky_header',
|
|
|
|
'enabled' => true,
|
|
|
|
],
|
|
|
|
]
|
|
|
|
],
|
|
|
|
# Bad experiment (no unsampled bucket)
|
|
|
|
[
|
|
|
|
[
|
2022-10-06 00:38:38 +00:00
|
|
|
'VectorSearchApiUrl' => 'https://en.wikipedia.org/w/rest.php',
|
2021-12-14 19:24:32 +00:00
|
|
|
'VectorWebABTestEnrollment' => [
|
|
|
|
'name' => 'vector.sticky_header',
|
|
|
|
'enabled' => true,
|
|
|
|
'buckets' => [
|
|
|
|
'a' => [
|
|
|
|
'samplingRate' => 0
|
|
|
|
],
|
|
|
|
]
|
|
|
|
],
|
|
|
|
]
|
|
|
|
],
|
|
|
|
# Bad experiment (wrong format)
|
|
|
|
[
|
|
|
|
[
|
2022-10-06 00:38:38 +00:00
|
|
|
'VectorSearchApiUrl' => 'https://en.wikipedia.org/w/rest.php',
|
2021-12-14 19:24:32 +00:00
|
|
|
'VectorWebABTestEnrollment' => [
|
|
|
|
'name' => 'vector.sticky_header',
|
|
|
|
'enabled' => true,
|
|
|
|
'buckets' => [
|
|
|
|
'unsampled' => 1,
|
|
|
|
]
|
|
|
|
],
|
|
|
|
]
|
|
|
|
],
|
|
|
|
# Bad experiment (samplingRate defined as string)
|
|
|
|
[
|
|
|
|
[
|
2022-10-06 00:38:38 +00:00
|
|
|
'VectorSearchApiUrl' => 'https://en.wikipedia.org/w/rest.php',
|
2021-12-14 19:24:32 +00:00
|
|
|
'VectorWebABTestEnrollment' => [
|
|
|
|
'name' => 'vector.sticky_header',
|
|
|
|
'enabled' => true,
|
|
|
|
'buckets' => [
|
|
|
|
'unsampled' => [
|
|
|
|
'samplingRate' => '1'
|
|
|
|
],
|
|
|
|
]
|
|
|
|
],
|
|
|
|
]
|
|
|
|
],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2021-01-06 21:50:19 +00:00
|
|
|
/**
|
|
|
|
* @covers ::shouldDisableMaxWidth
|
|
|
|
*/
|
|
|
|
public function providerShouldDisableMaxWidth() {
|
|
|
|
$excludeTalkFooConfig = self::makeMaxWidthConfig(
|
|
|
|
false,
|
|
|
|
[ NS_TALK ],
|
|
|
|
[ 'Talk:Foo' ],
|
|
|
|
[]
|
|
|
|
);
|
|
|
|
|
|
|
|
return [
|
|
|
|
[
|
|
|
|
'No options, nothing disables max width',
|
|
|
|
[],
|
|
|
|
Title::makeTitle( NS_MAIN, 'Foo' ),
|
|
|
|
[],
|
|
|
|
false
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'Main page disables max width if exclude.mainpage set',
|
|
|
|
self::makeMaxWidthConfig( true ),
|
|
|
|
Title::newMainPage(),
|
|
|
|
[],
|
|
|
|
true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'Namespaces can be excluded',
|
|
|
|
self::makeMaxWidthConfig( false, [ NS_CATEGORY ] ),
|
|
|
|
Title::makeTitle( NS_CATEGORY, 'Category' ),
|
|
|
|
[],
|
|
|
|
true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'Namespaces are included if not excluded',
|
|
|
|
self::makeMaxWidthConfig( false, [ NS_CATEGORY ] ),
|
|
|
|
Title::makeTitle( NS_SPECIAL, 'SpecialPages' ),
|
|
|
|
[],
|
|
|
|
false
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'More than one namespace can be included',
|
|
|
|
self::makeMaxWidthConfig( false, [ NS_CATEGORY, NS_SPECIAL ] ),
|
|
|
|
Title::makeTitle( NS_SPECIAL, 'Specialpages' ),
|
|
|
|
[],
|
|
|
|
true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'Can be disabled on history page',
|
|
|
|
self::makeMaxWidthConfig(
|
|
|
|
false,
|
|
|
|
[
|
|
|
|
/* no namespaces excluded */
|
|
|
|
],
|
|
|
|
[
|
|
|
|
/* no includes */
|
|
|
|
],
|
|
|
|
[ 'action' => 'history' ]
|
|
|
|
),
|
|
|
|
Title::makeTitle( NS_MAIN, 'History page' ),
|
|
|
|
[ 'action' => 'history' ],
|
|
|
|
true
|
|
|
|
],
|
2022-05-19 05:32:40 +00:00
|
|
|
[
|
|
|
|
'Can be disabled with a regex match.',
|
|
|
|
self::makeMaxWidthConfig(
|
|
|
|
false,
|
|
|
|
[
|
|
|
|
/* no namespaces excluded */
|
|
|
|
],
|
|
|
|
[
|
|
|
|
/* no includes */
|
|
|
|
],
|
|
|
|
[ 'foo' => '[0-9]+' ]
|
|
|
|
),
|
|
|
|
Title::makeTitle( NS_MAIN, 'Test' ),
|
|
|
|
[ 'foo' => '1234' ],
|
|
|
|
true
|
|
|
|
],
|
2022-10-20 18:37:10 +00:00
|
|
|
[
|
|
|
|
'Can be disabled with a regex match, also for falsy 0.',
|
|
|
|
self::makeMaxWidthConfig(
|
|
|
|
false,
|
|
|
|
[
|
|
|
|
/* no namespaces excluded */
|
|
|
|
],
|
|
|
|
[
|
|
|
|
/* no includes */
|
|
|
|
],
|
|
|
|
[ 'foo' => '[0-9]+' ]
|
|
|
|
),
|
|
|
|
Title::makeTitle( NS_MAIN, 'Test' ),
|
|
|
|
[ 'foo' => '0' ],
|
|
|
|
true
|
|
|
|
],
|
2022-05-19 05:32:40 +00:00
|
|
|
[
|
|
|
|
'Can be disabled with a non-regex wildcard (for backwards compatibility).',
|
|
|
|
self::makeMaxWidthConfig(
|
|
|
|
false,
|
|
|
|
[
|
|
|
|
/* no namespaces excluded */
|
|
|
|
],
|
|
|
|
[
|
|
|
|
/* no includes */
|
|
|
|
],
|
|
|
|
[ 'foo' => '*' ]
|
|
|
|
),
|
|
|
|
Title::makeTitle( NS_MAIN, 'Test' ),
|
|
|
|
[ 'foo' => 'bar' ],
|
|
|
|
true
|
|
|
|
],
|
2021-01-06 21:50:19 +00:00
|
|
|
[
|
|
|
|
'Include can override exclusions',
|
|
|
|
self::makeMaxWidthConfig(
|
|
|
|
false,
|
|
|
|
[ NS_CATEGORY, NS_SPECIAL ],
|
|
|
|
[ 'Special:Specialpages' ],
|
|
|
|
[ 'action' => 'history' ]
|
|
|
|
),
|
|
|
|
Title::makeTitle( NS_SPECIAL, 'Specialpages' ),
|
|
|
|
[ 'action' => 'history' ],
|
|
|
|
false
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'Max width can be disabled on talk pages',
|
|
|
|
$excludeTalkFooConfig,
|
|
|
|
Title::makeTitle( NS_TALK, 'A talk page' ),
|
|
|
|
[],
|
|
|
|
true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'includes can be used to override any page in a disabled namespace',
|
|
|
|
$excludeTalkFooConfig,
|
|
|
|
Title::makeTitle( NS_TALK, 'Foo' ),
|
|
|
|
[],
|
|
|
|
false
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'Excludes/includes are based on root title so should apply to subpages',
|
|
|
|
$excludeTalkFooConfig,
|
|
|
|
Title::makeTitle( NS_TALK, 'Foo/subpage' ),
|
|
|
|
[],
|
|
|
|
false
|
|
|
|
]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-10-21 17:39:16 +00:00
|
|
|
* @todo move into MediaWiki\Skins\Vector\FeatureManagement\Requirements\LimitedWidthContentRequirement
|
|
|
|
* test in future.
|
|
|
|
* @covers MediaWiki\Skins\Vector\FeatureManagement\Requirements\LimitedWidthContentRequirement::isMet
|
2021-01-06 21:50:19 +00:00
|
|
|
* @dataProvider providerShouldDisableMaxWidth
|
|
|
|
*/
|
|
|
|
public function testShouldDisableMaxWidth(
|
|
|
|
$msg,
|
|
|
|
$options,
|
|
|
|
$title,
|
|
|
|
$requestValues,
|
|
|
|
$shouldDisableMaxWidth
|
|
|
|
) {
|
2022-10-21 17:39:16 +00:00
|
|
|
$requirement = new LimitedWidthContentRequirement(
|
|
|
|
new HashConfig( [ 'VectorMaxWidthOptions' => $options ] ),
|
|
|
|
new FauxRequest( $requestValues ),
|
|
|
|
$title
|
|
|
|
);
|
2021-01-06 21:50:19 +00:00
|
|
|
$this->assertSame(
|
2022-10-21 17:39:16 +00:00
|
|
|
!$shouldDisableMaxWidth,
|
|
|
|
$requirement->isMet(),
|
2021-01-06 21:50:19 +00:00
|
|
|
$msg
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-12-14 19:24:32 +00:00
|
|
|
/**
|
2023-04-10 18:56:19 +00:00
|
|
|
* @covers ::getActiveABTest
|
|
|
|
* @dataProvider provideGetActiveABTest
|
2021-12-14 19:24:32 +00:00
|
|
|
*/
|
2023-04-10 18:56:19 +00:00
|
|
|
public function testGetActiveABTest( $configData, $expected ) {
|
2021-12-14 19:24:32 +00:00
|
|
|
$config = new HashConfig( $configData );
|
2023-04-10 18:56:19 +00:00
|
|
|
$vectorConfig = Hooks::getActiveABTest(
|
2021-12-14 19:24:32 +00:00
|
|
|
$this->createMock( ResourceLoaderContext::class ),
|
|
|
|
$config
|
|
|
|
);
|
|
|
|
|
|
|
|
$this->assertSame(
|
2022-05-21 12:35:24 +00:00
|
|
|
$expected,
|
|
|
|
$vectorConfig
|
2021-12-14 19:24:32 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-04-10 18:56:19 +00:00
|
|
|
* @covers ::getActiveABTest
|
|
|
|
* @dataProvider provideGetActiveABTestWithExceptions
|
2021-12-14 19:24:32 +00:00
|
|
|
*/
|
2023-04-10 18:56:19 +00:00
|
|
|
public function testGetActiveABTestWithExceptions( $configData ) {
|
2021-12-14 19:24:32 +00:00
|
|
|
$config = new HashConfig( $configData );
|
|
|
|
$this->expectException( RuntimeException::class );
|
2023-04-10 18:56:19 +00:00
|
|
|
Hooks::getActiveABTest(
|
2021-12-14 19:24:32 +00:00
|
|
|
$this->createMock( ResourceLoaderContext::class ),
|
|
|
|
$config
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
/**
|
|
|
|
* @covers ::onLocalUserCreated
|
|
|
|
*/
|
|
|
|
public function testOnLocalUserCreatedLegacy() {
|
2022-04-05 13:54:23 +00:00
|
|
|
$this->setMwGlobals( [
|
|
|
|
'wgVectorDefaultSkinVersionForNewAccounts' => Constants::SKIN_VERSION_LEGACY,
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
] );
|
|
|
|
|
2021-03-25 04:06:14 +00:00
|
|
|
$user = $this->createMock( User::class );
|
2021-03-30 21:50:11 +00:00
|
|
|
$userOptionsManager = $this->createMock( UserOptionsManager::class );
|
|
|
|
$userOptionsManager->expects( $this->once() )
|
2020-08-11 14:13:12 +00:00
|
|
|
->method( 'setOption' )
|
2022-01-20 22:14:19 +00:00
|
|
|
->with( $user, 'skin', Constants::SKIN_NAME_LEGACY );
|
2021-03-30 21:50:11 +00:00
|
|
|
$this->setService( 'UserOptionsManager', $userOptionsManager );
|
2021-01-02 13:11:04 +00:00
|
|
|
|
|
|
|
// NOTE: Using $this->getServiceContainer()->getHookContainer()->run( ... )
|
|
|
|
// will instead call Echo's legacy hook as that is already registered which
|
|
|
|
// will break this test. Use Vector's hook handler instead.
|
|
|
|
( new Hooks() )->onLocalUserCreated( $user, false );
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::onLocalUserCreated
|
|
|
|
*/
|
|
|
|
public function testOnLocalUserCreatedLatest() {
|
2022-04-05 13:54:23 +00:00
|
|
|
$this->setMwGlobals( [
|
|
|
|
'wgVectorDefaultSkinVersionForNewAccounts' => Constants::SKIN_VERSION_LATEST,
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
] );
|
|
|
|
|
2021-03-25 04:06:14 +00:00
|
|
|
$user = $this->createMock( User::class );
|
2021-03-30 21:50:11 +00:00
|
|
|
$userOptionsManager = $this->createMock( UserOptionsManager::class );
|
|
|
|
$userOptionsManager->expects( $this->once() )
|
2020-08-11 14:13:12 +00:00
|
|
|
->method( 'setOption' )
|
2022-01-20 22:14:19 +00:00
|
|
|
->with( $user, 'skin', Constants::SKIN_NAME_MODERN );
|
2021-03-30 21:50:11 +00:00
|
|
|
$this->setService( 'UserOptionsManager', $userOptionsManager );
|
2021-01-02 13:11:04 +00:00
|
|
|
|
|
|
|
// NOTE: Using $this->getServiceContainer()->getHookContainer()->run( ... )
|
|
|
|
// will instead call Echo's legacy hook as that is already registered which
|
|
|
|
// will break this test. Use Vector's hook handler instead.
|
|
|
|
( new Hooks() )->onLocalUserCreated( $user, false );
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
}
|
2020-05-11 22:09:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::onSkinTemplateNavigation
|
|
|
|
*/
|
|
|
|
public function testOnSkinTemplateNavigation() {
|
|
|
|
$this->setMwGlobals( [
|
2022-09-02 14:57:31 +00:00
|
|
|
'wgVectorUseIconWatch' => true,
|
2020-05-11 22:09:21 +00:00
|
|
|
] );
|
2022-01-20 22:14:19 +00:00
|
|
|
$skin = new SkinVector22( [ 'name' => 'vector' ] );
|
2020-06-12 21:43:58 +00:00
|
|
|
$skin->getContext()->setTitle( Title::newFromText( 'Foo' ) );
|
2020-05-11 22:09:21 +00:00
|
|
|
$contentNavWatch = [
|
2022-09-02 14:57:31 +00:00
|
|
|
'associated-pages' => [],
|
|
|
|
'views' => [],
|
2020-05-11 22:09:21 +00:00
|
|
|
'actions' => [
|
2022-09-02 14:57:31 +00:00
|
|
|
'watch' => [ 'class' => [ 'watch' ], 'icon' => 'star' ],
|
2020-05-11 22:09:21 +00:00
|
|
|
]
|
|
|
|
];
|
|
|
|
$contentNavUnWatch = [
|
2022-09-02 14:57:31 +00:00
|
|
|
'associated-pages' => [],
|
|
|
|
'views' => [],
|
2020-05-11 22:09:21 +00:00
|
|
|
'actions' => [
|
2022-08-01 22:06:32 +00:00
|
|
|
'move' => [ 'class' => [ 'move' ] ],
|
2022-09-02 14:57:31 +00:00
|
|
|
'unwatch' => [ 'icon' => 'unStar' ],
|
2020-05-11 22:09:21 +00:00
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
Hooks::onSkinTemplateNavigation( $skin, $contentNavUnWatch );
|
|
|
|
Hooks::onSkinTemplateNavigation( $skin, $contentNavWatch );
|
|
|
|
|
2022-08-01 22:06:32 +00:00
|
|
|
$this->assertContains(
|
|
|
|
'icon', $contentNavWatch['views']['watch']['class'],
|
2020-05-11 22:09:21 +00:00
|
|
|
'Watch list items require an "icon" class'
|
|
|
|
);
|
2022-08-01 22:06:32 +00:00
|
|
|
$this->assertContains(
|
|
|
|
'icon', $contentNavUnWatch['views']['unwatch']['class'],
|
2020-05-11 22:09:21 +00:00
|
|
|
'Unwatch list items require an "icon" class'
|
|
|
|
);
|
2022-08-01 22:06:32 +00:00
|
|
|
$this->assertNotContains(
|
|
|
|
'icon', $contentNavUnWatch['actions']['move']['class'],
|
2020-05-11 22:09:21 +00:00
|
|
|
'List item other than watch or unwatch should not have an "icon" class'
|
|
|
|
);
|
|
|
|
}
|
2022-03-04 15:45:45 +00:00
|
|
|
|
2022-03-17 16:25:02 +00:00
|
|
|
/**
|
|
|
|
* @covers ::updateUserLinksItems
|
|
|
|
*/
|
|
|
|
public function testUpdateUserLinksItems() {
|
|
|
|
$vector2022Skin = new SkinVector22( [ 'name' => 'vector-2022' ] );
|
|
|
|
$contentNav = [
|
2022-09-02 14:57:31 +00:00
|
|
|
'associated-pages' => [],
|
|
|
|
'views' => [],
|
2022-03-17 16:25:02 +00:00
|
|
|
'user-page' => [
|
|
|
|
'userpage' => [ 'class' => [], 'icon' => 'userpage' ],
|
|
|
|
],
|
|
|
|
'user-menu' => [
|
|
|
|
'login' => [ 'class' => [], 'icon' => 'login' ],
|
|
|
|
]
|
|
|
|
];
|
|
|
|
$vectorLegacySkin = new SkinVectorLegacy( [ 'name' => 'vector' ] );
|
|
|
|
$contentNavLegacy = [
|
2022-09-02 14:57:31 +00:00
|
|
|
'associated-pages' => [],
|
|
|
|
'views' => [],
|
2022-03-17 16:25:02 +00:00
|
|
|
'user-page' => [
|
|
|
|
'userpage' => [ 'class' => [], 'icon' => 'userpage' ],
|
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
Hooks::onSkinTemplateNavigation( $vector2022Skin, $contentNav );
|
|
|
|
$this->assertFalse( isset( $contentNav['user-page']['login'] ),
|
2022-04-19 17:50:01 +00:00
|
|
|
'updateUserLinksDropdownItems is called when not legacy'
|
2022-03-17 16:25:02 +00:00
|
|
|
);
|
|
|
|
Hooks::onSkinTemplateNavigation( $vectorLegacySkin, $contentNavLegacy );
|
|
|
|
$this->assertFalse( isset( $contentNavLegacy['user-page'] ),
|
|
|
|
'user-page is unset for legacy vector'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-03-04 15:45:45 +00:00
|
|
|
/**
|
|
|
|
* @covers ::updateUserLinksDropdownItems
|
|
|
|
*/
|
|
|
|
public function testUpdateUserLinksDropdownItems() {
|
|
|
|
$updateUserLinksDropdownItems = new ReflectionMethod(
|
|
|
|
Hooks::class,
|
|
|
|
'updateUserLinksDropdownItems'
|
|
|
|
);
|
|
|
|
$updateUserLinksDropdownItems->setAccessible( true );
|
2022-04-14 16:27:31 +00:00
|
|
|
|
|
|
|
// Anon users
|
2022-03-04 20:24:10 +00:00
|
|
|
$skin = new SkinVector22( [ 'name' => 'vector-2022' ] );
|
2022-03-04 15:45:45 +00:00
|
|
|
$contentAnon = [
|
|
|
|
'user-menu' => [
|
|
|
|
'anonuserpage' => [ 'class' => [], 'icon' => 'anonuserpage' ],
|
|
|
|
'createaccount' => [ 'class' => [], 'icon' => 'createaccount' ],
|
|
|
|
'login' => [ 'class' => [], 'icon' => 'login' ],
|
2023-02-01 23:38:44 +00:00
|
|
|
'anontalk' => [ 'class' => [], 'icon' => 'anontalk' ],
|
|
|
|
'anoncontribs' => [ 'class' => [], 'icon' => 'anoncontribs' ],
|
2022-03-04 15:45:45 +00:00
|
|
|
],
|
|
|
|
];
|
|
|
|
$updateUserLinksDropdownItems->invokeArgs( null, [ $skin, &$contentAnon ] );
|
|
|
|
$this->assertTrue(
|
2023-02-01 23:38:44 +00:00
|
|
|
count( $contentAnon['user-menu'] ) === 2 &&
|
|
|
|
isset( $contentAnon['user-menu']['createaccount'] ) &&
|
|
|
|
isset( $contentAnon['user-menu']['login'] ),
|
2023-03-08 19:50:20 +00:00
|
|
|
'Anon user page, anon talk, anon contribs links are removed from user-menu'
|
2023-02-01 23:38:44 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
$this->assertTrue(
|
|
|
|
count( $contentAnon['user-menu'] ) === 2 &&
|
|
|
|
isset( $contentAnon['user-menu-anon-editor']['anontalk'] ) &&
|
|
|
|
isset( $contentAnon['user-menu-anon-editor']['anoncontribs'] ),
|
|
|
|
'Anon talk, anon contribs links are moved to user-menu-anon-editor'
|
2022-03-04 15:45:45 +00:00
|
|
|
);
|
2022-03-24 20:34:02 +00:00
|
|
|
|
2022-03-04 15:45:45 +00:00
|
|
|
// Registered user
|
2022-03-24 20:34:02 +00:00
|
|
|
$registeredUser = $this->createMock( User::class );
|
|
|
|
$registeredUser->method( 'isRegistered' )->willReturn( true );
|
|
|
|
$context = new RequestContext();
|
|
|
|
$context->setUser( $registeredUser );
|
|
|
|
$skin->setContext( $context );
|
2022-03-04 15:45:45 +00:00
|
|
|
$contentRegistered = [
|
|
|
|
'user-menu' => [
|
|
|
|
'userpage' => [ 'class' => [], 'icon' => 'userpage' ],
|
|
|
|
'watchlist' => [ 'class' => [], 'icon' => 'watchlist' ],
|
|
|
|
'logout' => [ 'class' => [], 'icon' => 'logout' ],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
$updateUserLinksDropdownItems->invokeArgs( null, [ $skin, &$contentRegistered ] );
|
|
|
|
$this->assertContains( 'user-links-collapsible-item', $contentRegistered['user-menu']['userpage']['class'],
|
|
|
|
'User page link in user links dropdown requires collapsible class'
|
|
|
|
);
|
2022-04-14 16:27:31 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
'<span class="mw-ui-icon mw-ui-icon-userpage mw-ui-icon-wikimedia-userpage"></span>',
|
|
|
|
$contentRegistered['user-menu']['userpage']['link-html'],
|
|
|
|
'User page link in user links dropdown has link-html'
|
2022-03-04 15:45:45 +00:00
|
|
|
);
|
|
|
|
$this->assertContains( 'user-links-collapsible-item', $contentRegistered['user-menu']['watchlist']['class'],
|
|
|
|
'Watchlist link in user links dropdown requires collapsible class'
|
|
|
|
);
|
2022-04-14 16:27:31 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
'<span class="mw-ui-icon mw-ui-icon-watchlist mw-ui-icon-wikimedia-watchlist"></span>',
|
|
|
|
$contentRegistered['user-menu']['watchlist']['link-html'],
|
|
|
|
'Watchlist link in user links dropdown has link-html'
|
2022-03-04 15:45:45 +00:00
|
|
|
);
|
|
|
|
$this->assertFalse( isset( $contentRegistered['user-menu']['logout'] ),
|
|
|
|
'Logout link in user links dropdown is not set'
|
|
|
|
);
|
2023-02-01 23:38:44 +00:00
|
|
|
$this->assertTrue( isset( $contentRegistered['user-menu-logout']['logout'] ),
|
|
|
|
'Logout link in user links dropdown is not set'
|
|
|
|
);
|
2022-03-04 15:45:45 +00:00
|
|
|
}
|
2022-03-04 20:24:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::updateUserLinksOverflowItems
|
|
|
|
*/
|
|
|
|
public function testUpdateUserLinksOverflowItems() {
|
|
|
|
$updateUserLinksOverflowItems = new ReflectionMethod(
|
|
|
|
Hooks::class,
|
|
|
|
'updateUserLinksOverflowItems'
|
|
|
|
);
|
|
|
|
$updateUserLinksOverflowItems->setAccessible( true );
|
2022-04-19 17:50:01 +00:00
|
|
|
$skin = new SkinVector22( [ 'name' => 'vector-2022' ] );
|
|
|
|
|
|
|
|
// Registered user
|
|
|
|
$registeredUser = $this->createMock( User::class );
|
|
|
|
$registeredUser->method( 'isRegistered' )->willReturn( true );
|
|
|
|
$context = new RequestContext();
|
|
|
|
$context->setUser( $registeredUser );
|
|
|
|
$skin->setContext( $context );
|
2022-03-04 20:24:10 +00:00
|
|
|
$content = [
|
|
|
|
'notifications' => [
|
|
|
|
'alert' => [ 'class' => [], 'icon' => 'alert' ],
|
|
|
|
],
|
|
|
|
'user-interface-preferences' => [
|
|
|
|
'uls' => [ 'class' => [], 'icon' => 'uls' ],
|
|
|
|
],
|
|
|
|
'user-page' => [
|
|
|
|
'userpage' => [ 'class' => [], 'icon' => 'userpage' ],
|
2022-04-19 17:50:01 +00:00
|
|
|
'watchlist' => [ 'class' => [], 'icon' => 'watchlist' ],
|
2022-03-04 20:24:10 +00:00
|
|
|
],
|
2022-04-19 17:50:01 +00:00
|
|
|
'user-menu' => [
|
2022-03-04 20:24:10 +00:00
|
|
|
'watchlist' => [ 'class' => [], 'icon' => 'watchlist' ],
|
|
|
|
],
|
|
|
|
];
|
2022-04-19 17:50:01 +00:00
|
|
|
$updateUserLinksOverflowItems->invokeArgs( null, [ $skin, &$content ] );
|
2022-03-04 20:24:10 +00:00
|
|
|
$this->assertContains( 'user-links-collapsible-item',
|
2022-04-19 17:50:01 +00:00
|
|
|
$content['vector-user-menu-overflow']['uls']['class'],
|
2022-03-04 20:24:10 +00:00
|
|
|
'ULS link in user links overflow requires collapsible class'
|
|
|
|
);
|
|
|
|
$this->assertContains( 'user-links-collapsible-item',
|
2022-04-19 17:50:01 +00:00
|
|
|
$content['vector-user-menu-overflow']['userpage']['class'],
|
2022-03-04 20:24:10 +00:00
|
|
|
'User page link in user links overflow requires collapsible class'
|
|
|
|
);
|
|
|
|
$this->assertNotContains( 'mw-ui-icon',
|
2022-04-19 17:50:01 +00:00
|
|
|
$content['vector-user-menu-overflow']['userpage']['class'],
|
2022-03-04 20:24:10 +00:00
|
|
|
'User page link in user links overflow does not have icon classes'
|
|
|
|
);
|
|
|
|
$this->assertContains( 'user-links-collapsible-item',
|
|
|
|
$content['vector-user-menu-overflow']['watchlist']['class'],
|
|
|
|
'Watchlist link in user links overflow requires collapsible class'
|
|
|
|
);
|
|
|
|
$this->assertContains( 'mw-ui-button',
|
|
|
|
$content['vector-user-menu-overflow']['watchlist']['link-class'],
|
|
|
|
'Watchlist link in user links overflow requires button classes'
|
|
|
|
);
|
|
|
|
$this->assertContains( 'mw-ui-quiet',
|
|
|
|
$content['vector-user-menu-overflow']['watchlist']['link-class'],
|
|
|
|
'Watchlist link in user links overflow requires quiet button classes'
|
|
|
|
);
|
|
|
|
$this->assertContains( 'mw-ui-icon-element',
|
|
|
|
$content['vector-user-menu-overflow']['watchlist']['link-class'],
|
|
|
|
'Watchlist link in user links overflow hides text'
|
|
|
|
);
|
|
|
|
$this->assertTrue(
|
|
|
|
$content['vector-user-menu-overflow']['watchlist']['id'] === 'pt-watchlist-2',
|
|
|
|
'Watchlist link in user links has unique id'
|
|
|
|
);
|
|
|
|
}
|
2022-04-14 16:27:31 +00:00
|
|
|
|
2022-08-01 22:06:32 +00:00
|
|
|
public function provideAppendClassToItem() {
|
|
|
|
return [
|
|
|
|
// Add array class to array
|
|
|
|
[
|
|
|
|
[],
|
|
|
|
[ 'array1', 'array2' ],
|
|
|
|
[ 'array1', 'array2' ],
|
|
|
|
],
|
|
|
|
// Add string class to array
|
|
|
|
[
|
|
|
|
[],
|
|
|
|
'array1 array2',
|
|
|
|
[ 'array1 array2' ],
|
|
|
|
],
|
|
|
|
// Add array class to string
|
|
|
|
[
|
|
|
|
'',
|
|
|
|
[ 'array1', 'array2' ],
|
|
|
|
'array1 array2',
|
|
|
|
],
|
|
|
|
// Add string class to string
|
|
|
|
[
|
|
|
|
'',
|
|
|
|
'array1 array2',
|
|
|
|
'array1 array2',
|
|
|
|
],
|
|
|
|
// Add string class to undefined
|
|
|
|
[
|
|
|
|
null,
|
|
|
|
'array1 array2',
|
|
|
|
'array1 array2',
|
|
|
|
],
|
|
|
|
// Add array class to undefined
|
|
|
|
[
|
|
|
|
null,
|
|
|
|
[ 'array1', 'array2' ],
|
|
|
|
[ 'array1', 'array2' ],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @covers ::appendClassToItem
|
|
|
|
* @dataProvider provideAppendClassToItem
|
|
|
|
*/
|
|
|
|
public function testAppendClassToItem(
|
|
|
|
$item,
|
|
|
|
$classes,
|
|
|
|
$expected
|
|
|
|
) {
|
|
|
|
$appendClassToItem = new ReflectionMethod(
|
|
|
|
Hooks::class,
|
|
|
|
'appendClassToItem'
|
|
|
|
);
|
|
|
|
$appendClassToItem->setAccessible( true );
|
|
|
|
$appendClassToItem->invokeArgs( null, [ &$item, $classes ] );
|
|
|
|
$this->assertEquals( $expected, $item );
|
|
|
|
}
|
|
|
|
|
|
|
|
public function provideUpdateItemData() {
|
2022-04-14 16:27:31 +00:00
|
|
|
return [
|
|
|
|
// Removes extra attributes
|
|
|
|
[
|
|
|
|
[ 'class' => [], 'icon' => '', 'button' => false, 'text-hidden' => false, 'collapsible' => false ],
|
2022-08-01 22:06:32 +00:00
|
|
|
'link-class',
|
|
|
|
'link-html',
|
2022-04-14 16:27:31 +00:00
|
|
|
[ 'class' => [] ],
|
|
|
|
],
|
2022-08-01 22:06:32 +00:00
|
|
|
// Adds icon html
|
2022-04-14 16:27:31 +00:00
|
|
|
[
|
|
|
|
[ 'class' => [], 'icon' => 'userpage' ],
|
2022-08-01 22:06:32 +00:00
|
|
|
'link-class',
|
|
|
|
'link-html',
|
2022-04-14 16:27:31 +00:00
|
|
|
[
|
|
|
|
'class' => [],
|
|
|
|
'link-html' =>
|
|
|
|
'<span class="mw-ui-icon mw-ui-icon-userpage mw-ui-icon-wikimedia-userpage"></span>'
|
|
|
|
],
|
|
|
|
],
|
|
|
|
// Adds collapsible class
|
|
|
|
[
|
|
|
|
[ 'class' => [], 'collapsible' => true ],
|
2022-08-01 22:06:32 +00:00
|
|
|
'link-class',
|
|
|
|
'link-html',
|
2022-04-14 16:27:31 +00:00
|
|
|
[ 'class' => [ 'user-links-collapsible-item' ] ],
|
|
|
|
],
|
|
|
|
// Adds button classes
|
|
|
|
[
|
|
|
|
[ 'class' => [], 'button' => true ],
|
2022-08-01 22:06:32 +00:00
|
|
|
'link-class',
|
|
|
|
'link-html',
|
2022-04-14 16:27:31 +00:00
|
|
|
[ 'class' => [], 'link-class' => [ 'mw-ui-button', 'mw-ui-quiet' ] ],
|
|
|
|
],
|
|
|
|
// Adds text hidden classes
|
|
|
|
[
|
|
|
|
[ 'class' => [], 'text-hidden' => true, 'icon' => 'userpage' ],
|
2022-08-01 22:06:32 +00:00
|
|
|
'link-class',
|
|
|
|
'link-html',
|
2023-05-02 19:03:13 +00:00
|
|
|
[
|
|
|
|
'class' => [],
|
|
|
|
'link-class' => [ 'mw-ui-icon-element' ],
|
|
|
|
'link-html' => '<span class="mw-ui-icon mw-ui-icon-userpage mw-ui-icon-wikimedia-userpage"></span>'
|
|
|
|
],
|
2022-04-14 16:27:31 +00:00
|
|
|
],
|
2022-08-01 22:06:32 +00:00
|
|
|
// Adds button and icon classes
|
2022-04-14 16:27:31 +00:00
|
|
|
[
|
2022-08-01 22:06:32 +00:00
|
|
|
[ 'class' => [], 'button' => true, 'icon' => 'userpage' ],
|
|
|
|
'class',
|
|
|
|
'link-html',
|
2023-05-02 19:03:13 +00:00
|
|
|
[
|
|
|
|
'class' => [ 'mw-ui-button', 'mw-ui-quiet' ],
|
|
|
|
'link-html' => '<span class="mw-ui-icon mw-ui-icon-userpage mw-ui-icon-wikimedia-userpage"></span>'
|
2022-08-01 22:06:32 +00:00
|
|
|
],
|
2022-04-14 16:27:31 +00:00
|
|
|
]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-08-01 22:06:32 +00:00
|
|
|
* @covers ::updateItemData
|
|
|
|
* @dataProvider provideUpdateItemData
|
2022-04-14 16:27:31 +00:00
|
|
|
*/
|
2022-08-01 22:06:32 +00:00
|
|
|
public function testUpdateItemData(
|
|
|
|
array $item,
|
|
|
|
string $buttonClassProp,
|
|
|
|
string $iconHtmlProp,
|
2022-04-14 16:27:31 +00:00
|
|
|
array $expected
|
|
|
|
) {
|
2022-08-01 22:06:32 +00:00
|
|
|
$updateItemData = new ReflectionMethod(
|
2022-04-14 16:27:31 +00:00
|
|
|
Hooks::class,
|
2022-08-01 22:06:32 +00:00
|
|
|
'updateItemData'
|
2022-04-14 16:27:31 +00:00
|
|
|
);
|
2022-08-01 22:06:32 +00:00
|
|
|
$updateItemData->setAccessible( true );
|
|
|
|
$data = $updateItemData->invokeArgs( null, [ $item, $buttonClassProp, $iconHtmlProp ] );
|
2023-03-10 09:57:37 +00:00
|
|
|
$this->assertArraySubmapSame( $expected, $data );
|
2022-04-14 16:27:31 +00:00
|
|
|
}
|
[Special:Preferences] [PHP] Add skin version user preference and configs
Add a Vector-specific user preference to Special:Preferences for
toggling skin version, either Legacy Vector or the latest Vector.
The presentation of the new preference section and the default values
for anonymous, new, and existing accounts are configurable via
$wgVectorShowSkinPreferences, $wgVectorDefaultSkinVersion (to be used by
the feature manager in T244481),
$wgVectorDefaultSkinVersionForExistingAccounts, and
$wgVectorDefaultSkinVersionForNewAccounts. These configurations default
to the fullest experience so that third-party configuration is minimal.
See skin.json for details. The configurations are each tested in
VectorHooksTest.php.
When presentation is enabled, the new preference appears as a checkbox;
enabled is Legacy mode and disable is latest. There are a number of
unfortunate details:
- Showing and hiding a checkbox is supported by OOUI. Showing and hiding
a whole section (Vector skin preferences, in this case) is not so this
additional client JavaScript functionality is added in Core (see
Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377).
- Stylization as a checkbox is wanted. However, the implied storage type
for OOUI checkboxes is a boolean. This is not wanted in the event that
another skin version is added (e.g., '3' or 'alpha'). As a workaround,
the preference is converted from a boolean to a version string ('1' or
'2') on save in Hooks::onPreferencesFormPreSave() and from a version
string to a checkbox enable / disable string ('1' or '0') in
onGetPreferences(). There a number of test cases to help cover these
concerning details.
Documentation for overriding the skin version as a URL query parameter
is provided in anticipation of T244481.
Bug: T242381
Bug: T245793
Depends-On: Iaf68b238a8ac7a4fb22b9ef5d6c5a3394ee2e377
Depends-On: Ifc2863fca9cd9efd11ac30c780420e8d89e8cb22
Change-Id: I177dad88fc982170641059b6a4f53fbb38eefad6
2020-01-23 21:53:09 +00:00
|
|
|
}
|