Срез 5
Изучение теории. Неделя 5
Срез 5
1. Unit-tests, testing pyramid, integration tests
- Что такое юнит-тест и какова его основная цель в разработке (в том числе в React-проектах)?
- Основная цель юнит-тестирования — проверить корректность работы наименьших частей приложения (юнитов), таких как функции или классы, в полной изоляции. Оно позволяет быстро находить и устранять дефекты на самых ранних этапах разработки. Юнит-тесты служат живой документацией к коду, показывая, как должны использоваться компоненты. Кроме того, они обеспечивают безопасность рефакторинга, так как мгновенно сигнализируют о появлении ошибок.
- Объясните различия между юнит-тестами и интеграционными тестами: что именно они проверяют, какие зависимости обычно изолируют и какие типичные примеры есть в React-приложении
- Ключевое отличие заключается в их фокусе: юнит-тесты проверяют изолированный модуль кода, в то время как интеграционные тесты проверяют взаимодействие между несколькими модулями или системами. Юнит-тесты быстрые и простые в отладке, так как падение указывает на дефект в конкретном компоненте. Интеграционные тесты медленнее и сложнее, так как их падение может быть вызвано проблемой в любом из взаимодействующих модулей или в коммуникации между ними.
- Опишите принципы F.I.R.S.T для юнит-тестов и разберите, какие компромиссы возникают при их применении в React (например, скорость vs реалистичность, изоляция vs уверенность), и как вы бы решали эти компромиссы на практике.
- Принципы F.I.R.S.T. — это акроним, описывающий ключевые качества качественных юнит-тестов. Fast (быстрые): тесты должны выполняться быстро. Independent (независимые): тесты не должны зависеть друг от друга. Repeatable (повторяемые): результат должен быть одинаковым в любой среде. Self-Validating (самопроверяющиеся): тест должен однозначно показывать pass/fail статус без ручной проверки. Timely (своевременные): их лучше писать непосредственно перед или во время разработки кода.
- Опишите, как принципы TDD и BDD влияют на процесс разработки React-компонента: как меняются формулировка требований, структура тестов и коммуникация в команде, и какие основные плюсы/минусы вы видите у каждого подхода.
- TDD — это методология разработки, при которой тесты пишутся до написания самого кода. Основная идея: сначала формулируется требование в виде автоматизированного теста, затем пишется минимальный код, чтобы тест прошёл, и после этого выполняется рефакторинг.
- BDD — это эволюция TDD, которая фокусируется на поведении системы с точки зрения пользователя или заказчика. BDD использует общий, понятный всем язык для описания сценариев. Тесты пишутся на естественном языке с использованием шаблона Given-When-Then (Дано – Когда – Тогда). Сценарии описывают ожидаемое поведение системы.
- BDD сильно влияет на процесс, выступая в роли моста между бизнес-требованиями и технической реализацией. Использование общего языка (Gherkin) позволяет разработчикам, тестировщикам и продукт-менеджерам совместно обсуждать и формализовывать функции через их поведение. Это снижает количество недопониманий и дефектов, вызванных некорректной интерпретацией требований. В результате все участники команды имеют общее и однозначное понимание того, что должно быть разработано.
- В чём ключевые отличия юнит-тестов от интеграционных тестов и как это отражается на пирамиде тестирования (что и почему должно быть в основании)?
- Опишите принципы F.I.R.S.T для юнит-тестов и разберите, как вы бы применили их к тестированию React-компонента с внешними зависимостями (например, сеть, таймеры, контекст), чтобы сохранить изоляцию и надёжность тестов.
2. App speed estimation, app debugging
- Какие первые шаги вы бы сделали, чтобы устно оценить, почему React-приложение стало «тормозить» (например, после релиза), используя только инструменты браузера: консоль и вкладку Performance/Profiler?
- Отладка — это систематический процесс поиска и устранения причин ошибок в программном обеспечении. Его основа — это гипотезы: разработчик выдвигает предположение о источнике сбоя, а затем проводит эксперименты для его подтверждения или опровержения.
- Largest Contentful Paint (LCP) - когда загрузилось самое большое содержание
- Cumulative Layout Shift (CLS) - насколько прыгает верстка
- Time to Interactive (TTI) - когда можно кликать
- Interaction to Next Paint (INP) - время реакции на действия пользователя
- Как вы отличите проблему производительности из-за сети (долгие запросы, блокирующие ресурсы) от проблемы из-за рендеринга/JS в React, и какие сигналы вы бы искали во вкладке Network и в Lighthouse?
- Представьте, что Lighthouse показывает плохие LCP и TBT, а пользователи жалуются на лаги при взаимодействии. Объясните, как вы бы построили план диагностики: какие метрики и трассировки смотреть, как локализовать «длинные задачи» и лишние перерисовки, и как проверить гипотезы без написания кода.
- TBT (Total Blocking Time) - это метрика, измеряющая общее время в миллисекундах, в течение которого страница блокируется и не реагирует на действия пользователя
- Как вы используете точки останова (breakpoints) в DevTools для поиска ошибки в логике компонента React, и чем отличаются обычные breakpoints, conditional breakpoints и logpoints с точки зрения отладки?
- Представьте, что Lighthouse показывает низкие показатели LCP и TBT в React-приложении. Как вы бы интерпретировали эти метрики, какие вероятные причины в коде/загрузке ресурсов вы бы заподозрили, и какой план проверки выстроили бы через Network/Performance, чтобы подтвердить гипотезы?
3. Working with forms
- Что такое контролируемый компонент формы в React и какие преимущества он даёт по сравнению с неконтролируемым при работе с полями ввода?
- Контролируемый компонент — это компонент формы, значение которого управляется состоянием React. Вместо того, чтобы хранить свое значение в DOM, элемент формы получает его через проп value или checked. Любое изменение значения обрабатывается обработчиком событий (например, onChange), который обновляет состояние. Это делает React единственным источником истины для значения поля, обеспечивая полный контроль над данными формы на каждом этапе.
- Главное преимущество — полный контроль над данными формы, что позволяет легко реализовывать сложную логику. Вы можете мгновенно проверять ввод, форматировать значения (например, добавляя маску номера телефона) или программно изменять значения полей на основе других данных. Это также упрощает отправку данных, так как все значения уже хранятся в состоянии и не требуют дополнительного извлечения из DOM.
- Объясните, как в Formik обычно организованы хранение значений полей, обработка изменений и отправка формы, и чем такой подход отличается от управления формой только через useState в React
- Formik — это популярная библиотека, которая помогает решать три ключевые задачи: получение значений из формы, валидация и отправка данных. Она предоставляет компонент
<Formik>, который управляет состоянием формы, ошибками и историей посещений полей. Formik значительно сокращает объем шаблонного кода, автоматически связывая поля с состоянием и предоставляя удобные функции для обработки сабмита и валидации.
- Formik — это популярная библиотека, которая помогает решать три ключевые задачи: получение значений из формы, валидация и отправка данных. Она предоставляет компонент
- Опишите жизненный цикл формы в Formik (например, инициализация, изменения, валидация, отправка, сброс) и как вы бы реализовали сложную условную валидацию, зависящую от нескольких полей, не ухудшая читаемость и производительность
- Formik предоставляет колбэки для ключевых событий. Основные из них: onSubmit (отправка формы), onReset (сброс значений) и validateOnChange/validateOnBlur (когда нужна валидация). Состояние формы (значения, ошибки, флаги отправки) изменяется в ответ на действия пользователя, и Formik предоставляет хуки и пропсы для реагирования на эти изменения.
- Formik позволяет легко добавлять собственную логику валидации. Для этого можно передать функцию validate в компонент
<Formik>. Эта функция получает значения формы и должна возвращать объект с ошибками, где ключи совпадают с именами полей. Formik автоматически свяжет эти ошибки с соответствующими полями. Также можно использовать схему валидации из сторонних библиотек, таких как Yup, с помощью пропа validationSchema. - Для реализации сложных условий (например, поле A обязательно, только если поле B имеет определенное значение) используются функции валидации, которые получают все текущие значения формы. В Formik это делается внутри функции validate, где есть доступ ко всем значениям. В Final Form функция валидации поля также получает все значения формы. Это позволяет проанализировать зависимые поля и вернуть ошибку только в случае выполнения определенных условий.
- Объясните, как обычно организуют создание формы на основе состояния в React: какие данные хранят в state, как обновляют значения полей и как обрабатывают отправку формы — на уровне концепции, без кода.
- Для создания формы необходимо создать состояние для каждого поля, используя хук useState. Каждому полю ввода присваивается атрибут value, равный соответствующему значению из состояния. Обработчик события onChange для каждого поля обновляет состояние при каждом вводе пользователя, вызывая перерендер компонента с новым значением. Таким образом, состояние компонента и отображаемое значение в поле ввода всегда синхронизированы.
- Как Formik управляет состоянием формы (values, touched, errors) и в какой момент обычно запускается валидация при изменении поля, потере фокуса и отправке формы?
- Объясните, как вы бы спроектировали сложную условную валидацию в форме (например, правила зависят от нескольких полей и меняются по шагам) и чем подходы Formik и React Final Form отличаются с точки зрения механизма валидации и жизненного цикла формы.
4. JSX handlers
- Как в React в JSX обычно добавляют обработчик события (например, клика) к элементу, и чем это отличается от HTML-атрибутов вроде onclick?
- Как можно передать параметры в обработчик события в React и какие компромиссы/риски (например, лишние перерисовки или создание новых функций) стоит учитывать?
- Объясните, что такое синтетические события в React, чем они отличаются от нативных событий браузера и какие преимущества это даёт при работе с обработчиками в разных браузерах и средах?
5. Binding
- Зачем в классовых компонентах React нужно привязывать (bind) обработчики событий к экземпляру компонента, и что обычно происходит с this, если этого не сделать?
- Сравните два подхода в классовых компонентах: привязка обработчика в конструкторе через bind и объявление обработчика как стрелочной функции в public class fields. В чем различия по удобству, поведению this и возможным побочным эффектам?
- Какие проблемы производительности и лишних перерендеров могут возникать, если создавать стрелочные функции прямо в render для обработчиков событий, и какие устные стратегии вы бы предложили, чтобы сохранить контекст и при этом минимизировать создание новых функций (например, в классах и в функциональных компонентах)?
6. SyntheticEvent
- Что такое SyntheticEvent в React и зачем React использует его вместо прямой работы с нативными событиями браузера?
- Какие ключевые отличия есть между обработкой событий в React и в чистом JavaScript (например, где и как навешиваются обработчики, как ведёт себя this/контекст, и что получает обработчик в аргументах)?
- Как менялось поведение SyntheticEvent в новых версиях React (включая отказ от пуллинга), и какие практические последствия это имеет для производительности и для кода, который использует объект события асинхронно?
7. Bubbling event in react
- Что такое всплытие событий в React и как оно проявляется при клике по вложенным элементам (например, кнопка внутри контейнера)?
- Чем синтетические события React отличаются от нативных DOM-событий, и как эти отличия могут влиять на понимание всплытия и обработчиков событий?
- Как порталы (React Portals) влияют на всплытие событий: почему событие может всплывать по дереву React-компонентов, даже если элемент физически находится в другом месте DOM, и какие практические проблемы это может вызвать?
- Как в React можно предотвратить всплытие события и в каких ситуациях это действительно нужно, а в каких может быть вредно?
8. Jest, Enzyme and other tools
- Что такое Jest и для каких задач его обычно используют при тестировании React-приложений (например, какие типы тестов он поддерживает на базовом уровне)?
- Объясните, в чём смысл snapshot-тестирования в Jest, какие у него преимущества и какие типичные риски/антипаттерны могут сделать такие тесты бесполезными.
- Как бы вы спроектировали стратегию тестирования компонента, который делает запросы к API и использует Redux и кастомные хуки: что и на каких уровнях вы бы мокровали, как изолировали бы компонент, и как обеспечили бы устойчивость тестов к изменениям реализации?
- Как в Enzyme можно проверить, что компонент корректно реагирует на пользовательское событие (например, клик), и чем отличается подход при shallow и mount?
9. Snapshot testing, components testing
- Что такое snapshot testing в React и в каких случаях его уместно использовать при тестировании UI-компонентов?
- Какие основные причины «ложных» падений snapshot-тестов и какие практики помогают сделать снимки более стабильными и полезными?
- Как бы вы выстроили стратегию тестирования компонента, который зависит от контекста/Redux и делает асинхронные запросы: что проверять snapshot-тестами, что — поведенческими тестами, и как это интегрировать в CI/CD, чтобы минимизировать шум?
10. e2e
- Что такое e2e-тестирование в контексте React-веб-приложения и какую основную цель оно преследует по сравнению с ручной проверкой?
- Объясните ключевые различия между e2e, интеграционными и юнит-тестами: что именно проверяет каждый тип и на каком уровне обычно возникают ошибки, которые он ловит лучше всего?
- Какие стратегии вы бы применили, чтобы e2e-тесты для React-приложения были надежными и не флапали: как вы управляете ожиданиями/асинхронностью, тестовыми данными, зависимостями от сети и состоянием окружения в CI?
11. React router
- Что делает компонент
<BrowserRouter>в React Router и какую задачу он решает в приложении? - Как в React Router передают параметры в маршрут и как затем получить эти параметры внутри компонента страницы (например, через useParams)? Объясните на уровне концепции.
- Как бы вы спроектировали защищённые маршруты (protected routes) в React Router: где хранить состояние аутентификации, как обрабатывать редирект на страницу логина и как вернуть пользователя на исходный маршрут после входа?
12. Hooks routing
- Объясните, что такое роутинг в React-приложении и какую задачу решает React Router в SPA.
- Как хук useParams помогает получать данные из URL, и в каких случаях вы бы предпочли параметры пути вместо query-параметров?
- Опишите, как вы бы спроектировали кастомный хук для защищённого роутинга (guard): какие данные он должен учитывать (аутентификация, роль, редирект назад), как взаимодействовать с навигацией и как избежать проблем вроде бесконечных редиректов.
13. React-router API
- Какие задачи в приложении решают компоненты React Router
<Route>и<Link>, и чем отличается их роль в навигации? - Объясните, зачем в React Router используют
<Switch>(или его современный аналог в новых версиях) и как он влияет на выбор маршрута при совпадении нескольких путей. - Сравните
<BrowserRouter>, <HashRouter> и <StaticRouter>: в каких сценариях каждый из них уместен, какие у них ограничения и как они влияют на URL и работу сервера/SSR?
14. history, location, match
- Объясните, что такое маршрутизация в SPA на React и какую роль в этом играет React Router (в общих чертах, без кода).
- Что представляет собой объект history в React Router и какие типичные сценарии навигации он позволяет реализовать (например, переходы, возврат, замена записи), и чем это отличается по смыслу?
- Сравните объект history в React Router с историей браузера: какие есть различия в ответственности и поведении, и какие практические последствия это имеет при реализации защищённых маршрутов и редиректов (включая влияние location/state и возможные проблемы производительности)?
This post is licensed under CC BY 4.0 by the author.