import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, act } from '@testing-library/svelte'; import PostView from './PostView.svelte'; import type { PostData } from '$lib/types/content-blocks'; import { page } from '$app/state'; // Mock toast store vi.mock('$lib/stores/toast.svelte', () => ({ addToast: vi.fn() })); const mockPost: PostData = { uri: 'at://did:plc:user1/at.riven.post/123', cid: 'cid123', author: { did: 'did:plc:user1', handle: 'user1.test', displayName: 'User One' }, createdAt: new Date().toISOString(), body: { text: 'Hello world' } }; describe('PostView', () => { beforeEach(() => { vi.useFakeTimers(); // @ts-ignore page.data.session = null; }); it('renders post content', () => { render(PostView, { post: mockPost }); expect(screen.getByText('User One')).toBeInTheDocument(); expect(screen.getByText('Hello world')).toBeInTheDocument(); }); it('shows reactive time updates', async () => { const past = new Date(Date.now() - 1000 * 60).toISOString(); // 1m ago const post = { ...mockPost, createdAt: past }; render(PostView, { post }); expect(screen.getByText(/1m ago/)).toBeInTheDocument(); // Fast forward 1 minute await act(() => { vi.advanceTimersByTime(60000); }); expect(screen.getByText(/2m ago/)).toBeInTheDocument(); }); it('shows delete button only for owner', () => { // Not owner const { unmount } = render(PostView, { post: mockPost }); expect(screen.queryByLabelText('Delete post')).not.toBeInTheDocument(); unmount(); // Owner // @ts-ignore page.data.session = { did: 'did:plc:user1' }; render(PostView, { post: mockPost }); expect(screen.getByLabelText('Delete post')).toBeInTheDocument(); }); it('calls delete API when delete button is clicked', async () => { // @ts-ignore page.data.session = { did: 'did:plc:user1' }; const fetchMock = vi.fn().mockResolvedValue({ ok: true }); global.fetch = fetchMock; render(PostView, { post: mockPost }); // Initial delete button click to show confirmation const deleteBtn = screen.getByLabelText('Delete post'); await fireEvent.click(deleteBtn); // Click confirm button const confirmBtn = screen.getByLabelText('Confirm delete post'); await fireEvent.click(confirmBtn); expect(fetchMock).toHaveBeenCalledWith('/api/posts', expect.objectContaining({ method: 'DELETE', body: JSON.stringify({ uri: mockPost.uri }) })); }); });