Files
formbricks-formbricks/apps/web/modules/storage/file-upload.test.ts
pandeymangg 8cbf58fe8d fix: tests
2025-09-02 10:29:36 +05:30

226 lines
6.8 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import * as fileUploadModule from "./file-upload";
// Mock global fetch
const mockFetch = vi.fn();
global.fetch = mockFetch;
const mockAtoB = vi.fn();
global.atob = mockAtoB;
// Mock FileReader
const mockFileReader = {
readAsDataURL: vi.fn(),
result: "data:image/jpeg;base64,test",
onload: null as any,
onerror: null as any,
};
// Mock File object
const createMockFile = (name: string, type: string, size: number) => {
const file = new File([], name, { type });
Object.defineProperty(file, "size", {
value: size,
writable: false,
});
return file;
};
describe("fileUpload", () => {
beforeEach(() => {
vi.clearAllMocks();
// Mock FileReader
global.FileReader = vi.fn(() => mockFileReader) as any;
global.atob = (base64) => Buffer.from(base64, "base64").toString("binary");
});
afterEach(() => {
vi.clearAllMocks();
});
test("should return error when no file is provided", async () => {
const result = await fileUploadModule.handleFileUpload(null as any, "test-env");
expect(result.error).toBe(fileUploadModule.FileUploadError.NO_FILE);
expect(result.url).toBe("");
});
test("should return FILE_SIZE_EXCEEDED if arrayBuffer is > 10MB even if file.size is OK", async () => {
const file = createMockFile("test.jpg", "image/jpeg", 1000); // file.size = 1KB
// Mock arrayBuffer to return >10MB buffer
file.arrayBuffer = vi.fn().mockResolvedValueOnce(new ArrayBuffer(11 * 1024 * 1024)); // 11MB
const result = await fileUploadModule.handleFileUpload(file, "env-oversize-buffer");
expect(result.error).toBe(fileUploadModule.FileUploadError.FILE_SIZE_EXCEEDED);
expect(result.url).toBe("");
});
test("should handle API error when getting signed URL", async () => {
const file = createMockFile("test.jpg", "image/jpeg", 1000);
// Mock failed API response
mockFetch.mockResolvedValueOnce({
ok: false,
});
const result = await fileUploadModule.handleFileUpload(file, "test-env");
expect(result.error).toBe("Upload failed. Please try again.");
expect(result.url).toBe("");
});
test("should handle successful file upload with presigned fields", async () => {
const file = createMockFile("test.jpg", "image/jpeg", 1000);
// Mock successful API response
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
data: {
signedUrl: "https://s3.example.com/upload",
fileUrl: "https://s3.example.com/file.jpg",
presignedFields: {
key: "value",
},
},
}),
});
// Mock successful upload response
mockFetch.mockResolvedValueOnce({
ok: true,
});
// Simulate FileReader onload
setTimeout(() => {
mockFileReader.onload();
}, 0);
const result = await fileUploadModule.handleFileUpload(file, "test-env");
expect(result.error).toBeUndefined();
expect(result.url).toBe("https://s3.example.com/file.jpg");
});
test("should handle upload error with presigned fields", async () => {
const file = createMockFile("test.jpg", "image/jpeg", 1000);
// Mock successful API response
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
data: {
signedUrl: "https://s3.example.com/upload",
fileUrl: "https://s3.example.com/file.jpg",
presignedFields: {
key: "value",
},
},
}),
});
global.atob = vi.fn(() => {
throw new Error("Failed to decode base64 string");
});
// Simulate FileReader onload
setTimeout(() => {
mockFileReader.onload();
}, 0);
const result = await fileUploadModule.handleFileUpload(file, "test-env");
expect(result.error).toBe("Upload failed. Please try again.");
expect(result.url).toBe("");
});
test("should handle upload error", async () => {
const file = createMockFile("test.jpg", "image/jpeg", 1000);
// Mock successful API response
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
data: {
signedUrl: "https://s3.example.com/upload",
fileUrl: "https://s3.example.com/file.jpg",
presignedFields: {
key: "value",
},
},
}),
});
// Mock failed upload response
mockFetch.mockResolvedValueOnce({
ok: false,
});
// Simulate FileReader onload
setTimeout(() => {
mockFileReader.onload();
}, 0);
const result = await fileUploadModule.handleFileUpload(file, "test-env");
expect(result.error).toBe("Upload failed. Please try again.");
expect(result.url).toBe("");
});
test("should catch unexpected errors and return UPLOAD_FAILED", async () => {
const file = createMockFile("test.jpg", "image/jpeg", 1000);
// Force arrayBuffer() to throw
file.arrayBuffer = vi.fn().mockImplementation(() => {
throw new Error("Unexpected crash in arrayBuffer");
});
const result = await fileUploadModule.handleFileUpload(file, "env-crash");
expect(result.error).toBe(fileUploadModule.FileUploadError.UPLOAD_FAILED);
expect(result.url).toBe("");
});
});
describe("fileUploadModule.toBase64", () => {
test("resolves with base64 string when FileReader succeeds", async () => {
const dummyFile = new File(["hello"], "hello.txt", { type: "text/plain" });
// Mock FileReader
const mockReadAsDataURL = vi.fn();
const mockFileReaderInstance = {
readAsDataURL: mockReadAsDataURL,
onload: null as ((this: FileReader, ev: ProgressEvent<FileReader>) => any) | null,
onerror: null,
result: "data:text/plain;base64,aGVsbG8=",
};
globalThis.FileReader = vi.fn(() => mockFileReaderInstance as unknown as FileReader) as any;
const promise = fileUploadModule.toBase64(dummyFile);
// Trigger the onload manually
mockFileReaderInstance.onload?.call(mockFileReaderInstance as unknown as FileReader, new Error("load"));
const result = await promise;
expect(result).toBe("data:text/plain;base64,aGVsbG8=");
});
test("rejects when FileReader errors", async () => {
const dummyFile = new File(["oops"], "oops.txt", { type: "text/plain" });
const mockReadAsDataURL = vi.fn();
const mockFileReaderInstance = {
readAsDataURL: mockReadAsDataURL,
onload: null,
onerror: null as ((this: FileReader, ev: ProgressEvent<FileReader>) => any) | null,
result: null,
};
globalThis.FileReader = vi.fn(() => mockFileReaderInstance as unknown as FileReader) as any;
const promise = fileUploadModule.toBase64(dummyFile);
// Simulate error
mockFileReaderInstance.onerror?.call(mockFileReaderInstance as unknown as FileReader, new Error("error"));
await expect(promise).rejects.toThrow();
});
});