'use strict'; const common = require('../common'); const assert = require('assert'); const { Blob, File } = require('buffer'); const { inspect } = require('util'); { // ensure File extends Blob assert.deepStrictEqual(Object.getPrototypeOf(File.prototype), Blob.prototype); } { assert.throws(() => new File(), TypeError); assert.throws(() => new File([]), TypeError); } { const properties = ['name', 'lastModified']; for (const prop of properties) { const desc = Object.getOwnPropertyDescriptor(File.prototype, prop); assert.notStrictEqual(desc, undefined); // Ensure these properties are getters. assert.strictEqual(desc.get?.name, `get ${prop}`); assert.strictEqual(desc.set, undefined); assert.strictEqual(desc.enumerable, true); assert.strictEqual(desc.configurable, true); } } { const file = new File([], ''); assert.strictEqual(file[Symbol.toStringTag], 'File'); assert.strictEqual(File.prototype[Symbol.toStringTag], 'File'); } { assert.throws(() => File.prototype.name, TypeError); assert.throws(() => File.prototype.lastModified, TypeError); } { const keys = Object.keys(File.prototype).sort(); assert.deepStrictEqual(keys, ['lastModified', 'name']); } { const file = new File([], 'dummy.txt.exe'); assert.strictEqual(file.name, 'dummy.txt.exe'); assert.strictEqual(file.size, 0); assert.strictEqual(typeof file.lastModified, 'number'); assert(file.lastModified <= Date.now()); } { const emptyFile = new File([], 'empty.txt'); const blob = new Blob(['hello world']); emptyFile.text.call(blob).then(common.mustCall((text) => { assert.strictEqual(text, 'hello world'); })); } { const toPrimitive = { [Symbol.toPrimitive]() { return 'NaN'; } }; const invalidLastModified = [ null, 'string', false, toPrimitive, ]; for (const lastModified of invalidLastModified) { const file = new File([], '', { lastModified }); assert.strictEqual(file.lastModified, 0); } } { const file = new File([], '', { lastModified: undefined }); assert.notStrictEqual(file.lastModified, 0); } { const toPrimitive = { [Symbol.toPrimitive]() { throw new TypeError('boom'); } }; const throwValues = [ BigInt(3n), toPrimitive, ]; for (const lastModified of throwValues) { assert.throws(() => new File([], '', { lastModified }), TypeError); } } { const valid = [ { [Symbol.toPrimitive]() { return 10; } }, new Number(10), 10, ]; for (const lastModified of valid) { assert.strictEqual(new File([], '', { lastModified }).lastModified, 10); } } { const file = new File([], ''); assert(inspect(file).startsWith('File { size: 0, type: \'\', name: \'\', lastModified:')); } { function MyClass() {} MyClass.prototype.lastModified = 10; const file = new File([], '', new MyClass()); assert.strictEqual(file.lastModified, 10); } { let counter = 0; new File([], '', { get lastModified() { counter++; return 10; } }); assert.strictEqual(counter, 1); } { const getter = Object.getOwnPropertyDescriptor(File.prototype, 'name').get; [ undefined, null, true, ].forEach((invalidThis) => { assert.throws( () => getter.call(invalidThis), TypeError ); }); } (async () => { // File should be cloneable via structuredClone. // Refs: https://github.com/nodejs/node/issues/47612 const body = ['hello, ', 'world']; const lastModified = Date.now() - 10_000; const name = 'hello_world.txt'; const file = new File(body, name, { lastModified }); const clonedFile = structuredClone(file); assert.deepStrictEqual(await clonedFile.text(), await file.text()); assert.deepStrictEqual(clonedFile.lastModified, file.lastModified); assert.deepStrictEqual(clonedFile.name, file.name); const clonedFile2 = structuredClone(clonedFile); assert.deepStrictEqual(await clonedFile2.text(), await clonedFile.text()); assert.deepStrictEqual(clonedFile2.lastModified, clonedFile.lastModified); assert.deepStrictEqual(clonedFile2.name, clonedFile.name); })().then(common.mustCall());