tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

runParallelAsyncHarness.js (5349B)


      1 (function(root){
      2 'use strict';
      3 // testharness doesn't know about async test queues,
      4 // so this wrapper takes care of that
      5 
      6 /* USAGE:
      7    runParallelAsyncHarness({
      8        // list of data to test, must be array of objects.
      9        // each object must contain a "name" property to describe the test
     10        // besides name, the object can contain whatever data you need
     11        tests: [
     12            {name: "name of test 1", custom: "data"},
     13            {name: "name of test 2", custom: "data"},
     14            // ...
     15        ],
     16 
     17        // number of tests (tests, not test-cases!) to run concurrently
     18        testsPerSlice: 100,
     19 
     20        // time in milliseconds a test-run takes
     21        duration: 1000,
     22 
     23        // test-cases to run for for the test - there must be at least one
     24        // each case creates its separate async_test() instance
     25        cases: {
     26            // test case named "test1"
     27            test1: {
     28                // run as a async_test.step() this callback contains your primary assertions
     29                start: function(testCaseKey, data, options){},
     30                // run as a async_test.step() this callback contains assertions to be run
     31                // when the test ended, immediately before teardown
     32                done: function(testCaseKey, data, options){}
     33            },
     34            // ...
     35        }
     36 
     37        // all callbacks are optional:
     38 
     39        // invoked for individual test before it starts so you can setup the environment
     40        // like DOM, CSS, adding event listeners and such
     41        setup: function(data, options){},
     42 
     43        // invoked after a test ended, so you can clean up the environment
     44        // like DOM, CSS, removing event listeners and such
     45        teardown: function(data, options){},
     46 
     47        // invoked before a batch of tests ("slice") are run concurrently
     48        // tests is an array of test data objects
     49        sliceStart: function(options, tests)
     50 
     51        // invoked after a batch of tests ("slice") were run concurrently
     52        // tests is an array of test data objects
     53        sliceDone: function(options, tests)
     54 
     55        // invoked once all tests are done
     56        done: function(options){}
     57    })
     58 */
     59 
     60 function DomContentLoadedPromise() {
     61    return new Promise(resolve => {
     62        document.addEventListener("DOMContentLoaded", (event) => {
     63            resolve();
     64        });
     65    });
     66 }
     67 
     68 root.runParallelAsyncHarness = async function(options) {
     69    const ready = DomContentLoadedPromise();
     70 
     71    if (!options.cases) {
     72        throw new Error("Options don't contain test cases!");
     73    }
     74 
     75    var noop = function(){};
     76 
     77    // names of individual tests
     78    var cases = Object.keys(options.cases);
     79 
     80    // run tests in a batch of slices
     81    // primarily not to overload weak devices (tablets, phones, …)
     82    // with too many tests running simultaneously
     83    var iteration = -1;
     84    var testPerSlice = options.testsPerSlice || 100;
     85    var slices = Math.ceil(options.tests.length / testPerSlice);
     86 
     87    // initialize all async test cases
     88    // Note: satisfying testharness.js needs to know all async tests before load-event
     89    options.tests.forEach(function(data, index) {
     90        data.cases = {};
     91        cases.forEach(function(name) {
     92            data.cases[name] = async_test(data.name + " / " + name);
     93        });
     94    });
     95 
     96    function runLoop() {
     97        iteration++;
     98        if (iteration >= slices) {
     99            // no more slice, we're done
    100            (options.done || noop)(options);
    101            return;
    102        }
    103 
    104        // grab a slice of testss and initialize them
    105        var offset = iteration * testPerSlice;
    106        var tests = options.tests.slice(offset, offset + testPerSlice);
    107        tests.forEach(function(data) {
    108            (options.setup || noop)(data, options);
    109        });
    110 
    111        // kick off the current slice of tests
    112        (options.sliceStart || noop)(options, tests);
    113 
    114        // perform individual "start" test-case
    115        tests.forEach(function(data) {
    116            cases.forEach(function(name) {
    117                data.cases[name].step(function() {
    118                    (options.cases[name].start || noop)(data.cases[name], data, options);
    119                });
    120            });
    121        });
    122 
    123        // Start sampling.
    124        (options.transitionsStarted || noop)(options, tests);
    125 
    126        // conclude slice (possibly abort)
    127        var concludeSlice = function() {
    128            tests.forEach(function(data) {
    129                // perform individual "done" test-case
    130                cases.forEach(function(name) {
    131                    data.cases[name].step(function() {
    132                        (options.cases[name].done || noop)(data.cases[name], data, options);
    133                    });
    134                });
    135                // clean up after individual test
    136                (options.teardown || noop)(data, options);
    137                // tell harness we're done with individual test-cases
    138                cases.forEach(function(name) {
    139                    data.cases[name].done();
    140                });
    141            });
    142 
    143            // finish the test for current slice of tests
    144            (options.sliceDone || noop)(options, tests);
    145 
    146            requestAnimationFrame(runLoop);
    147        }
    148 
    149        options.allTransitionsCompleted = concludeSlice;
    150    }
    151 
    152    // allow DOMContentLoaded before actually doing something
    153    ready.then(runLoop);
    154 };
    155 
    156 })(window);