Skip to content
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
"dev": "vite",
"build": "vite build",
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
"preview": "vite preview",
"test": "vitest",
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage"
},
"dependencies": {
"@dbml/core": "^3.13.9",
Expand Down Expand Up @@ -51,6 +54,7 @@
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.3.4",
"@vitest/ui": "3.2.4",
"eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-react": "^7.33.2",
Expand All @@ -59,7 +63,8 @@
"postcss": "^8.4.32",
"prettier": "3.2.5",
"tailwindcss": "^4.0.14",
"vite": "^6.3.6"
"vite": "^6.3.6",
"vitest": "^3.2.4"
},
"overrides": {
"follow-redirects": "^1.15.4"
Expand Down
161 changes: 161 additions & 0 deletions src/tests/utils/cache.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { describe, it, expect, beforeEach, vi } from "vitest";
import { loadCache, saveCache, deleteFromCache, STORAGE_KEY } from "../../utils/cache";

// Mock localStorage
const localStorageMock = {
getItem: vi.fn(),
setItem: vi.fn(),
removeItem: vi.fn(),
clear: vi.fn(),
};

Object.defineProperty(window, 'localStorage', {
value: localStorageMock,
writable: true,
});

describe("src/utils/cache.js", () => {
beforeEach(() => {
// Clear all mocks before each test
vi.clearAllMocks();
localStorageMock.getItem.mockReturnValue(null);
});

describe("loadCache", () => {
it("should retrieve the cached value if it exists", () => {
const mockCacheData = { key1: "value1", key2: "value2" };
localStorageMock.getItem.mockReturnValue(JSON.stringify(mockCacheData));

const result = loadCache();

expect(localStorageMock.getItem).toHaveBeenCalledWith(STORAGE_KEY);
expect(result).toEqual(mockCacheData);
});

it("should return empty object if the cache does not exist", () => {
localStorageMock.getItem.mockReturnValue(null);

const result = loadCache();

expect(localStorageMock.getItem).toHaveBeenCalledWith(STORAGE_KEY);
expect(result).toEqual({});
});

it("should return empty object if localStorage contains invalid JSON", () => {
localStorageMock.getItem.mockReturnValue("invalid json");

const result = loadCache();

expect(localStorageMock.getItem).toHaveBeenCalledWith(STORAGE_KEY);
expect(result).toEqual({});
});

it("should return empty object if localStorage throws an error", () => {
localStorageMock.getItem.mockImplementation(() => {
throw new Error("Storage error");
});

const result = loadCache();

expect(result).toEqual({});
});
});

describe("saveCache", () => {
it("should store the value in the cache", () => {
const cacheData = { key1: "value1", key2: "value2" };

saveCache(cacheData);

expect(localStorageMock.setItem).toHaveBeenCalledWith(
STORAGE_KEY,
JSON.stringify(cacheData)
);
});

it("should overwrite existing cache values", () => {
const initialCache = { key1: "oldValue" };
const newCache = { key1: "newValue", key2: "value2" };

// First save
saveCache(initialCache);
expect(localStorageMock.setItem).toHaveBeenCalledWith(
STORAGE_KEY,
JSON.stringify(initialCache)
);

// Overwrite with new cache
saveCache(newCache);
expect(localStorageMock.setItem).toHaveBeenCalledWith(
STORAGE_KEY,
JSON.stringify(newCache)
);
expect(localStorageMock.setItem).toHaveBeenCalledTimes(2);
});

it("should handle empty cache object", () => {
const emptyCache = {};

saveCache(emptyCache);

expect(localStorageMock.setItem).toHaveBeenCalledWith(
STORAGE_KEY,
JSON.stringify(emptyCache)
);
});
});

describe("deleteFromCache", () => {
it("should remove the specified cache entry", () => {
const initialCache = { key1: "value1", key2: "value2", key3: "value3" };
const expectedCache = { key1: "value1", key3: "value3" };

// Mock loadCache to return initial cache
localStorageMock.getItem.mockReturnValue(JSON.stringify(initialCache));

deleteFromCache("key2");

// Should load cache first
expect(localStorageMock.getItem).toHaveBeenCalledWith(STORAGE_KEY);

// Should save the updated cache
expect(localStorageMock.setItem).toHaveBeenCalledWith(
STORAGE_KEY,
JSON.stringify(expectedCache)
);
});

it("should do nothing if the cache entry does not exist", () => {
const initialCache = { key1: "value1", key2: "value2" };

// Mock loadCache to return initial cache
localStorageMock.getItem.mockReturnValue(JSON.stringify(initialCache));

deleteFromCache("nonExistentKey");

// Should load cache
expect(localStorageMock.getItem).toHaveBeenCalledWith(STORAGE_KEY);

// Should not call setItem since no changes were made
expect(localStorageMock.setItem).not.toHaveBeenCalled();
});

it("should handle empty cache when trying to delete", () => {
localStorageMock.getItem.mockReturnValue(JSON.stringify({}));

deleteFromCache("someKey");

expect(localStorageMock.getItem).toHaveBeenCalledWith(STORAGE_KEY);
expect(localStorageMock.setItem).not.toHaveBeenCalled();
});

it("should handle null cache when trying to delete", () => {
localStorageMock.getItem.mockReturnValue(null);

deleteFromCache("someKey");

expect(localStorageMock.getItem).toHaveBeenCalledWith(STORAGE_KEY);
expect(localStorageMock.setItem).not.toHaveBeenCalled();
});
});
})
161 changes: 161 additions & 0 deletions src/tests/utils/fullscreen.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { describe, it, expect, beforeEach, vi } from "vitest";
import { enterFullscreen, exitFullscreen } from "../../utils/fullscreen";

describe("src/utils/fullscreen.js", () => {
beforeEach(() => {
// Reset all mocks before each test
vi.clearAllMocks();

// Clear any existing fullscreen methods on documentElement
delete document.documentElement.requestFullscreen;
delete document.documentElement.mozRequestFullScreen;
delete document.documentElement.webkitRequestFullscreen;
delete document.documentElement.msRequestFullscreen;

// Clear any existing fullscreen methods on document
delete document.exitFullscreen;
delete document.mozCancelFullScreen;
delete document.webkitExitFullscreen;
delete document.msExitFullscreen;
});

describe("enterFullscreen", () => {
it("should call requestFullscreen when available", () => {
const mockRequestFullscreen = vi.fn();
document.documentElement.requestFullscreen = mockRequestFullscreen;

enterFullscreen();

expect(mockRequestFullscreen).toHaveBeenCalledTimes(1);
});

it("should call mozRequestFullScreen when requestFullscreen is not available", () => {
const mockMozRequestFullScreen = vi.fn();
document.documentElement.requestFullscreen = undefined;
document.documentElement.mozRequestFullScreen = mockMozRequestFullScreen;

enterFullscreen();

expect(mockMozRequestFullScreen).toHaveBeenCalledTimes(1);
});

it("should call webkitRequestFullscreen when standard and moz methods are not available", () => {
const mockWebkitRequestFullscreen = vi.fn();
document.documentElement.requestFullscreen = undefined;
document.documentElement.mozRequestFullScreen = undefined;
document.documentElement.webkitRequestFullscreen = mockWebkitRequestFullscreen;

enterFullscreen();

expect(mockWebkitRequestFullscreen).toHaveBeenCalledTimes(1);
});

it("should call msRequestFullscreen when other methods are not available", () => {
const mockMsRequestFullscreen = vi.fn();
document.documentElement.requestFullscreen = undefined;
document.documentElement.mozRequestFullScreen = undefined;
document.documentElement.webkitRequestFullscreen = undefined;
document.documentElement.msRequestFullscreen = mockMsRequestFullscreen;

enterFullscreen();

expect(mockMsRequestFullscreen).toHaveBeenCalledTimes(1);
});

it("should handle case when no fullscreen methods are available", () => {
document.documentElement.requestFullscreen = undefined;
document.documentElement.mozRequestFullScreen = undefined;
document.documentElement.webkitRequestFullscreen = undefined;
document.documentElement.msRequestFullscreen = undefined;

// Should not throw an error
expect(() => enterFullscreen()).not.toThrow();
});

it("should prioritize standard method over vendor-specific ones", () => {
const mockRequestFullscreen = vi.fn();
const mockMozRequestFullScreen = vi.fn();
const mockWebkitRequestFullscreen = vi.fn();

document.documentElement.requestFullscreen = mockRequestFullscreen;
document.documentElement.mozRequestFullScreen = mockMozRequestFullScreen;
document.documentElement.webkitRequestFullscreen = mockWebkitRequestFullscreen;

enterFullscreen();

expect(mockRequestFullscreen).toHaveBeenCalledTimes(1);
expect(mockMozRequestFullScreen).not.toHaveBeenCalled();
expect(mockWebkitRequestFullscreen).not.toHaveBeenCalled();
});
});

describe("exitFullscreen", () => {
it("should call exitFullscreen when available", () => {
const mockExitFullscreen = vi.fn();
document.exitFullscreen = mockExitFullscreen;

exitFullscreen();

expect(mockExitFullscreen).toHaveBeenCalledTimes(1);
});

it("should call mozCancelFullScreen when exitFullscreen is not available", () => {
const mockMozCancelFullScreen = vi.fn();
document.exitFullscreen = undefined;
document.mozCancelFullScreen = mockMozCancelFullScreen;

exitFullscreen();

expect(mockMozCancelFullScreen).toHaveBeenCalledTimes(1);
});

it("should call webkitExitFullscreen when standard and moz methods are not available", () => {
const mockWebkitExitFullscreen = vi.fn();
document.exitFullscreen = undefined;
document.mozCancelFullScreen = undefined;
document.webkitExitFullscreen = mockWebkitExitFullscreen;

exitFullscreen();

expect(mockWebkitExitFullscreen).toHaveBeenCalledTimes(1);
});

it("should call msExitFullscreen when other methods are not available", () => {
const mockMsExitFullscreen = vi.fn();
document.exitFullscreen = undefined;
document.mozCancelFullScreen = undefined;
document.webkitExitFullscreen = undefined;
document.msExitFullscreen = mockMsExitFullscreen;

exitFullscreen();

expect(mockMsExitFullscreen).toHaveBeenCalledTimes(1);
});

it("should handle case when no exit fullscreen methods are available", () => {
document.exitFullscreen = undefined;
document.mozCancelFullScreen = undefined;
document.webkitExitFullscreen = undefined;
document.msExitFullscreen = undefined;

// Should not throw an error
expect(() => exitFullscreen()).not.toThrow();
});

it("should prioritize standard method over vendor-specific ones", () => {
const mockExitFullscreen = vi.fn();
const mockMozCancelFullScreen = vi.fn();
const mockWebkitExitFullscreen = vi.fn();

document.exitFullscreen = mockExitFullscreen;
document.mozCancelFullScreen = mockMozCancelFullScreen;
document.webkitExitFullscreen = mockWebkitExitFullscreen;

exitFullscreen();

expect(mockExitFullscreen).toHaveBeenCalledTimes(1);
expect(mockMozCancelFullScreen).not.toHaveBeenCalled();
expect(mockWebkitExitFullscreen).not.toHaveBeenCalled();
});
});
});
Loading