Bug 1704910 [wpt PR 28460] - chore: restructure xhr/formdata tests, a=testonly
authorLuca Casonato <lucacasonato@yahoo.com>
Fri, 23 Apr 2021 10:17:51 +0000
changeset 577251 b7de827ad53013741cee8a2ba6ca1dc47159c028
parent 577250 da4db35e7325d059eff40083b1c95d62d4f001e7
child 577252 aad6c263f60af1fb478263b1e23b050ea977f7de
push id141827
push userwptsync@mozilla.com
push dateSat, 24 Apr 2021 02:11:12 +0000
treeherderautoland@3a7d9d49c316 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1704910, 28460
milestone90.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1704910 [wpt PR 28460] - chore: restructure xhr/formdata tests, a=testonly Automatic update from web-platform-tests XHR: restructure FormData tests This commit restrucutres xhr/formdata tests that do not require a form element to be .any.js tests, and thus runnable outside the browser, and in workers (like in Deno). This commit only moves tests around (no changes or removals), with the exception of the "Passing a String object to FormData.set should work" and "Passing a String object to FormData.append should work." tests because the tests are exact replicas of the "formdata with string" test in xhr/formdata.html. Because of that they have been removed. -- wpt-commits: e45a9f9e65d039c76817ee2a6a1ef02c9311a1cb wpt-pr: 28460
testing/web-platform/tests/xhr/FormData-append.html
testing/web-platform/tests/xhr/formdata-blob.htm
testing/web-platform/tests/xhr/formdata-constructor.html
testing/web-platform/tests/xhr/formdata-delete.htm
testing/web-platform/tests/xhr/formdata-foreach.html
testing/web-platform/tests/xhr/formdata-get.htm
testing/web-platform/tests/xhr/formdata-has.htm
testing/web-platform/tests/xhr/formdata-set-blob.html
testing/web-platform/tests/xhr/formdata-set.htm
testing/web-platform/tests/xhr/formdata.htm
testing/web-platform/tests/xhr/formdata.html
testing/web-platform/tests/xhr/formdata/append-formelement.html
testing/web-platform/tests/xhr/formdata/append.any.js
testing/web-platform/tests/xhr/formdata/constructor-formelement.html
testing/web-platform/tests/xhr/formdata/constructor.any.js
testing/web-platform/tests/xhr/formdata/delete-formelement.html
testing/web-platform/tests/xhr/formdata/delete.any.js
testing/web-platform/tests/xhr/formdata/foreach.any.js
testing/web-platform/tests/xhr/formdata/get-formelement.html
testing/web-platform/tests/xhr/formdata/get.any.js
testing/web-platform/tests/xhr/formdata/has-formelement.html
testing/web-platform/tests/xhr/formdata/has.any.js
testing/web-platform/tests/xhr/formdata/set-blob.any.js
testing/web-platform/tests/xhr/formdata/set-formelement.html
testing/web-platform/tests/xhr/formdata/set.any.js
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/FormData-append.html
+++ /dev/null
@@ -1,107 +0,0 @@
-<!doctype html>
-<meta charset="utf-8">
-<title>FormData.append</title>
-<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-append">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<form id="form" />
-<script>
-    function test_formdata(creator, verifier, description) {
-        async_test(description).step(function() {
-            var fd = creator();
-            var xhr = new XMLHttpRequest();
-            xhr.onload = this.step_func(function() {
-                verifier(xhr.responseText);
-                this.done();
-            });
-            xhr.open("POST", "resources/upload.py");
-            xhr.send(fd);
-        });
-    }
-
-    test_formdata(function() {
-        var fd = new FormData();
-        fd.append("name", new String("value"));
-        return fd;
-    }, function(data) {
-        assert_equals(data, "name=value,\n");
-    }, "Passing a String object to FormData.append should work.");
-
-    test(function() {
-        assert_equals(create_formdata(['key', 'value1']).get('key'), "value1");
-    }, 'testFormDataAppend1');
-    test(function() {
-        assert_equals(create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), "value2");
-    }, 'testFormDataAppend2');
-    test(function() {
-        assert_equals(create_formdata(['key', undefined]).get('key'), "undefined");
-    }, 'testFormDataAppendUndefined1');
-    test(function() {
-        assert_equals(create_formdata(['key', undefined], ['key', 'value1']).get('key'), "undefined");
-    }, 'testFormDataAppendUndefined2');
-    test(function() {
-        assert_equals(create_formdata(['key', null]).get('key'), "null");
-    }, 'testFormDataAppendNull1');
-    test(function() {
-        assert_equals(create_formdata(['key', null], ['key', 'value1']).get('key'), "null");
-    }, 'testFormDataAppendNull2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.append('key', 'value1');
-        assert_equals(fd.get('key'), "value1");
-    }, 'testFormDataAppendToForm1');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.append('key', 'value2');
-        fd.append('key', 'value1');
-        assert_equals(fd.get('key'), "value2");
-    }, 'testFormDataAppendToForm2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.append('key', undefined);
-        assert_equals(fd.get('key'), "undefined");
-    }, 'testFormDataAppendToFormUndefined1');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.append('key', undefined);
-        fd.append('key', 'value1');
-        assert_equals(fd.get('key'), "undefined");
-    }, 'testFormDataAppendToFormUndefined2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.append('key', null);
-        assert_equals(fd.get('key'), "null");
-    }, 'testFormDataAppendToFormNull1');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.append('key', null);
-        fd.append('key', 'value1');
-        assert_equals(fd.get('key'), "null");
-    }, 'testFormDataAppendToFormNull2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        assert_throws_js(TypeError, () => {fd.append('name', "string", 'filename')});
-    }, 'testFormDataAppendToFormString');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        assert_throws_js(TypeError, () => {fd.append('name', new URLSearchParams(), 'filename')});
-    }, 'testFormDataAppendToFormWrongPlatformObject');
-    test(function() {
-        var before = new Date(new Date().getTime() - 2000); // two seconds ago, in case there's clock drift
-        var fd = create_formdata(['key', new Blob(), 'blank.txt']).get('key');
-        assert_equals(fd.name, "blank.txt");
-        assert_equals(fd.type, "");
-        assert_equals(fd.size, 0);
-        assert_greater_than_equal(fd.lastModified, before);
-        assert_less_than_equal(fd.lastModified, new Date());
-    }, 'testFormDataAppendEmptyBlob');
-
-    function create_formdata() {
-        var fd = new FormData();
-        for (var i = 0; i < arguments.length; i++) {
-            fd.append.apply(fd, arguments[i]);
-        };
-        return fd;
-    }
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-blob.htm
+++ /dev/null
@@ -1,46 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>XMLHttpRequest: upload formdata with blob</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#interface-formdata" data-tested-assertations="following::P[1]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata" data-tested-assertations="following::P[2]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-append" data-tested-assertations=".. following::P[1]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-append" data-tested-assertations="following::P[2] following::UL[1]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-XMLHttpRequest-send-FormData" data-tested-assertations="following::DD[1]" />
-<div id="log"></div>
-<script>
-  function do_test (name, fd, expected) {
-    var test = async_test(name);
-    test.step(function() {
-      var client = new XMLHttpRequest();
-      client.onreadystatechange = test.step_func(function () {
-        if (client.readyState !== 4) return;
-        assert_equals(client.responseText, expected);
-        test.done();
-      });
-      client.open("POST", "resources/upload.py");
-      client.send(fd);
-    });
-  }
-
-  function create_formdata () {
-    var fd = new FormData();
-    for (var i = 0; i < arguments.length; i++) {
-      fd.append.apply(fd, arguments[i]);
-    }
-    return fd;
-  }
-
-  do_test("formdata with blob", create_formdata(['key', new Blob(['value'], {type: 'text/x-value'})]), '\nkey=blob:text/x-value:5,');
-  do_test("formdata with named blob", create_formdata(['key', new Blob(['value'], {type: 'text/x-value'}), 'blob.txt']), '\nkey=blob.txt:text/x-value:5,');
-  // If 3rd argument is given and 2nd is not a Blob, formdata.append() should throw
-  var test = async_test('formdata.append() should throw if value is string and file name is given'); // needs to be async just because the others above are
-  test.step(function(){
-    assert_throws_js(TypeError, function(){
-      create_formdata('a', 'b', 'c');
-    });
-  });
-  test.done();
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-constructor.html
+++ /dev/null
@@ -1,150 +0,0 @@
-<!DOCTYPE html>
-<title>FormData construction from a form element</title>
-<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
-<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata">
-<link rel="help" href="https://html.spec.whatwg.org/multipage/#constructing-form-data-set">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<form>
-  <output name="do-not-submit-me-1"></output>
-
-  <datalist>
-    <input type="text" name="do-not-submit-me-2" value="bad">
-    <select name="do-not-submit-me-3">
-      <option value="bad" selected></option>
-    </select>
-    <input type="checkbox" name="do-not-submit-me-4" checked>
-  </datalist>
-
-  <input type="text" name="do-not-submit-me-5" disabled value="bad">
-  <fieldset disabled>
-    <input type="text" name="do-not-submit-me-6" value="bad">
-  </fieldset>
-
-  <button name="do-not-submit-me-7">bad</button>
-  <input type="submit" name="do-not-submit-me-8" value="bad">
-  <input type="reset" name="do-not-submit-me-9" value="bad">
-  <input type="image" name="do-not-submit-me-10" value="bad">
-
-  <input type="checkbox" name="do-not-submit-me-11">
-  <input type="radio" name="do-not-submit-me-12">
-
-  <input type="text" value="do-not-submit-me-13">
-  <input type="text" name="" value="do-not-submit-me-14">
-
-  <object name="do-not-submit-me-15"></object>
-
-  <select name="select-1">
-    <option disabled value="do-not-submit-me-16"></option>
-    <option value="do-not-submit-me-17"></option>
-    <option disabled value="do-not-submit-me-18" selected></option>
-  </select>
-
-  <select name="select-2">
-    <option value="do-not-submit-me-19"></option>
-    <option value="submit-me-1" selected></option>
-  </select>
-
-  <select name="select-3" multiple>
-    <option value="do-not-submit-me-20"></option>
-    <option value="submit-me-2" selected></option>
-    <option value="do-not-submit-me-21"></option>
-    <option value="submit-me-3" selected></option>
-  </select>
-
-  <input type="checkbox" name="submit-me-4" value="checkbox-1" checked>
-  <input type="checkbox" name="submit-me-5" checked>
-
-  <input type="radio" name="submit-me-6" value="radio-1" checked>
-  <input type="radio" name="submit-me-7" checked>
-
-  <!-- not tested: <input type="file"> with selected files -->
-
-  <input type="file" name="file-1">
-
-  <!-- not tested: <object>s that allow form submission -->
-
-  <input type="text" name="submit-me-8" value="text-1">
-  <input type="text" name="submit-me-8" value="text-2">
-  <input type="search" name="submit-me-9" value="search-1">
-  <input type="url" name="submit-me-10" value="url-1">
-  <input type="hidden" name="submit-me-11" value="hidden-1">
-  <input type="password" name="submit-me-12" value="password-1">
-  <input type="number" name="submit-me-13" value="11">
-  <input type="range" name="submit-me-14" value="11">
-  <input type="color" name="submit-me-15" value="#123456">
-
-  <textarea name="submit-me-16">textarea value
-with linebreaks set to CRLF</textarea>
-
-  <!-- this generates two form data entries! -->
-  <input type="text" name="dirname-is-special" dirname="submit-me-17" value="dirname-value">
-
-  <input type="text" name="submit-me-21">
-</form>
-
-<script>
-"use strict";
-
-test(() => {
-
-  const form = document.querySelector("form");
-
-  const input = document.createElement("input");
-  input.name = "submit-me-18-\uDC01";
-  input.value = "value-\uDC01";
-  assert_equals(input.name, "submit-me-18-\uDC01", "input.name accepts unpaired surrogates");
-  assert_equals(input.value, "value-\uDC01", "input.value accepts unpaired surrogates");
-  form.appendChild(input);
-
-  const input2 = document.createElement("input");
-  input2.name = "submit-me-\r19\n";
-  input2.value = "value\n\r";
-  assert_equals(input2.name, "submit-me-\r19\n", "input.name accepts \\r and \\n");
-  assert_equals(input2.value, "value", "input.value when type=text should not contain newlines");
-  form.appendChild(input2);
-
-  const formData = new FormData(form);
-
-  const expected = [
-    ["select-2", "submit-me-1"],
-    ["select-3", ["submit-me-2", "submit-me-3"]],
-    ["submit-me-4", "checkbox-1"],
-    ["submit-me-5", "on"],
-    ["submit-me-6", "radio-1"],
-    ["submit-me-7", "on"],
-    ["submit-me-8", ["text-1", "text-2"]],
-    ["submit-me-9", "search-1"],
-    ["submit-me-10", "url-1"],
-    ["submit-me-11", "hidden-1"],
-    ["submit-me-12", "password-1"],
-    ["submit-me-13", "11"],
-    ["submit-me-14", "11"],
-    ["submit-me-15", "#123456"],
-    ["submit-me-16", "textarea value\r\nwith linebreaks set to CRLF"],
-    ["dirname-is-special", "dirname-value"],
-    ["submit-me-17", "ltr"],
-    ["submit-me-18-\uFFFD", "value-\uFFFD"],
-    ["submit-me-\r\n19\r\n", "value"],
-    ["submit-me-21", ""]
-  ];
-
-  for (const t of expected) {
-    const field = t[0];
-    const valueOrValues = t[1];
-    const values = Array.isArray(valueOrValues) ? valueOrValues : [valueOrValues];
-    assert_array_equals(formData.getAll(field), values, field);
-  }
-
-  const fileEntry = formData.getAll("file-1");
-  assert_equals(fileEntry.length, 1);
-  assert_equals(fileEntry[0], formData.get("file-1"));
-  assert_equals(fileEntry[0].constructor, File);
-  assert_equals(fileEntry[0].size, 0);
-  assert_equals(fileEntry[0].name, "");
-  assert_equals(fileEntry[0].type, "application/octet-stream");
-
-}, "test that FormData is correctly constructed from the form data set");
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-delete.htm
+++ /dev/null
@@ -1,65 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>FormData: delete</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-get" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-getall" />
-<div id="log"></div>
-<form id="form1">
-    <input type="hidden" name="key" value="value1">
-    <input type="hidden" name="key" value="value2">
-</form>
-<form id="form2">
-    <input type="hidden" name="key1" value="value1">
-    <input type="hidden" name="key2" value="value2">
-</form>
-<form id="empty-form" />
-<script>
-    test(function() {
-        var fd = create_formdata(['key', 'value1'], ['key', 'value2']);
-        fd.delete('key');
-        assert_equals(fd.get('key'), null);
-    }, 'testFormDataDelete');
-    test(function() {
-        var fd = new FormData(document.getElementById('form1'));
-        fd.delete('key');
-        assert_equals(fd.get('key'), null);
-    }, 'testFormDataDeleteFromForm');
-    test(function() {
-        var fd = new FormData(document.getElementById('form1'));
-        fd.delete('nil');
-        assert_equals(fd.get('key'), 'value1');
-    }, 'testFormDataDeleteFromFormNonExistentKey');
-    test(function() {
-        var fd = new FormData(document.getElementById('form2'));
-        fd.delete('key1');
-        assert_equals(fd.get('key1'), null);
-        assert_equals(fd.get('key2'), 'value2');
-    }, 'testFormDataDeleteFromFormOtherKey');
-    test(function() {
-        var fd = new FormData(document.getElementById('empty-form'));
-        fd.delete('key');
-        assert_equals(fd.get('key'), null);
-    }, 'testFormDataDeleteFromEmptyForm');
-    test(function() {
-        var fd = create_formdata(['key', 'value1'], ['key', 'value2']);
-        fd.delete('nil');
-        assert_equals(fd.get('key'), 'value1');
-    }, 'testFormDataDeleteNonExistentKey');
-    test(function() {
-        var fd = create_formdata(['key1', 'value1'], ['key2', 'value2']);
-        fd.delete('key1');
-        assert_equals(fd.get('key1'), null);
-        assert_equals(fd.get('key2'), 'value2');
-    }, 'testFormDataDeleteOtherKey');
-
-    function create_formdata() {
-        var fd = new FormData();
-        for (var i = 0; i < arguments.length; i++) {
-            fd.append.apply(fd, arguments[i]);
-        };
-        return fd;
-    }
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-foreach.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>FormData: foreach</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#interface-formdata" />
-<script>
-    var fd = new FormData();
-    fd.append('n1', 'v1');
-    fd.append('n2', 'v2');
-    fd.append('n3', 'v3');
-    fd.append('n1', 'v4');
-    fd.append('n2', 'v5');
-    fd.append('n3', 'v6');
-    fd.delete('n2');
-
-    var file = new File(['hello'], "hello.txt");
-    fd.append('f1', file);
-
-    var expected_keys = ['n1', 'n3', 'n1', 'n3', 'f1'];
-    var expected_values = ['v1', 'v3', 'v4', 'v6', file];
-    test(function() {
-        var mykeys = [], myvalues = [];
-        for(var entry of fd) {
-            assert_equals(entry.length, 2,
-                          'Default iterator should yield key/value pairs');
-            mykeys.push(entry[0]);
-            myvalues.push(entry[1]);
-        }
-        assert_array_equals(mykeys, expected_keys,
-                            'Default iterator should see duplicate keys');
-        assert_array_equals(myvalues, expected_values,
-                            'Default iterator should see non-deleted values');
-    }, 'Iterator should return duplicate keys and non-deleted values');
-    test(function() {
-        var mykeys = [], myvalues = [];
-        for(var entry of fd.entries()) {
-            assert_equals(entry.length, 2,
-                          'entries() iterator should yield key/value pairs');
-            mykeys.push(entry[0]);
-            myvalues.push(entry[1]);
-        }
-        assert_array_equals(mykeys, expected_keys,
-                            'entries() iterator should see duplicate keys');
-        assert_array_equals(myvalues, expected_values,
-                            'entries() iterator should see non-deleted values');
-    }, 'Entries iterator should return duplicate keys and non-deleted values');
-    test(function() {
-        var mykeys = [];
-        for(var entry of fd.keys())
-            mykeys.push(entry);
-        assert_array_equals(mykeys, expected_keys,
-                            'keys() iterator should see duplicate keys');
-    }, 'Keys iterator should return duplicates');
-    test(function() {
-        var myvalues = [];
-        for(var entry of fd.values())
-            myvalues.push(entry);
-        assert_array_equals(myvalues, expected_values,
-                            'values() iterator should see non-deleted values');
-    }, 'Values iterator should return non-deleted values');
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-get.htm
+++ /dev/null
@@ -1,60 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>FormData: get and getAll</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-get" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-getall" />
-<div id="log"></div>
-<form id="form">
-    <input type="hidden" name="key" value="value1">
-    <input type="hidden" name="key" value="value2">
-</form>
-<form id="empty-form" />
-<script>
-    test(function() {
-        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).get('key'), "value1");
-    }, 'testFormDataGet');
-    test(function() {
-        assert_equals(new FormData(document.getElementById('form')).get('key'), "value1");
-    }, 'testFormDataGetFromForm');
-    test(function() {
-        assert_equals(new FormData(document.getElementById('form')).get('nil'), null);
-    }, 'testFormDataGetFromFormNull');
-    test(function() {
-        assert_equals(new FormData(document.getElementById('empty-form')).get('key'), null);
-    }, 'testFormDataGetFromEmptyForm');
-    test(function() {
-        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).get('nil'), null);
-    }, 'testFormDataGetNull1');
-    test(function() {
-        assert_equals(create_formdata().get('key'), null);
-    }, 'testFormDataGetNull2');
-    test(function() {
-        assert_array_equals(create_formdata(['key', 'value1'], ['key', 'value2']).getAll('key'), ["value1", "value2"]);
-    }, 'testFormDataGetAll');
-    test(function() {
-        assert_array_equals(create_formdata(['key', 'value1'], ['key', 'value2']).getAll('nil'), []);
-    }, 'testFormDataGetAllEmpty1');
-    test(function() {
-        assert_array_equals(create_formdata().getAll('key'), []);
-    }, 'testFormDataGetAllEmpty2');
-    test(function() {
-        assert_array_equals(new FormData(document.getElementById('form')).getAll('key'), ["value1", "value2"]);
-    }, 'testFormDataGetAllFromForm');
-    test(function() {
-        assert_array_equals(new FormData(document.getElementById('form')).getAll('nil'), []);
-    }, 'testFormDataGetAllFromFormNull');
-    test(function() {
-        assert_array_equals(new FormData(document.getElementById('empty-form')).getAll('key'), []);
-    }, 'testFormDataGetAllFromEmptyForm');
-
-    function create_formdata() {
-        var fd = new FormData();
-        for (var i = 0; i < arguments.length; i++) {
-            fd.append.apply(fd, arguments[i]);
-        };
-        return fd;
-    }
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-has.htm
+++ /dev/null
@@ -1,42 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>FormData: has</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-get" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-getall" />
-<div id="log"></div>
-<form id="form">
-    <input type="hidden" name="key" value="value1">
-    <input type="hidden" name="key" value="value2">
-</form>
-<form id="empty-form" />
-<script>
-    test(function() {
-        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).has('key'), true);
-    }, 'testFormDataHas');
-    test(function() {
-        assert_equals(new FormData(document.getElementById('form')).has('key'), true);
-    }, 'testFormDataHasFromForm');
-    test(function() {
-        assert_equals(new FormData(document.getElementById('form')).has('nil'), false);
-    }, 'testFormDataHasFromFormNull');
-    test(function() {
-        assert_equals(new FormData(document.getElementById('empty-form')).has('key'), false);
-    }, 'testFormDataHasFromEmptyForm');
-    test(function() {
-        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).has('nil'), false);
-    }, 'testFormDataHasEmpty1');
-    test(function() {
-        assert_equals(create_formdata().has('key'), false);
-    }, 'testFormDataHasEmpty2');
-
-    function create_formdata() {
-        var fd = new FormData();
-        for (var i = 0; i < arguments.length; i++) {
-            fd.append.apply(fd, arguments[i]);
-        };
-        return fd;
-    }
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-set-blob.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>formData.set(blob) and formData.set(file)</title>
-<link rel="author" title="Timothy Gu" href="mailto:timothygu99@gmail.com">
-<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata">
-<link rel="help" href="https://html.spec.whatwg.org/multipage/#constructing-form-data-set">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<script>
-"use strict";
-
-const formData = new FormData();
-
-test(() => {
-  formData.set("blob-1", new Blob());
-  const blob1 = formData.get("blob-1");
-  assert_equals(blob1.constructor.name, "File");
-  assert_equals(blob1.name, "blob");
-  assert_equals(blob1.type, "");
-  assert_less_than(Math.abs(blob1.lastModified - Date.now()), 200, "lastModified should be now");
-}, "blob without type");
-
-test(() => {
-  formData.set("blob-2", new Blob([], { type: "text/plain" }));
-  const blob2 = formData.get("blob-2");
-  assert_equals(blob2.constructor.name, "File");
-  assert_equals(blob2.name, "blob");
-  assert_equals(blob2.type, "text/plain");
-  assert_less_than(Math.abs(blob2.lastModified - Date.now()), 200, "lastModified should be now");
-}, "blob with type");
-
-test(() => {
-  formData.set("blob-3", new Blob(), "custom name");
-  const blob3 = formData.get("blob-3");
-  assert_equals(blob3.constructor.name, "File");
-  assert_equals(blob3.name, "custom name");
-  assert_equals(blob3.type, "");
-  assert_less_than(Math.abs(blob3.lastModified - Date.now()), 200, "lastModified should be now");
-}, "blob with custom name");
-
-test(() => {
-  formData.set("file-1", new File([], "name"));
-  const file1 = formData.get("file-1");
-  assert_equals(file1.constructor.name, "File");
-  assert_equals(file1.name, "name");
-  assert_equals(file1.type, "");
-  assert_less_than(Math.abs(file1.lastModified - Date.now()), 200, "lastModified should be now");
-}, "file without lastModified or custom name");
-
-test(() => {
-  formData.set("file-2", new File([], "name", { lastModified: 123 }), "custom name");
-  const file2 = formData.get("file-2");
-  assert_equals(file2.constructor.name, "File");
-  assert_equals(file2.name, "custom name");
-  assert_equals(file2.type, "");
-  assert_equals(file2.lastModified, 123, "lastModified should be 123");
-}, "file with lastModified and custom name");
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata-set.htm
+++ /dev/null
@@ -1,106 +0,0 @@
-<!doctype html>
-<meta charset="utf-8">
-<title>FormData: set</title>
-<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-set">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<form id="form" />
-<script>
-    function test_formdata(creator, verifier, description) {
-        async_test(description).step(function() {
-            var fd = creator();
-            var xhr = new XMLHttpRequest();
-            xhr.onload = this.step_func(function() {
-                verifier(xhr.responseText);
-                this.done();
-            });
-            xhr.open("POST", "resources/upload.py");
-            xhr.send(fd);
-        });
-    }
-
-    test_formdata(function() {
-        var fd = new FormData();
-        fd.set("name", new String("value"));
-        return fd;
-    }, function(data) {
-        assert_equals(data, "name=value,\n");
-    }, "Passing a String object to FormData.set should work");
-
-    test(function() {
-        assert_equals(create_formdata(['key', 'value1']).get('key'), "value1");
-    }, 'testFormDataSet1');
-    test(function() {
-        assert_equals(create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), "value1");
-    }, 'testFormDataSet2');
-    test(function() {
-        assert_equals(create_formdata(['key', undefined]).get('key'), "undefined");
-    }, 'testFormDataSetUndefined1');
-    test(function() {
-        assert_equals(create_formdata(['key', undefined], ['key', 'value1']).get('key'), "value1");
-    }, 'testFormDataSetUndefined2');
-    test(function() {
-        assert_equals(create_formdata(['key', null]).get('key'), "null");
-    }, 'testFormDataSetNull1');
-    test(function() {
-        assert_equals(create_formdata(['key', null], ['key', 'value1']).get('key'), "value1");
-    }, 'testFormDataSetNull2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.set('key', 'value1');
-        assert_equals(fd.get('key'), "value1");
-    }, 'testFormDataSetToForm1');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.set('key', 'value2');
-        fd.set('key', 'value1');
-        assert_equals(fd.get('key'), "value1");
-    }, 'testFormDataSetToForm2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.set('key', undefined);
-        assert_equals(fd.get('key'), "undefined");
-    }, 'testFormDataSetToFormUndefined1');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.set('key', undefined);
-        fd.set('key', 'value1');
-        assert_equals(fd.get('key'), "value1");
-    }, 'testFormDataSetToFormUndefined2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.set('key', null);
-        assert_equals(fd.get('key'), "null");
-    }, 'testFormDataSetToFormNull1');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        fd.set('key', null);
-        fd.set('key', 'value1');
-        assert_equals(fd.get('key'), "value1");
-    }, 'testFormDataSetToFormNull2');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        assert_throws_js(TypeError, () => {fd.set('name', "string", 'filename')});
-    }, 'testFormDataSetToFormString');
-    test(function() {
-        var fd = new FormData(document.getElementById("form"));
-        assert_throws_js(TypeError, () => {fd.set('name', new URLSearchParams(), 'filename')});
-    }, 'testFormDataSetToFormWrongPlatformObject');
-    test(function() {
-        var fd = new FormData();
-        fd.set('key', new Blob([]), 'blank.txt');
-        var file = fd.get('key');
-
-        assert_true(file instanceof File);
-        assert_equals(file.name, 'blank.txt');
-    }, 'testFormDataSetEmptyBlob');
-
-    function create_formdata() {
-        var fd = new FormData();
-        for (var i = 0; i < arguments.length; i++) {
-            fd.set.apply(fd, arguments[i]);
-        };
-        return fd;
-    }
-</script>
deleted file mode 100644
--- a/testing/web-platform/tests/xhr/formdata.htm
+++ /dev/null
@@ -1,83 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>XMLHttpRequest: Construct and upload FormData</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/html/semantics/forms/form-submission-0/resources/targetted-form.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#interface-formdata" data-tested-assertations="following::P[1]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata" data-tested-assertations=".. following::P[1]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-append" data-tested-assertations=".. following::UL[1]/LI[1] following::UL[1]/LI[2] following::UL[1]/LI[3]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-XMLHttpRequest-send-FormData" data-tested-assertations="following::DD[1]" />
-<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set">
-
-<div id="log"></div>
-<form id="form">
-  <input type="hidden" name="key" value="value">
-</form>
-<script>
-  function do_test (name, fd, expected) {
-    var test = async_test(name);
-    test.step(function() {
-      var client = new XMLHttpRequest();
-      client.onreadystatechange = test.step_func(function () {
-        if (client.readyState !== 4) return;
-        assert_equals(client.responseText, expected);
-        test.done();
-      });
-      client.open("POST", "resources/upload.py");
-      client.send(fd);
-    });
-  }
-
-  function create_formdata () {
-    var fd = new FormData();
-    for (var i = 0; i < arguments.length; i++) {
-      fd.append.apply(fd, arguments[i]);
-    };
-    return fd;
-  }
-
-  test(() => {
-    assert_throws_js(TypeError, () => { new FormData(null); });
-    assert_throws_js(TypeError, () => { new FormData("string"); });
-  }, "Constructors should throw a type error");
-
-  do_test("empty formdata", new FormData(), '\n');
-  do_test("formdata with string", create_formdata(['key', 'value']), 'key=value,\n');
-  do_test("formdata with named string", create_formdata(['key', new Blob(['value'], {type: 'text/plain'}), 'kv.txt']), '\nkey=kv.txt:text/plain:5,');
-  do_test("formdata from form", new FormData(document.getElementById('form')), 'key=value,\n');
-
-  test(() => {
-    let form = populateForm('<input name=n1 value=v1>');
-    let formDataInEvent = null;
-    form.addEventListener('formdata', e => {
-      e.formData.append('h1', 'vh1');
-      formDataInEvent = e.formData;
-    });
-    let formData = new FormData(form);
-    assert_equals(formData.get('h1'), 'vh1');
-    assert_equals(formData.get('n1'), 'v1');
-    assert_not_equals(formData, formDataInEvent,
-                      '"formData" attribute should be different from the ' +
-                      'FromData object created by "new"');
-
-    formDataInEvent.append('later-key', 'later-value');
-    assert_false(formData.has('later-key'));
-  }, 'Newly created FormData contains entries added to "formData" IDL ' +
-     'attribute of FormDataEvent.');
-
-  test(() => {
-    let form = populateForm('<input name=n11 value=v11>');
-    let counter = 0;
-    form.addEventListener('formdata', e => {
-      ++counter;
-      assert_throws_dom('InvalidStateError', () => { new FormData(e.target) });
-    });
-    new FormData(form);
-    assert_equals(counter, 1);
-
-    form.submit();
-    assert_equals(counter, 2);
-  }, '|new FormData()| in formdata event handler should throw');
-</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<html lang=en>
+<meta charset=utf-8>
+<title>XMLHttpRequest: Construct and upload FormData</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/html/semantics/forms/form-submission-0/resources/targetted-form.js"></script>
+    <link rel="help" href="https://xhr.spec.whatwg.org/#interface-formdata" data-tested-assertations="following::P[1]" />
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata" data-tested-assertations=".. following::P[1]" />
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-append" data-tested-assertations=".. following::UL[1]/LI[1] following::UL[1]/LI[2] following::UL[1]/LI[3]" />
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-XMLHttpRequest-send-FormData" data-tested-assertations="following::DD[1]" />
+<link rel="help" href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set">
+
+<div id="log"></div>
+<form id="form">
+  <input type="hidden" name="key" value="value">
+</form>
+<script>
+  function do_test (name, fd, expected) {
+    var test = async_test(name);
+    test.step(function() {
+      var client = new XMLHttpRequest();
+      client.onreadystatechange = test.step_func(function () {
+        if (client.readyState !== 4) return;
+        assert_equals(client.responseText, expected);
+        test.done();
+      });
+      client.open("POST", "resources/upload.py");
+      client.send(fd);
+    });
+  }
+
+  function create_formdata () {
+    var fd = new FormData();
+    for (var i = 0; i < arguments.length; i++) {
+      fd.append.apply(fd, arguments[i]);
+    };
+    return fd;
+  }
+
+  do_test("empty formdata", new FormData(), '\n');
+  do_test("formdata with string", create_formdata(['key', 'value']), 'key=value,\n');
+  do_test("formdata with named string", create_formdata(['key', new Blob(['value'], {type: 'text/plain'}), 'kv.txt']), '\nkey=kv.txt:text/plain:5,');
+  do_test("formdata from form", new FormData(document.getElementById('form')), 'key=value,\n');
+
+  do_test("formdata with blob", create_formdata(['key', new Blob(['value'], {type: 'text/x-value'})]), '\nkey=blob:text/x-value:5,');
+  do_test("formdata with named blob", create_formdata(['key', new Blob(['value'], {type: 'text/x-value'}), 'blob.txt']), '\nkey=blob.txt:text/x-value:5,');
+
+  // If 3rd argument is given and 2nd is not a Blob, formdata.append() should throw
+  const append_test = async_test('formdata.append() should throw if value is string and file name is given'); // needs to be async just because the others above are
+  append_test.step(function(){
+    assert_throws_js(TypeError, function(){
+      create_formdata('a', 'b', 'c');
+    });
+  });
+  append_test.done();
+
+  test(() => {
+    let form = populateForm('<input name=n1 value=v1>');
+    let formDataInEvent = null;
+    form.addEventListener('formdata', e => {
+      e.formData.append('h1', 'vh1');
+      formDataInEvent = e.formData;
+    });
+    let formData = new FormData(form);
+    assert_equals(formData.get('h1'), 'vh1');
+    assert_equals(formData.get('n1'), 'v1');
+    assert_not_equals(formData, formDataInEvent,
+                      '"formData" attribute should be different from the ' +
+                      'FromData object created by "new"');
+
+    formDataInEvent.append('later-key', 'later-value');
+    assert_false(formData.has('later-key'));
+  }, 'Newly created FormData contains entries added to "formData" IDL ' +
+     'attribute of FormDataEvent.');
+
+  test(() => {
+    let form = populateForm('<input name=n11 value=v11>');
+    let counter = 0;
+    form.addEventListener('formdata', e => {
+      ++counter;
+      assert_throws_dom('InvalidStateError', () => { new FormData(e.target) });
+    });
+    new FormData(form);
+    assert_equals(counter, 1);
+
+    form.submit();
+    assert_equals(counter, 2);
+  }, '|new FormData()| in formdata event handler should throw');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/append-formelement.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>FormData.append (with form element)
+</title>
+<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-append">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<form id="form"></form>
+<script>
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.append('key', 'value1');
+        assert_equals(fd.get('key'), "value1");
+    }, 'testFormDataAppendToForm1');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.append('key', 'value2');
+        fd.append('key', 'value1');
+        assert_equals(fd.get('key'), "value2");
+    }, 'testFormDataAppendToForm2');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.append('key', undefined);
+        assert_equals(fd.get('key'), "undefined");
+    }, 'testFormDataAppendToFormUndefined1');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.append('key', undefined);
+        fd.append('key', 'value1');
+        assert_equals(fd.get('key'), "undefined");
+    }, 'testFormDataAppendToFormUndefined2');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.append('key', null);
+        assert_equals(fd.get('key'), "null");
+    }, 'testFormDataAppendToFormNull1');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.append('key', null);
+        fd.append('key', 'value1');
+        assert_equals(fd.get('key'), "null");
+    }, 'testFormDataAppendToFormNull2');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        assert_throws_js(TypeError, () => {fd.append('name', "string", 'filename')});
+    }, 'testFormDataAppendToFormString');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        assert_throws_js(TypeError, () => {fd.append('name', new URLSearchParams(), 'filename')});
+    }, 'testFormDataAppendToFormWrongPlatformObject');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/append.any.js
@@ -0,0 +1,37 @@
+// META: title=FormData.append
+
+    test(function() {
+        assert_equals(create_formdata(['key', 'value1']).get('key'), "value1");
+    }, 'testFormDataAppend1');
+    test(function() {
+        assert_equals(create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), "value2");
+    }, 'testFormDataAppend2');
+    test(function() {
+        assert_equals(create_formdata(['key', undefined]).get('key'), "undefined");
+    }, 'testFormDataAppendUndefined1');
+    test(function() {
+        assert_equals(create_formdata(['key', undefined], ['key', 'value1']).get('key'), "undefined");
+    }, 'testFormDataAppendUndefined2');
+    test(function() {
+        assert_equals(create_formdata(['key', null]).get('key'), "null");
+    }, 'testFormDataAppendNull1');
+    test(function() {
+        assert_equals(create_formdata(['key', null], ['key', 'value1']).get('key'), "null");
+    }, 'testFormDataAppendNull2');
+    test(function() {
+        var before = new Date(new Date().getTime() - 2000); // two seconds ago, in case there's clock drift
+        var fd = create_formdata(['key', new Blob(), 'blank.txt']).get('key');
+        assert_equals(fd.name, "blank.txt");
+        assert_equals(fd.type, "");
+        assert_equals(fd.size, 0);
+        assert_greater_than_equal(fd.lastModified, before);
+        assert_less_than_equal(fd.lastModified, new Date());
+    }, 'testFormDataAppendEmptyBlob');
+
+    function create_formdata() {
+        var fd = new FormData();
+        for (var i = 0; i < arguments.length; i++) {
+            fd.append.apply(fd, arguments[i]);
+        };
+        return fd;
+    }
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/constructor-formelement.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<title>FormData: constructor (with form element)</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#constructing-form-data-set">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<form>
+  <output name="do-not-submit-me-1"></output>
+
+  <datalist>
+    <input type="text" name="do-not-submit-me-2" value="bad">
+    <select name="do-not-submit-me-3">
+      <option value="bad" selected></option>
+    </select>
+    <input type="checkbox" name="do-not-submit-me-4" checked>
+  </datalist>
+
+  <input type="text" name="do-not-submit-me-5" disabled value="bad">
+  <fieldset disabled>
+    <input type="text" name="do-not-submit-me-6" value="bad">
+  </fieldset>
+
+  <button name="do-not-submit-me-7">bad</button>
+  <input type="submit" name="do-not-submit-me-8" value="bad">
+  <input type="reset" name="do-not-submit-me-9" value="bad">
+  <input type="image" name="do-not-submit-me-10" value="bad">
+
+  <input type="checkbox" name="do-not-submit-me-11">
+  <input type="radio" name="do-not-submit-me-12">
+
+  <input type="text" value="do-not-submit-me-13">
+  <input type="text" name="" value="do-not-submit-me-14">
+
+  <object name="do-not-submit-me-15"></object>
+
+  <select name="select-1">
+    <option disabled value="do-not-submit-me-16"></option>
+    <option value="do-not-submit-me-17"></option>
+    <option disabled value="do-not-submit-me-18" selected></option>
+  </select>
+
+  <select name="select-2">
+    <option value="do-not-submit-me-19"></option>
+    <option value="submit-me-1" selected></option>
+  </select>
+
+  <select name="select-3" multiple>
+    <option value="do-not-submit-me-20"></option>
+    <option value="submit-me-2" selected></option>
+    <option value="do-not-submit-me-21"></option>
+    <option value="submit-me-3" selected></option>
+  </select>
+
+  <input type="checkbox" name="submit-me-4" value="checkbox-1" checked>
+  <input type="checkbox" name="submit-me-5" checked>
+
+  <input type="radio" name="submit-me-6" value="radio-1" checked>
+  <input type="radio" name="submit-me-7" checked>
+
+  <!-- not tested: <input type="file"> with selected files -->
+
+  <input type="file" name="file-1">
+
+  <!-- not tested: <object>s that allow form submission -->
+
+  <input type="text" name="submit-me-8" value="text-1">
+  <input type="text" name="submit-me-8" value="text-2">
+  <input type="search" name="submit-me-9" value="search-1">
+  <input type="url" name="submit-me-10" value="url-1">
+  <input type="hidden" name="submit-me-11" value="hidden-1">
+  <input type="password" name="submit-me-12" value="password-1">
+  <input type="number" name="submit-me-13" value="11">
+  <input type="range" name="submit-me-14" value="11">
+  <input type="color" name="submit-me-15" value="#123456">
+
+  <textarea name="submit-me-16">textarea value
+with linebreaks set to CRLF</textarea>
+
+  <!-- this generates two form data entries! -->
+  <input type="text" name="dirname-is-special" dirname="submit-me-17" value="dirname-value">
+
+  <input type="text" name="submit-me-21">
+</form>
+
+<script>
+"use strict";
+
+test(() => {
+
+  const form = document.querySelector("form");
+
+  const input = document.createElement("input");
+  input.name = "submit-me-18-\uDC01";
+  input.value = "value-\uDC01";
+  assert_equals(input.name, "submit-me-18-\uDC01", "input.name accepts unpaired surrogates");
+  assert_equals(input.value, "value-\uDC01", "input.value accepts unpaired surrogates");
+  form.appendChild(input);
+
+  const input2 = document.createElement("input");
+  input2.name = "submit-me-\r19\n";
+  input2.value = "value\n\r";
+  assert_equals(input2.name, "submit-me-\r19\n", "input.name accepts \\r and \\n");
+  assert_equals(input2.value, "value", "input.value when type=text should not contain newlines");
+  form.appendChild(input2);
+
+  const formData = new FormData(form);
+
+  const expected = [
+    ["select-2", "submit-me-1"],
+    ["select-3", ["submit-me-2", "submit-me-3"]],
+    ["submit-me-4", "checkbox-1"],
+    ["submit-me-5", "on"],
+    ["submit-me-6", "radio-1"],
+    ["submit-me-7", "on"],
+    ["submit-me-8", ["text-1", "text-2"]],
+    ["submit-me-9", "search-1"],
+    ["submit-me-10", "url-1"],
+    ["submit-me-11", "hidden-1"],
+    ["submit-me-12", "password-1"],
+    ["submit-me-13", "11"],
+    ["submit-me-14", "11"],
+    ["submit-me-15", "#123456"],
+    ["submit-me-16", "textarea value\r\nwith linebreaks set to CRLF"],
+    ["dirname-is-special", "dirname-value"],
+    ["submit-me-17", "ltr"],
+    ["submit-me-18-\uFFFD", "value-\uFFFD"],
+    ["submit-me-\r\n19\r\n", "value"],
+    ["submit-me-21", ""]
+  ];
+
+  for (const t of expected) {
+    const field = t[0];
+    const valueOrValues = t[1];
+    const values = Array.isArray(valueOrValues) ? valueOrValues : [valueOrValues];
+    assert_array_equals(formData.getAll(field), values, field);
+  }
+
+  const fileEntry = formData.getAll("file-1");
+  assert_equals(fileEntry.length, 1);
+  assert_equals(fileEntry[0], formData.get("file-1"));
+  assert_equals(fileEntry[0].constructor, File);
+  assert_equals(fileEntry[0].size, 0);
+  assert_equals(fileEntry[0].name, "");
+  assert_equals(fileEntry[0].type, "application/octet-stream");
+
+}, "test that FormData is correctly constructed from the form data set");
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/constructor.any.js
@@ -0,0 +1,6 @@
+// META: title=FormData: constructor
+
+test(() => {
+  assert_throws_js(TypeError, () => { new FormData(null); });
+  assert_throws_js(TypeError, () => { new FormData("string"); });
+}, "Constructors should throw a type error");
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/delete-formelement.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<html lang=en>
+<meta charset=utf-8>
+<title>FormData: delete (with form element)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-get" />
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-getall" />
+<div id="log"></div>
+<form id="form1">
+    <input type="hidden" name="key" value="value1">
+    <input type="hidden" name="key" value="value2">
+</form>
+<form id="form2">
+    <input type="hidden" name="key1" value="value1">
+    <input type="hidden" name="key2" value="value2">
+</form>
+<form id="empty-form"></form>
+<script>
+    test(function() {
+        var fd = new FormData(document.getElementById('form1'));
+        fd.delete('key');
+        assert_equals(fd.get('key'), null);
+    }, 'testFormDataDeleteFromForm');
+    test(function() {
+        var fd = new FormData(document.getElementById('form1'));
+        fd.delete('nil');
+        assert_equals(fd.get('key'), 'value1');
+    }, 'testFormDataDeleteFromFormNonExistentKey');
+    test(function() {
+        var fd = new FormData(document.getElementById('form2'));
+        fd.delete('key1');
+        assert_equals(fd.get('key1'), null);
+        assert_equals(fd.get('key2'), 'value2');
+    }, 'testFormDataDeleteFromFormOtherKey');
+    test(function() {
+        var fd = new FormData(document.getElementById('empty-form'));
+        fd.delete('key');
+        assert_equals(fd.get('key'), null);
+    }, 'testFormDataDeleteFromEmptyForm');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/delete.any.js
@@ -0,0 +1,26 @@
+// META: title=FormData: delete
+
+    test(function() {
+        var fd = create_formdata(['key', 'value1'], ['key', 'value2']);
+        fd.delete('key');
+        assert_equals(fd.get('key'), null);
+    }, 'testFormDataDelete');
+    test(function() {
+        var fd = create_formdata(['key', 'value1'], ['key', 'value2']);
+        fd.delete('nil');
+        assert_equals(fd.get('key'), 'value1');
+    }, 'testFormDataDeleteNonExistentKey');
+    test(function() {
+        var fd = create_formdata(['key1', 'value1'], ['key2', 'value2']);
+        fd.delete('key1');
+        assert_equals(fd.get('key1'), null);
+        assert_equals(fd.get('key2'), 'value2');
+    }, 'testFormDataDeleteOtherKey');
+
+    function create_formdata() {
+        var fd = new FormData();
+        for (var i = 0; i < arguments.length; i++) {
+            fd.append.apply(fd, arguments[i]);
+        };
+        return fd;
+    }
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/foreach.any.js
@@ -0,0 +1,56 @@
+// META: title=FormData: foreach
+
+    var fd = new FormData();
+    fd.append('n1', 'v1');
+    fd.append('n2', 'v2');
+    fd.append('n3', 'v3');
+    fd.append('n1', 'v4');
+    fd.append('n2', 'v5');
+    fd.append('n3', 'v6');
+    fd.delete('n2');
+
+    var file = new File(['hello'], "hello.txt");
+    fd.append('f1', file);
+
+    var expected_keys = ['n1', 'n3', 'n1', 'n3', 'f1'];
+    var expected_values = ['v1', 'v3', 'v4', 'v6', file];
+    test(function() {
+        var mykeys = [], myvalues = [];
+        for(var entry of fd) {
+            assert_equals(entry.length, 2,
+                          'Default iterator should yield key/value pairs');
+            mykeys.push(entry[0]);
+            myvalues.push(entry[1]);
+        }
+        assert_array_equals(mykeys, expected_keys,
+                            'Default iterator should see duplicate keys');
+        assert_array_equals(myvalues, expected_values,
+                            'Default iterator should see non-deleted values');
+    }, 'Iterator should return duplicate keys and non-deleted values');
+    test(function() {
+        var mykeys = [], myvalues = [];
+        for(var entry of fd.entries()) {
+            assert_equals(entry.length, 2,
+                          'entries() iterator should yield key/value pairs');
+            mykeys.push(entry[0]);
+            myvalues.push(entry[1]);
+        }
+        assert_array_equals(mykeys, expected_keys,
+                            'entries() iterator should see duplicate keys');
+        assert_array_equals(myvalues, expected_values,
+                            'entries() iterator should see non-deleted values');
+    }, 'Entries iterator should return duplicate keys and non-deleted values');
+    test(function() {
+        var mykeys = [];
+        for(var entry of fd.keys())
+            mykeys.push(entry);
+        assert_array_equals(mykeys, expected_keys,
+                            'keys() iterator should see duplicate keys');
+    }, 'Keys iterator should return duplicates');
+    test(function() {
+        var myvalues = [];
+        for(var entry of fd.values())
+            myvalues.push(entry);
+        assert_array_equals(myvalues, expected_values,
+                            'values() iterator should see non-deleted values');
+    }, 'Values iterator should return non-deleted values');
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/get-formelement.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html lang=en>
+<meta charset=utf-8>
+<title>FormData: get and getAll (with form element)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-get" />
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-getall" />
+<div id="log"></div>
+<form id="form">
+    <input type="hidden" name="key" value="value1">
+    <input type="hidden" name="key" value="value2">
+</form>
+<form id="empty-form"></form>
+<script>
+    test(function() {
+        assert_equals(new FormData(document.getElementById('form')).get('key'), "value1");
+    }, 'testFormDataGetFromForm');
+    test(function() {
+        assert_equals(new FormData(document.getElementById('form')).get('nil'), null);
+    }, 'testFormDataGetFromFormNull');
+    test(function() {
+        assert_equals(new FormData(document.getElementById('empty-form')).get('key'), null);
+    }, 'testFormDataGetFromEmptyForm');
+    test(function() {
+        assert_array_equals(new FormData(document.getElementById('form')).getAll('key'), ["value1", "value2"]);
+    }, 'testFormDataGetAllFromForm');
+    test(function() {
+        assert_array_equals(new FormData(document.getElementById('form')).getAll('nil'), []);
+    }, 'testFormDataGetAllFromFormNull');
+    test(function() {
+        assert_array_equals(new FormData(document.getElementById('empty-form')).getAll('key'), []);
+    }, 'testFormDataGetAllFromEmptyForm');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/get.any.js
@@ -0,0 +1,28 @@
+// META: title=FormData: get and getAll
+
+    test(function() {
+        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).get('key'), "value1");
+    }, 'testFormDataGet');
+    test(function() {
+        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).get('nil'), null);
+    }, 'testFormDataGetNull1');
+    test(function() {
+        assert_equals(create_formdata().get('key'), null);
+    }, 'testFormDataGetNull2');
+    test(function() {
+        assert_array_equals(create_formdata(['key', 'value1'], ['key', 'value2']).getAll('key'), ["value1", "value2"]);
+    }, 'testFormDataGetAll');
+    test(function() {
+        assert_array_equals(create_formdata(['key', 'value1'], ['key', 'value2']).getAll('nil'), []);
+    }, 'testFormDataGetAllEmpty1');
+    test(function() {
+        assert_array_equals(create_formdata().getAll('key'), []);
+    }, 'testFormDataGetAllEmpty2');
+
+    function create_formdata() {
+        var fd = new FormData();
+        for (var i = 0; i < arguments.length; i++) {
+            fd.append.apply(fd, arguments[i]);
+        };
+        return fd;
+    }
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/has-formelement.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html lang=en>
+<meta charset=utf-8>
+<title>FormData: has (with form element)</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-get" />
+    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-getall" />
+<div id="log"></div>
+<form id="form">
+    <input type="hidden" name="key" value="value1">
+    <input type="hidden" name="key" value="value2">
+</form>
+<form id="empty-form"></form>
+<script>
+    test(function() {
+        assert_equals(new FormData(document.getElementById('form')).has('key'), true);
+    }, 'testFormDataHasFromForm');
+    test(function() {
+        assert_equals(new FormData(document.getElementById('form')).has('nil'), false);
+    }, 'testFormDataHasFromFormNull');
+    test(function() {
+        assert_equals(new FormData(document.getElementById('empty-form')).has('key'), false);
+    }, 'testFormDataHasFromEmptyForm');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/has.any.js
@@ -0,0 +1,19 @@
+// META: title=FormData: has
+
+    test(function() {
+        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).has('key'), true);
+    }, 'testFormDataHas');
+    test(function() {
+        assert_equals(create_formdata(['key', 'value1'], ['key', 'value2']).has('nil'), false);
+    }, 'testFormDataHasEmpty1');
+    test(function() {
+        assert_equals(create_formdata().has('key'), false);
+    }, 'testFormDataHasEmpty2');
+
+    function create_formdata() {
+        var fd = new FormData();
+        for (var i = 0; i < arguments.length; i++) {
+            fd.append.apply(fd, arguments[i]);
+        };
+        return fd;
+    }
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/set-blob.any.js
@@ -0,0 +1,50 @@
+// META: title=formData.set(blob) and formData.set(file)
+
+"use strict";
+
+const formData = new FormData();
+
+test(() => {
+  formData.set("blob-1", new Blob());
+  const blob1 = formData.get("blob-1");
+  assert_equals(blob1.constructor.name, "File");
+  assert_equals(blob1.name, "blob");
+  assert_equals(blob1.type, "");
+  assert_less_than(Math.abs(blob1.lastModified - Date.now()), 200, "lastModified should be now");
+}, "blob without type");
+
+test(() => {
+  formData.set("blob-2", new Blob([], { type: "text/plain" }));
+  const blob2 = formData.get("blob-2");
+  assert_equals(blob2.constructor.name, "File");
+  assert_equals(blob2.name, "blob");
+  assert_equals(blob2.type, "text/plain");
+  assert_less_than(Math.abs(blob2.lastModified - Date.now()), 200, "lastModified should be now");
+}, "blob with type");
+
+test(() => {
+  formData.set("blob-3", new Blob(), "custom name");
+  const blob3 = formData.get("blob-3");
+  assert_equals(blob3.constructor.name, "File");
+  assert_equals(blob3.name, "custom name");
+  assert_equals(blob3.type, "");
+  assert_less_than(Math.abs(blob3.lastModified - Date.now()), 200, "lastModified should be now");
+}, "blob with custom name");
+
+test(() => {
+  formData.set("file-1", new File([], "name"));
+  const file1 = formData.get("file-1");
+  assert_equals(file1.constructor.name, "File");
+  assert_equals(file1.name, "name");
+  assert_equals(file1.type, "");
+  assert_less_than(Math.abs(file1.lastModified - Date.now()), 200, "lastModified should be now");
+}, "file without lastModified or custom name");
+
+test(() => {
+  formData.set("file-2", new File([], "name", { lastModified: 123 }), "custom name");
+  const file2 = formData.get("file-2");
+  assert_equals(file2.constructor.name, "File");
+  assert_equals(file2.name, "custom name");
+  assert_equals(file2.type, "");
+  assert_equals(file2.lastModified, 123, "lastModified should be 123");
+}, "file with lastModified and custom name");
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/set-formelement.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>FormData: set (with form element)</title>
+<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata-set">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<form id="form"></form>
+<script>
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.set('key', 'value1');
+        assert_equals(fd.get('key'), "value1");
+    }, 'testFormDataSetToForm1');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.set('key', 'value2');
+        fd.set('key', 'value1');
+        assert_equals(fd.get('key'), "value1");
+    }, 'testFormDataSetToForm2');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.set('key', undefined);
+        assert_equals(fd.get('key'), "undefined");
+    }, 'testFormDataSetToFormUndefined1');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.set('key', undefined);
+        fd.set('key', 'value1');
+        assert_equals(fd.get('key'), "value1");
+    }, 'testFormDataSetToFormUndefined2');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.set('key', null);
+        assert_equals(fd.get('key'), "null");
+    }, 'testFormDataSetToFormNull1');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        fd.set('key', null);
+        fd.set('key', 'value1');
+        assert_equals(fd.get('key'), "value1");
+    }, 'testFormDataSetToFormNull2');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        assert_throws_js(TypeError, () => {fd.set('name', "string", 'filename')});
+    }, 'testFormDataSetToFormString');
+    test(function() {
+        var fd = new FormData(document.getElementById("form"));
+        assert_throws_js(TypeError, () => {fd.set('name', new URLSearchParams(), 'filename')});
+    }, 'testFormDataSetToFormWrongPlatformObject');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/xhr/formdata/set.any.js
@@ -0,0 +1,36 @@
+// META: title=FormData: set
+
+    test(function() {
+        assert_equals(create_formdata(['key', 'value1']).get('key'), "value1");
+    }, 'testFormDataSet1');
+    test(function() {
+        assert_equals(create_formdata(['key', 'value2'], ['key', 'value1']).get('key'), "value1");
+    }, 'testFormDataSet2');
+    test(function() {
+        assert_equals(create_formdata(['key', undefined]).get('key'), "undefined");
+    }, 'testFormDataSetUndefined1');
+    test(function() {
+        assert_equals(create_formdata(['key', undefined], ['key', 'value1']).get('key'), "value1");
+    }, 'testFormDataSetUndefined2');
+    test(function() {
+        assert_equals(create_formdata(['key', null]).get('key'), "null");
+    }, 'testFormDataSetNull1');
+    test(function() {
+        assert_equals(create_formdata(['key', null], ['key', 'value1']).get('key'), "value1");
+    }, 'testFormDataSetNull2');
+    test(function() {
+        var fd = new FormData();
+        fd.set('key', new Blob([]), 'blank.txt');
+        var file = fd.get('key');
+
+        assert_true(file instanceof File);
+        assert_equals(file.name, 'blank.txt');
+    }, 'testFormDataSetEmptyBlob');
+
+    function create_formdata() {
+        var fd = new FormData();
+        for (var i = 0; i < arguments.length; i++) {
+            fd.set.apply(fd, arguments[i]);
+        };
+        return fd;
+    }