Bug 1851372 [wpt PR 41785] - HTML: search setter always uses UTF-8, a=testonly
[gecko.git] / testing / web-platform / tests / html / infrastructure / urls / resolving-urls / query-encoding / resources / resolve-url.js
blobcda98fb021319f5723f62c9938cd759cdc5efec6
1 // NOTE: this file needs to be split up rather than expanded. See ../location.sub.html for some
2 // extracted tests. Tracked by https://github.com/web-platform-tests/wpt/issues/4934.
4 /*
5 * help:
6 *   https://html.spec.whatwg.org/multipage/#the-link-element
7 *   https://html.spec.whatwg.org/multipage/#styling
8 *   https://html.spec.whatwg.org/multipage/#prepare-a-script
9 *   https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm
10 *   https://html.spec.whatwg.org/multipage/#track-url
11 *   https://html.spec.whatwg.org/multipage/#concept-form-submit
12 *   https://html.spec.whatwg.org/multipage/#set-the-frozen-base-url
13 *   https://dom.spec.whatwg.org/#dom-node-baseuri
14 *   https://html.spec.whatwg.org/multipage/#the-a-element
15 *   https://html.spec.whatwg.org/multipage/#dom-worker
16 *   https://html.spec.whatwg.org/multipage/#dom-sharedworker
17 *   https://html.spec.whatwg.org/multipage/#dom-eventsource
18 *   https://html.spec.whatwg.org/multipage/#dom-xmldocument-load
19 *   https://html.spec.whatwg.org/multipage/#dom-open
20 *   http://url.spec.whatwg.org/#dom-url-search
21 *   https://www.w3.org/Bugs/Public/show_bug.cgi?id=24148
22 *   https://xhr.spec.whatwg.org/#the-open()-method
23 *   https://html.spec.whatwg.org/multipage/#set-up-a-worker-script-settings-object
24 *   https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-importscripts
25 *   https://html.spec.whatwg.org/multipage/#parse-a-websocket-url's-components
26 *   https://html.spec.whatwg.org/multipage/#dom-websocket-url
27 *   https://www.w3.org/Bugs/Public/show_bug.cgi?id=23968
28 *   http://dev.w3.org/csswg/cssom/#requirements-on-user-agents-implementing-the-xml-stylesheet-processing-instruction
29 *   http://url.spec.whatwg.org/#dom-url
31 setup({explicit_done:true});
32 onload = function() {
33   var encoding = '{{GET[encoding]}}';
34   var input_url = 'resources/resource.py?q=\u00E5&encoding=' + encoding + '&type=';
35   ('html css js worker sharedworker worker_importScripts sharedworker_importScripts worker_worker worker_sharedworker sharedworker_worker '+
36    'sharedworker_sharedworker eventstream png svg xmlstylesheet_css video webvtt').split(' ').forEach(function(str) {
37     window['input_url_'+str] = input_url + str;
38   });
39   var blank = 'resources/blank.py?encoding=' + encoding;
40   var stash_put = 'resources/stash.py?q=\u00E5&action=put&id=';
41   var stash_take = 'resources/stash.py?action=take&id=';
42   var expected_obj = {
43     'utf-8':'%C3%A5',
44     'utf-16be':'%C3%A5',
45     'utf-16le':'%C3%A5',
46     'windows-1252':'%E5',
47     'windows-1251':'%26%23229%3B'
48   };
49   var expected_current = expected_obj[encoding];
50   var expected_utf8 = expected_obj['utf-8'];
52   function msg(expected, got) {
53     return 'expected substring '+expected+' got '+got;
54   }
56   function poll_for_stash(test_obj, uuid, expected) {
57     var start = new Date();
58     var poll = test_obj.step_func(function () {
59       var xhr = new XMLHttpRequest();
60       xhr.open('GET', stash_take + uuid);
61       xhr.onload = test_obj.step_func(function(e) {
62         if (xhr.response == "") {
63           if (new Date() - start > 10000) {
64             // If we set the status to TIMEOUT here we avoid a race between the
65             // page and the test timing out
66             test_obj.force_timeout();
67           }
68           test_obj.step_timeout(poll, 200);
69         } else {
70           assert_equals(xhr.response, expected);
71           test_obj.done();
72         }
73       });
74       xhr.send();
75     })
76     test_obj.step_timeout(poll, 200);
77   }
79   // loading html (or actually svg to support <embed>)
80   function test_load_nested_browsing_context(tag, attr, spec_url) {
81     subsetTestByKey('nested-browsing', async_test, function() {
82       var id = 'test_load_nested_browsing_context_'+tag;
83       var elm = document.createElement(tag);
84       elm.setAttribute(attr, input_url_svg);
85       elm.name = id;
86       document.body.appendChild(elm);
87       this.add_cleanup(function() {
88         document.body.removeChild(elm);
89       });
90       elm.onload = this.step_func_done(function() {
91         assert_equals(window[id].document.documentElement.textContent, expected_current);
92       });
94     }, 'load nested browsing context <'+tag+' '+attr+'>');
95   }
97   spec_url_load_nested_browsing_context = {
98     frame:'https://html.spec.whatwg.org/multipage/#process-the-frame-attributes',
99     iframe:'https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes',
100     object:'https://html.spec.whatwg.org/multipage/#the-object-element',
101     embed:'https://html.spec.whatwg.org/multipage/#the-embed-element-setup-steps'
102   };
104   'frame src, iframe src, object data, embed src'.split(', ').forEach(function(str) {
105     var arr = str.split(' ');
106     test_load_nested_browsing_context(arr[0], arr[1], spec_url_load_nested_browsing_context[arr[0]]);
107   });
109   // loading css with <link>
110   subsetTestByKey('loading', async_test, function() {
111     var elm = document.createElement('link');
112     elm.href = input_url_css;
113     elm.rel = 'stylesheet';
114     document.head.appendChild(elm);
115     this.add_cleanup(function() {
116       document.head.removeChild(elm);
117     });
118     elm.onload = this.step_func_done(function() {
119       var got = elm.sheet.href;
120       assert_true(elm.sheet.href.indexOf(expected_current) > -1, 'sheet.href ' + msg(expected_current, got));
121       assert_equals(elm.sheet.cssRules[0].style.content, '"'+expected_current+'"', 'sheet.cssRules[0].style.content');
122     });
123   }, 'loading css <link>');
125   // loading js
126   subsetTestByKey('loading-css', async_test, function() {
127     var elm = document.createElement('script');
128     elm.src = input_url_js + '&var=test_load_js_got';
129     document.head.appendChild(elm); // no cleanup
130     elm.onload = this.step_func_done(function() {
131       assert_equals(window.test_load_js_got, expected_current);
132     });
133   }, 'loading js <script>');
135   // loading image
136   function test_load_image(tag, attr, spec_url) {
137     subsetTestByKey('loading', async_test, function() {
138       var elm = document.createElement(tag);
139       if (tag == 'input') {
140         elm.type = 'image';
141       }
142       elm.setAttribute(attr, input_url_png);
143       document.body.appendChild(elm);
144       this.add_cleanup(function() {
145         document.body.removeChild(elm);
146       });
147       elm.onload = this.step_func_done(function() {
148         var got = elm.offsetWidth;
149         assert_equals(got, query_to_image_width[expected_current], msg(expected_current, image_width_to_query[got]));
150       });
151       // <video poster> doesn't notify when the image is loaded so we need to poll :-(
152       var interval;
153       var check_video_width = function() {
154         var width = elm.offsetWidth;
155         if (width != 300 && width != 0) {
156           clearInterval(interval);
157           elm.onload();
158         }
159       }
160       if (tag == 'video') {
161         interval = setInterval(check_video_width, 10);
162       }
163     }, 'loading image <'+tag+' '+attr+'>');
164   }
166   var query_to_image_width = {
167     '%E5':1,
168     '%C3%A5':2,
169     '%3F':16,
170     'unknown query':256,
171     'default intrinsic width':300
172   };
174   var image_width_to_query = {};
175   (function() {
176     for (var x in query_to_image_width) {
177       image_width_to_query[query_to_image_width[x]] = x;
178     }
179   })();
181   var spec_url_load_image = {
182     img:'https://html.spec.whatwg.org/multipage/#update-the-image-data',
183     embed:'https://html.spec.whatwg.org/multipage/#the-embed-element-setup-steps',
184     object:'https://html.spec.whatwg.org/multipage/#the-object-element',
185     input:'https://html.spec.whatwg.org/multipage/#image-button-state-(type=image)',
186     video:'https://html.spec.whatwg.org/multipage/#poster-frame'
187   };
189   'img src, embed src, object data, input src, video poster'.split(', ').forEach(function(str) {
190     var arr = str.split(' ');
191     test_load_image(arr[0], arr[1], spec_url_load_image[arr[0]]);
192   });
194   // XXX test <img srcset> or its successor
196   // loading video
197   function test_load_video(tag, use_source_element) {
198     subsetTestByKey('loading', async_test, function() {
199       var elm = document.createElement(tag);
200       var video_ext = '';
201       if (elm.canPlayType('video/ogg; codecs="theora,flac"')) {
202         video_ext = 'ogv';
203       } else if (elm.canPlayType('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')) {
204         video_ext = 'mp4';
205       }
206       assert_not_equals(video_ext, '', 'no supported video format');
207       var source;
208       if (use_source_element) {
209         source = document.createElement('source');
210         elm.appendChild(source);
211       } else {
212         source = elm;
213       }
214       source.src = input_url_video + '&ext=' + video_ext;
215       elm.preload = 'auto';
216       elm.load();
217       this.add_cleanup(function() {
218         elm.removeAttribute('src');
219         if (elm.firstChild) {
220           elm.removeChild(elm.firstChild);
221         }
222         elm.load();
223       });
224       elm.onloadedmetadata = this.step_func_done(function() {
225         var got = Math.round(elm.duration);
226         assert_equals(got, query_to_video_duration[expected_current], msg(expected_current, video_duration_to_query[got]));
227       });
228     }, 'loading video <'+tag+'>' + (use_source_element ? '<source>' : ''));
229   }
231   var query_to_video_duration = {
232     '%E5':3,
233     '%C3%A5':5,
234     '%3F':30,
235     'unknown query':300,
236     'Infinity':Infinity,
237     'NaN':NaN
238   };
240   var video_duration_to_query = {};
241   (function() {
242     for (var x in query_to_video_duration) {
243       video_duration_to_query[query_to_video_duration[x]] = x;
244     }
245   })();
247   'video, audio'.split(', ').forEach(function(str) {
248     test_load_video(str);
249     test_load_video(str, true);
250   });
252   // loading webvtt
253   subsetTestByKey('loading', async_test, function() {
254     var video = document.createElement('video');
255     var track = document.createElement('track');
256     video.appendChild(track);
257     track.src = input_url_webvtt;
258     track.track.mode = 'showing';
259     track.onload = this.step_func_done(function() {
260       var got = track.track.cues[0].text;
261       assert_equals(got, expected_current);
262     });
263   }, 'loading webvtt <track>');
265   // XXX downloading seems hard to automate
266   // <a href download>
267   // <area href download>
269   // submit forms
270   function test_submit_form(tag, attr) {
271     subsetTestByKey('submit', async_test, function(){
272       var elm = document.createElement(tag);
273       elm.setAttribute(attr, input_url_html);
274       var form;
275       var button;
276       if (tag == 'form') {
277         form = elm;
278         button = document.createElement('button');
279       } else {
280         form = document.createElement('form');
281         button = elm;
282       }
283       form.method = 'post';
284       form.appendChild(button);
285       var iframe = document.createElement('iframe');
286       var id = 'test_submit_form_' + tag;
287       iframe.name = id;
288       form.target = id;
289       button.type = 'submit';
290       document.body.appendChild(form);
291       document.body.appendChild(iframe);
292       this.add_cleanup(function() {
293         document.body.removeChild(form);
294         document.body.removeChild(iframe);
295       });
296       button.click();
297       iframe.onload = this.step_func_done(function() {
298         var got = iframe.contentDocument.body.textContent;
299         if (got == '') {
300           return;
301         }
302         assert_equals(got, expected_current);
303       });
304     }, 'submit form <'+tag+' '+attr+'>');
305   }
307   'form action, input formaction, button formaction'.split(', ').forEach(function(str) {
308     var arr = str.split(' ');
309     test_submit_form(arr[0], arr[1]);
310   });
312   // <base href>
313   subsetTestByKey('base-href', async_test, function() {
314     var iframe = document.createElement('iframe');
315     iframe.src = blank;
316     document.body.appendChild(iframe);
317     this.add_cleanup(function() {
318       document.body.removeChild(iframe);
319     });
320     iframe.onload = this.step_func_done(function() {
321       var doc = iframe.contentDocument;
322       doc.write('<!doctype html><base href="'+input_url+'"><a href></a>');
323       doc.close();
324       var got_baseURI = doc.baseURI;
325       assert_true(got_baseURI.indexOf(expected_current) > -1, msg(expected_current, got_baseURI), 'doc.baseURI');
326       var got_a_href = doc.links[0].href;
327       assert_true(got_a_href.indexOf(expected_current) > -1, msg(expected_current, got_a_href), 'a.href');
328     });
329   }, '<base href>');
331   // XXX drag and drop (<a href> or <img src>) seems hard to automate
333   // Worker()
334   subsetTestByKey('workers', async_test, function() {
335     var worker = new Worker(input_url_worker);
336     worker.onmessage = this.step_func_done(function(e) {
337       assert_equals(e.data, expected_current);
338     });
339   }, 'Worker constructor');
341   // SharedWorker()
342   subsetTestByKey('workers', async_test, function() {
343     var worker = new SharedWorker(input_url_sharedworker);
344     worker.port.onmessage = this.step_func_done(function(e) {
345       assert_equals(e.data, expected_current);
346     });
347   }, 'SharedWorker constructor');
349   // EventSource()
350   subsetTestByKey('eventsource', async_test, function() {
351     var source = new EventSource(input_url_eventstream);
352     this.add_cleanup(function() {
353       source.close();
354     });
355     source.onmessage = this.step_func_done(function(e) {
356       assert_equals(e.data, expected_current);
357     });
358   }, 'EventSource constructor');
360   // EventSource#url
361   subsetTestByKey('eventsource', test, function() {
362     var source = new EventSource(input_url_eventstream);
363     source.close();
364     var got = source.url;
365     assert_true(source.url.indexOf(expected_current) > -1, msg(expected_current, got));
366   }, 'EventSource#url');
368   // window.open
369   subsetTestByKey('window-open', async_test, function() {
370     var id = 'test_window_open';
371     var iframe = document.createElement('iframe');
372     iframe.name = id;
373     document.body.appendChild(iframe);
374     this.add_cleanup(function() {
375       document.body.removeChild(iframe);
376     });
377     window.open(input_url_html, id);
378     iframe.onload = this.step_func(function() {
379       var got = iframe.contentDocument.body.textContent;
380       if (got != "") {
381         assert_equals(got, expected_current);
382         this.done();
383       }
384     });
385   }, 'window.open()');
387   // a.search, area.search
388   function test_hyperlink_search(tag) {
389     subsetTestByKey('hyperlink-search', test, function() {
390       var elm = document.createElement(tag);
391       var input_arr = input_url_html.split('?');
392       elm.href = input_arr[0];
393       elm.search = '?' + input_arr[1];
394       var got_href = elm.getAttribute('href');
395       assert_true(got_href.indexOf(expected_utf8) > -1, 'href content attribute ' + msg(expected_utf8, got_href));
396       var got_search = elm.search;
397       assert_true(got_search.indexOf(expected_utf8) > -1, 'getting .search '+msg(expected_utf8, got_search));
398     }, '<'+tag+'>.search');
399   }
400   'a, area'.split(', ').forEach(function(str) {
401     test_hyperlink_search(str);
402   });
404   // history.pushState
405   // history.replaceState
406   function test_history(prop) {
407     subsetTestByKey('history', async_test, function() {
408       var iframe = document.createElement('iframe');
409       iframe.src = blank;
410       document.body.appendChild(iframe);
411       this.add_cleanup(function() {
412         document.body.removeChild(iframe);
413       });
414       iframe.onload = this.step_func_done(function() {
415         iframe.contentWindow.history[prop](null, null, input_url_html); // this should resolve against the test's URL, not the iframe's URL
416         var got = iframe.contentWindow.location.href;
417         assert_true(got.indexOf(expected_current) > -1, msg(expected_current, got));
418         assert_equals(got.indexOf('/resources/resources/'), -1, 'url was resolved against the iframe\'s URL instead of the settings object\'s API base URL');
419       });
420     }, 'history.'+prop);
421   }
423   'pushState, replaceState'.split(', ').forEach(function(str) {
424     test_history(str);
425   });
427   // SVG
428   var ns = {svg:'http://www.w3.org/2000/svg', xlink:'http://www.w3.org/1999/xlink'};
429   // a
430   subsetTestByKey('svg', async_test, function() {
431     SVGAElement; // check support
432     var iframe = document.createElement('iframe');
433     var id = 'test_svg_a';
434     iframe.name = id;
435     var svg = document.createElementNS(ns.svg, 'svg');
436     var a = document.createElementNS(ns.svg, 'a');
437     a.setAttributeNS(ns.xlink, 'xlink:href', input_url_html);
438     a.setAttribute('target', id);
439     var span = document.createElement('span');
440     a.appendChild(span);
441     svg.appendChild(a);
442     document.body.appendChild(iframe);
443     document.body.appendChild(svg);
444     this.add_cleanup(function() {
445       document.body.removeChild(iframe);
446       document.body.removeChild(svg);
447     });
448     span.click();
449     iframe.onload = this.step_func_done(function() {
450       var got = iframe.contentDocument.body.textContent;
451       if (got != '') {
452         assert_equals(got, expected_current);
453       }
454     });
455   }, 'SVG <a>');
457   // feImage, image, use
458   function test_svg(func, tag) {
459     subsetTestByKey('svg', async_test, function() {
460       var uuid = token();
461       var id = 'test_svg_'+tag;
462       var svg = document.createElementNS(ns.svg, 'svg');
463       var parent = func(svg, id);
464       var elm = document.createElementNS(ns.svg, tag);
465       elm.setAttributeNS(ns.xlink, 'xlink:href', stash_put + uuid + '#foo');
466       parent.appendChild(elm);
467       document.body.appendChild(svg);
468       this.add_cleanup(function() {
469         document.body.removeChild(svg);
470       });
471       poll_for_stash(this, uuid, expected_current);
472     }, 'SVG <' + tag + '>');
473   }
475   [[function(svg, id) {
476       SVGFEImageElement; // check support
477       var filter = document.createElementNS(ns.svg, 'filter');
478       filter.setAttribute('id', id);
479       svg.appendChild(filter);
480       var rect = document.createElementNS(ns.svg, 'rect');
481       rect.setAttribute('filter', 'url(#'+id+')');
482       svg.appendChild(rect);
483       return filter;
484     }, 'feImage'],
485    [function(svg, id) { SVGImageElement; return svg; }, 'image'],
486    [function(svg, id) { SVGUseElement; return svg; }, 'use']].forEach(function(arr) {
487     test_svg(arr[0], arr[1]);
488   });
490   // UTF-8:
491   // XHR
492   subsetTestByKey('xhr', async_test, function() {
493     var xhr = new XMLHttpRequest();
494     xhr.open('GET', input_url_html);
495     xhr.onload = this.step_func_done(function() {
496       assert_equals(xhr.response, expected_utf8);
497     });
498     xhr.send();
499   }, 'XMLHttpRequest#open()');
501   // in a worker
502   subsetTestByKey('workers', async_test, function() {
503     var worker = new Worker(input_url_worker_importScripts);
504     worker.onmessage = this.step_func_done(function(e) {
505       assert_equals(e.data, expected_utf8);
506     });
507   }, 'importScripts() in a dedicated worker');
509   subsetTestByKey('workers', async_test, function() {
510     var worker = new Worker(input_url_worker_worker);
511     worker.onmessage = this.step_func_done(function(e) {
512       assert_equals(e.data, expected_utf8);
513     });
514   }, 'Worker() in a dedicated worker');
516   subsetTestByKey('workers', async_test, function() {
517     var worker = new SharedWorker(input_url_sharedworker_importScripts);
518     worker.port.onmessage = this.step_func_done(function(e) {
519       assert_equals(e.data, expected_utf8);
520     });
521   }, 'importScripts() in a shared worker');
523   subsetTestByKey('workers', async_test, function() {
524     var worker = new SharedWorker(input_url_sharedworker_worker);
525     worker.port.onmessage = this.step_func_done(function(e) {
526       assert_equals(e.data, expected_utf8);
527     });
528   }, 'Worker() in a shared worker');
530   // WebSocket()
531   subsetTestByKey('websocket', async_test, function() {
532     var ws = new WebSocket('ws://{{host}}:{{ports[ws][0]}}/echo-query?\u00E5');
533     this.add_cleanup(function() {
534       ws.close();
535     });
536     ws.onmessage = this.step_func_done(function(e) {
537       assert_equals(e.data, expected_utf8);
538     });
539   }, 'WebSocket constructor');
541   // WebSocket#url
542   subsetTestByKey('websocket', test, function() {
543     var ws = new WebSocket('ws://{{host}}:{{ports[ws][0]}}/echo-query?\u00E5');
544     ws.close();
545     var got = ws.url;
546     assert_true(ws.url.indexOf(expected_utf8) > -1, msg(expected_utf8, got));
547   }, 'WebSocket#url');
549   // CSS
550   function test_css(tmpl, expected_cssom, encoding, use_style_element) {
551     var desc = ['CSS', (use_style_element ? '<style>' : '<link> (' + encoding + ')'),  tmpl].join(' ');
552     subsetTestByKey('css', async_test, function(){
553       css_is_supported(tmpl, expected_cssom, this);
554       var uuid = token();
555       var id = 'test_css_' + uuid;
556       var url = 'url(stash.py?q=%s&action=put&id=' + uuid + ')';
557       tmpl = tmpl.replace(/<id>/g, id).replace(/<url>/g, url);
558       var link;
559       if (use_style_element) {
560         link = document.createElement('style');
561         link.textContent = tmpl.replace(/%s/g, '\u00E5').replace(/stash\.py/g, 'resources/stash.py');
562       } else {
563         link = document.createElement('link');
564         link.rel = 'stylesheet';
565         link.href = 'resources/css-tmpl.py?encoding='+encoding+'&tmpl='+encodeURIComponent(tmpl);
566       }
567       var div = document.createElement('div');
568       div.id = id;
569       div.textContent='x';
570       document.head.appendChild(link);
571       document.body.appendChild(div);
572       this.add_cleanup(function() {
573         document.head.removeChild(link);
574         document.body.removeChild(div);
575       });
576       poll_for_stash(this, uuid, expected_utf8);
577     }, desc);
578   }
580   // fail fast if the input doesn't parse into the expected cssom
581   function css_is_supported(tmpl, expected_cssom, test_obj) {
582     if (expected_cssom === null) {
583       return;
584     }
585     var style = document.createElement('style');
586     style.textContent = tmpl.replace(/<id>/g, 'x').replace(/<url>/g, 'url(data:,)');
587     document.head.appendChild(style);
588     test_obj.add_cleanup(function() {
589       document.head.removeChild(style);
590     });
591     assert_equals(style.sheet.cssRules.length, expected_cssom.length, 'number of style rules');
592     for (var i = 0; i < expected_cssom.length; ++i) {
593       if (expected_cssom[i] === null) {
594         continue;
595       }
596       assert_equals(style.sheet.cssRules[i].style.length, expected_cssom[i], 'number of declarations in style rule #'+i);
597     }
598   }
600   [['#<id> { background-image:<url> }', [1] ],
601    ['#<id> { border-image-source:<url> }', [1] ],
602    ['#<id>::before { content:<url> }', [1] ],
603    ['@font-face { font-family:<id>; src:<url> } #<id> { font-family:<id> }', [null, 1] ],
604    ['#<id> { display:list-item; list-style-image:<url> }', [2] ],
605    ['@import <url>;', null ],
606    // XXX maybe cursor isn't suitable for automation here if browsers delay fetching it
607    ['#<id> { cursor:<url>, pointer }', [1] ]].forEach(function(arr) {
608     var input = arr[0];
609     var expected_cssom = arr[1];
610     var other_encoding = encoding == 'utf-8' ? 'windows-1252' : 'utf-8';
611     test_css(input, expected_cssom, encoding);
612     test_css(input, expected_cssom, other_encoding);
613     test_css(input, expected_cssom, null, true);
614    });
616   // XXX maybe test if they become relevant:
617   // binding (obsolete?)
618   // aural: cue-after, cue-before, play-during (not implemented?)
619   // hyphenate-resource (not implemented?)
620   // image() (not implemented?)
622   // <?xml-stylesheet?>
623   subsetTestByKey('xml', async_test, function() {
624     var iframe = document.createElement('iframe');
625     iframe.src = input_url_xmlstylesheet_css;
626     document.body.appendChild(iframe);
627     this.add_cleanup(function() {
628       document.body.removeChild(iframe);
629     });
630     iframe.onload = this.step_func_done(function() {
631       assert_equals(iframe.contentDocument.firstChild.sheet.cssRules[0].style.content, '"' + expected_utf8 + '"');
632     });
633   }, '<?xml-stylesheet?> (CSS)');
635   // new URL()
636   subsetTestByKey('url', test, function() {
637     var url = new URL('http://example.org/'+input_url);
638     var expected = expected_utf8;
639     assert_true(url.href.indexOf(expected) > -1, 'url.href '+msg(expected, url.href));
640     assert_true(url.search.indexOf(expected) > -1, 'url.search '+msg(expected, url.search));
641   }, 'URL constructor, url');
643   subsetTestByKey('url', test, function() {
644     var url = new URL('', 'http://example.org/'+input_url);
645     var expected = expected_utf8;
646     assert_true(url.href.indexOf(expected) > -1, 'url.href '+msg(expected, url.href));
647     assert_true(url.search.indexOf(expected) > -1, 'url.search '+msg(expected, url.search));
648   }, 'URL constructor, base');
650   // Test different schemes
651   function test_scheme(url, utf8) {
652     subsetTestByKey('scheme', test, function() {
653       var a = document.createElement('a');
654       a.setAttribute('href', url);
655       var got = a.href;
656       var expected = utf8 ? expected_utf8 : expected_current;
657       assert_true(got.indexOf(expected) != -1, msg(expected, got));
658     }, 'Scheme ' + url.split(':')[0] + ' (getting <a>.href)');
659   }
661   var test_scheme_urls = ['ftp://example.invalid/?x=\u00E5',
662                           'file:///?x=\u00E5',
663                           'http://example.invalid/?x=\u00E5',
664                           'https://example.invalid/?x=\u00E5',
665                          ];
667   var test_scheme_urls_utf8 = ['ws://example.invalid/?x=\u00E5',
668                                'wss://example.invalid/?x=\u00E5',
669                                'gopher://example.invalid/?x=\u00E5',
670                                'mailto:example@invalid?x=\u00E5',
671                                'data:text/plain;charset='+encoding+',?x=\u00E5',
672                                'javascript:"?x=\u00E5"',
673                                'ftps://example.invalid/?x=\u00E5',
674                                'httpbogus://example.invalid/?x=\u00E5',
675                                'bitcoin:foo?x=\u00E5',
676                                'geo:foo?x=\u00E5',
677                                'im:foo?x=\u00E5',
678                                'irc:foo?x=\u00E5',
679                                'ircs:foo?x=\u00E5',
680                                'magnet:foo?x=\u00E5',
681                                'mms:foo?x=\u00E5',
682                                'news:foo?x=\u00E5',
683                                'nntp:foo?x=\u00E5',
684                                'sip:foo?x=\u00E5',
685                                'sms:foo?x=\u00E5',
686                                'smsto:foo?x=\u00E5',
687                                'ssh:foo?x=\u00E5',
688                                'tel:foo?x=\u00E5',
689                                'urn:foo?x=\u00E5',
690                                'webcal:foo?x=\u00E5',
691                                'wtai:foo?x=\u00E5',
692                                'xmpp:foo?x=\u00E5',
693                                'web+http:foo?x=\u00E5',
694                               ];
696   test_scheme_urls.forEach(function(url) {
697     test_scheme(url);
698   });
700   test_scheme_urls_utf8.forEach(function(url) {
701     test_scheme(url, true);
702   });
704   done();