Open kagomen opened 2 months ago
書籍検索アプリケーションの場合、以下のようなテストを実装することをお勧めします。各テストタイプごとに具体的な例を挙げ、ファイル構成についても説明します。
テスト対象:
例:
// src/utils/search.test.ts
import { describe, it, expect } from 'vitest'
import { searchBooks } from './search'
describe('searchBooks', () => {
it('should return matching books', async () => {
const result = await searchBooks('JavaScript')
expect(result.length).toBeGreaterThan(0)
expect(result[0]).toHaveProperty('title')
})
it('should return empty array for no matches', async () => {
const result = await searchBooks('xyzxyzxyz')
expect(result).toEqual([])
})
})
// src/utils/favorites.test.ts
import { describe, it, expect } from 'vitest'
import { addToFavorites, removeFromFavorites } from './favorites'
describe('Favorites', () => {
it('should add a book to favorites', () => {
const userId = 'user1'
const bookId = 'book1'
const result = addToFavorites(userId, bookId)
expect(result).toBeTruthy()
})
it('should remove a book from favorites', () => {
const userId = 'user1'
const bookId = 'book1'
const result = removeFromFavorites(userId, bookId)
expect(result).toBeTruthy()
})
})
テスト対象:
例:
// src/components/SearchForm.test.tsx
import { describe, it, expect, vi } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import SearchForm from './SearchForm'
describe('SearchForm', () => {
it('should call onSearch when form is submitted', () => {
const mockOnSearch = vi.fn()
render(<SearchForm onSearch={mockOnSearch} />)
const input = screen.getByPlaceholderText('Search books...')
fireEvent.change(input, { target: { value: 'React' } })
const submitButton = screen.getByText('Search')
fireEvent.click(submitButton)
expect(mockOnSearch).toHaveBeenCalledWith('React')
})
})
// src/components/BookList.test.tsx
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import BookList from './BookList'
describe('BookList', () => {
it('should render books correctly', () => {
const books = [
{ id: '1', title: 'React Basics', author: 'John Doe' },
{ id: '2', title: 'Advanced JavaScript', author: 'Jane Smith' },
]
render(<BookList books={books} />)
expect(screen.getByText('React Basics')).toBeInTheDocument()
expect(screen.getByText('Advanced JavaScript')).toBeInTheDocument()
})
})
テスト対象:
例:
// src/integration/searchFlow.test.ts
import { describe, it, expect, vi } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import App from '../App'
describe('Search Flow', () => {
it('should search and display results', async () => {
render(<App />)
const searchInput = screen.getByPlaceholderText('Search books...')
fireEvent.change(searchInput, { target: { value: 'JavaScript' } })
const searchButton = screen.getByText('Search')
fireEvent.click(searchButton)
await waitFor(() => {
expect(screen.getByText('Search Results')).toBeInTheDocument()
expect(screen.getAllByTestId('book-item').length).toBeGreaterThan(0)
})
})
})
テスト対象:
例:
// cypress/integration/bookSearch.spec.js
describe('Book Search and Favorite', () => {
it('should allow a user to register, search for a book, and add it to favorites', () => {
cy.visit('/')
// ユーザー登録
cy.get('[data-testid=register-link]').click()
cy.get('[data-testid=username-input]').type('testuser')
cy.get('[data-testid=password-input]').type('password123')
cy.get('[data-testid=register-button]').click()
// 検索
cy.get('[data-testid=search-input]').type('JavaScript')
cy.get('[data-testid=search-button]').click()
// 結果の確認
cy.get('[data-testid=book-item]').should('have.length.greaterThan', 0)
// お気に入り登録
cy.get('[data-testid=favorite-button]').first().click()
// お気に入りページでの確認
cy.get('[data-testid=favorites-link]').click()
cy.get('[data-testid=favorite-book]').should('have.length.greaterThan', 0)
})
})
ファイル構成:
src/
components/
SearchForm.tsx
SearchForm.test.tsx
BookList.tsx
BookList.test.tsx
utils/
search.ts
search.test.ts
favorites.ts
favorites.test.ts
integration/
searchFlow.test.ts
App.tsx
App.test.tsx
cypress/
integration/
bookSearch.spec.js
このような構成で、各コンポーネントや機能に対応するテストファイルを同じディレクトリに配置します。統合テストは別のディレクトリ(integration/)に配置し、E2EテストはCypressの規約に従ってcypress/integrationディレクトリに配置します。
これらのテストを実装することで、アプリケーションの主要な機能や流れを網羅的にカバーし、品質を確保することができます。テストを段階的に追加し、継続的に改善していくことをお勧めします。
参考