1// META: title=File constructor 2 3const to_string_obj = { toString: () => 'a string' }; 4const to_string_throws = { toString: () => { throw new Error('expected'); } }; 5 6test(function() { 7 assert_true("File" in globalThis, "globalThis should have a File property."); 8}, "File interface object exists"); 9 10test(t => { 11 assert_throws_js(TypeError, () => new File(), 12 'Bits argument is required'); 13 assert_throws_js(TypeError, () => new File([]), 14 'Name argument is required'); 15}, 'Required arguments'); 16 17function test_first_argument(arg1, expectedSize, testName) { 18 test(function() { 19 var file = new File(arg1, "dummy"); 20 assert_true(file instanceof File); 21 assert_equals(file.name, "dummy"); 22 assert_equals(file.size, expectedSize); 23 assert_equals(file.type, ""); 24 // assert_false(file.isClosed); XXX: File.isClosed doesn't seem to be implemented 25 assert_not_equals(file.lastModified, ""); 26 }, testName); 27} 28 29test_first_argument([], 0, "empty fileBits"); 30test_first_argument(["bits"], 4, "DOMString fileBits"); 31test_first_argument([""], 16, "Unicode DOMString fileBits"); 32test_first_argument([new String('string object')], 13, "String object fileBits"); 33test_first_argument([new Blob()], 0, "Empty Blob fileBits"); 34test_first_argument([new Blob(["bits"])], 4, "Blob fileBits"); 35test_first_argument([new File([], 'world.txt')], 0, "Empty File fileBits"); 36test_first_argument([new File(["bits"], 'world.txt')], 4, "File fileBits"); 37test_first_argument([new ArrayBuffer(8)], 8, "ArrayBuffer fileBits"); 38test_first_argument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4, "Typed array fileBits"); 39test_first_argument(["bits", new Blob(["bits"]), new Blob(), new Uint8Array([0x50, 0x41]), 40 new Uint16Array([0x5353]), new Uint32Array([0x53534150])], 16, "Various fileBits"); 41test_first_argument([12], 2, "Number in fileBits"); 42test_first_argument([[1,2,3]], 5, "Array in fileBits"); 43test_first_argument([{}], 15, "Object in fileBits"); // "[object Object]" 44if (globalThis.document !== undefined) { 45 test_first_argument([document.body], 24, "HTMLBodyElement in fileBits"); // "[object HTMLBodyElement]" 46} 47test_first_argument([to_string_obj], 8, "Object with toString in fileBits"); 48test_first_argument({[Symbol.iterator]() { 49 let i = 0; 50 return {next: () => [ 51 {done:false, value:'ab'}, 52 {done:false, value:'cde'}, 53 {done:true} 54 ][i++]}; 55}}, 5, 'Custom @@iterator'); 56 57[ 58 'hello', 59 0, 60 null 61].forEach(arg => { 62 test(t => { 63 assert_throws_js(TypeError, () => new File(arg, 'world.html'), 64 'Constructor should throw for invalid bits argument'); 65 }, `Invalid bits argument: ${JSON.stringify(arg)}`); 66}); 67 68test(t => { 69 assert_throws_js(Error, () => new File([to_string_throws], 'name.txt'), 70 'Constructor should propagate exceptions'); 71}, 'Bits argument: object that throws'); 72 73 74function test_second_argument(arg2, expectedFileName, testName) { 75 test(function() { 76 var file = new File(["bits"], arg2); 77 assert_true(file instanceof File); 78 assert_equals(file.name, expectedFileName); 79 }, testName); 80} 81 82test_second_argument("dummy", "dummy", "Using fileName"); 83test_second_argument("dummy/foo", "dummy/foo", 84 "No replacement when using special character in fileName"); 85test_second_argument(null, "null", "Using null fileName"); 86test_second_argument(1, "1", "Using number fileName"); 87test_second_argument('', '', "Using empty string fileName"); 88if (globalThis.document !== undefined) { 89 test_second_argument(document.body, '[object HTMLBodyElement]', "Using object fileName"); 90} 91 92// testing the third argument 93[ 94 {type: 'text/plain', expected: 'text/plain'}, 95 {type: 'text/plain;charset=UTF-8', expected: 'text/plain;charset=utf-8'}, 96 {type: 'TEXT/PLAIN', expected: 'text/plain'}, 97 {type: '/', expected: ''}, 98 {type: 'ascii/nonprintable\u001F', expected: ''}, 99 {type: 'ascii/nonprintable\u007F', expected: ''}, 100 {type: 'nonascii\u00EE', expected: ''}, 101 {type: 'nonascii\u1234', expected: ''}, 102 {type: 'nonparsable', expected: 'nonparsable'} 103].forEach(testCase => { 104 test(t => { 105 var file = new File(["bits"], "dummy", { type: testCase.type}); 106 assert_true(file instanceof File); 107 assert_equals(file.type, testCase.expected); 108 }, `Using type in File constructor: ${testCase.type}`); 109}); 110test(function() { 111 var file = new File(["bits"], "dummy", { lastModified: 42 }); 112 assert_true(file instanceof File); 113 assert_equals(file.lastModified, 42); 114}, "Using lastModified"); 115test(function() { 116 var file = new File(["bits"], "dummy", { name: "foo" }); 117 assert_true(file instanceof File); 118 assert_equals(file.name, "dummy"); 119}, "Misusing name"); 120test(function() { 121 var file = new File(["bits"], "dummy", { unknownKey: "value" }); 122 assert_true(file instanceof File); 123 assert_equals(file.name, "dummy"); 124}, "Unknown properties are ignored"); 125 126[ 127 123, 128 123.4, 129 true, 130 'abc' 131].forEach(arg => { 132 test(t => { 133 assert_throws_js(TypeError, () => new File(['bits'], 'name.txt', arg), 134 'Constructor should throw for invalid property bag type'); 135 }, `Invalid property bag: ${JSON.stringify(arg)}`); 136}); 137 138[ 139 null, 140 undefined, 141 [1,2,3], 142 /regex/, 143 function() {} 144].forEach(arg => { 145 test(t => { 146 assert_equals(new File(['bits'], 'name.txt', arg).size, 4, 147 'Constructor should accept object-ish property bag type'); 148 }, `Unusual but valid property bag: ${arg}`); 149}); 150 151test(t => { 152 assert_throws_js(Error, 153 () => new File(['bits'], 'name.txt', {type: to_string_throws}), 154 'Constructor should propagate exceptions'); 155}, 'Property bag propagates exceptions'); 156