3 use MediaWiki\Linker\LinkTarget
;
4 use MediaWiki\MediaWikiServices
;
11 * @covers ApiQueryWatchlist
13 class ApiQueryWatchlistIntegrationTest
extends ApiTestCase
{
15 public function __construct( $name = null, array $data = [], $dataName = '' ) {
16 parent
::__construct( $name, $data, $dataName );
17 $this->tablesUsed
= array_unique(
18 array_merge( $this->tablesUsed
, [ 'watchlist', 'recentchanges', 'page' ] )
22 protected function setUp() {
24 self
::$users['ApiQueryWatchlistIntegrationTestUser'] = $this->getMutableTestUser();
25 self
::$users['ApiQueryWatchlistIntegrationTestUser2'] = $this->getMutableTestUser();
26 $this->doLogin( 'ApiQueryWatchlistIntegrationTestUser' );
29 private function getLoggedInTestUser() {
30 return self
::$users['ApiQueryWatchlistIntegrationTestUser']->getUser();
33 private function getNonLoggedInTestUser() {
34 return self
::$users['ApiQueryWatchlistIntegrationTestUser2']->getUser();
37 private function doPageEdit( User
$user, LinkTarget
$target, $content, $summary ) {
38 $title = Title
::newFromLinkTarget( $target );
39 $page = WikiPage
::factory( $title );
41 ContentHandler
::makeContent( $content, $title ),
49 private function doMinorPageEdit( User
$user, LinkTarget
$target, $content, $summary ) {
50 $title = Title
::newFromLinkTarget( $target );
51 $page = WikiPage
::factory( $title );
53 ContentHandler
::makeContent( $content, $title ),
61 private function doBotPageEdit( User
$user, LinkTarget
$target, $content, $summary ) {
62 $title = Title
::newFromLinkTarget( $target );
63 $page = WikiPage
::factory( $title );
65 ContentHandler
::makeContent( $content, $title ),
73 private function doAnonPageEdit( LinkTarget
$target, $content, $summary ) {
74 $title = Title
::newFromLinkTarget( $target );
75 $page = WikiPage
::factory( $title );
77 ContentHandler
::makeContent( $content, $title ),
85 private function doPatrolledPageEdit(
92 $title = Title
::newFromLinkTarget( $target );
93 $page = WikiPage
::factory( $title );
94 $status = $page->doEditContent(
95 ContentHandler
::makeContent( $content, $title ),
101 /** @var Revision $rev */
102 $rev = $status->value
['revision'];
103 $rc = $rev->getRecentChange();
104 $rc->doMarkPatrolled( $patrollingUser, false, [] );
107 private function deletePage( LinkTarget
$target, $reason ) {
108 $title = Title
::newFromLinkTarget( $target );
109 $page = WikiPage
::factory( $title );
110 $page->doDeleteArticleReal( $reason );
114 * Performs a batch of page edits as a specified user
116 * @param array $editData associative array, keys:
117 * - target => LinkTarget page to edit
118 * - content => string new content
119 * - summary => string edit summary
120 * - minorEdit => bool mark as minor edit if true (defaults to false)
121 * - botEdit => bool mark as bot edit if true (defaults to false)
123 private function doPageEdits( User
$user, array $editData ) {
124 foreach ( $editData as $singleEditData ) {
125 if ( array_key_exists( 'minorEdit', $singleEditData ) && $singleEditData['minorEdit'] ) {
126 $this->doMinorPageEdit(
128 $singleEditData['target'],
129 $singleEditData['content'],
130 $singleEditData['summary']
134 if ( array_key_exists( 'botEdit', $singleEditData ) && $singleEditData['botEdit'] ) {
135 $this->doBotPageEdit(
137 $singleEditData['target'],
138 $singleEditData['content'],
139 $singleEditData['summary']
145 $singleEditData['target'],
146 $singleEditData['content'],
147 $singleEditData['summary']
152 private function getWatchedItemStore() {
153 return MediaWikiServices
::getInstance()->getWatchedItemStore();
158 * @param LinkTarget[] $targets
160 private function watchPages( User
$user, array $targets ) {
161 $store = $this->getWatchedItemStore();
162 $store->addWatchBatchForUser( $user, $targets );
165 private function doListWatchlistRequest( array $params = [], $user = null ) {
166 return $this->doApiRequest(
168 [ 'action' => 'query', 'list' => 'watchlist' ],
170 ), null, false, $user
174 private function doGeneratorWatchlistRequest( array $params = [] ) {
175 return $this->doApiRequest(
177 [ 'action' => 'query', 'generator' => 'watchlist' ],
183 private function getItemsFromApiResponse( array $response ) {
184 return $response[0]['query']['watchlist'];
188 * Convenience method to assert that actual items array fetched from API is equal to the expected
189 * array, Unlike assertEquals this only checks if values of specified keys are equal in both
190 * arrays. This could be used e.g. not to compare IDs that could change between test run
191 * but only stable keys.
192 * Optionally this also checks that specified keys are present in the actual item without
193 * performing any checks on the related values.
195 * @param array $actualItems array of actual items (associative arrays)
196 * @param array $expectedItems array of expected items (associative arrays),
197 * those items have less keys than actual items
198 * @param array $keysUsedInValueComparison list of keys of the actual item that will be used
199 * in the comparison of values
200 * @param array $requiredKeys optional, list of keys that must be present in the
201 * actual items. Values of those keys are not checked.
203 private function assertArraySubsetsEqual(
205 array $expectedItems,
206 array $keysUsedInValueComparison,
207 array $requiredKeys = []
209 $this->assertCount( count( $expectedItems ), $actualItems );
211 // not checking values of all keys of the actual item, so removing unwanted keys from comparison
212 $actualItemsOnlyComparedValues = array_map(
213 function( array $item ) use ( $keysUsedInValueComparison ) {
214 return array_intersect_key( $item, array_flip( $keysUsedInValueComparison ) );
221 $actualItemsOnlyComparedValues
224 // Check that each item in $actualItems contains all of keys specified in $requiredKeys
225 $actualItemsKeysOnly = array_map( 'array_keys', $actualItems );
226 foreach ( $actualItemsKeysOnly as $keysOfTheItem ) {
227 $this->assertEmpty( array_diff( $requiredKeys, $keysOfTheItem ) );
231 private function getTitleFormatter() {
232 return new MediaWikiTitleCodec(
233 Language
::factory( 'en' ),
234 MediaWikiServices
::getInstance()->getGenderCache()
238 private function getPrefixedText( LinkTarget
$target ) {
239 $formatter = $this->getTitleFormatter();
240 return $formatter->getPrefixedText( $target );
243 private function cleanTestUsersWatchlist() {
244 $user = $this->getLoggedInTestUser();
245 $store = $this->getWatchedItemStore();
246 $items = $store->getWatchedItemsForUser( $user );
247 foreach ( $items as $item ) {
248 $store->removeWatch( $user, $item->getLinkTarget() );
252 public function testListWatchlist_returnsWatchedItemsWithRCInfo() {
253 // Clean up after previous tests that might have added something to the watchlist of
254 // the user with the same user ID as user used here as the test user
255 $this->cleanTestUsersWatchlist();
257 $user = $this->getLoggedInTestUser();
258 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
265 $this->watchPages( $user, [ $target ] );
267 $result = $this->doListWatchlistRequest();
269 $this->assertArrayHasKey( 'query', $result[0] );
270 $this->assertArrayHasKey( 'watchlist', $result[0]['query'] );
272 $this->assertArraySubsetsEqual(
273 $this->getItemsFromApiResponse( $result ),
277 'ns' => $target->getNamespace(),
278 'title' => $this->getPrefixedText( $target ),
284 [ 'type', 'ns', 'title', 'bot', 'new', 'minor' ],
285 [ 'pageid', 'revid', 'old_revid' ]
289 public function testIdsPropParameter() {
290 $user = $this->getLoggedInTestUser();
291 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
298 $this->watchPages( $user, [ $target ] );
300 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'ids', ] );
301 $items = $this->getItemsFromApiResponse( $result );
303 $this->assertCount( 1, $items );
304 $this->assertArrayHasKey( 'pageid', $items[0] );
305 $this->assertArrayHasKey( 'revid', $items[0] );
306 $this->assertArrayHasKey( 'old_revid', $items[0] );
307 $this->assertEquals( 'new', $items[0]['type'] );
310 public function testTitlePropParameter() {
311 $user = $this->getLoggedInTestUser();
312 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
313 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
318 'target' => $subjectTarget,
319 'content' => 'Some Content',
320 'summary' => 'Create the page',
323 'target' => $talkTarget,
324 'content' => 'Some Talk Page Content',
325 'summary' => 'Create Talk page',
329 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
331 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', ] );
337 'ns' => $talkTarget->getNamespace(),
338 'title' => $this->getPrefixedText( $talkTarget ),
342 'ns' => $subjectTarget->getNamespace(),
343 'title' => $this->getPrefixedText( $subjectTarget ),
346 $this->getItemsFromApiResponse( $result )
350 public function testFlagsPropParameter() {
351 $user = $this->getLoggedInTestUser();
352 $normalEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
353 $minorEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageM' );
354 $botEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageB' );
359 'target' => $normalEditTarget,
360 'content' => 'Some Content',
361 'summary' => 'Create the page',
364 'target' => $minorEditTarget,
365 'content' => 'Some Content',
366 'summary' => 'Create the page',
369 'target' => $minorEditTarget,
370 'content' => 'Slightly Better Content',
371 'summary' => 'Change content',
375 'target' => $botEditTarget,
376 'content' => 'Some Content',
377 'summary' => 'Create the page with a bot',
382 $this->watchPages( $user, [ $normalEditTarget, $minorEditTarget, $botEditTarget ] );
384 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'flags', ] );
407 $this->getItemsFromApiResponse( $result )
411 public function testUserPropParameter() {
412 $user = $this->getLoggedInTestUser();
413 $userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
414 $anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
421 $this->doAnonPageEdit(
426 $this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
428 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'user', ] );
435 'user' => User
::newFromId( 0 )->getName(),
439 'user' => $user->getName(),
442 $this->getItemsFromApiResponse( $result )
446 public function testUserIdPropParameter() {
447 $user = $this->getLoggedInTestUser();
448 $userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
449 $anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
456 $this->doAnonPageEdit(
461 $this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
463 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'userid', ] );
475 'user' => $user->getId(),
476 'userid' => $user->getId(),
479 $this->getItemsFromApiResponse( $result )
483 public function testCommentPropParameter() {
484 $user = $this->getLoggedInTestUser();
485 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
490 'Create the <b>page</b>'
492 $this->watchPages( $user, [ $target ] );
494 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'comment', ] );
500 'comment' => 'Create the <b>page</b>',
503 $this->getItemsFromApiResponse( $result )
507 public function testParsedCommentPropParameter() {
508 $user = $this->getLoggedInTestUser();
509 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
514 'Create the <b>page</b>'
516 $this->watchPages( $user, [ $target ] );
518 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'parsedcomment', ] );
524 'parsedcomment' => 'Create the <b>page</b>',
527 $this->getItemsFromApiResponse( $result )
531 public function testTimestampPropParameter() {
532 $user = $this->getLoggedInTestUser();
533 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
540 $this->watchPages( $user, [ $target ] );
542 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'timestamp', ] );
543 $items = $this->getItemsFromApiResponse( $result );
545 $this->assertCount( 1, $items );
546 $this->assertArrayHasKey( 'timestamp', $items[0] );
547 $this->assertInternalType( 'string', $items[0]['timestamp'] );
550 public function testSizesPropParameter() {
551 $user = $this->getLoggedInTestUser();
552 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
559 $this->watchPages( $user, [ $target ] );
561 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'sizes', ] );
571 $this->getItemsFromApiResponse( $result )
575 public function testNotificationTimestampPropParameter() {
576 $otherUser = $this->getNonLoggedInTestUser();
577 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
584 $store = $this->getWatchedItemStore();
585 $store->addWatch( $this->getLoggedInTestUser(), $target );
586 $store->updateNotificationTimestamp(
592 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'notificationtimestamp', ] );
598 'notificationtimestamp' => '2015-12-12T01:01:01Z',
601 $this->getItemsFromApiResponse( $result )
605 private function setupPatrolledSpecificFixtures( User
$user ) {
606 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
608 $this->doPatrolledPageEdit(
612 'Create the page (this gets patrolled)',
616 $this->watchPages( $user, [ $target ] );
619 public function testPatrolPropParameter() {
620 $testUser = static::getTestSysop();
621 $user = $testUser->getUser();
622 $this->setupPatrolledSpecificFixtures( $user );
624 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'patrol', ], $user );
631 'unpatrolled' => false,
634 $this->getItemsFromApiResponse( $result )
638 private function createPageAndDeleteIt( LinkTarget
$target ) {
640 $this->getLoggedInTestUser(),
643 'Create the page that will be deleted'
645 $this->deletePage( $target, 'Important Reason' );
648 public function testLoginfoPropParameter() {
649 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
650 $this->createPageAndDeleteIt( $target );
652 $this->watchPages( $this->getLoggedInTestUser(), [ $target ] );
654 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'loginfo', ] );
656 $this->assertArraySubsetsEqual(
657 $this->getItemsFromApiResponse( $result ),
661 'logtype' => 'delete',
662 'logaction' => 'delete',
666 [ 'type', 'logtype', 'logaction', 'logparams' ],
671 public function testEmptyPropParameter() {
672 $user = $this->getLoggedInTestUser();
673 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
680 $this->watchPages( $user, [ $target ] );
682 $result = $this->doListWatchlistRequest( [ 'wlprop' => '', ] );
690 $this->getItemsFromApiResponse( $result )
694 public function testNamespaceParam() {
695 $user = $this->getLoggedInTestUser();
696 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
697 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
702 'target' => $subjectTarget,
703 'content' => 'Some Content',
704 'summary' => 'Create the page',
707 'target' => $talkTarget,
708 'content' => 'Some Content',
709 'summary' => 'Create the talk page',
713 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
715 $result = $this->doListWatchlistRequest( [ 'wlnamespace' => '0', ] );
717 $this->assertArraySubsetsEqual(
718 $this->getItemsFromApiResponse( $result ),
722 'title' => $this->getPrefixedText( $subjectTarget ),
729 public function testUserParam() {
730 $user = $this->getLoggedInTestUser();
731 $otherUser = $this->getNonLoggedInTestUser();
732 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
733 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
743 'What is this page about?',
744 'Create the talk page'
746 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
748 $result = $this->doListWatchlistRequest( [
749 'wlprop' => 'user|title',
750 'wluser' => $otherUser->getName(),
757 'ns' => $talkTarget->getNamespace(),
758 'title' => $this->getPrefixedText( $talkTarget ),
759 'user' => $otherUser->getName(),
762 $this->getItemsFromApiResponse( $result )
766 public function testExcludeUserParam() {
767 $user = $this->getLoggedInTestUser();
768 $otherUser = $this->getNonLoggedInTestUser();
769 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
770 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
780 'What is this page about?',
781 'Create the talk page'
783 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
785 $result = $this->doListWatchlistRequest( [
786 'wlprop' => 'user|title',
787 'wlexcludeuser' => $otherUser->getName(),
794 'ns' => $subjectTarget->getNamespace(),
795 'title' => $this->getPrefixedText( $subjectTarget ),
796 'user' => $user->getName(),
799 $this->getItemsFromApiResponse( $result )
803 public function testShowMinorParams() {
804 $user = $this->getLoggedInTestUser();
805 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
811 'content' => 'Some Content',
812 'summary' => 'Create the page',
816 'content' => 'Slightly Better Content',
817 'summary' => 'Change content',
822 $this->watchPages( $user, [ $target ] );
824 $resultMinor = $this->doListWatchlistRequest( [ 'wlshow' => 'minor', 'wlprop' => 'flags' ] );
825 $resultNotMinor = $this->doListWatchlistRequest( [ 'wlshow' => '!minor', 'wlprop' => 'flags' ] );
827 $this->assertArraySubsetsEqual(
828 $this->getItemsFromApiResponse( $resultMinor ),
834 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotMinor ) );
837 public function testShowBotParams() {
838 $user = $this->getLoggedInTestUser();
839 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
840 $this->doBotPageEdit(
846 $this->watchPages( $user, [ $target ] );
848 $resultBot = $this->doListWatchlistRequest( [ 'wlshow' => 'bot' ] );
849 $resultNotBot = $this->doListWatchlistRequest( [ 'wlshow' => '!bot' ] );
851 $this->assertArraySubsetsEqual(
852 $this->getItemsFromApiResponse( $resultBot ),
858 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotBot ) );
861 public function testShowAnonParams() {
862 $user = $this->getLoggedInTestUser();
863 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
864 $this->doAnonPageEdit(
869 $this->watchPages( $user, [ $target ] );
871 $resultAnon = $this->doListWatchlistRequest( [
875 $resultNotAnon = $this->doListWatchlistRequest( [
880 $this->assertArraySubsetsEqual(
881 $this->getItemsFromApiResponse( $resultAnon ),
887 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotAnon ) );
890 public function testShowUnreadParams() {
891 $user = $this->getLoggedInTestUser();
892 $otherUser = $this->getNonLoggedInTestUser();
893 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
894 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
905 'Create the talk page'
907 $store = $this->getWatchedItemStore();
908 $store->addWatchBatchForUser( $user, [ $subjectTarget, $talkTarget ] );
909 $store->updateNotificationTimestamp(
915 $resultUnread = $this->doListWatchlistRequest( [
916 'wlprop' => 'notificationtimestamp|title',
919 $resultNotUnread = $this->doListWatchlistRequest( [
920 'wlprop' => 'notificationtimestamp|title',
921 'wlshow' => '!unread'
928 'notificationtimestamp' => '2015-12-12T01:01:01Z',
929 'ns' => $talkTarget->getNamespace(),
930 'title' => $this->getPrefixedText( $talkTarget )
933 $this->getItemsFromApiResponse( $resultUnread )
939 'notificationtimestamp' => '',
940 'ns' => $subjectTarget->getNamespace(),
941 'title' => $this->getPrefixedText( $subjectTarget )
944 $this->getItemsFromApiResponse( $resultNotUnread )
948 public function testShowPatrolledParams() {
949 $user = static::getTestSysop()->getUser();
950 $this->setupPatrolledSpecificFixtures( $user );
952 $resultPatrolled = $this->doListWatchlistRequest( [
953 'wlprop' => 'patrol',
954 'wlshow' => 'patrolled'
956 $resultNotPatrolled = $this->doListWatchlistRequest( [
957 'wlprop' => 'patrol',
958 'wlshow' => '!patrolled'
966 'unpatrolled' => false,
969 $this->getItemsFromApiResponse( $resultPatrolled )
971 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotPatrolled ) );
974 public function testNewAndEditTypeParameters() {
975 $user = $this->getLoggedInTestUser();
976 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
977 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
982 'target' => $subjectTarget,
983 'content' => 'Some Content',
984 'summary' => 'Create the page',
987 'target' => $subjectTarget,
988 'content' => 'Some Other Content',
989 'summary' => 'Change the content',
992 'target' => $talkTarget,
993 'content' => 'Some Talk Page Content',
994 'summary' => 'Create Talk page',
998 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1000 $resultNew = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'new' ] );
1001 $resultEdit = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'edit' ] );
1003 $this->assertEquals(
1007 'ns' => $talkTarget->getNamespace(),
1008 'title' => $this->getPrefixedText( $talkTarget ),
1011 $this->getItemsFromApiResponse( $resultNew )
1013 $this->assertEquals(
1017 'ns' => $subjectTarget->getNamespace(),
1018 'title' => $this->getPrefixedText( $subjectTarget ),
1021 $this->getItemsFromApiResponse( $resultEdit )
1025 public function testLogTypeParameters() {
1026 $user = $this->getLoggedInTestUser();
1027 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1028 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1029 $this->createPageAndDeleteIt( $subjectTarget );
1033 'Some Talk Page Content',
1036 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1038 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'log' ] );
1040 $this->assertEquals(
1044 'ns' => $subjectTarget->getNamespace(),
1045 'title' => $this->getPrefixedText( $subjectTarget ),
1048 $this->getItemsFromApiResponse( $result )
1052 private function getExternalRC( LinkTarget
$target ) {
1053 $title = Title
::newFromLinkTarget( $target );
1055 $rc = new RecentChange
;
1056 $rc->mTitle
= $title;
1058 'rc_timestamp' => wfTimestamp( TS_MW
),
1059 'rc_namespace' => $title->getNamespace(),
1060 'rc_title' => $title->getDBkey(),
1061 'rc_type' => RC_EXTERNAL
,
1062 'rc_source' => 'foo',
1064 'rc_cur_id' => $title->getArticleID(),
1066 'rc_user_text' => 'External User',
1068 'rc_this_oldid' => $title->getLatestRevID(),
1069 'rc_last_oldid' => $title->getLatestRevID(),
1072 'rc_patrolled' => 0,
1074 'rc_old_len' => $title->getLength(),
1075 'rc_new_len' => $title->getLength(),
1078 'rc_log_type' => null,
1079 'rc_log_action' => '',
1083 'prefixedDBkey' => $title->getPrefixedDBkey(),
1084 'lastTimestamp' => 0,
1085 'oldSize' => $title->getLength(),
1086 'newSize' => $title->getLength(),
1087 'pageStatus' => 'changed'
1093 public function testExternalTypeParameters() {
1094 $user = $this->getLoggedInTestUser();
1095 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1096 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1106 'Some Talk Page Content',
1110 $rc = $this->getExternalRC( $subjectTarget );
1113 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1115 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'external' ] );
1117 $this->assertEquals(
1120 'type' => 'external',
1121 'ns' => $subjectTarget->getNamespace(),
1122 'title' => $this->getPrefixedText( $subjectTarget ),
1125 $this->getItemsFromApiResponse( $result )
1129 public function testCategorizeTypeParameter() {
1130 $user = $this->getLoggedInTestUser();
1131 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1132 $categoryTarget = new TitleValue( NS_CATEGORY
, 'ApiQueryWatchlistIntegrationTestCategory' );
1137 'target' => $categoryTarget,
1138 'content' => 'Some Content',
1139 'summary' => 'Create the category',
1142 'target' => $subjectTarget,
1143 'content' => 'Some Content [[Category:ApiQueryWatchlistIntegrationTestCategory]]t',
1144 'summary' => 'Create the page and add it to the category',
1148 $title = Title
::newFromLinkTarget( $subjectTarget );
1149 $revision = Revision
::newFromTitle( $title );
1151 $rc = RecentChange
::newForCategorization(
1152 $revision->getTimestamp(),
1153 Title
::newFromLinkTarget( $categoryTarget ),
1155 $revision->getComment(),
1164 $this->watchPages( $user, [ $subjectTarget, $categoryTarget ] );
1166 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'categorize' ] );
1168 $this->assertEquals(
1171 'type' => 'categorize',
1172 'ns' => $categoryTarget->getNamespace(),
1173 'title' => $this->getPrefixedText( $categoryTarget ),
1176 $this->getItemsFromApiResponse( $result )
1180 public function testLimitParam() {
1181 $user = $this->getLoggedInTestUser();
1182 $target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1183 $target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1184 $target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
1189 'target' => $target1,
1190 'content' => 'Some Content',
1191 'summary' => 'Create the page',
1194 'target' => $target2,
1195 'content' => 'Some Talk Page Content',
1196 'summary' => 'Create Talk page',
1199 'target' => $target3,
1200 'content' => 'Some Other Content',
1201 'summary' => 'Create the page',
1205 $this->watchPages( $user, [ $target1, $target2, $target3 ] );
1207 $resultWithoutLimit = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
1208 $resultWithLimit = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
1210 $this->assertEquals(
1214 'ns' => $target3->getNamespace(),
1215 'title' => $this->getPrefixedText( $target3 )
1219 'ns' => $target2->getNamespace(),
1220 'title' => $this->getPrefixedText( $target2 )
1224 'ns' => $target1->getNamespace(),
1225 'title' => $this->getPrefixedText( $target1 )
1228 $this->getItemsFromApiResponse( $resultWithoutLimit )
1230 $this->assertEquals(
1234 'ns' => $target3->getNamespace(),
1235 'title' => $this->getPrefixedText( $target3 )
1239 'ns' => $target2->getNamespace(),
1240 'title' => $this->getPrefixedText( $target2 )
1243 $this->getItemsFromApiResponse( $resultWithLimit )
1245 $this->assertArrayHasKey( 'continue', $resultWithLimit[0] );
1246 $this->assertArrayHasKey( 'wlcontinue', $resultWithLimit[0]['continue'] );
1249 public function testAllRevParam() {
1250 $user = $this->getLoggedInTestUser();
1251 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1256 'target' => $target,
1257 'content' => 'Some Content',
1258 'summary' => 'Create the page',
1261 'target' => $target,
1262 'content' => 'Some Other Content',
1263 'summary' => 'Change the content',
1267 $this->watchPages( $user, [ $target ] );
1269 $resultAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wlallrev' => '', ] );
1270 $resultNoAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
1272 $this->assertEquals(
1276 'ns' => $target->getNamespace(),
1277 'title' => $this->getPrefixedText( $target ),
1280 $this->getItemsFromApiResponse( $resultNoAllRev )
1282 $this->assertEquals(
1286 'ns' => $target->getNamespace(),
1287 'title' => $this->getPrefixedText( $target ),
1291 'ns' => $target->getNamespace(),
1292 'title' => $this->getPrefixedText( $target ),
1295 $this->getItemsFromApiResponse( $resultAllRev )
1299 public function testDirParams() {
1300 $user = $this->getLoggedInTestUser();
1301 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1302 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1307 'target' => $subjectTarget,
1308 'content' => 'Some Content',
1309 'summary' => 'Create the page',
1312 'target' => $talkTarget,
1313 'content' => 'Some Talk Page Content',
1314 'summary' => 'Create Talk page',
1318 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1320 $resultDirOlder = $this->doListWatchlistRequest( [ 'wldir' => 'older', 'wlprop' => 'title' ] );
1321 $resultDirNewer = $this->doListWatchlistRequest( [ 'wldir' => 'newer', 'wlprop' => 'title' ] );
1323 $this->assertEquals(
1327 'ns' => $talkTarget->getNamespace(),
1328 'title' => $this->getPrefixedText( $talkTarget )
1332 'ns' => $subjectTarget->getNamespace(),
1333 'title' => $this->getPrefixedText( $subjectTarget )
1336 $this->getItemsFromApiResponse( $resultDirOlder )
1338 $this->assertEquals(
1342 'ns' => $subjectTarget->getNamespace(),
1343 'title' => $this->getPrefixedText( $subjectTarget )
1347 'ns' => $talkTarget->getNamespace(),
1348 'title' => $this->getPrefixedText( $talkTarget )
1351 $this->getItemsFromApiResponse( $resultDirNewer )
1355 public function testStartEndParams() {
1356 $user = $this->getLoggedInTestUser();
1357 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1364 $this->watchPages( $user, [ $target ] );
1366 $resultStart = $this->doListWatchlistRequest( [
1367 'wlstart' => '20010115000000',
1369 'wlprop' => 'title',
1371 $resultEnd = $this->doListWatchlistRequest( [
1372 'wlend' => '20010115000000',
1374 'wlprop' => 'title',
1377 $this->assertEquals(
1381 'ns' => $target->getNamespace(),
1382 'title' => $this->getPrefixedText( $target ),
1385 $this->getItemsFromApiResponse( $resultStart )
1387 $this->assertEmpty( $this->getItemsFromApiResponse( $resultEnd ) );
1390 public function testContinueParam() {
1391 $user = $this->getLoggedInTestUser();
1392 $target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1393 $target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1394 $target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
1399 'target' => $target1,
1400 'content' => 'Some Content',
1401 'summary' => 'Create the page',
1404 'target' => $target2,
1405 'content' => 'Some Talk Page Content',
1406 'summary' => 'Create Talk page',
1409 'target' => $target3,
1410 'content' => 'Some Other Content',
1411 'summary' => 'Create the page',
1415 $this->watchPages( $user, [ $target1, $target2, $target3 ] );
1417 $firstResult = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
1418 $this->assertArrayHasKey( 'continue', $firstResult[0] );
1419 $this->assertArrayHasKey( 'wlcontinue', $firstResult[0]['continue'] );
1421 $continuationParam = $firstResult[0]['continue']['wlcontinue'];
1423 $continuedResult = $this->doListWatchlistRequest(
1424 [ 'wlcontinue' => $continuationParam, 'wlprop' => 'title' ]
1427 $this->assertEquals(
1431 'ns' => $target3->getNamespace(),
1432 'title' => $this->getPrefixedText( $target3 ),
1436 'ns' => $target2->getNamespace(),
1437 'title' => $this->getPrefixedText( $target2 ),
1440 $this->getItemsFromApiResponse( $firstResult )
1442 $this->assertEquals(
1446 'ns' => $target1->getNamespace(),
1447 'title' => $this->getPrefixedText( $target1 )
1450 $this->getItemsFromApiResponse( $continuedResult )
1454 public function testOwnerAndTokenParams() {
1455 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1457 $this->getLoggedInTestUser(),
1463 $otherUser = $this->getNonLoggedInTestUser();
1464 $otherUser->setOption( 'watchlisttoken', '1234567890' );
1465 $otherUser->saveSettings();
1467 $this->watchPages( $otherUser, [ $target ] );
1469 $result = $this->doListWatchlistRequest( [
1470 'wlowner' => $otherUser->getName(),
1471 'wltoken' => '1234567890',
1472 'wlprop' => 'title',
1475 $this->assertEquals(
1479 'ns' => $target->getNamespace(),
1480 'title' => $this->getPrefixedText( $target )
1483 $this->getItemsFromApiResponse( $result )
1487 public function testOwnerAndTokenParams_wrongToken() {
1488 $otherUser = $this->getNonLoggedInTestUser();
1489 $otherUser->setOption( 'watchlisttoken', '1234567890' );
1490 $otherUser->saveSettings();
1492 $this->setExpectedException( UsageException
::class, 'Incorrect watchlist token provided' );
1494 $this->doListWatchlistRequest( [
1495 'wlowner' => $otherUser->getName(),
1496 'wltoken' => 'wrong-token',
1500 public function testOwnerAndTokenParams_noWatchlistTokenSet() {
1501 $this->setExpectedException( UsageException
::class, 'Incorrect watchlist token provided' );
1503 $this->doListWatchlistRequest( [
1504 'wlowner' => $this->getNonLoggedInTestUser()->getName(),
1505 'wltoken' => 'some-token',
1509 public function testGeneratorWatchlistPropInfo_returnsWatchedPages() {
1510 $user = $this->getLoggedInTestUser();
1511 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1518 $this->watchPages( $user, [ $target ] );
1520 $result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'info' ] );
1522 $this->assertArrayHasKey( 'query', $result[0] );
1523 $this->assertArrayHasKey( 'pages', $result[0]['query'] );
1525 // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
1526 $pages = array_values( $result[0]['query']['pages'] );
1528 $this->assertArraySubsetsEqual(
1532 'ns' => $target->getNamespace(),
1533 'title' => $this->getPrefixedText( $target ),
1537 [ 'ns', 'title', 'new' ]
1541 public function testGeneratorWatchlistPropRevisions_returnsWatchedItemsRevisions() {
1542 $user = $this->getLoggedInTestUser();
1543 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1548 'target' => $target,
1549 'content' => 'Some Content',
1550 'summary' => 'Create the page',
1553 'target' => $target,
1554 'content' => 'Some Other Content',
1555 'summary' => 'Change the content',
1559 $this->watchPages( $user, [ $target ] );
1561 $result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'revisions', 'gwlallrev' => '' ] );
1563 $this->assertArrayHasKey( 'query', $result[0] );
1564 $this->assertArrayHasKey( 'pages', $result[0]['query'] );
1566 // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
1567 $pages = array_values( $result[0]['query']['pages'] );
1569 $this->assertCount( 1, $pages );
1570 $this->assertEquals( 0, $pages[0]['ns'] );
1571 $this->assertEquals( $this->getPrefixedText( $target ), $pages[0]['title'] );
1572 $this->assertArraySubsetsEqual(
1573 $pages[0]['revisions'],
1576 'comment' => 'Create the page',
1577 'user' => $user->getName(),
1581 'comment' => 'Change the content',
1582 'user' => $user->getName(),
1586 [ 'comment', 'user', 'minor' ]