Skip to content
Snippets Groups Projects
helper.js 17.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • /// Copyright (c) 2012 Ecma International.  All rights reserved. 
    
    /// This code is governed by the BSD license found in the LICENSE file.
    
    
    /* Handles updating the page with information from the runner. */
    function Presenter() {
        var altStyle = '',
            logger,
            date,
            version,
            table,
            backLink,
    
    
            globalSection = new Section(null, "0", STANDARD),
    
            currentSection = globalSection,
            tests = {},
            totalTests = 0;
    
    
    David Fugate's avatar
    David Fugate committed
        var progressBar;
    
        TOCFILEPATH = "metadata/" + STANDARD.toLowerCase() + "-toc.xml";
    
    David Fugate's avatar
    David Fugate committed
      //**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's avatar
    David Fugate committed
            updateCounts();
    
            //TODO: eventually remove this guard.
    
    David Fugate's avatar
    David Fugate committed
            if(test.result === 'fail') {
                logResult(test);
            }
        }
        
    
        /* Updates the displayed version. */
    
    David Fugate's avatar
    David Fugate committed
        this.setVersion = function(v) {
            version = v;
            $(".targetTestSuiteVersion").text(v);
        }
    
        
        /* Updates the displayed date. */
        this.setDate = function(d) {
    
    David Fugate's avatar
    David Fugate committed
            date = d;
            $(".targetTestSuiteDate").text(d);
        }
    
        
        /* Updates the displayed number of tests to run. */
    
    David Fugate's avatar
    David Fugate committed
        this.setTotalTests = function(tests) {
            totalTests = tests;
            $('#testsToRun').text(tests);
        }
      
    
        /* Write status to the activity bar. */
    
    David Fugate's avatar
    David Fugate committed
        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");
    
            // 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!"); 
    
    David Fugate's avatar
    David Fugate committed
            if (isSiteDebugMode()) {
                this.activityBar.text('Overall Execution Time: ' + elapsed + ' minutes');
            } else {
    
                this.activityBar.text('');
    
    David Fugate's avatar
    David Fugate committed
            }
        }
    
        this.reset = function () {
    
    David Fugate's avatar
    David Fugate committed
            globalSection.reset();
            updateCounts();
    
            this.activityBar.text('');
    
    David Fugate's avatar
    David Fugate committed
            logger.empty();
    
    David Fugate's avatar
    David Fugate committed
            currentSection = globalSection;
            renderCurrentSection();
    
        /* Do some setup tasks. */
    
    David Fugate's avatar
    David Fugate committed
        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***************************************************
    
    
        /* Renders the current section into the report window. */
        function renderCurrentSection() {
            renderBreadcrumbs();
            if(globalSection.totalTests === 0) {
                $('#resultMessage').show();
            } else {
                $('#resultMessage').hide();
    
    
            $('.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 = '';
    
            innerHTML += '<b>' + test.id + '</b> <br /><br />\n';
    
            if (test.description) {
                innerHTML += '<b>Description</b>';
    
                innerHTML += '<pre>' +
                    test.description.replace(/</g, '&lt;').replace(/>/g, '&gt;') +
    
                    ' </pre>\n';
    
            innerHTML += '<br /><br /><br /><b>Testcase</b>';
    
            innerHTML += '<pre>' + test.code + '</pre>\n';
    
            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's avatar
    David Fugate committed
        /* 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&amp;bug_severity=normal&amp;component=Tests&amp;short_desc=';
            bugTemplate += encodeURIComponent('Invalid test? ' + test.id) + "&amp;comment=";
            bugTemplate += encodeURIComponent(bugDetails);
            
    
    David Fugate's avatar
    David Fugate committed
            innerHTML += '<b>Test </b>';
    
            innerHTML += '<b>' + test.id + '</b> <br /><br />\n';
    
    David Fugate's avatar
    David Fugate committed
            innerHTML += '<b>Failure</b>';
    
            innerHTML += '<pre>' + test.error + '</pre>\n';
    
    David Fugate's avatar
    David Fugate committed
            
            innerHTML += '<br /><br /><b>Testcase</b>';
    
            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's avatar
    David Fugate committed
            
            popWnd.document.write(innerHTML);
    
        /* Returns the section object for the specified section id
         * (eg. "7.1" or "15.4.4.12").
         */
    
        function getSectionById(id) {
            if(id == 0)
                return globalSection;
    
            var match = id.match(/\d+|[A-F](?=\.)/g);
    
            for(var i = 0; i < match.length; i++) {
                if(typeof section.subsections[match[i]] !== "undefined") {
                    section = section.subsections[match[i]];
                } else {
                    break;
    
        /* 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);
        }
    
        /* Append a result to the run page's result log. */
        function logResult(test) {
    
            altStyle = (altStyle !== ' ') ? ' ' : 'alternate';
    
            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 + "'!";
            }
        
                
    
            logger.append(appendStr);
            logger.parent().attr("scrollTop", logger.parent().attr("scrollHeight"));
        }
    
    David Fugate's avatar
    David Fugate committed
        
        
        
        //*************************************************************************
        /* Go back to the previous section */
        function goBack(e) {
            e.preventDefault();
    
    David Fugate's avatar
    David Fugate committed
            if(currentSection === globalSection)
                return;
    
    David Fugate's avatar
    David Fugate committed
            currentSection = currentSection.parentSection;
    
    David Fugate's avatar
    David Fugate committed
            // 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's avatar
    David Fugate committed
            renderCurrentSection();
    
    David Fugate's avatar
    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;
    
    David Fugate's avatar
    David Fugate committed
            addSectionsFromXML(nodes, globalSection);
        }
    
    David Fugate's avatar
    David Fugate committed
        /* Recursively parses the TOC xml, producing nested sections. */
        function addSectionsFromXML(nodes, parentSection){
            var subsection;
    
    David Fugate's avatar
    David Fugate committed
            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;
    
    David Fugate's avatar
    David Fugate committed
                    addSectionsFromXML(nodes[i].childNodes, subsection);
                }
            }
    
    David Fugate's avatar
    David Fugate committed
        
        /* Renders the breadcrumbs for report navigation. */
        function renderBreadcrumbs() {
            var container = $('div.crumbContainer div.crumbs');
            var sectionChain = [];
    
    David Fugate's avatar
    David Fugate committed
            var current = currentSection;
    
    David Fugate's avatar
    David Fugate committed
            // Walk backwards until we reach the global section.
            while(current !== globalSection && current.parentSection !== globalSection) {
                sectionChain.push(current);
                current = current.parentSection;
            }
    
    David Fugate's avatar
    David Fugate committed
            // Reverse the array since we want to print earlier sections first.
            sectionChain.reverse();
    
    David Fugate's avatar
    David Fugate committed
            // Empty any existing breadcrumbs.
            container.empty();
    
    David Fugate's avatar
    David Fugate committed
            // Static first link to go back to the root.
            var link = $("<a href='#0' class='setBlack'>Test Sections &gt; </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 + " &gt; </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's avatar
    David Fugate committed
                backLink.hide();
    
    David Fugate's avatar
    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's avatar
    David Fugate committed
            dateNow = new Date();
    
    David Fugate's avatar
    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's avatar
    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's avatar
    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);
    
    David Fugate's avatar
    David Fugate committed
        
        //*************************************************************************
        // Load the sections.
        loadSections();