Repository: capricorn86/happy-dom (TypeScript)

Issue:
FileReader never throws errors
**Describe the bug**
```
const reader = new FileReader();
reader.readAsDataURL(file);

reader.onload = function () {
  resolve(reader.result);
  };
reader.onerror = function (error) {
  reject(error); // never goes here
};
```

The following test failed:
```
it('should reject with an error when passed an invalid file', async () => {
    const invalidFile = {};
    await expect(fileToBase64(invalidFile)).rejects.toThrowError();
  });
  
  - Expected: 
[Error: rejected promise]

+ Received: 
"data:application/octet-stream;base64,"
```

**Expected behavior**
To throw an error. For example, Mozilla throws the error:
Uncaught TypeError: FileReader.readAsDataURL: Argument 1 does not implement interface Blob.

**Screenshots**

**Device:**
 - OS: MacOS 14.6.1
 - Browser Mozilla
 - Version 15.7.4

**Additional context**
Vitest tests.
The test provided passes on `jsdom` environment



Discussion:

Patch:
diff --git a/packages/happy-dom/src/file/FileReader.ts b/packages/happy-dom/src/file/FileReader.ts
index 521257ae0..1c9de3c72 100644
--- a/packages/happy-dom/src/file/FileReader.ts
+++ b/packages/happy-dom/src/file/FileReader.ts
@@ -49,6 +49,11 @@ export default class FileReader extends EventTarget {
 	 * @param blob Blob.
 	 */
 	public readAsArrayBuffer(blob: Blob): void {
+		if (!(blob instanceof Blob)) {
+			throw new this[PropertySymbol.window].TypeError(
+				`Failed to execute 'readAsArrayBuffer' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		}
 		this.#readFile(blob, FileReaderFormatEnum.buffer);
 	}
 
@@ -58,6 +63,11 @@ export default class FileReader extends EventTarget {
 	 * @param blob Blob.
 	 */
 	public readAsBinaryString(blob: Blob): void {
+		if (!(blob instanceof Blob)) {
+			throw new this[PropertySymbol.window].TypeError(
+				`Failed to execute 'readAsBinaryString' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		}
 		this.#readFile(blob, FileReaderFormatEnum.binaryString);
 	}
 
@@ -67,6 +77,11 @@ export default class FileReader extends EventTarget {
 	 * @param blob Blob.
 	 */
 	public readAsDataURL(blob: Blob): void {
+		if (!(blob instanceof Blob)) {
+			throw new this[PropertySymbol.window].TypeError(
+				`Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		}
 		this.#readFile(blob, FileReaderFormatEnum.dataURL);
 	}
 
@@ -77,6 +92,11 @@ export default class FileReader extends EventTarget {
 	 * @param [encoding] Encoding.
 	 */
 	public readAsText(blob: Blob, encoding: string | null = null): void {
+		if (!(blob instanceof Blob)) {
+			throw new this[PropertySymbol.window].TypeError(
+				`Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		}
 		this.#readFile(blob, FileReaderFormatEnum.text, encoding || 'UTF-8');
 	}
 


Test patch:
diff --git a/packages/happy-dom/test/file/FileReader.test.ts b/packages/happy-dom/test/file/FileReader.test.ts
index dbb8455e4..edcce55a0 100644
--- a/packages/happy-dom/test/file/FileReader.test.ts
+++ b/packages/happy-dom/test/file/FileReader.test.ts
@@ -25,5 +25,82 @@ describe('FileReader', () => {
 			await window.happyDOM?.waitUntilComplete();
 			expect(result).toBe('data:text/plain;charset=utf-8;base64,VEVTVA==');
 		});
+
+		it('Reads Blob as data URL passing invalid parameter.', () => {
+			expect(() => {
+				fileReader.readAsDataURL(<any>'invalid');
+			}).toThrow(
+				`Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		});
+	});
+
+	describe('readAsText()', () => {
+		it('Reads Blob as text.', async () => {
+			const blob = new Blob(['TEST'], {
+				type: 'text/plain;charset=utf-8'
+			});
+			let result: string | null = null;
+			fileReader.addEventListener('load', () => {
+				result = <string>fileReader.result;
+			});
+			fileReader.readAsText(blob);
+			await window.happyDOM?.waitUntilComplete();
+			expect(result).toBe('TEST');
+		});
+
+		it('Reads Blob as text passing invalid parameter.', () => {
+			expect(() => {
+				fileReader.readAsText(<any>'invalid');
+			}).toThrow(
+				`Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		});
+	});
+
+	describe('readAsArrayBuffer()', () => {
+		it('Reads Blob as array buffer.', async () => {
+			const blob = new Blob(['TEST'], {
+				type: 'text/plain;charset=utf-8'
+			});
+			let result: ArrayBuffer | null = null;
+			fileReader.addEventListener('load', () => {
+				result = <ArrayBuffer>fileReader.result;
+			});
+			fileReader.readAsArrayBuffer(blob);
+			await window.happyDOM?.waitUntilComplete();
+			expect(result).toBeInstanceOf(ArrayBuffer);
+		});
+
+		it('Reads Blob as array buffer passing invalid parameter.', () => {
+			expect(() => {
+				fileReader.readAsArrayBuffer(<any>'invalid');
+			}).toThrow(
+				`Failed to execute 'readAsArrayBuffer' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		});
+	});
+
+	describe('readAsBinaryString()', () => {
+		it('Reads Blob as binary string.', async () => {
+			const blob = new Blob(['TEST'], {
+				type: 'text/plain;charset=utf-8'
+			});
+			let result: string | null = null;
+			fileReader.addEventListener('load', () => {
+				result = <string>fileReader.result;
+			});
+			fileReader.readAsBinaryString(blob);
+			await window.happyDOM?.waitUntilComplete();
+			expect(result).toBe('TEST');
+		});
+
+		it('Reads Blob as binary string passing invalid parameter.', () => {
+			expect(() => {
+				fileReader.readAsBinaryString(<any>'invalid');
+			}).toThrow(
+				`Failed to execute 'readAsBinaryString' on 'FileReader': parameter 1 is not of type 'Blob'.`
+			);
+		});
 	});
 });