fix: resolve frontend build issues with fetch mocks and MUI Select component

This commit is contained in:
2026-02-05 17:26:34 -05:00
parent 512a9db08f
commit 551ae1890d
2 changed files with 40 additions and 17 deletions

View File

@@ -21,18 +21,23 @@ Object.defineProperty(window, 'matchMedia', {
}); });
// Mock fetch // Mock fetch
global.fetch = jest.fn((url: string) => { global.fetch = jest.fn((input: RequestInfo | URL, init?: RequestInit) => {
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
if (url.includes('/api/files') && !url.includes('/api/files/')) { if (url.includes('/api/files') && !url.includes('/api/files/')) {
return Promise.resolve({ return Promise.resolve({
ok: true, ok: true,
status: 200,
headers: new Headers(),
json: () => Promise.resolve({ files: ['test.md'] }), json: () => Promise.resolve({ files: ['test.md'] }),
}); } as Response);
} }
return Promise.resolve({ return Promise.resolve({
ok: true, ok: true,
status: 200,
headers: new Headers(),
json: () => Promise.resolve({}), json: () => Promise.resolve({}),
}); } as Response);
}) as jest.Mock; }) as jest.MockedFunction<typeof fetch>;
describe('App', () => { describe('App', () => {
beforeEach(() => { beforeEach(() => {
@@ -54,22 +59,32 @@ describe('App', () => {
}); });
test('opens file when clicked', async () => { test('opens file when clicked', async () => {
// Mock the file content fetch // Mock the file content fetch with a custom mock
fetch.mockImplementationOnce((url: string) => { const mockFetch = jest.fn((input: RequestInfo | URL, init?: RequestInit) => {
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
if (url.includes('/api/files')) { if (url.includes('/api/files')) {
return Promise.resolve({ return Promise.resolve({
ok: true, ok: true,
status: 200,
headers: new Headers(),
json: () => Promise.resolve({ files: ['test.md'] }), json: () => Promise.resolve({ files: ['test.md'] }),
}); } as Response);
} }
if (url.includes('test.md')) { if (url.includes('test.md')) {
return Promise.resolve({ return Promise.resolve({
ok: true, ok: true,
status: 200,
headers: new Headers(),
json: () => Promise.resolve({ content: '# Test Content' }), json: () => Promise.resolve({ content: '# Test Content' }),
}); } as Response);
} }
return Promise.resolve({ ok: true }); return Promise.resolve({
ok: true,
status: 200,
headers: new Headers(),
} as Response);
}); });
global.fetch = mockFetch;
render(<App />); render(<App />);
@@ -89,15 +104,23 @@ describe('App', () => {
test('creates new file', async () => { test('creates new file', async () => {
// Mock the create file endpoint // Mock the create file endpoint
fetch.mockImplementationOnce((url: string) => { const mockFetch = jest.fn((input: RequestInfo | URL, init?: RequestInit) => {
if (url.includes('/api/files') && fetch.mock.calls.length === 1) { const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
if (url.includes('/api/files') && !init?.method) {
return Promise.resolve({ return Promise.resolve({
ok: true, ok: true,
status: 200,
headers: new Headers(),
json: () => Promise.resolve({ files: [] }), json: () => Promise.resolve({ files: [] }),
}); } as Response);
} }
return Promise.resolve({ ok: true }); return Promise.resolve({
ok: true,
status: 200,
headers: new Headers(),
} as Response);
}); });
global.fetch = mockFetch;
render(<App />); render(<App />);
@@ -117,7 +140,7 @@ describe('App', () => {
// Verify fetch was called with POST // Verify fetch was called with POST
await waitFor(() => { await waitFor(() => {
expect(fetch).toHaveBeenCalledWith('/api/files', { expect(mockFetch).toHaveBeenCalledWith('/api/files', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import { Box, Typography, TextField, Button, List, ListItem, ListItemText, IconButton, Divider, AppBar, Toolbar, Drawer, CssBaseline, useTheme, ThemeProvider, createTheme, Select, MenuItem, FormControl, InputLabel } from '@mui/material'; import { Box, Typography, TextField, Button, List, ListItem, ListItemText, IconButton, Divider, AppBar, Toolbar, Drawer, CssBaseline, ThemeProvider, createTheme, Select, MenuItem, FormControl, InputLabel, SelectChangeEvent } from '@mui/material';
import { Delete, Edit, Add, Save, Menu as MenuIcon } from '@mui/icons-material'; import { Delete, Add, Save, Menu as MenuIcon } from '@mui/icons-material';
interface FileItem { interface FileItem {
filename: string; filename: string;
@@ -116,7 +116,7 @@ const App: React.FC = () => {
}, },
}); });
const handleThemeChange = (event: React.ChangeEvent<{ value: unknown }>) => { const handleThemeChange = (event: SelectChangeEvent<'light' | 'dark' | 'system'>) => {
setThemeMode(event.target.value as 'light' | 'dark' | 'system'); setThemeMode(event.target.value as 'light' | 'dark' | 'system');
}; };