சோதனை வழிகாட்டி
Dropup பயன்படுத்தும் கூறுகளை எவ்வாறு சோதிப்பது.
அமைப்பு
சோதனை சார்புநிலைகளை நிறுவவும்:
npm install -D vitest @testing-library/react @testing-library/user-event jsdom
Vitest ஐ கட்டமைக்கவும்:
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
setupFiles: './src/test/setup.ts',
},
});
// src/test/setup.ts
import '@testing-library/jest-dom';
அடிப்படை கூறு சோதனை
// components/Uploader.tsx
import { useDropup } from '@samithahansaka/dropup';
export function Uploader() {
const { files, getDropProps, getInputProps } = useDropup({
accept: 'image/*',
});
return (
<div {...getDropProps()} data-testid="dropzone">
<input {...getInputProps()} data-testid="file-input" />
<p>படங்களை இங்கே விடுங்கள்</p>
<ul data-testid="file-list">
{files.map(file => (
<li key={file.id} data-testid="file-item">
{file.name}
</li>
))}
</ul>
</div>
);
}
// components/Uploader.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect } from 'vitest';
import { Uploader } from './Uploader';
describe('Uploader', () => {
it('விடு மண்டலத்தை ரெண்டர் செய்கிறது', () => {
render(<Uploader />);
expect(screen.getByTestId('dropzone')).toBeInTheDocument();
expect(screen.getByText('படங்களை இங்கே விடுங்கள்')).toBeInTheDocument();
});
it('கோப்பு உள்ளீட்டை ஏற்கிறது', async () => {
const user = userEvent.setup();
render(<Uploader />);
const input = screen.getByTestId('file-input');
const file = new File(['test'], 'test.png', { type: 'image/png' });
await user.upload(input, file);
expect(screen.getByTestId('file-item')).toHaveTextContent('test.png');
});
it('பல கோப்புகளை ஏற்கிறது', async () => {
const user = userEvent.setup();
render(<Uploader />);
const input = screen.getByTestId('file-input');
const files = [
new File(['test1'], 'photo1.png', { type: 'image/png' }),
new File(['test2'], 'photo2.png', { type: 'image/png' }),
];
await user.upload(input, files);
const items = screen.getAllByTestId('file-item');
expect(items).toHaveLength(2);
});
});
இழுத்து விடுவை சோதிப்பது
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { Uploader } from './Uploader';
describe('இழுத்து விடு', () => {
it('மேல் இழுக்கும்போது இழுத்தல் நிலையைக் காட்டுகிறது', () => {
render(<Uploader />);
const dropzone = screen.getByTestId('dropzone');
fireEvent.dragEnter(dropzone, {
dataTransfer: {
types: ['Files'],
items: [{ kind: 'file' }],
},
});
expect(dropzone).toHaveAttribute('data-dragging', 'true');
});
it('கோப்பு விடுவதைக் கையாளுகிறது', () => {
render(<Uploader />);
const dropzone = screen.getByTestId('dropzone');
const file = new File(['test'], 'dropped.png', { type: 'image/png' });
fireEvent.drop(dropzone, {
dataTransfer: {
files: [file],
types: ['Files'],
},
});
expect(screen.getByText('dropped.png')).toBeInTheDocument();
});
});
சரிபார்ப்பை சோதிப்பது
// components/ValidatedUploader.tsx
import { useDropup } from '@samithahansaka/dropup';
import { useState } from 'react';
export function ValidatedUploader() {
const [errors, setErrors] = useState<string[]>([]);
const { files, getDropProps, getInputProps } = useDropup({
accept: 'image/*',
maxSize: 1024 * 1024, // 1MB
onValidationError: (validationErrors) => {
const messages = validationErrors.flatMap(e => e.errors);
setErrors(messages);
},
});
return (
<div {...getDropProps()} data-testid="dropzone">
<input {...getInputProps()} data-testid="file-input" />
{errors.length > 0 && (
<ul data-testid="error-list">
{errors.map((error, i) => (
<li key={i} data-testid="error-item">{error}</li>
))}
</ul>
)}
</div>
);
}
// components/ValidatedUploader.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect } from 'vitest';
import { ValidatedUploader } from './ValidatedUploader';
describe('சரிபார்ப்பு', () => {
it('தவறான கோப்பு வகையை நிராகரிக்கிறது', async () => {
const user = userEvent.setup();
render(<ValidatedUploader />);
const input = screen.getByTestId('file-input');
const file = new File(['test'], 'document.pdf', { type: 'application/pdf' });
await user.upload(input, file);
expect(screen.getByTestId('error-list')).toBeInTheDocument();
});
it('அளவு வரம்பை மீறும் கோப்புகளை நிராகரிக்கிறது', async () => {
const user = userEvent.setup();
render(<ValidatedUploader />);
const input = screen.getByTestId('file-input');
// 2MB கோப்பை உருவாக்கு (1MB வரம்பை மீறும்)
const content = new Array(2 * 1024 * 1024).fill('a').join('');
const file = new File([content], 'large.png', { type: 'image/png' });
await user.upload(input, file);
expect(screen.getByTestId('error-list')).toBeInTheDocument();
});
});
பதிவேற்றத்தை சோதிப்பது
// components/UploadingComponent.tsx
import { useDropup } from '@samithahansaka/dropup';
export function UploadingComponent() {
const { files, actions, state, getDropProps, getInputProps } = useDropup({
upload: { url: '/api/upload' },
});
return (
<div {...getDropProps()} data-testid="dropzone">
<input {...getInputProps()} data-testid="file-input" />
{files.map(file => (
<div key={file.id} data-testid="file-status">
{file.status === 'uploading' && `பதிவேறுகிறது: ${file.progress}%`}
{file.status === 'complete' && 'முடிந்தது!'}
{file.status === 'error' && `பிழை: ${file.error?.message}`}
</div>
))}
<button
onClick={() => actions.upload()}
disabled={state.isUploading}
data-testid="upload-btn"
>
பதிவேற்று
</button>
</div>
);
}
// components/UploadingComponent.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { UploadingComponent } from './UploadingComponent';
// fetch ஐ மாக் செய்
const mockFetch = vi.fn();
global.fetch = mockFetch;
describe('பதிவேற்றம்', () => {
beforeEach(() => {
mockFetch.mockReset();
});
it('கோப்புகளை வெற்றிகரமாக பதிவேற்றுகிறது', async () => {
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ url: 'https://example.com/file.png' }),
});
const user = userEvent.setup();
render(<UploadingComponent />);
// கோப்பைச் சேர்
const input = screen.getByTestId('file-input');
const file = new File(['test'], 'test.png', { type: 'image/png' });
await user.upload(input, file);
// பதிவேற்று கிளிக் செய்
await user.click(screen.getByTestId('upload-btn'));
// முடிவுக்கு காத்திரு
await waitFor(() => {
expect(screen.getByTestId('file-status')).toHaveTextContent('முடிந்தது!');
});
expect(mockFetch).toHaveBeenCalledWith('/api/upload', expect.anything());
});
it('பதிவேற்ற பிழையைக் கையாளுகிறது', async () => {
mockFetch.mockRejectedValue(new Error('நெட்வொர்க் பிழை'));
const user = userEvent.setup();
render(<UploadingComponent />);
const input = screen.getByTestId('file-input');
await user.upload(input, new File(['test'], 'test.png', { type: 'image/png' }));
await user.click(screen.getByTestId('upload-btn'));
await waitFor(() => {
expect(screen.getByTestId('file-status')).toHaveTextContent('பிழை');
});
});
});
useDropup ஐ மாக் செய்தல்
தனிமைப்படுத்தப்பட்ட யூனிட் சோதனைகளுக்கு:
// __mocks__/@samithahansaka/dropup.ts
import { vi } from 'vitest';
export const useDropup = vi.fn(() => ({
files: [],
state: {
isDragging: false,
isDragAccept: false,
isDragReject: false,
isUploading: false,
progress: 0,
status: 'idle',
},
actions: {
upload: vi.fn(),
cancel: vi.fn(),
remove: vi.fn(),
reset: vi.fn(),
retry: vi.fn(),
addFiles: vi.fn(),
updateFileMeta: vi.fn(),
},
getDropProps: vi.fn(() => ({})),
getInputProps: vi.fn(() => ({ type: 'file' })),
openFileDialog: vi.fn(),
}));
// சோதனைகளில் பயன்பாடு
import { vi } from 'vitest';
import { useDropup } from '@samithahansaka/dropup';
vi.mock('@samithahansaka/dropup');
const mockUseDropup = vi.mocked(useDropup);
describe('மாக் செய்யப்பட்ட ஹூக்குடன்', () => {
it('கோப்புகளுடன் ரெண்டர் செய்கிறது', () => {
mockUseDropup.mockReturnValue({
files: [
{ id: '1', name: 'test.png', status: 'idle', progress: 0, size: 1000, type: 'image/png' },
],
// ... மற்ற மதிப்புகள்
});
render(<Uploader />);
expect(screen.getByText('test.png')).toBeInTheDocument();
});
});
MSW உடன் சோதிப்பது
யதார்த்தமான API சோதனைக்கு Mock Service Worker ஐப் பயன்படுத்தவும்:
// src/test/handlers.ts
import { http, HttpResponse } from 'msw';
export const handlers = [
http.post('/api/upload', async ({ request }) => {
const formData = await request.formData();
const file = formData.get('file') as File;
return HttpResponse.json({
url: `https://example.com/uploads/${file.name}`,
});
}),
http.post('/api/upload-error', () => {
return HttpResponse.json(
{ error: 'பதிவேற்றம் தோல்வி' },
{ status: 500 }
);
}),
];
// src/test/setup.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Playwright உடன் E2E சோதனை
// e2e/upload.spec.ts
import { test, expect } from '@playwright/test';
test.describe('கோப்பு பதிவேற்றம்', () => {
test('ஒரு கோப்பை பதிவேற்றுகிறது', async ({ page }) => {
await page.goto('/upload');
// கோப்பு உள்ளீட்டைப் பெறு
const fileInput = page.locator('input[type="file"]');
// கோப்பை பதிவேற்று
await fileInput.setInputFiles({
name: 'test.png',
mimeType: 'image/png',
buffer: Buffer.from('fake image content'),
});
// கோப்பு பட்டியலில் தோன்றுகிறதா சரிபார்
await expect(page.locator('text=test.png')).toBeVisible();
// பதிவேற்று பொத்தானை கிளிக் செய்
await page.click('button:has-text("பதிவேற்று")');
// வெற்றிக்கு காத்திரு
await expect(page.locator('text=முடிந்தது')).toBeVisible();
});
test('இழுத்து விடு பதிவேற்றம்', async ({ page }) => {
await page.goto('/upload');
const dropzone = page.locator('[data-testid="dropzone"]');
// கோப்பு தரவை உருவாக்கு
const buffer = Buffer.from('test content');
// இழுத்து விடுவை உருவகப்படுத்து
const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
await page.dispatchEvent('[data-testid="dropzone"]', 'drop', {
dataTransfer,
});
// கோப்பு சேர்க்கப்பட்டதா சரிபார்
await expect(page.locator('[data-testid="file-item"]')).toBeVisible();
});
});
சிறந்த நடைமுறைகள்
- நடத்தையை சோதிக்கவும், செயலாக்கத்தை அல்ல - பயனர்கள் பார்ப்பது மற்றும் செய்வதில் கவனம் செலுத்தவும்
- நம்பகத்தன்மைக்கு data-testid பயன்படுத்தவும் - CSS வகுப்புகளால் சோதிப்பதைத் தவிர்க்கவும்
- நெட்வொர்க் கோரிக்கைகளை மாக் செய்யவும் - API அழைப்புகளுக்கு MSW அல்லது vi.mock பயன்படுத்தவும்
- விளிம்பு வழக்குகளை சோதிக்கவும் - காலி நிலைகள், பிழைகள், பெரிய கோப்புகள்
- அணுகல்தன்மையை சோதிக்கவும் - விசைப்பலகை வழிசெலுத்தல், திரை வாசிப்பாளர்கள்