← Назад к вопросам
Добавляешь ли что-либо для тестирования в приложение
2.0 Middle🔥 161 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Добавление кода для тестирования: Best Practices
Да, при разработке фронтенда я добавляю специальный код, чтобы облегчить тестирование. Это нормальная практика, которая ускоряет как разработку, так и автоматизацию тестов.
1. Data Attributes для селекторов в тестах
Зачем: Тестовые фреймворки (Playwright, Cypress, Testing Library) нужны селекторы для поиска элементов. Вместо хрупких селекторов по классам CSS используем специальные атрибуты.
// Плохо — селектор зависит от CSS класса
const button = document.querySelector('.primary-button.lg');
// Если дизайнер изменит класс, тест сломается
// Хорошо — используем data-testid
<button data-testid="submit-button" className="primary-button lg">
Отправить
</button>
// Тест
test('submit button works', async ({ page }) => {
const button = page.getByTestId('submit-button');
await button.click();
});
2. Test ID Constants
Для больших приложений создаём файл с константами тестовых ID:
// constants/testIds.ts
export const TEST_IDS = {
auth: {
emailInput: 'auth-email-input',
passwordInput: 'auth-password-input',
loginButton: 'auth-login-button',
logoutButton: 'auth-logout-button',
},
questions: {
questionCard: 'question-card',
answerButton: 'answer-button',
filterSelect: 'filter-select',
},
common: {
loader: 'common-loader',
errorMessage: 'common-error-message',
successMessage: 'common-success-message',
},
} as const;
3. Role-based Селекторы (Accessibility)
Это лучше чем data-testid, так как тестирует и accessibility:
// Отлично — используем role
<button role="button" aria-label="Отправить форму">
Отправить
</button>
// Тест
test('submit button', async ({ page }) => {
const button = page.getByRole('button', { name: 'Отправить форму' });
await button.click();
});
// Другие роли
const input = page.getByRole('textbox', { name: 'Email' });
const select = page.getByRole('combobox');
const heading = page.getByRole('heading', { level: 1 });
4. Testing Library в Unit Тестах
Unit тесты с Testing Library:
import { render, screen } from '@testing-library/react';
import { LoginForm } from './LoginForm';
test('renders login form', () => {
render(<LoginForm onSubmit={() => {}} />);
// Лучше: по role (тестирует accessibility)
const emailInput = screen.getByRole('textbox', { name: /email/i });
expect(emailInput).toBeInTheDocument();
// Альтернатива: по testid
const submitButton = screen.getByTestId('login-button');
expect(submitButton).toBeInTheDocument();
});
5. Mock Data и Fixtures
Для тестирования создаём фиксчуры с тестовыми данными:
// fixtures/mockData.ts
export const mockUser = {
id: '1',
name: 'John Doe',
email: 'john@example.com',
role: 'admin',
};
export const mockQuestions = [
{ id: '1', title: 'What is React?', difficulty: 'easy' },
{ id: '2', title: 'What is Hook?', difficulty: 'medium' },
];
// В тесте
test('render questions list', () => {
render(<QuestionsList questions={mockQuestions} />);
expect(screen.getByText('What is React?')).toBeInTheDocument();
});
6. Environment-specific Code
Некоторый код нужен только для тестирования:
// Добавляем глобальный объект только в тестах
if (process.env.NODE_ENV === 'test') {
(window as any).__TEST_DATA__ = {
users: [
{ id: 1, name: 'Test User' },
],
};
}
// Используем в тестах
test('user data', () => {
const testData = (window as any).__TEST_DATA__;
expect(testData.users).toHaveLength(1);
});
7. API Mocking
Для тестов мокируем API запросы:
// Используем MSW (Mock Service Worker)
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
const server = setupServer(
http.get('/api/v1/user', () => {
return HttpResponse.json({ id: '1', name: 'John' });
})
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
test('fetch user', async () => {
const response = await fetch('/api/v1/user');
const data = await response.json();
expect(data.name).toBe('John');
});
8. React Component Testing
export function LoginForm({ onSubmit }: { onSubmit: (data: any) => void }) {
const [email, setEmail] = useState('');
return (
<form onSubmit={(e) => {
e.preventDefault();
onSubmit({ email });
}}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
data-testid="email-input"
placeholder="Email"
/>
<button type="submit" data-testid="login-button">Login</button>
</form>
);
}
Тест:
test('login form submission', async () => {
const handleSubmit = vi.fn();
const { getByTestId } = render(<LoginForm onSubmit={handleSubmit} />);
const emailInput = getByTestId('email-input');
const submitButton = getByTestId('login-button');
await userEvent.type(emailInput, 'user@example.com');
await userEvent.click(submitButton);
expect(handleSubmit).toHaveBeenCalledWith({
email: 'user@example.com',
});
});
9. Что НЕ нужно добавлять
Не добавляй:
- console.log для debug
- Комментарии "TODO: remove for production"
- Хардкодированные тестовые значения в production коде
- Дополнительные зависимости только для тестов в production сборке
Добавляй только:
- data-testid и aria-* для доступности
- Mock функции и фиксчуры
- Test-специфичный код за флагом process.env.NODE_ENV
10. Best Practices
| Практика | Хорошо | Плохо |
|---|---|---|
| Селекторы | data-testid или role | className, id (хрупкие) |
| Constants | Централизованные TEST_IDS | Строки в коде |
| Mock Data | Fixtures в отдельном файле | Прямо в тестах |
| Debug | Только для development | В production коде |
| Environment | process.env.NODE_ENV | Хардкод условий |
На собеседовании
Полный ответ должен показать:
- Понимание разницы — что добавлять, что нет
- Data-testid практика — как делать селекторы стабильными
- Accessibility-first — использовать role когда возможно
- Организация кода — constants, fixtures, mocks
- Опыт с фреймворками — Playwright, Testing Library, Vitest