Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/llms-txt-hub / apps/web/__tests__/integration/submit-project-validation.test.tsx |
| Date | Not specified in source |
| Repository | Janady13/llms-txt-hub |
| Revision | e0f4bf978d4df168369c7601d9c5f5ea89e84377 |
| Branch | main |
| Path or archive member | apps/web/__tests__/integration/submit-project-validation.test.tsx |
| Original SHA-256 | bb5c1f5afca617eeb81e5c8a23f1a2b3aa570ce8b52702bdcf8ad9997cbeded8 |
| Git blob SHA | aaf8b81555f2758e739acb17e66ec6929647c0d4 |
| Reading-copy SHA-256 | bb5c1f5afca617eeb81e5c8a23f1a2b3aa570ce8b52702bdcf8ad9997cbeded8 |
Recovered source transcript
Download complete source text ↓166 lines · 5.3 KB
/**
* Validation tests for project submission flow
*
* Tests form validation, error handling, and error recovery.
*/
import { expectValidationErrors } from '@/__tests__/utils/form-test-helpers'
import { TestSubmitProjectForm } from '@/__tests__/utils/test-components'
import { fireEvent, render, screen, userEvent, waitFor } from '@/__tests__/utils/test-utils.helper'
// Mock the API calls
const mockCheckUrl = jest.fn()
const mockFetchMetadata = jest.fn()
const mockSubmitProject = jest.fn()
// Make mocks available globally for the test component
;(global as any).mockCheckUrl = mockCheckUrl
;(global as any).mockFetchMetadata = mockFetchMetadata
;(global as any).mockSubmitProject = mockSubmitProject
describe('Submit Project Flow - Validation', () => {
let user: ReturnType<typeof userEvent.setup>
beforeEach(() => {
jest.clearAllMocks()
mockCheckUrl.mockResolvedValue({ valid: true, exists: false })
mockFetchMetadata.mockResolvedValue({
title: 'Fetched Title',
description: 'Fetched description'
})
mockSubmitProject.mockResolvedValue({ success: true })
user = userEvent.setup()
})
describe('Required Field Validation', () => {
it('shows validation errors for empty required fields', async () => {
render(<TestSubmitProjectForm />)
// Try to submit without filling any fields
await user.click(screen.getByTestId('submit-button'))
// Check all validation errors appear
await expectValidationErrors({
url: 'URL is required',
title: 'Title is required',
description: 'Description is required',
category: 'Category is required',
tags: 'At least one tag is required'
})
// Verify form was not submitted
expect(mockSubmitProject).not.toHaveBeenCalled()
})
it('clears validation errors when fields are corrected', async () => {
render(<TestSubmitProjectForm />)
// Submit to trigger validation
await user.click(screen.getByTestId('submit-button'))
// Verify error appears
expect(await screen.findByTestId('url-error')).toBeInTheDocument()
// Fix the error
await user.type(screen.getByTestId('url-input'), 'https://example.com')
await user.tab()
// Wait for error to clear
await waitFor(() => {
expect(screen.queryByTestId('url-error')).not.toBeInTheDocument()
})
})
})
describe('URL Validation', () => {
it('shows error for duplicate URLs', async () => {
// Mock duplicate URL check
mockCheckUrl.mockResolvedValue({ valid: true, exists: true })
render(<TestSubmitProjectForm />)
await user.type(screen.getByTestId('url-input'), 'https://duplicate.com')
await user.tab()
expect(await screen.findByTestId('url-error')).toHaveTextContent('This URL already exists')
// Verify metadata was not fetched for duplicate URL
expect(mockFetchMetadata).not.toHaveBeenCalled()
})
it('handles URL validation failure gracefully', async () => {
// Mock API error
mockCheckUrl.mockRejectedValue(new Error('Network error'))
render(<TestSubmitProjectForm />)
await user.type(screen.getByTestId('url-input'), 'https://example.com')
await user.tab()
expect(await screen.findByTestId('url-error')).toHaveTextContent('Failed to validate URL')
})
})
describe('Metadata Handling', () => {
it('handles metadata fetch failure gracefully', async () => {
// URL check succeeds but metadata fails
mockCheckUrl.mockResolvedValue({ valid: true, exists: false })
mockFetchMetadata.mockRejectedValue(new Error('Failed to fetch'))
render(<TestSubmitProjectForm />)
await user.type(screen.getByTestId('url-input'), 'https://example.com')
await user.tab()
await waitFor(() => {
expect(mockCheckUrl).toHaveBeenCalled()
})
// Fields should remain empty when metadata fetch fails
expect(screen.getByTestId('title-input')).toHaveValue('')
expect(screen.getByTestId('description-input')).toHaveValue('')
})
})
describe('Submission Error Handling', () => {
it('handles submission failure with error message', async () => {
// Mock submission failure
mockSubmitProject.mockRejectedValue(new Error('Server error'))
render(<TestSubmitProjectForm />)
// Fill URL and trigger blur to fetch metadata
const urlInput = screen.getByTestId('url-input')
await user.type(urlInput, 'https://example.com')
await user.tab() // This triggers blur and metadata fetch
// Wait for metadata fetch to complete
await waitFor(() => {
expect(screen.getByTestId('title-input')).toHaveValue('Fetched Title')
})
// Now select tags after metadata has been fetched
fireEvent.click(screen.getByTestId('tag-ai'))
await waitFor(() => {
expect(screen.getByTestId('tag-ai')).toBeChecked()
})
// Select category (this can be done anytime)
await user.selectOptions(screen.getByTestId('category-select'), 'AI Tools')
// Submit
await user.click(screen.getByTestId('submit-button'))
// Check error message
expect(await screen.findByTestId('submit-error')).toHaveTextContent(
'Failed to submit project'
)
// Verify success message is not shown
expect(screen.queryByTestId('success-message')).not.toBeInTheDocument()
})
})
})