Newer
Older
/// Copyright (c) 2012 Ecma International. All rights reserved.
/// This code is governed by the BSD license found in the LICENSE file.
David Fugate
committed
/* Handles updating the page with information from the runner. */
function Presenter() {
var altStyle = '',
logger,
date,
version,
table,
backLink,
Norbert Lindenberg
committed
globalSection = new Section(null, "0", STANDARD),
David Fugate
committed
currentSection = globalSection,
tests = {},
totalTests = 0;
Norbert Lindenberg
committed
TOCFILEPATH = "metadata/" + STANDARD.toLowerCase() + "-toc.xml";
//**INTERFACE****************************************************************
/* Updates progress with the given test, which should have its results in it as well. */
this.addTestResult = function(test) {
tests[test.id] = test;
getSectionById(test.id).addTest(test);
David Fugate
committed
David Fugate
committed
//TODO: eventually remove this guard.
if(test.result === 'fail') {
logResult(test);
}
}
/* Updates the displayed version. */
this.setVersion = function(v) {
version = v;
$(".targetTestSuiteVersion").text(v);
}
/* Updates the displayed date. */
this.setDate = function(d) {
/* Updates the displayed number of tests to run. */
this.setTotalTests = function(tests) {
totalTests = tests;
$('#testsToRun').text(tests);
}
/* Write status to the activity bar. */
this.updateStatus = function (str) {
this.activityBar.text(str);
}
/* When starting to load a test, create a table row entry and buttons. Display file path. */
this.setTestWaiting = function(index, path) {
var appendMsg = '<tr class="waiting"><td height="29" class="chapterName">Waiting to load test file: ' + path + '</td>';
appendMsg += '<td width="83"><img src="images/select.png" alt="Select" title="Toggle the selection of this chapter." /></td>';
appendMsg += '<td width="83"><img src="images/run.png" alt="Run" title="Run this chapter individually." /></td></tr>';
$('#chapterSelector table').append(appendMsg);
// Find the table row
var tr = $('#chapterSelector table tr').filter(":last-child");
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Attach click listeners to the buttons
tr.find("img").filter('[alt="Select"]').bind("click", {tr: tr, index: index}, function(event) {
controller.toggleSelection(event.data.index);
// Deselect row
if(event.data.tr.hasClass("selectedChapter")) {
event.data.tr.removeClass("selectedChapter");
event.data.tr.find('img').filter('[alt="Selected"]').attr({
src: 'images/select.png',
alt: 'Select'
});
}
// Select row
else {
event.data.tr.addClass("selectedChapter");
event.data.tr.find('img').filter('[alt="Select"]').attr({
src: 'images/selected.png',
alt: 'Selected'
});
}
});
}
this.setTestLoading = function(index, path) {
var tr = $('#chapterSelector table tr').filter(":nth-child(" + (index+1) + ")");
tr.removeClass("waiting");
tr.addClass("loading");
tr.find(":first-child").html("Loading test file: " + path);
};
/* On test loaded, display the chapter name and the number of tests */
this.setTestLoaded = function(index, name, numTests) {
var tr = $('#chapterSelector table tr').filter(":nth-child(" + (index+1) + ")");
tr.removeClass("loading");
tr.find("td").filter(":first-child").html(name + " (" + numTests + " tests)");
}
/* Called when the tests finish executing. */
this.finished = function(elapsed) {
progressBar.find(".text").html("Testing complete!");
if (isSiteDebugMode()) {
this.activityBar.text('Overall Execution Time: ' + elapsed + ' minutes');
} else {
this.activityBar.text('');
this.reset = function () {
this.activityBar.text('');
David Fugate
committed
currentSection = globalSection;
renderCurrentSection();
/* Do some setup tasks. */
this.setup = function() {
backLink = $('#backlinkDiv');
backLink.click(goBack);
table = $('.results-data-table');
logger = $("#tableLogger");
progressBar = $('#progressbar');
this.activityBar = $('#nextActivity');
$('a.showSource', logger).live("click", openSourceWindow);
$('a.showError', logger).live("click", openErrorWindow);
$('#ancGenXMLReport').click(createXMLReportWindow);
}
/* Refresh display of the report */
this.refresh = function() {
renderCurrentSection();
}
/* The state machine for the button display. */
this.setState = function(state) {
// Hide all the buttons
$('.progressBarButtons img').addClass("hide");
// Only show what is needed.
if(state == 'loading') {
$('#btnRunAll').removeClass('hide');
$('#btnRunSelected').removeClass('hide');
}
else if(state == 'paused') {
$('#btnResume').removeClass('hide');
$('#btnReset').removeClass('hide');
}
else if(state == 'running') {
$('#btnPause').removeClass('hide');
}
else if(state == 'loaded') {
$('#btnRunAll').removeClass('hide');
$('#btnRunSelected').removeClass('hide');
}
};
//**IMPLEMENTATION DETAILS***************************************************
David Fugate
committed
/* Renders the current section into the report window. */
function renderCurrentSection() {
renderBreadcrumbs();
if(globalSection.totalTests === 0) {
$('#resultMessage').show();
} else {
$('#resultMessage').hide();
David Fugate
committed
$('.totalCases').text(currentSection.totalTests);
$('.passedCases').text(currentSection.totalPassed);
$('.failedCases').text(currentSection.totalFailed);
$('#failedToLoadCounterDetails').text(currentSection.totalFailedToLoad);
table.empty();
table.append(currentSection.toHTML());
// Observe section selection and show source links
$('a.section', table).click(sectionSelected);
$('a.showSource', table).click(openSourceWindow);
}
/* Opens a window with a test's source code. */
function openSourceWindow(e) {
var test = tests[e.target.href.match(/#(.+)$/)[1]],
popWnd = window.open("", "", "scrollbars=1, resizable=1"),
innerHTML = '';
David Fugate
committed
innerHTML += '<b>Test </b>';
innerHTML += '<b>' + test.id + '</b> <br /><br />\n';
David Fugate
committed
if (test.description) {
innerHTML += '<b>Description</b>';
innerHTML += '<pre>' +
test.description.replace(/</g, '<').replace(/>/g, '>') +
David Fugate
committed
innerHTML += '<br /><br /><br /><b>Testcase</b>';
innerHTML += '<pre>' + test.code + '</pre>\n';
David Fugate
committed
innerHTML += '<br /><b>Path</b>';
innerHTML += '<pre>' + test.path + '</pre>';
innerHTML += '<br /><a href="javascript:void(window.open(\'https://github.com/tc39/test262/raw/master/test'
innerHTML += test.path.replace("TestCases", "") + '\'));">' + 'GitHub source' + '</a> (might be newer than the testcase source shown above)\n'
David Fugate
committed
popWnd.document.write(innerHTML);
}
/* Opens a window with a test's failure message. */
function openErrorWindow(e) {
var test = tests[e.target.href.match(/#(.+)$/)[1]],
popWnd = window.open("", "", "scrollbars=1, resizable=1"),
innerHTML = '';
var bugDetails = "";
bugDetails += "DESCRIPTION\n*Please insert your description here!*\n\n";
bugDetails += "------------------\n";
bugDetails += "TEST: " + test.path + "\n";
bugDetails += "SOURCE: https://github.com/tc39/test262/raw/master/test" + test.path.replace("TestCases", "") + "\n";
bugDetails += "TEST SUITE DATE: " + date + "\n";
bugDetails += "PLATFORM: " + navigator.userAgent + "\n";
bugDetails += "ERROR: " + test.error + "\n\n";
var bugTemplate = 'https://bugs.ecmascript.org/enter_bug.cgi?product=Test262&bug_severity=normal&component=Tests&short_desc=';
bugTemplate += encodeURIComponent('Invalid test? ' + test.id) + "&comment=";
bugTemplate += encodeURIComponent(bugDetails);
innerHTML += '<b>' + test.id + '</b> <br /><br />\n';
innerHTML += '<pre>' + test.error + '</pre>\n';
innerHTML += '<pre>' + test.code + '</pre>\n';
innerHTML += '<br /><br /><b>Broken test?</b>';
innerHTML += '<p>If you have reason to believe the JavaScript engine being tested<br />\n';
innerHTML += 'is actually OK and there\'s instead something wrong with the test<br />\n';
innerHTML += 'itself, please <a href="' + bugTemplate + '" onclick="window.moveTo(0,0);window.resizeTo(screen.width, screen.height);">file a bug.</a></p>\n'
David Fugate
committed
}
/* Returns the section object for the specified section id
* (eg. "7.1" or "15.4.4.12").
*/
David Fugate
committed
function getSectionById(id) {
if(id == 0)
return globalSection;
var match = id.match(/\d+|[A-F](?=\.)/g);
David Fugate
committed
var section = globalSection;
if (match === null)
return section;
David Fugate
committed
for(var i = 0; i < match.length; i++) {
if(typeof section.subsections[match[i]] !== "undefined") {
section = section.subsections[match[i]];
} else {
break;
David Fugate
committed
}
return section;
}
David Fugate
committed
/* Update the page with current status */
function updateCounts() {
$('#Pass').text(globalSection.totalPassed);
$('#Fail').text(globalSection.totalFailed);
$('#totalCounter').text(globalSection.totalTests);
$('#failedToLoadCounter1').text(globalSection.totalFailedToLoad);
$('#failedToLoadCounter').text(globalSection.totalFailedToLoad);
progressBar.reportprogress(globalSection.totalTests, totalTests);
}
David Fugate
committed
/* Append a result to the run page's result log. */
function logResult(test) {
David Fugate
committed
var appendStr = "";
David Fugate
committed
altStyle = (altStyle !== ' ') ? ' ' : 'alternate';
David Fugate
committed
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
if (test.result==="fail") {
appendStr += '<tbody>';
appendStr += '<tr class=\"' + altStyle + '\">';
appendStr += '<td width=\"20%\">';
appendStr += "<a class='showSource' href='#" + test.id + "'>";
appendStr += test.id + "</a>";
appendStr += '</td>';
appendStr += '<td>' + test.description + '</td>';
appendStr += '<td align="right">';
appendStr += '<span class=\"Fail\">' + "<a class='showError' href='#" + test.id + "'>";
appendStr += 'Fail</a></span></td></tr></tbody>';
}
else if (test.result==="pass") {
if (! isSiteDebugMode()) { return;}
appendStr += '<tbody><tr class=\"' + altStyle + '\"><td width=\"20%\">';
appendStr += "<a class='showSource' href='#" + test.id + "'>";
appendStr += test.id + "</a>" + '</td><td>' + test.description;
appendStr += '</td><td align="right"><span class=\"Fail\">';
appendStr += 'Pass</span></td></tr></tbody>';
}
else {
throw "Result for '" + test.id + "' must either be 'pass' or 'fail', not '" + test.result + "'!";
}
David Fugate
committed
logger.append(appendStr);
logger.parent().attr("scrollTop", logger.parent().attr("scrollHeight"));
}
//*************************************************************************
/* Go back to the previous section */
function goBack(e) {
e.preventDefault();
// Since users click directly on sub-chapters of the main chapters, don't go back to main
// chapters.
if(currentSection.parentSection === globalSection)
currentSection = globalSection;
David Fugate
committed
}
/* Load the table of contents xml to populate the sections. */
function loadSections() {
var sectionsLoader = new XMLHttpRequest();
sectionsLoader.open("GET", TOCFILEPATH, false);
sectionsLoader.send();
var xmlDoc = sectionsLoader.responseXML;
var nodes = xmlDoc.documentElement.childNodes;
/* Recursively parses the TOC xml, producing nested sections. */
function addSectionsFromXML(nodes, parentSection){
var subsection;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].nodeName === "sec") {
subsection = new Section(parentSection, nodes[i].getAttribute('id'), nodes[i].getAttribute('name'));
parentSection.subsections[subsection.id.match(/\d+$|[A-F]$/)] = subsection;
addSectionsFromXML(nodes[i].childNodes, subsection);
}
}
David Fugate
committed
}
/* Renders the breadcrumbs for report navigation. */
function renderBreadcrumbs() {
var container = $('div.crumbContainer div.crumbs');
var sectionChain = [];
David Fugate
committed
// Walk backwards until we reach the global section.
while(current !== globalSection && current.parentSection !== globalSection) {
sectionChain.push(current);
current = current.parentSection;
}
// Reverse the array since we want to print earlier sections first.
sectionChain.reverse();
David Fugate
committed
// Empty any existing breadcrumbs.
container.empty();
David Fugate
committed
// Static first link to go back to the root.
var link = $("<a href='#0' class='setBlack'>Test Sections > </a>");
link.bind('click', {sectionId: 0}, sectionSelected)
container.append(link);
for(var i = 0; i < sectionChain.length;i++) {
link = $("<a href='#" + sectionChain[i].id + "' class='setBlack'>" + sectionChain[i].id + ": " + sectionChain[i].name + " > </a>");
link.bind('click', sectionSelected)
container.append(link);
}
// If we can go back, show the back link.
if(sectionChain.length > 0) {
backLink.show();
David Fugate
committed
} else {
David Fugate
committed
}
/* Pops up a window with an xml dump of the results of a test. */
function createXMLReportWindow() {
var reportWindow; //window that will output the xml data
var xmlData; //array instead of string concatenation
var dateNow;
var xml; // stop condition of for loop stored in a local variable to improve performance
David Fugate
committed
David Fugate
committed
xml = '<testRun>\r\n' +
'<userAgent>' + window.navigator.userAgent + '</userAgent>\r\n' +
'<Date>' + dateNow.toDateString() + '</Date>\r\n' +
'<targetTestSuiteName>ECMAScript Test262 Site</targetTestSuiteName>\r\n' +
'<targetTestSuiteVersion>' + version + '</targetTestSuiteVersion>\r\n' +
'<targetTestSuiteDate>' + date + '</targetTestSuiteDate>\r\n' +
' <Tests>\r\n\r\n';
David Fugate
committed
reportWindow = window.open();
reportWindow.document.writeln("<title>ECMAScript Test262 XML</title>");
reportWindow.document.write("<textarea id='results' style='width: 100%; height: 800px;'>");
reportWindow.document.write(xml);
reportWindow.document.write(globalSection.toXML());
reportWindow.document.write('</Tests>\r\n</testRun>\r\n</textarea>\r\n');
reportWindow.document.close();
David Fugate
committed
}
/* Callback for when the user clicks on a section in the report table. */
function sectionSelected(e) {
e.preventDefault();
currentSection = getSectionById(e.target.href.match(/#(.+)$/)[1]);
renderCurrentSection();
table.attr("scrollTop", 0);
//*************************************************************************
// Load the sections.
loadSections();
David Fugate
committed
var presenter = new Presenter();