Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.

  • Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
  • Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
  • Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
  • Opera: Strg+F5
//Dokumentation unter [[Benutzer:Schnark/js/browsertest]] <nowiki>
/*global mediaWiki, console*/
/*jshint evil: true*/
(function ($, mw, libs) {
"use strict";
var isNewPage, testGenerator, currentId, currentTest, expectedWarning;

function setRandomKey () {
	window.name = 'browsertest' + Math.floor(Math.random() * 100000);
}

function getKey () {
	var key = window.name;
	if (key.indexOf('browsertest') === 0) {
		return key;
	}
	return false;
}

function getData () {
	var data = localStorage.getItem('schnark-' + getKey());
	if (data !== null) {
		data = JSON.parse(data);
	}
	return data;
}

function saveData (data) {
	localStorage.setItem('schnark-' + getKey(), JSON.stringify(data));
}

function removeData () {
	localStorage.removeItem('schnark-' + getKey());
}

function logErrors () {
	var mwLogWarn = mw.log.warn,
		ignoreModules = ['jquery.ui', 'jquery.throttle-debounce'],
		ignoreRe;
	ignoreRe = new RegExp('This page is using the deprecated ResourceLoader module "(' +
		ignoreModules.map(mw.util.escapeRegExp).join('|') + ')');
	mw.log.warn = function (msg) {
		mwLogWarn(msg);
		if (!ignoreRe.test(msg) && (!expectedWarning || !expectedWarning.test(msg))) {
			libs.browsertest.data.mwLogWarnError.push(currentTest + ' - ' + msg);
		}
	};
	$(document).on({
		ajaxSuccess: function (a, b, c, d) {
			if (typeof d !== 'object') {
				return;
			}
			if (d.warnings) {
				mw.log.warn('API-Warnung: ' + JSON.stringify(d.warnings));
			}
			if (d.error) {
				mw.log.warn('API-Fehler: ' + JSON.stringify(d.error));
			}
		},
		ajaxError: function (a, b, c) {
			mw.log.warn('AJAX-Fehler' + (typeof c === 'object' ? ' von ' + c.url : ''));
		}
	});
}

isNewPage = true;

function saveTempData () {
	var data = getData();
	data.data = libs.browsertest.data;
	saveData(data);
}

function loadTempData () {
	var data = getData();
	libs.browsertest.data = data.data;
}

function getNextJob () {
	var data = getData(), jobs, job;
	if (data.jobs.length === 0) {
		saveData(data);
		location.href = mw.util.getUrl('Special:Browsertest');
		return false;
	}
	jobs = data.jobs[0];
	if (jobs.length === 0) {
		data.jobs.shift();
		data.done.push('');
		saveData(data);
		return getNextJob();
	}
	job = jobs.shift();
	data.jobs[0] = jobs;
	saveData(data);
	currentTest = data.desc[data.done.length];
	return job;
}

function error (e) {
	var data = getData();
	data.jobs.shift();
	data.done.push(e);
	saveData(data);
}

function doJob (job) {
	var done, yes, id1, id2;
	switch (job[0]) {
	case 'interactive':
		done = getData().done;
		done = done[done.length - 1];
		if (done) {
			mw.log.warn(done);
		} else {
			console.log('OK');
		}
		removeData();
		return;
	case 'ignoreWarning':
		expectedWarning = job[1] && new RegExp(job[1], job[2] || '');
		break;
	case 'exec':
		try {
			eval(job[1]);
		} catch (e) {
			error(job[2] + ': ' + String(e));
		}
		break;
	case 'pause':
		window.setTimeout(run, job[1]);
		return;
	case 'wait':
		if (isNewPage) {
			isNewPage = false;
		} else {
			error(job[1] + ': Keine neue Seite geladen.');
		}
		break;
	case 'waitFor':
		id1 = window.setTimeout(function () {
			window.clearInterval(id2);
			error(job[3] + ': Bedingung nicht eingetreten.');
			run();
		}, job[2]);
		id2 = window.setInterval(function () {
			try {
				yes = eval(job[1]);
			} catch (e) {
				error(job[3] + ': ' + String(e));
				yes = true;
			}
			if (yes) {
				window.clearTimeout(id1);
				window.clearInterval(id2);
				run();
			}
		}, 100);
		return;
	case 'assert':
		try {
			yes = eval(job[1]);
		} catch (e) {
			error(job[2] + ': ' + String(e));
			yes = true;
		}
		if (!yes) {
			error(job[2] + ': Fehlgeschlagen.');
		}
	}
	run();
}

function run () {
	saveTempData();
	var job = getNextJob();
	if (job) {
		doJob(job);
	}
}

function makeUrl (id) {
	var base = mw.util.wikiScript();
	/*jshint onecase: true*/
	switch (id) {
	case 'global': base = 'https://de.wikipedia.org/w/index.php';
	/*falls through*/
	default: return base + '?' +
		$.param({title: 'Benutzer:Schnark/js/browsertest.js/' + id + '.js', action: 'raw', ctype: 'text/javascript'});
	}
}

function loadTests (tests, callback) {
	function loadNext () {
		if (tests.length === 0) {
			callback();
		} else {
			currentId = tests.shift();
			$.getScript(makeUrl(currentId)).then(loadNext, function (dummy1, dummy2, error) {
				makeTest(currentId, function (S) {
					S.exec('throw new Error(' + JSON.stringify(String(error)) + ');');
				});
				loadNext();
			});
		}
	}
	loadNext();
}

testGenerator = {
	exec: function (a, b) {
		testGenerator.test.push(['exec', a, b]);
	},
	click: function (a, b) {
		var el = a.charAt(0) === '$' ? a : '$("' + a.replace(/"/g, '\\"') + '")';
		testGenerator.test.push(['exec', el +
			'.trigger($.Event("mousedown", {which: 1}))' +
			'.each(function () {' +
				'this.dispatchEvent(new MouseEvent("mouseup"));' +
				'this.click();' +
			'});', b]);
	},
	click2: function (a, b) {
		var el = a.charAt(0) === '$' ? a : '$("' + a.replace(/"/g, '\\"') + '")';
		testGenerator.test.push(['exec', el +
			'.trigger($.Event("mousedown", {which: 1, originalEvent: {}}))' +
			'.each(function () {' +
				'this.dispatchEvent(new MouseEvent("mouseup"));' +
				'this.click();' +
			'});', b]);
	},
	load: function (a, b, c) {
		testGenerator.test.push(['exec', 'location.href="' + mw.util.getUrl(a, b || {}).replace(/"/g, '\\"') + '";', c]);
	},
	pause: function (a) {
		testGenerator.test.push(['pause', a]);
	},
	wait: function (a) {
		testGenerator.test.push(['pause', 15000]);
		testGenerator.test.push(['wait', a]);
	},
	waitFor: function (a, b, c) {
		testGenerator.test.push(['waitFor', a, b, c]);
	},
	waitFor2: function (a, b, c, d) {
		testGenerator.test.push(['exec', 'mw.libs.browsertest.data.waitFor2Start = mw.now();', '']);
		testGenerator.test.push(['exec', 'mw.libs.browsertest.data.waitFor2Warn = false;', '']);
		testGenerator.test.push(['exec', 'mw.libs.browsertest.data.waitFor2Timeout = setTimeout(function () {' +
				'mw.libs.browsertest.data.waitFor2Warn = true;' +
			'}, ' + b + ');', '']);
		testGenerator.test.push(['waitFor', a, c, d]);
		testGenerator.test.push(['exec', 'if (mw.libs.browsertest.data.waitFor2Warn) {' +
				'mw.log.warn("Lange Dauer (" + ' +
					'Math.round((mw.now() - mw.libs.browsertest.data.waitFor2Start) / 1000) +' +
					' "s) für „' + d.replace(/"/g, '\\"') + '“");' +
			'}', '']);
		testGenerator.test.push(['exec', 'clearTimeout(mw.libs.browsertest.data.waitFor2Timeout);', '']);
	},
	assert: function (a, b) {
		testGenerator.test.push(['assert', a, b]);
	},
	ignoreWarning: function (a, b) {
		testGenerator.test.push(['ignoreWarning', a, b]);
	}
};

function makeTest (name, code) {
	var data = getData();
	testGenerator.test = [];
	code(testGenerator);
	data.desc.push(name);
	data.ids.push(currentId);
	data.jobs.push(testGenerator.test);
	saveData(data);
}

function runInteractiveTest (test) {
	var data = getData() || {done: [], jobs: [], desc: [], ids: [], data: {}}, i;
	testGenerator.test = [];
	for (i = 0; i < test.length; i++) {
		testGenerator[test[i][0]].apply(testGenerator, test[i][1]);
	}
	data.desc.push('', '');
	data.ids.push('', '');
	data.jobs.push(testGenerator.test, [['interactive']]);
	saveData(data);
	run();
}

function enableInteractiveTests () {
	var proxy = {}, test = [], runTimeout;

	if (!getKey()) {
		setRandomKey();
	}

	function addTest (method, args) {
		if (runTimeout) {
			clearTimeout(runTimeout);
		}
		test.push([method, args]);
		runTimeout = setTimeout(function () {
			runTimeout = false;
			runInteractiveTest(test);
			test = [];
		}, 100);
	}

	$.each(testGenerator, function (method) {
		proxy[method] = function () {
			addTest(method, arguments);
		};
	});

	window.S = proxy;
	return proxy;
}

function getRetryHtml (ids) {
	var i, links = [];
	function makeLink (id, text) {
		return mw.html.element('a', {href: mw.util.getUrl('Special:Browsertest', {tests: id})}, text || id);
	}
	if (ids.length > 1) {
		links.push(makeLink(ids.join('|'), 'alle fehlgeschlagenen'));
	}
	for (i = 0; i < ids.length; i++) {
		links.push(makeLink(ids[i]));
	}
	return links.join(' · ');
}

function getResults () {
	var success = true, data, log, i, tr = [], errorIds = [], table, warnings, retry;
	data = getData();
	log = libs.browsertest.data.mwLogWarnError || [];
	for (i = 0; i < data.desc.length; i++) {
		if (data.done[i]) {
			success = false;
			if (errorIds.indexOf(data.ids[i]) === -1) {
				errorIds.push(data.ids[i]);
			}
		}
		tr.push(mw.html.element('tr', {'class': data.done[i] ? 'error' : 'success'}, new mw.html.Raw(
			mw.html.element('td', {}, data.desc[i]) + mw.html.element('td', {}, data.done[i])
		)));
	}
	removeData();
	table = '<table class="wikitable"><tr><th>Test</th><th>Ergebnis</th></tr>' + tr.join('') + '</table>';
	warnings = log.length ? '<ul>' + log.map(function (entry) {
		return mw.html.element('li', {}, entry);
	}).join('') + '</ul>' : '';
	retry = errorIds.length ? '<p>Tests wiederholen: ' + getRetryHtml(errorIds)  + '</p>' : '';
	return {
		html: table + warnings + retry,
		warnings: log.length,
		success: success
	};
}

function onStart () {
	saveData({done: [], jobs: [], desc: [], ids: [], data: {}});
	loadTests(mw.util.getParamValue('tests').split('|'), run);
}

function onFinish () {
	var result = getResults();
	document.title = (result.success ? '\u2713' : '\u2717') + ' ' +
		(result.warnings ? result.warnings + ' Warnung(en) ' : '') + 'Testergebnisse';
	$('#firstHeading').html('Testergebnisse');
	$('#mw-content-text').html(result.html);
	window.name = '';
}

function init () {
	var key = getKey(),
		testpage = mw.config.get('wgNamespaceNumber') === -1 && mw.config.get('wgTitle') === 'Browsertest';
	if (!key && testpage) {
		setRandomKey();
		libs.browsertest.data.mwLogWarnError = [];
		logErrors();
		onStart();
		return;
	}
	if (!key) {
		return;
	}
	if (testpage) {
		loadTempData();
		$(onFinish);
	} else {
		loadTempData();
		logErrors();
		run();
	}
}

libs.browsertest = {
	test: makeTest,
	interactive: enableInteractiveTests,
	data: {}
};

mw.loader.using('mediawiki.util').then(init);
})(jQuery, mediaWiki, mediaWiki.libs);
//</nowiki>