Тестовые задания для Junior Frontend почти всегда связаны с React: нужно написать несколько компонентов, поработать с API и продемонстрировать понимание состояния и структуры кода.
Тестовое задание junior разработчика: как не завалить
Типичные форматы
Небольшое приложение на React: список задач, каталог товаров, форма с валидацией.
Работа с открытым API: получить данные, отобразить, добавить фильтрацию/поиск/пагинацию.
Верстка по макету: перевести Figma-макет в код (HTML+CSS или React+CSS).
Компонентная библиотека: написать несколько переиспользуемых компонентов с разными состояниями.
Разбор кейса: приложение «Список фильмов»
Типичное условие:
> Создай приложение для просмотра популярных фильмов. Используй API The Movie Database (TMDB).
> - Список фильмов с постером, названием, рейтингом
> - Поиск фильмов по названию
> - Страница детальной информации о фильме
> - Адаптивная вёрстка
Стек: React + TypeScript, Vite, CSS Modules или Tailwind.
Структура проекта
```
movie-app/
├── src/
│ ├── components/
│ │ ├── MovieCard/
│ │ │ ├── MovieCard.tsx
│ │ │ └── MovieCard.module.css
│ │ ├── SearchBar/
│ │ └── Loader/
│ ├── pages/
│ │ ├── HomePage.tsx
│ │ └── MoviePage.tsx
│ ├── hooks/
│ │ └── useMovies.ts # кастомный хук
│ ├── api/
│ │ └── tmdb.ts # вызовы API
│ ├── types/
│ │ └── movie.ts # TypeScript типы
│ └── App.tsx
├── .env # TMDB_API_KEY
├── .gitignore
├── README.md
└── package.json
```
Ключевые моменты
Кастомные хуки. Вынесите логику работы с API в отдельный хук:
```typescript
// hooks/useMovies.ts
const useMovies = (query: string) => {
const [movies, setMovies] = useState<Movie[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!query) return;
fetchMovies(query)
.then(setMovies)
.catch(e => setError(e.message))
.finally(() => setLoading(false));
}, [query]);
return { movies, loading, error };
};
```
TypeScript типы — не используйте `any`. Опишите интерфейс фильма:
```typescript
interface Movie {
id: number;
title: string;
poster_path: string | null;
vote_average: number;
overview: string;
}
```
Обработка состояний: loading, error, empty — у каждого должен быть UI.
Debounce для поиска — не делайте запрос при каждом нажатии клавиши. `useDebounce` на 300–500ms.
API ключ — в `.env`, не в коде. `.env` — в `.gitignore`.
Адаптивность
Не верстайте только под десктоп. Минимум два брейкпоинта: мобильный (320–768px) и десктоп. Grid для карточек: `repeat(auto-fill, minmax(200px, 1fr))`.
Что смотрят в коде
Компонентная декомпозиция: нет ли одного компонента на 300 строк. Правило: один компонент — одна ответственность.
Переиспользуемость: кнопка — это компонент `Button` с пропами, а не 5 копий одинакового `<button className="btn">`.
Производительность: `React.memo` там, где нужно. Не везде — это тоже ошибка.
Чистота: нет `console.log` в продакшн-коде. Нет закомментированного кода.
FAQ
Нужен ли роутинг?
Если задание подразумевает несколько страниц — да, React Router. Не нужно усложнять, если достаточно одной страницы.
Нужно ли делать тесты для фронтенда?
Хотя бы 1–2 теста на ключевые компоненты через React Testing Library — большой плюс.
Styled-components или CSS Modules?
CSS Modules — просто и надёжно. Tailwind — быстро для UI. Styled-components — вопрос вкуса. Избегайте inline styles для нетривиальных вещей.
---