Added Tests, Fixed Small Issue, Removed More Caching, and General Code Fixes

This commit is contained in:
Ahmad 2025-01-01 16:46:43 -05:00
parent 9e45249377
commit dbbfc7a9d8
No known key found for this signature in database
GPG key ID: 8FD8A93530D182BF
8 changed files with 116 additions and 28 deletions

View file

@ -1,21 +1,9 @@
import '@testing-library/jest-dom';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { toast } from 'sonner';
import { BoardTitleForm } from '@/app/(platform)/(dashboard)/board/[boardId]/_components/board-title-form';
import { Board } from '@prisma/client';
jest.mock('sonner', () => ({
toast: {
success: jest.fn(),
error: jest.fn(),
},
}));
jest.mock('@/actions/update-board', () => ({
updateBoard: jest.fn(),
}));
jest.mock('@/hooks/use-action', () => ({
useAction: jest.fn().mockImplementation(() => ({
execute: jest.fn().mockImplementation(({ title }) => {

View file

@ -1,4 +1,3 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import Page from '@/app/(main)/page';

View file

@ -0,0 +1,80 @@
import '@testing-library/jest-dom';
import {
render,
screen,
fireEvent,
act,
waitFor,
} from '@testing-library/react';
import { toast } from 'sonner';
import { ListHeader } from '@/app/(platform)/(dashboard)/board/[boardId]/_components/list-header';
jest.mock('@/hooks/use-action', () => ({
useAction: jest.fn().mockImplementation(() => ({
execute: jest.fn().mockImplementation(({ title }) => {
Promise.resolve().then(() => {
toast.success(`Renamed to "${title}"`);
});
}),
})),
}));
const mockList = {
id: '1',
title: 'Test List',
boardId: 'board1',
order: 1,
createdAt: new Date(),
updatedAt: new Date(),
};
const mockOnAddCard = jest.fn();
describe('ListHeader', () => {
it('should render correctly in browser environment', () => {
render(<ListHeader data={mockList} onAddCard={mockOnAddCard} />);
expect(screen.getByText('Test List')).toBeInTheDocument();
});
it('should switch to edit mode when clicked', async () => {
render(<ListHeader data={mockList} onAddCard={mockOnAddCard} />);
const listButton = screen.getByText('Test List');
fireEvent.click(listButton);
const editableInput = await screen.findByDisplayValue('Test List');
expect(editableInput).toBeInTheDocument();
});
it('should update list title when form is blurred', async () => {
render(<ListHeader data={mockList} onAddCard={mockOnAddCard} />);
const listButton = screen.getByText('Test List');
fireEvent.click(listButton);
const editableInput = await screen.findByDisplayValue('Test List');
fireEvent.change(editableInput, { target: { value: 'Updated Title' } });
fireEvent.blur(editableInput);
await waitFor(() => {
expect(toast.success).toHaveBeenCalledWith('Renamed to "Updated Title"');
});
});
it('should update list title when escape key is pressed', async () => {
render(<ListHeader data={mockList} onAddCard={mockOnAddCard} />);
const listButton = screen.getByText('Test List');
fireEvent.click(listButton);
const editableInput = await screen.findByDisplayValue('Test List');
fireEvent.change(editableInput, { target: { value: 'Updated Title' } });
fireEvent.keyDown(editableInput, { key: 'Escape', code: 'Escape' });
await waitFor(() => {
expect(toast.success).toHaveBeenCalledWith('Renamed to "Updated Title"');
});
});
});

View file

@ -1,6 +1,6 @@
'use client';
import { useState, useRef } from 'react';
import { useState, useRef, useEffect } from 'react';
import { useEventListener } from 'usehooks-ts';
import { List } from '@prisma/client';
import { toast } from 'sonner';
@ -20,7 +20,10 @@ export const ListHeader = ({ data, onAddCard }: ListHeaderProps) => {
const [title, setTitle] = useState(data.title);
const [isEditing, setIsEditing] = useState(false);
const formRef = useRef<HTMLFormElement>(document.createElement('form'));
const formRef = useRef<HTMLFormElement>(null);
useEffect(() => {
formRef.current = document.createElement('form');
}, []);
const inputRef = useRef<HTMLInputElement>(null);
const enableEditing = () => {
@ -72,8 +75,13 @@ export const ListHeader = ({ data, onAddCard }: ListHeaderProps) => {
<div className='flex items-start justify-between gap-x-2 px-2 pt-2 text-sm font-semibold'>
{isEditing ? (
<form ref={formRef} action={onSubmit} className='flex-1 px-[2px]'>
<input hidden id='id' name='id' value={data.id} />
<input hidden id='boardId' name='boardId' value={data.boardId} />
<input hidden id='id' name='id' defaultValue={data.id} />
<input
hidden
id='boardId'
name='boardId'
defaultValue={data.boardId}
/>
<FormInput
ref={inputRef}
onBlur={onBlur}

View file

@ -35,7 +35,6 @@ const BoardIdPage = async (props: BoardIdPageProps) => {
orderBy: {
order: 'asc',
},
cacheStrategy: { ttl: 30, swr: 60 },
});
return (

View file

@ -35,11 +35,6 @@ export async function GET(
return new NextResponse(JSON.stringify(auditLogs), {
status: 200,
headers: {
'Cache-Control': 'public, s-maxage=1',
'CDN-Cache-Control': 'public, s-maxage=30',
'Vercel-CDN-Cache-Control': 'public, s-maxage=60',
},
});
} catch (error) {
return new NextResponse(JSON.stringify(error), { status: 500 });

View file

@ -40,11 +40,6 @@ export async function GET(
return new NextResponse(JSON.stringify(card), {
status: 200,
headers: {
'Cache-Control': 'public, s-maxage=1',
'CDN-Cache-Control': 'public, s-maxage=30',
'Vercel-CDN-Cache-Control': 'public, s-maxage=60',
},
});
} catch (error) {
return new NextResponse(JSON.stringify(error), { status: 500 });

View file

@ -1 +1,25 @@
import '@testing-library/jest-dom';
import { toast } from 'sonner';
jest.mock('sonner', () => ({
toast: {
success: jest.fn(),
error: jest.fn(),
},
}));
jest.mock('@/actions/update-list', () => ({
updateList: jest.fn(),
}));
jest.mock('@/actions/delete-list', () => ({
deleteList: jest.fn(),
}));
jest.mock('@/actions/copy-list', () => ({
copyList: jest.fn(),
}));
jest.mock('@/actions/update-board', () => ({
updateBoard: jest.fn(),
}));