User:DannyS712 test/Global watchlist tests.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// <nowiki>
/* jshint maxerr: 999 */
/* globals window, GlobalWatchlist, $, mw, OO */
$(function (){
var GlobalWatchlistTests = {};
window.GlobalWatchlistTests = GlobalWatchlistTests;

GlobalWatchlistTests.config = {
	testVersion: '2.3.1', // Last time tests were updated
	scriptVersion: '8.2.2', // Corresponding script version
};
GlobalWatchlistTests.init = async function() {
	console.log( 'Started' );
	mw.util.addCSS(
		'table, th, td { border: 1px solid black; }' +
		'th, td { padding: 5px; }' +
		'.GlobalWatchlistTestsPass { background-color: #00FF00; }' +
		'.GlobalWatchlistTestsFail { background-color: #FF4444; }' +
		'.GlobalWatchlistTestsCheck { background-color: #03fcd7; }' +
		'.GlobalWatchlistTestsWarn { background-color: #ff8400; }'
	);

	$('#mw-content-text').empty().append(
		$( '<table id="GlobalWatchlistTest">' ).append(
			$( '<tr>' ).append( 
				$( '<th>Test</th>' ),
				$( '<th>Expected</th>' ),
				$( '<th>Actual</th>' ),
				$( '<th>Verdict</th>' )
			)
		)
	);
	
	// Every object in GlobalWatchlistTests except the helper methods listed below is a test, which must have at least
	//      * A `desc` string to add as the heading
	//      * A `run` async method, that returns the results of the test
	var tests = Object.keys(GlobalWatchlistTests).filter(e => ['config', 'init', 'testEquality', 'addTestGroupHeading', 'addTestResult', 'makeString', 'addContainerRow'].indexOf(e) === -1);
	var test, testName;
	for ( var iii = 0; iii < tests.length; iii++ ) {
		testName = tests[iii];
		test = GlobalWatchlistTests[ testName ];
		GlobalWatchlistTests.addTestGroupHeading( testName, test.desc );
		var results = await test.run();
		var sum = 0;
		results.forEach((t) => {
			sum = sum + GlobalWatchlistTests.addTestResult( testName, ...t );
		});
		var groupResult = sum === results.length ? 'Pass' : ( sum === 0 ? 'Fail' : 'Warn' );
		$(`#GlobalWatchlistTest-${testName}`).addClass( `GlobalWatchlistTests${groupResult}` );
	}
	$('tr.GlobalWatchlistTestsPass > th.GlobalWatchlistTest-showhide').click();
};
GlobalWatchlistTests.testEquality = function ( a, b ) {
	return Object.is( GlobalWatchlistTests.makeString( a ), GlobalWatchlistTests.makeString( b ) );
};
GlobalWatchlistTests.makeString = function ( o ) {
	var s = o.toString();
	if ( Array.isArray( o ) ) {
		s = o.join(', ');
	} else if ( s === '[object Object]' ) {
		s = Object.entries( o ).toString();
	}
	return s;
};
GlobalWatchlistTests.addTestGroupHeading = function ( name, desc ) {
	$( '#GlobalWatchlistTest' ).append(
		$( `<tr id="GlobalWatchlistTest-${name}">` ).append(
			$( `<th colspan="3" scope="colgroup">${desc}</th>` ),
			$( `<th id="GlobalWatchlistTest-${name}-showhide" class="GlobalWatchlistTest-showhide">Show/hide</th>` )
		)
	);
	$( `#GlobalWatchlistTest-${name}-showhide` ).click( function () {
		$( `.GlobalWatchlistTest-${name}-result` ).toggle();
	});
};
GlobalWatchlistTests.addTestResult = function ( name, desc, expected, actual, warn = false ) {
	if ( expected === 'content' ) {
		GlobalWatchlistTests.addContainerRow( desc, actual, name );
		return 0.5;
	} else {
		var verdict, passTest, result;
		if ( actual !== 'check' ) {
			passTest = GlobalWatchlistTests.testEquality( expected, actual );
			verdict = passTest ? 'Pass' : ( warn ? 'Warn' : 'Fail' );
			result = passTest ? 1 : ( warn ? 0.5 : 0 );
		} else {
			passTest = false;
			verdict = 'Check';
			actual = 'Please check manually';
			result = 0.5;
		}
		$( '#GlobalWatchlistTest' ).append(
			$( `<tr class="GlobalWatchlistTest-${name}-result">` ).append( 
				$( `<td>${ desc }</td>` ),
				$( `<td>${ GlobalWatchlistTests.makeString( expected ) }</td>` ),
				$( `<td>${ GlobalWatchlistTests.makeString( actual ) }</td>` ),
				$( '<td class="GlobalWatchlistTests' + verdict + '">' + verdict + '</td>' )
			)
		);
		console.log( name, expected, actual, verdict );
		return result;
	}
};
GlobalWatchlistTests.addContainerRow = function ( desc, content, name ) {
	$( '#GlobalWatchlistTest' ).append(
		$( `<tr class="GlobalWatchlistTest-${name}-result">` ).append( 
			$( `<td>${ desc }</td>` ),
			$( `<td colspan="2">` ).append( content ),
			$( '<td class="GlobalWatchlistTestsCheck">Check</td>' )
		)
	);
};
GlobalWatchlistTests.sanityCheck = {
	desc: 'Verify that test passing and failing works',
	run: async function () {
		return [
			[ 'Should pass', true, true ],
			[ 'Should fail', true, false ]
		];
	}
};
GlobalWatchlistTests.testInit = {
	desc: 'Test startup processes (`init`, `setMode`, and messages)',
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			resolve([
				[ 'Activated in test mode', 4, GlobalWatchlist.cfg.mode ],
				[ 'Testing without actions', true, GlobalWatchlist.cfg.testNoActions ],
				[ 'Retrieved `rcfilters-filter-minor-label` properly', "Minor edits", mw.msg( 'gw-msg-filter-minor') ],
				[ 'Set `globalWatchlistBackLink` properly', "Back to Global watchlist", mw.msg( 'gw-msg-globalWatchlistBackLink') ],
			]);
		});
	}
};
GlobalWatchlistTests.settingsValidate = {
	desc: 'Test `settings.validate`',
	run: async function () {
		const GlobalWatchlist = window.GlobalWatchlist;
		var tests = GlobalWatchlistTests.settingsValidate.data;
		var results = [];
		for ( var iii = 0; iii < tests.length; iii++ ){
			results.push( [ tests[iii][0], tests[iii][2], await GlobalWatchlist.settings.validate( tests[iii][1] ) ] );
		}
		return results;
	},
	data: [
		[ 'Need at least 1 site',
			{
				sites: [],
				botFilter: 0,
				anonFilter: 0,
				minorFilter: 0,
				showEdits: true,
				showNewPages: true,
				showLogEntries: true,
				groupPage: true
			},
			[ 'No sites selected' ]
		],
		[ 'Invalid site',
			{
				sites: [ 'foo.bar' ],
				botFilter: 0,
				anonFilter: 0,
				minorFilter: 0,
				showEdits: true,
				showNewPages: true,
				showLogEntries: true,
				groupPage: true
			},
			[ 'Invalid site(s): foo.bar' ]
		],
		[ 'Some sites invalid',
			{
				sites: [ 'foo.bar', 'en.wikipedia' ],
				botFilter: 0,
				anonFilter: 0,
				minorFilter: 0,
				showEdits: true,
				showNewPages: true,
				showLogEntries: true,
				groupPage: true
			},
			[ 'Invalid site(s): foo.bar' ]
		],
		[ 'All sites invalid',
			{
				sites: [ 'foo.bar', 'biz.baz' ],
				botFilter: 0,
				anonFilter: 0,
				minorFilter: 0,
				showEdits: true,
				showNewPages: true,
				showLogEntries: true,
				groupPage: true
			},
			[ 'Invalid site(s): foo.bar, biz.baz' ]
		],
		[ 'Need to show something',
			{
				sites: [ 'en.wikipedia' ],
				botFilter: 0,
				anonFilter: 0,
				minorFilter: 0,
				showEdits: false,
				showNewPages: false,
				showLogEntries: false,
				groupPage: true
			},
			[ 'No change types selected' ]
		],
		[ 'No anon bots',
			{
				sites: [ 'en.wikipedia' ],
				botFilter: 1,
				anonFilter: 1,
				minorFilter: 0,
				showEdits: true,
				showNewPages: true,
				showLogEntries: true,
				groupPage: true
			},
			[ 'Anonymous users cannot make bot edits' ]
		],
		[ 'No anon minor edits',
			{
				sites: [ 'en.wikipedia' ],
				botFilter: 0,
				anonFilter: 1,
				minorFilter: 1,
				showEdits: true,
				showNewPages: true,
				showLogEntries: true,
				groupPage: true
			},
			[ 'Anonymous users cannot make minor edits' ]
		],
		[ 'No problems',
			{
				sites: [ 'en.wikipedia' ],
				botFilter: 0,
				anonFilter: 0,
				minorFilter: 0,
				showEdits: true,
				showNewPages: true,
				showLogEntries: true,
				groupPage: true
			},
			[]
		],
	]
};
GlobalWatchlistTests.helpFlag = {
	desc: 'Test `help.flag`',
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			var tests = GlobalWatchlistTests.helpFlag.data;
			var results = [];
			for ( var iii = 0; iii < tests.length; iii++ ){
				results.push( [ tests[iii][0], tests[iii][3], GlobalWatchlist.help.flag( tests[iii][1], tests[iii][2] ) ] );
			}
			resolve(results);
		});
	},
	data: [
		[ 'Inclusive', 1, 'filter', '|filter' ],
		[ 'Exclusive', 2, 'filter', '|!filter' ],
		[ 'Other', 0, 'filter', '' ]
	]
};
GlobalWatchlistTests.helpSetUp = {
	desc: 'Test `help.setUp`',
	msg: {
		'gw-msg-title-tests': 'Global watchlist tests (T)',
		'gw-msg-heading-tests': 'Global watchlist tests (H)'
	},
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			var msg = GlobalWatchlistTests.helpSetUp.msg;
			mw.messages.set( msg );
			GlobalWatchlist.help.setUp( 4, 'tests' );
			resolve([
				[ 'Page title', msg[ 'gw-msg-title-tests' ], 'check' ],
				[ 'Page heading', msg[ 'gw-msg-heading-tests' ], 'check' ]
			]);
		});
	}
};
GlobalWatchlistTests.checkDocsExist = {
	desc: 'Verify that QQQ documentation and unit numbers exist for all messages',
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			var en = GlobalWatchlist.i18n.en,
				enKeys = Object.keys( en ),
				enStringed = JSON.stringify( enKeys, null, ' ' ),
				qqq = GlobalWatchlist.i18n.qqq,
				qqqKeys = Object.keys( qqq ),
				qqqStringed = JSON.stringify( qqqKeys, null, ' ' ),
				units = GlobalWatchlist.i18n.units,
				unitsKeys = Object.keys( units ),
				unitsStringed = JSON.stringify( unitsKeys, null, ' ' );
	
			var unitsV = Object.values( units ),
				unitsS = [ ...new Set( unitsV ) ];
	
			resolve([
				[ 'Names of keys (qqq)', enStringed, qqqStringed ],
				[ 'Names of keys (units)', enStringed, unitsStringed, true ],
				[ 'No duplicate units (set = array)', unitsV, unitsS ],
			]);
		});
	}
};
GlobalWatchlistTests.checkNoExtraMsg = {
	desc: 'Verify that only messages with English definitions are translated',
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			var langs = Object.keys(GlobalWatchlist.i18n).filter(e => ['en', 'mwMsgs', 'qqq', 'units'].indexOf(e) === -1);
			var enkeys = Object.keys(GlobalWatchlist.i18n.en);
			var lang;
			var results = [];
			for ( var iii = 0; iii < langs.length; iii++ ) {
				lang = langs[iii];
				results.push( [ lang + ' translations', [], Object.keys(GlobalWatchlist.i18n[ langs[iii] ]).filter(e => enkeys.indexOf(e) === -1) ] );
			}
			resolve(results);
		});
	}
};
GlobalWatchlistTests.labelE = {
	desc: 'Test `OOUI.labelE`',
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			mw.messages.set( 'gw-msg-exampleLabel', 'Example label text' );
			resolve([ [
				'Label creation',
				'&lt;label class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-labelElement-label oo-ui-labelWidget" aria-disabled="false"&gt;Example label text&lt;/label&gt;',
				GlobalWatchlist.OOUI.labelE( 'exampleLabel' )[0].outerHTML.replace( /</g, '&lt;' ).replace( />/g, '&gt;' )
			] ]);
		});
	}
}
GlobalWatchlistTests.basicSiteObject = {
	desc: 'Test `GlobalWatchlist.Site` object (basic)',
	run: async function () {
		const GlobalWatchlist = window.GlobalWatchlist;
		var tests = GlobalWatchlistTests.basicSiteObject.data;
		var site, test, siteName;
		results = [];
		for ( var iii = 0; iii < tests.length; iii++ ){
			test = tests[iii];
			siteName = test[ 0 ];
			site = new GlobalWatchlist.Site( siteName )
			results.push( [ `Site.site - ${siteName}`, siteName, site.site ] );
			results.push( [ `Site.siteID - ${siteName}`, test[ 1 ], site.siteID ] );
			results.push( [ `Site.divID - ${siteName}`, test[ 2 ], site.divID ] );
			results.push( [ `getAssociatedPageTitle - ${siteName}`, test[ 3 ], decodeURIComponent( ( await site.getAssociatedPageTitle( test[ 4 ] ) ).replace(/%27/g, '\'').replace(/%22/g, 'DOUBLEQUOTE') ) ] );
		}
		return results;
	},
	data: [
		[ 'en.wikipedia', 'en_wikipedia', 'globalWatch-feed-site-en_wikipedia', 'User talk:DannyS712', 'User:DannyS712' ],
		[ 'es.wikinews', 'es_wikinews', 'globalWatch-feed-site-es_wikinews', 'Usuario discusión:Foo', 'Usuario:Foo' ],
		[ 'meta.wikimedia', 'meta_wikimedia', 'globalWatch-feed-site-meta_wikimedia', 'Meta:Requests for help from a sysop or bureaucrat', 'Meta talk:Requests for help from a sysop or bureaucrat' ],
		[ 'ko.wikiversity', 'ko_wikiversity', 'globalWatch-feed-site-ko_wikiversity', '사용자:Bar', '사용자토론:Bar' ],
	],
}
GlobalWatchlistTests.advancedSiteObject = {
	desc: 'Test `GlobalWatchlist.Site` object (advanced)',
	mockApi: function ( site ) {
		this.realApi = new mw.ForeignApi(`//${site}.org/w/api.php`);
		this.get = function ( options ) {
			return new Promise((resolve) => {
				console.log( 'Tests API, get:', options );
				if ( options.action === 'parse' ) {
					console.log( 'Parsing for associated title, use real api' );
					resolve(this.realApi.get( options ));
				} else if ( options.action === 'query' ) {
					if ( options.list === 'tags' ) {
						console.log( 'Querying for tags, will need to return fake' );
						resolve(GlobalWatchlistTests.advancedSiteObject.fakeData.tags);
					} else if ( options.list === 'watchlist' ) {
						console.log( 'Querying for watchlist, will need to return fake' );
						resolve(GlobalWatchlistTests.advancedSiteObject.fakeData.watchlist);
					}
				} else if ( options.action === 'wbgetentities' ) {
					console.log( 'Querying for wikidata entities, will need to return fake' );
					resolve(this.realApi.get( options ));
				}
			});
		};
	},
	fakeData: {
		watchlist: {
			"batchcomplete": true,
			"limits": {
				"watchlist": 500
			},
			"query": {
				"watchlist": [
					{
						"type": "edit",
						"ns": 0,
						"title": "Foo",
						"pageid": 1,
						"revid": 1002,
						"old_revid": 1001,
						"user": "User 1",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "Summary 1",
						"tags": [ 'OAuth CID: 1234' ]
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Bar",
						"pageid": 2,
						"revid": 2002,
						"old_revid": 2001,
						"user": "User 2",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "<span dir=\"auto\"><span class=\"autocomment\"><a href=\"/wiki/Section heading\" title=\"Section heading\">→‎Section heading</a></span></span>",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Baz",
						"pageid": 3,
						"revid": 3003,
						"old_revid": 3001,
						"user": "Bot User",
						"bot": true,
						"new": false,
						"minor": false,
						"parsedcomment": "Bot comment",
						"tags": []
					},
					{
						"type": "new",
						"ns": 0,
						"title": "Qux",
						"pageid": 4,
						"revid": 4004,
						"user": "New page creator",
						"bot": false,
						"new": true,
						"minor": false,
						"parsedcomment": "Look what I made!",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Lorem ipsum",
						"pageid": 5,
						"revid": 5005,
						"old_revid": 5001,
						"user": "Copy editor",
						"bot": false,
						"new": false,
						"minor": true,
						"parsedcomment": "Fixed some typos",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Page",
						"pageid": 6,
						"revid": 6006,
						"old_revid": 6001,
						"user": "127.0.01",
						"anon": true,
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "The truth",
						"tags": [ 'blanking' ]
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Page to be edited with no summary",
						"pageid": 7,
						"revid": 7007,
						"old_revid": 7001,
						"user": "Demo user",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "",
						"tags": []
					},
					{
						"type": "log",
						"ns": 0,
						"title": "Page that was deleted",
						"pageid": 8,
						"revid": 0,
						"old_revid": 0,
						"user": "Admin",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "I did the deletion",
						"logid": 8008,
						"logtype": "delete",
						"logaction": "delete",
						"logparams": {},
						"tags": []
					},
					{
						"type": "log",
						"ns": 2,
						"title": "User:Vandal",
						"pageid": 0,
						"revid": 0,
						"old_revid": 0,
						"user": "Admin",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "You have been blocked for <a href=\"/wiki/WP:VD\" class=\"mw-redirect\" title=\"WP:VD\">vandalism</a>",
						"logid": 9009,
						"logtype": "block",
						"logaction": "block",
						"logparams": {
							"duration": "1 month",
							"flags": [ "nocreate", "noemail" ],
							"sitewide": true,
							"expiry": "2020-02-12T12:15:30Z"
						},
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Page to be edited with RTL users",
						"pageid": 8,
						"revid": 8008,
						"old_revid": 8001,
						"user": "ערן",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Page to be edited with RTL users",
						"pageid": 8,
						"revid": 8009,
						"old_revid": 8008,
						"user": "ערן",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Page to be edited with RTL users",
						"pageid": 8,
						"revid": 8010,
						"old_revid": 8009,
						"user": "DannyS712",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "Page to be edited with hidden user",
						"pageid": 9,
						"revid": 9009,
						"old_revid": 9001,
						"userhidden": true,
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "",
						"tags": []
					},
					{
						"type": "new",
						"ns": 0,
						"title": "New page with lots of edits",
						"pageid": 10,
						"revid": 10001,
						"user": "New page creator",
						"bot": false,
						"new": true,
						"minor": false,
						"parsedcomment": "Look what I made!",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "New pages with lots of edits",
						"pageid": 10,
						"revid": 10002,
						"old_revid": 10001,
						"user": "DannyS712",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "",
						"tags": []
					},
					{
						"type": "edit",
						"ns": 0,
						"title": "New pages with lots of edits",
						"pageid": 10,
						"revid": 10003,
						"old_revid": 10002,
						"user": "DannyS712",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "",
						"tags": []
					}
				]
			}
		},
		tags: {
			"batchcomplete": true,
			"limits": {
				"tags": 500
			},
			"query": {
				"tags": [
					{
						"name": "OAuth CID: 1234",
						"displayname": "<a href=\"/wiki/Special:OAuthListConsumers/view/OAuthTag\" title=\"Special:OAuthListConsumers/view/OAuthTag\">OAuthTag</a>"
					},
					{
						"name": "abusefilter-condition-limit",
						"displayname": "condition limit reached"
					},
					{
						"name": "blanking",
						"displayname": "blanking"
					},
				]
			}
		}
	},
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			GlobalWatchlist.help.api = function ( site ) {
				return new GlobalWatchlistTests.advancedSiteObject.mockApi( site );
			}
			const enwiki = new GlobalWatchlist.Site( 'en.wikipedia' );
			enwiki.getWatchlist().then( function () {
				var expectedTags = GlobalWatchlistTests.advancedSiteObject.fakeData.tags.query.tags,
					expectedTagsObject = {};
				expectedTags.forEach((t) => { expectedTagsObject[t.name] = t.displayname || false ? t.displayname.replace(/<a href="\/wiki\//g, `<a href="https://en.wikipedia.org/wiki/`) : t.name; })
				resolve([
					[ `Site.tags`, expectedTagsObject, enwiki.tags ],
					[ `Site.isEmpty`, false, enwiki.isEmpty ],
					[ `Edits - new`, '"New page creator" created Qux', 'check' ],
					[ `Edits - bot`, '"Bot User" edited Baz with a bot edit', 'check' ],
					[ `Edits - minor`, '"Copy editor" edited Lorem ipsum with a minor edit', 'check' ],
					[ `Edits - tag`, '"User 1"\'s edit is tagged as "OAuthTag"', 'check' ],
					[ `Edits - tag`, '"127.0.0.1"\'s edit is tagged as "blanking"', 'check' ],
					[ `Edits - link (user)`, '"User 2"\'s name is linked to their user page', 'check' ],
					[ `Edits - link (anon)`, '"127.0.0.1"\'s name is linked to their contributions', 'check' ],
					[ `Edits - empty summary`, 'There is no extra : when no summary accompanies an edit', 'check' ],
					[ `Log - deletion`, '"Admin" is shown deleting a page', 'check' ],
					[ `Log - block`, '"Admin" is shown blocking "Vandal"', 'check' ],
					[ 'Edits - RTL', 'RTL users with multiple edits work properly', 'check' ],
					[ 'Unwatch - strikethrough', 'Unwatching a page results in strikethrough through links', 'check' ],
					[ 'Hidden user', 'Edits where the user is hidden are shown as a hidden user, rather than undefined', 'check' ],
					[ 'Links in separate tabs', 'Links to pages, user pages, contributions, history, etc. open in a separate tab', 'check' ],
					[ 'Collapsable', 'A "hide" button allows collapsing the output of the site', 'check' ],
					[ `Enwiki feed object`, 'content', enwiki.$feedDiv ]
				]);
			} );
		});
	}
}
GlobalWatchlistTests.wikidataSite = {
	desc: 'Test `GlobalWatchlist.Site` object for wikidata',
	mockApi: function ( site ) {
		this.realApi = new mw.ForeignApi(`//${site}.org/w/api.php`);
		this.get = function ( options ) {
			return new Promise((resolve) => {
				console.log( 'Tests API, get:', options );
				if ( options.action === 'parse' ) {
					console.log( 'Parsing for associated title, use real api' );
					resolve(this.realApi.get( options ));
				} else if ( options.action === 'query' ) {
					if ( options.list === 'tags' ) {
						console.log( 'Querying for tags, will need to return fake' );
						resolve(GlobalWatchlistTests.wikidataSite.fakeData.tags);
					} else if ( options.list === 'watchlist' ) {
						console.log( 'Querying for watchlist, will need to return fake' );
						resolve(GlobalWatchlistTests.wikidataSite.fakeData.watchlist);
					}
				} else if ( options.action === 'wbgetentities' ) {
					console.log( 'Querying for wikidata entities, will need to return fake' );
					resolve(this.realApi.get( options ));
				}
			});
		};
	},
	fakeData: {
		watchlist: {
			"batchcomplete": true,
			"limits": {
				"watchlist": 500
			},
			"query": {
				"watchlist": [
					{
						"type": "edit",
						"ns": 0,
						"title": "Q5",
						"pageid": 1,
						"revid": 1002,
						"old_revid": 1001,
						"user": "User 1",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "Item summary"
					},
					{
						"type": "edit",
						"ns": 120,
						"title": "Property:P31",
						"pageid": 2,
						"revid": 2002,
						"old_revid": 2001,
						"user": "User 2",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "Property summary",
						"tags": [ 'property' ]
					},
					{
						"type": "edit",
						"ns": 146,
						"title": "Lexeme:L2",
						"pageid": 3,
						"revid": 3003,
						"old_revid": 3001,
						"user": "User 3",
						"bot": false,
						"new": false,
						"minor": false,
						"parsedcomment": "Lexeme summary",
						"tags": []
					}
				]
			}
		},
		tags: {
			"batchcomplete": true,
			"limits": {
				"tags": 500
			},
			"query": {
				"tags": [
					{
						"name": "property",
						"displayname": "Property edit"
					},
				]
			}
		}
	},
	run: function () {
		return new Promise((resolve) => {
			const GlobalWatchlist = window.GlobalWatchlist;
			GlobalWatchlist.help.api = function ( site ) {
				return new GlobalWatchlistTests.wikidataSite.mockApi( site );
			}
			const wd = new GlobalWatchlist.Site( 'www.wikidata' );
			wd.getWatchlist().then( function () {
				var expectedTags = GlobalWatchlistTests.wikidataSite.fakeData.tags.query.tags,
					expectedTagsObject = {};
				expectedTags.forEach((t) => { expectedTagsObject[t.name] = t.displayname || false ? t.displayname.replace(/<a href="\/wiki\//g, `<a href="https://www.wikidata.org/wiki/`) : t.name; })
				resolve([
					[ `Labels - Q`, 'Q5 is "human"', 'check' ],
					[ `Labels - P`, 'P31 is "instance of"', 'check' ],
					[ `Labels - L`, 'L2 is "first"', 'check' ],
					[ `Wikidata feed object`, 'content', wd.$feedDiv ]
				]);
			} );
		});
	}
}
} );
mw.loader.using( [ 'mediawiki.util', 'mediawiki.api', 'mediawiki.ForeignApi', 'oojs-ui-core', 'oojs-ui-windows' ], function () {
	$(document).ready( function () {
		if ( mw.config.get('wgNamespaceNumber') === -1 ){
			var page = mw.config.get('wgCanonicalSpecialPageName');
			if ( page === 'Blankpage'){
				var page2 = mw.config.get( 'wgTitle' ).split('/');
				if ( page2[1] ) {
					if ( page2[1] === 'GlobalWatchlistTests' ) {
						mw.hook( 'GlobalWatchlistInternal' ).add( window.GlobalWatchlistTests.init );
						mw.loader.getScript( '/w/index.php?title=User:DannyS712 test/Global watchlist.js&action=raw&ctype=text/javascript' ).then( function () {
							window.GlobalWatchlist.init( 4 );
						} );
					}
				}
			}
		}
	} );
} );

// </nowiki>