tor-browser

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

custom-elements-helpers.js (9697B)


      1 function create_window_in_test(t, srcdoc) {
      2  let p = new Promise((resolve) => {
      3    let f = document.createElement('iframe');
      4    f.srcdoc = srcdoc ? srcdoc : '';
      5    f.onload = (event) => {
      6      let w = f.contentWindow;
      7      t.add_cleanup(() => f.remove());
      8      resolve(w);
      9    };
     10    document.body.appendChild(f);
     11  });
     12  return p;
     13 }
     14 
     15 function create_window_in_test_async(test, mime, doc) {
     16    return new Promise((resolve) => {
     17        let iframe = document.createElement('iframe');
     18        blob = new Blob([doc], {type: mime});
     19        iframe.src = URL.createObjectURL(blob);
     20        iframe.onload = (event) => {
     21            let contentWindow = iframe.contentWindow;
     22            test.add_cleanup(() => iframe.remove());
     23            resolve(contentWindow);
     24        };
     25        document.body.appendChild(iframe);
     26    });
     27 }
     28 
     29 function test_with_window(f, name, srcdoc) {
     30  promise_test((t) => {
     31    return create_window_in_test(t, srcdoc)
     32    .then((w) => {
     33      f(w, w.document);
     34    });
     35  }, name);
     36 }
     37 
     38 function define_custom_element_in_window(window, name, observedAttributes) {
     39    let log = [];
     40 
     41    class CustomElement extends window.HTMLElement {
     42        constructor() {
     43            super();
     44            log.push(create_constructor_log(this));
     45        }
     46        attributeChangedCallback(...args) {
     47            log.push(create_attribute_changed_callback_log(this, ...args));
     48        }
     49        connectedCallback() { log.push(create_connected_callback_log(this)); }
     50        disconnectedCallback() { log.push(create_disconnected_callback_log(this)); }
     51        adoptedCallback(oldDocument, newDocument) { log.push({type: 'adopted', element: this, oldDocument: oldDocument, newDocument: newDocument}); }
     52    }
     53    CustomElement.observedAttributes = observedAttributes;
     54 
     55    window.customElements.define(name, CustomElement);
     56 
     57    return {
     58        name: name,
     59        class: CustomElement,
     60        takeLog: function () {
     61            let currentLog = log; log = [];
     62            currentLog.types = () => currentLog.map((entry) => entry.type);
     63            currentLog.last = () => currentLog[currentLog.length - 1];
     64            return currentLog;
     65        }
     66    };
     67 }
     68 
     69 function create_constructor_log(element) {
     70    return {type: 'constructed', element: element};
     71 }
     72 
     73 function assert_constructor_log_entry(log, element) {
     74    assert_equals(log.type, 'constructed');
     75    assert_equals(log.element, element);
     76 }
     77 
     78 function create_connected_callback_log(element) {
     79    return {type: 'connected', element: element};
     80 }
     81 
     82 function assert_connected_log_entry(log, element) {
     83    assert_equals(log.type, 'connected');
     84    assert_equals(log.element, element);
     85 }
     86 
     87 function create_disconnected_callback_log(element) {
     88    return {type: 'disconnected', element: element};
     89 }
     90 
     91 function assert_disconnected_log_entry(log, element) {
     92    assert_equals(log.type, 'disconnected');
     93    assert_equals(log.element, element);
     94 }
     95 
     96 function assert_adopted_log_entry(log, element) {
     97    assert_equals(log.type, 'adopted');
     98    assert_equals(log.element, element);
     99 }
    100 
    101 function create_adopted_callback_log(element) {
    102    return {type: 'adopted', element: element};
    103 }
    104 
    105 function create_attribute_changed_callback_log(element, name, oldValue, newValue, namespace) {
    106    return {
    107        type: 'attributeChanged',
    108        element: element,
    109        name: name,
    110        namespace: namespace,
    111        oldValue: oldValue,
    112        newValue: newValue,
    113        actualValue: element.getAttributeNS(namespace, name)
    114    };
    115 }
    116 
    117 function assert_attribute_log_entry(log, expected) {
    118    assert_equals(log.type, 'attributeChanged');
    119    assert_equals(log.name, expected.name);
    120    assert_equals(log.oldValue, expected.oldValue);
    121    assert_equals(log.newValue, expected.newValue);
    122    assert_equals(log.actualValue, expected.newValue);
    123    assert_equals(log.namespace, expected.namespace);
    124 }
    125 
    126 
    127 function define_new_custom_element(observedAttributes) {
    128    let log = [];
    129    let name = 'custom-element-' + define_new_custom_element._element_number++;
    130 
    131    class CustomElement extends HTMLElement {
    132        constructor() {
    133            super();
    134            log.push({type: 'constructed', element: this});
    135        }
    136        attributeChangedCallback(...args) {
    137            log.push(create_attribute_changed_callback_log(this, ...args));
    138        }
    139        connectedCallback() { log.push({type: 'connected', element: this}); }
    140        disconnectedCallback() { log.push({type: 'disconnected', element: this}); }
    141        adoptedCallback(oldDocument, newDocument) { log.push({type: 'adopted', element: this, oldDocument: oldDocument, newDocument: newDocument}); }
    142    }
    143    CustomElement.observedAttributes = observedAttributes;
    144 
    145    customElements.define(name, CustomElement);
    146 
    147    return {
    148        name: name,
    149        class: CustomElement,
    150        takeLog: function () {
    151            let currentLog = log; log = [];
    152            currentLog.types = () => currentLog.map((entry) => entry.type);
    153            currentLog.last = () => currentLog[currentLog.length - 1];
    154            return currentLog;
    155        }
    156    };
    157 }
    158 define_new_custom_element._element_number = 1;
    159 
    160 function define_build_in_custom_element(observedAttributes, extendedElement, extendsOption) {
    161    let log = [];
    162    let name = 'custom-element-' + define_build_in_custom_element._element_number++;
    163 
    164    class CustomElement extends extendedElement {
    165        constructor() {
    166            super();
    167            log.push({type: 'constructed', element: this});
    168        }
    169        attributeChangedCallback(...args) {
    170            log.push(create_attribute_changed_callback_log(this, ...args));
    171        }
    172        connectedCallback() { log.push({type: 'connected', element: this}); }
    173        disconnectedCallback() { log.push({type: 'disconnected', element: this}); }
    174        adoptedCallback(oldDocument, newDocument) { log.push({type: 'adopted', element: this, oldDocument: oldDocument, newDocument: newDocument}); }
    175    }
    176    CustomElement.observedAttributes = observedAttributes;
    177    customElements.define(name, CustomElement, { extends: extendsOption});
    178 
    179    return {
    180        name: name,
    181        class: CustomElement,
    182        takeLog: function () {
    183            let currentLog = log; log = [];
    184            currentLog.types = () => currentLog.map((entry) => entry.type);
    185            currentLog.last = () => currentLog[currentLog.length - 1];
    186            return currentLog;
    187        }
    188    };
    189 }
    190 define_build_in_custom_element._element_number = 1;
    191 
    192 function document_types() {
    193    return [
    194        {
    195            name: 'the document',
    196            create: function () { return Promise.resolve(document); },
    197            isOwner: true,
    198            hasBrowsingContext: true,
    199        },
    200        {
    201            name: 'the document of the template elements',
    202            create: function () {
    203                return new Promise(function (resolve) {
    204                    var template = document.createElementNS('http://www.w3.org/1999/xhtml', 'template');
    205                    var doc = template.content.ownerDocument;
    206                    if (!doc.documentElement)
    207                        doc.appendChild(doc.createElement('html'));
    208                    resolve(doc);
    209                });
    210            },
    211            hasBrowsingContext: false,
    212        },
    213        {
    214            name: 'a new document',
    215            create: function () {
    216                return new Promise(function (resolve) {
    217                    var doc = new Document();
    218                    doc.appendChild(doc.createElement('html'));
    219                    resolve(doc);
    220                });
    221            },
    222            hasBrowsingContext: false,
    223        },
    224        {
    225            name: 'a cloned document',
    226            create: function () {
    227                return new Promise(function (resolve) {
    228                    var doc = document.cloneNode(false);
    229                    doc.appendChild(doc.createElement('html'));
    230                    resolve(doc);
    231                });
    232            },
    233            hasBrowsingContext: false,
    234        },
    235        {
    236            name: 'a document created by createHTMLDocument',
    237            create: function () {
    238                return Promise.resolve(document.implementation.createHTMLDocument());
    239            },
    240            hasBrowsingContext: false,
    241        },
    242        {
    243            name: 'an HTML document created by createDocument',
    244            create: function () {
    245                return Promise.resolve(document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null));
    246            },
    247            hasBrowsingContext: false,
    248        },
    249        {
    250            name: 'the document of an iframe',
    251            create: function () {
    252                return new Promise(function (resolve, reject) {
    253                    var iframe = document.createElement('iframe');
    254                    iframe.onload = function () { resolve(iframe.contentDocument); }
    255                    iframe.onerror = function () { reject('Failed to load an empty iframe'); }
    256                    document.body.appendChild(iframe);
    257                });
    258            },
    259            hasBrowsingContext: true,
    260        },
    261        {
    262            name: 'an HTML document fetched by XHR',
    263            create: function () {
    264                return new Promise(function (resolve, reject) {
    265                    var xhr = new XMLHttpRequest();
    266                    xhr.open('GET', 'resources/empty-html-document.html');
    267                    xhr.overrideMimeType('text/xml');
    268                    xhr.onload = function () { resolve(xhr.responseXML); }
    269                    xhr.onerror = function () { reject('Failed to fetch the document'); }
    270                    xhr.send();
    271                });
    272            },
    273            hasBrowsingContext: false,
    274        }
    275    ];
    276 }