tor-browser

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

test_bug1499961.html (10870B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <!--
      4 https://bugzilla.mozilla.org/show_bug.cgi?id=1499961
      5 
      6 Some tests ported from IntersectionObserver/polyfill/intersection-observer-test.html
      7 
      8 Original license header:
      9 
     10 Copyright 2016 Google Inc. All Rights Reserved.
     11 Licensed under the Apache License, Version 2.0 (the "License");
     12 you may not use this file except in compliance with the License.
     13 You may obtain a copy of the License at
     14    http://www.apache.org/licenses/LICENSE-2.0
     15 Unless required by applicable law or agreed to in writing, software
     16 distributed under the License is distributed on an "AS IS" BASIS,
     17 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18 See the License for the specific language governing permissions and
     19 limitations under the License.
     20 -->
     21 <head>
     22  <meta charset="utf-8">
     23  <title>Test for Bug 1499961</title>
     24  <script src="/tests/SimpleTest/SimpleTest.js"></script>
     25  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     26 </head>
     27 <body onload="onLoad()">
     28 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1499961">Mozilla Bug 1499961</a>
     29 <p id="display"></p>
     30 <pre id="test">
     31 <script type="application/javascript">
     32  /* eslint-disable no-shadow */
     33  var tests = [];
     34  var curDescribeMsg = '';
     35  var curItMsg = '';
     36 
     37  function beforeEach_fn() { };
     38  function afterEach_fn() { };
     39 
     40  function before(fn) {
     41    fn();
     42  }
     43 
     44  function beforeEach(fn) {
     45    beforeEach_fn = fn;
     46  }
     47 
     48  function afterEach(fn) {
     49    afterEach_fn = fn;
     50  }
     51 
     52  function it(msg, fn) {
     53    tests.push({
     54      msg: `${msg} [${curDescribeMsg}]`,
     55      fn: fn
     56    });
     57  }
     58 
     59  var callbacks = [];
     60  function callDelayed(fn) {
     61    callbacks.push(fn);
     62  }
     63 
     64  requestAnimationFrame(function tick() {
     65    var i = callbacks.length;
     66    while (i--) {
     67      var cb = callbacks[i];
     68      SimpleTest.executeSoon(function() { SimpleTest.executeSoon(cb) });
     69      callbacks.splice(i, 1);
     70    }
     71    requestAnimationFrame(tick);
     72  });
     73 
     74  function expect(val) {
     75    return {
     76      to: {
     77        throwException: function (regexp) {
     78          try {
     79            val();
     80            ok(false, `${curItMsg} - an exception should have beeen thrown`);
     81          } catch (e) {
     82            ok(regexp.test(e), `${curItMsg} - supplied regexp should match thrown exception`);
     83          }
     84        },
     85        get be() {
     86          var fn = function (expected) {
     87            is(val, expected, curItMsg);
     88          };
     89          fn.ok = function () {
     90            ok(val, curItMsg);
     91          };
     92          fn.greaterThan = function (other) {
     93            ok(val > other, `${curItMsg} - ${val} should be greater than ${other}`);
     94          };
     95          fn.lessThan = function (other) {
     96            ok(val < other, `${curItMsg} - ${val} should be less than ${other}`);
     97          };
     98          return fn;
     99        },
    100        eql: function (expected) {
    101          if (Array.isArray(expected)) {
    102            if (!Array.isArray(val)) {
    103              ok(false, curItMsg, `${curItMsg} - should be an array,`);
    104              return;
    105            }
    106            is(val.length, expected.length, curItMsg, `${curItMsg} - arrays should be the same length`);
    107            if (expected.length != val.length) {
    108              return;
    109            }
    110            for (var i = 0; i < expected.length; i++) {
    111              is(val[i], expected[i], `${curItMsg} - array elements at position ${i} should be equal`);
    112              if (expected[i] != val[i]) {
    113                return;
    114              }
    115            }
    116            ok(true);
    117          }
    118        },
    119      }
    120    }
    121  }
    122 
    123  function describe(msg, fn) {
    124    curDescribeMsg = msg;
    125    fn();
    126    curDescribeMsg = '';
    127  }
    128 
    129  function next() {
    130    var test = tests.shift();
    131    if (test) {
    132      console.log(test.msg);
    133      curItMsg = test.msg;
    134      var fn = test.fn;
    135      beforeEach_fn();
    136      if (fn.length) {
    137        fn(function () {
    138          afterEach_fn();
    139          next();
    140        });
    141      } else {
    142        fn();
    143        afterEach_fn();
    144        next();
    145      }
    146    } else {
    147      SimpleTest.finish();
    148    }
    149  }
    150 
    151  var sinon = {
    152    spy: function () {
    153      var callbacks = [];
    154      var fn = function () {
    155        fn.callCount++;
    156        fn.lastCall = { args: arguments };
    157        if (callbacks.length) {
    158          callbacks.shift()();
    159        }
    160      };
    161      fn.callCount = 0;
    162      fn.lastCall = { args: [] };
    163      fn.waitForNotification = (fn) => {
    164        callbacks.push(fn);
    165      };
    166      return fn;
    167    }
    168  };
    169 
    170  var ASYNC_TIMEOUT = 300;
    171 
    172 
    173  var io;
    174  var noop = function() {};
    175 
    176 
    177  // References to DOM elements, which are accessible to any test
    178  // and reset prior to each test so state isn't shared.
    179  var rootEl;
    180  var grandParentEl;
    181  var parentEl;
    182  var targetEl1;
    183  var targetEl2;
    184  var targetEl3;
    185  var targetEl4;
    186  var targetEl5;
    187 
    188 
    189  describe('IntersectionObserver', function() {
    190 
    191    before(function() {
    192 
    193    });
    194 
    195 
    196    beforeEach(function() {
    197      addStyles();
    198      addFixtures();
    199    });
    200 
    201 
    202    afterEach(function() {
    203      if (io && 'disconnect' in io) io.disconnect();
    204      io = null;
    205 
    206      window.onmessage = null;
    207 
    208      removeStyles();
    209      removeFixtures();
    210    });
    211 
    212 
    213    describe('constructor', function() {
    214 
    215      it('move iframe and check reflow', function(done) {
    216 
    217        var spy = sinon.spy();
    218        io = new IntersectionObserver(spy, {root: rootEl});
    219 
    220        runSequence([
    221          // Do a first change and wait for its intersection observer
    222          // notification, to ensure one full reflow was completed.
    223          function(done) {
    224            targetEl1.style.top = '0px';
    225            io.observe(targetEl1);
    226            spy.waitForNotification(function() {
    227              var records = sortRecords(spy.lastCall.args[0]);
    228              expect(records.length).to.be(1);
    229              expect(records[0].target).to.be(targetEl1);
    230              done();
    231            });
    232          },
    233          // Do another change, which may trigger an incremental reflow only.
    234          function(done) {
    235            targetEl4.style.top = '-20px';
    236            targetEl4.style.left = '20px';
    237            io.observe(targetEl4);
    238            spy.waitForNotification(function() {
    239              expect(spy.callCount).to.be(2);
    240              var records = sortRecords(spy.lastCall.args[0]);
    241              expect(records.length).to.be(1);
    242              expect(records[0].target).to.be(targetEl4);
    243              // After the iframe is moved, reflow should include its parent,
    244              // even if the iframe is a reflow root.
    245              // If moved correctly (outside of rootEl), the intersection ratio
    246              // should now be 0.
    247              expect(records[0].intersectionRatio).to.be(0);
    248              done();
    249            });
    250          }
    251        ], done);
    252 
    253      });
    254 
    255    });
    256 
    257  });
    258 
    259 
    260  /**
    261   * Runs a sequence of function and when finished invokes the done callback.
    262   * Each function in the sequence is invoked with its own done function and
    263   * it should call that function once it's complete.
    264   *
    265   * @param {Array<Function>} functions An array of async functions.
    266   * @param {Function} done A final callback to be invoked once all function
    267   *     have run.
    268   */
    269  function runSequence(functions, done) {
    270    var next = functions.shift();
    271    if (next) {
    272      next(function() {
    273        runSequence(functions, done);
    274      });
    275    } else {
    276      done && done();
    277    }
    278  }
    279 
    280 
    281  /**
    282   * Sorts an array of records alphebetically by ascending ID. Since the current
    283   * native implementation doesn't sort change entries by `observe` order, we do
    284   * that ourselves for the non-polyfill case. Since all tests call observe
    285   * on targets in sequential order, this should always match.
    286   * https://crbug.com/613679
    287   *
    288   * @param {Array<IntersectionObserverEntry>} entries The entries to sort.
    289   * @return {Array<IntersectionObserverEntry>} The sorted array.
    290   */
    291  function sortRecords(entries) {
    292    entries = entries.sort(function(a, b) {
    293      return a.target.id < b.target.id ? -1 : 1;
    294    });
    295    return entries;
    296  }
    297 
    298 
    299  /**
    300   * Adds the common styles used by all tests to the page.
    301   */
    302  function addStyles() {
    303    var styles = document.createElement('style');
    304    styles.id = 'styles';
    305    document.documentElement.appendChild(styles);
    306 
    307    var cssText =
    308        '#root {' +
    309        '  position: relative;' +
    310        '  width: 400px;' +
    311        '  height: 200px;' +
    312        '  background: #eee' +
    313        '}' +
    314        '#grand-parent {' +
    315        '  position: relative;' +
    316        '  width: 200px;' +
    317        '  height: 200px;' +
    318        '}' +
    319        '#parent {' +
    320        '  position: absolute;' +
    321        '  top: 0px;' +
    322        '  left: 200px;' +
    323        '  overflow: hidden;' +
    324        '  width: 200px;' +
    325        '  height: 200px;' +
    326        '  background: #ddd;' +
    327        '}' +
    328        '#target1, #target2, #target3, #target4 {' +
    329        '  position: absolute;' +
    330        '  top: 0px;' +
    331        '  left: 0px;' +
    332        '  width: 20px;' +
    333        '  height: 20px;' +
    334        '  transform: translateX(0px) translateY(0px);' +
    335        '  transition: transform .5s;' +
    336        '  background: #f00;' +
    337        '  border: none;' +
    338        '}';
    339 
    340    styles.innerHTML = cssText;
    341  }
    342 
    343 
    344  /**
    345   * Adds the DOM fixtures used by all tests to the page and assigns them to
    346   * global variables so they can be referenced within the tests.
    347   */
    348  function addFixtures() {
    349    var fixtures = document.createElement('div');
    350    fixtures.id = 'fixtures';
    351 
    352    fixtures.innerHTML =
    353        '<div id="root">' +
    354        '  <div id="grand-parent">' +
    355        '    <div id="parent">' +
    356        '      <div id="target1"></div>' +
    357        '      <div id="target2"></div>' +
    358        '      <div id="target3"></div>' +
    359        '      <iframe id="target4"></iframe>' +
    360        '    </div>' +
    361        '  </div>' +
    362        '</div>';
    363 
    364    document.body.appendChild(fixtures);
    365 
    366    rootEl = document.getElementById('root');
    367    grandParentEl = document.getElementById('grand-parent');
    368    parentEl = document.getElementById('parent');
    369    targetEl1 = document.getElementById('target1');
    370    targetEl2 = document.getElementById('target2');
    371    targetEl3 = document.getElementById('target3');
    372    targetEl4 = document.getElementById('target4');
    373  }
    374 
    375 
    376  /**
    377   * Removes the common styles from the page.
    378   */
    379  function removeStyles() {
    380    var styles = document.getElementById('styles');
    381    styles.remove();
    382  }
    383 
    384 
    385  /**
    386   * Removes the DOM fixtures from the page and resets the global references.
    387   */
    388  function removeFixtures() {
    389    var fixtures = document.getElementById('fixtures');
    390    fixtures.remove();
    391 
    392    rootEl = null;
    393    grandParentEl = null;
    394    parentEl = null;
    395    targetEl1 = null;
    396    targetEl2 = null;
    397    targetEl3 = null;
    398    targetEl4 = null;
    399  }
    400 
    401  function onLoad() {
    402    next();
    403  }
    404 
    405  SimpleTest.waitForExplicitFinish();
    406 </script>
    407 </pre>
    408 <div id="log">
    409 </div>
    410 </body>
    411 </html>