Uibook — инструмент для визуального тестирования React-компонентов с медиа-запросами


    Всем привет! Меня зовут Виталий Ризо, я фронтенд-разработчик в «Амплифере». Мы сделали Uibook — простой инструмент для визуального тестирования React-компонентов с реальными медиа-запросами. Расскажу, как он работает и чем может быть полезен вам.




    Зачем сделали и в чём польза


    При создании новых компонентов мы страдали при рефакторинге — для проверки приходилось менять атрибуты через DevTools вручную, могли пропустить какие-то мелочи. Поэтому решили сделать страницу, где можно быстро тестировать компоненты.


    Uibook позволяет быстро увидеть компоненты в любых состояниях и комбинациях параметров (props). Благодаря поддержке медиа-запросов, разработчик на одной странице может отобразить настольные и мобильные версии компонентов. Но Uibook полезен не только разработчикам:


    • дизайнеры могут на своём устройстве, не поднимая локальный сервер, посмотреть всевозможные состояния компонентов и передать правки;
    • менеджеры видят, что даже простой, на первый взгляд попап, может содержать кучу граничных состояний, которые разработчики вынуждены учитывать — это помогает им лучше понимать устройство интерфейса продукта изнутри;
    • редакторы могут с помощью режима Live Text Editing примерить текст для интерфейса в реальных компонентах, чтобы он выглядел безупречно.

    Чем отличается от аналогов



    Вы можете спросить, зачем изобретать велосипед, когда есть готовые Storybook, Styleguidist и подобные решения? У моего проекта другой подход и я выделяю три основных отличия:


    • В Uibook сразу можно смотреть компоненты в условиях ограниченной ширины и высоты устройств;
    • Он не требует отдельного сборщика и легко подключается к существующему проекту парой строк в конфигурационном файле;
    • Подразумевается, что страницы с компонентами будут доступны публично, чтобы любой пользователь мог найти ошибки и оставить обратную связь.

    Uibook нужен в основном для визуального тестирования, а не разработки, хотя и разрабатывать «представляющую» часть проекта с ним удобно. Пришлось внести глобальные изменения в проект? Пробегитесь по всем страницам, чтобы убедиться в корректном отображении всех компонентов.



    Техническая реализация


    Uibook представляет собой React-приложение, в которое передаются Страницы — наборы «кейсов», то есть, состояний одного компонента (props и callbacks). Далее, Uibook рендерит выбранную Страницу на одном экране, используя два контроллера: с медиа-запросами и без них.


    Поскольку эмулировать медиа-запросы средствами CSS и JavaScript невозможно, мы пошли простым путём: рендерить компонент внутри <iframe>, если пользователь указал ширину или высоту экрана.


    Главный контроллер оборачивает компонент в любую пользовательскую обёртку, а также позволяет выбирать значения в браузере. В iframe данные передаются через ссылку. Также главный контроллер добавляет горячие клавиши и возможность редактировать текст.


    Я не хотел иметь отдельные сборщики для проекта и визуального тестирования. Другие продукты вынуждают это делать, из-за чего приходится хранить больше файлов, зависимостей, всё это дольше настраивается, дольше запускается, сложнее собирается и деплоится. Uibook же интегрируется в сборщик проекта, так как просто добавляется как Webpack-плагин:


    plugins: [
     …
     new UibookPlugin({
       controller: path.join(__dirname, '../controllers/uibook.js')
     })
    ]

    webpack.config.js


    Uibook создаёт отдельный чанк и не увеличивает размер основного приложения. Работает это через вебпаковские SingleEntryPlugin или MultiEntryPlugin. Он подтягивает стили и скрипты из основного приложения с учётом кэширования (”cachebuster”). Вот как плагин получает список нужных файлов:


     let files = compilation.chunks.find(function (i) {
       return i.name === 'uibook'
     }).files

    Затем он генерирует HTML-файл без использования зависимостей. Ведь это очень простая задача, нет необходимости тянуть библиотеки для этого. Берём шаблон, добавляем импорты, добавляем в выдачу:


     compilation.assets[outputPath + '/index.html'] = { … }

    Но если у вас всё же подключён HtmlWebpackPlugin, то придётся добавить uibook в исключения, о чём Uibook мило напомнит.



    Uibook очень прост


    У него в зависимостях только React, Webpack да create-react-class. Он написан на ES5, поэтому будет работать, даже если у вас нет Babel в проекте. А если есть, то не будет конфликтов плагинов. В Uibook встроены подсказки, если в конфигурационном файле что-то не так.



    Uibook гибок



    Вы можете обернуть все компоненты в свой контроллер. Это может быть обёртка для Redux, Context или всего сразу. Вот пример с новым Context API:


    export default UibookStarter({
     wrapper: (children, props) =>
       <Context.Provider value={ props }>
         { children }
       </Context.Provider>,
     values: {
       locale: ['ru', 'en'],
       theme: ['dark', 'light']
     },
     …
    })

    Список пользовательских ключей и их значений будет отображаться в верхнем навигационном меню.


    Как внедрить Uibook в проект


    Например, мы хотим добавить компонент Кнопка, который лежит в src/button.js. Нужно установить пакет uibook, создать файл-контроллер и файл-страницу. Файл-контроллер служит для импорта ваших Uibook-тестов, а файл-страница — это набор «кейсов», комбинаций параметров для одного компонента.


    Вот как это сделать:


    1) Приступим, $ yarn add uibook;
    2) Здесь можно воспользоваться командой $ npm init uibook, которая создаст файлы-примеры, а можно сделать всё вручную. Приблизительно структура получится такой:


    your-project
    ├── uibook
    │   ├── button.uibook.js
    │   └── uibook-controller.js
    ├── src
    │   └── button.js
    ├── webpack.config.js
    └── package.json

    3) Подключаем плагин в конфигурационном файле Webpack:


    let UibookPlugin = require('uibook/plugin')
    
    module.exports = {
     …
     plugins: [
       new UibookPlugin({
         controller: path.join(__dirname, '../src/uibook-controller.js'),
       })
     ],
    }

    webpack.config.js


    4) Запишем тест в uibook/button.uibook.js. Если вы воспользовались командой init, то этот пример уже создан:


    import UibookCase from 'uibook/case'
    import Button from '../src/button.js'
    
    const PROPS = {
     onClick: UibookCase.event('onClick')
    }
    
    const ButtonUibook = {
     component: Button,
     name: 'Button',
     cases: [
         () => <UibookCase props={{ ...PROPS, isLarge: true }}>
           Large Button
         </UibookCase>,
         () => <UibookCase props={{ ...PROPS, isDisabled: true }}>
           Disabled Button
         </UibookCase>
     ]
    }
    
    export default ButtonUibook

    button.uibook.js


    5) Импортируем и передаём этот uibook-тест в файле-контроллере:


    import UibookStarter from 'uibook/starter'
    import ButtonUibook from './button.uibook'
    
    export default UibookStarter({
     pages: {
       Button: ButtonUibook,
     }
    })

    uibook-controller.js


    6) Готово! Запускаем свой проект как обычно (например, $ yarn start) и открываем страницу /uibook в браузере. Мы увидим три кейса с кнопкой (если у вас есть компонент /src/button.js, конечно):



    Как Uibook помог нам


    Мы используем Uibook в своей работе уже больше года всей командой. Фронтендеры разрабатывают новые компоненты только через Uibook, попутно создавая тест-файл с граничными параметрами (props). Это намного быстрее, чем писать параллельно контроллер, чтобы увидеть компонент в реальном веб-приложении. Более того, этот тест-файл будет использоваться в дальнейшем для визуального тестирования после каких-либо глобальных изменений.


    Андрей Ситник Iskin, ведущий фронтенд-разработчик в «Злых марсианах» отмечает, что Uibook делает работу спокойнее:


    Uibook дал нам наконец-то уверенность, что после обновления normalize.css у нас ничего не сломалось. Просто открываем и просматриваем подряд все компоненты. Тут сильно помогает главная фича — поддержка @media, так что на странице все состояния компонентов. У разработчиков меньше страхов, у менеджеров — меньше багов. Все довольны.


    Да и сам процесс тестирования упростился. Теперь фронтендер пишет новый компонент (view-составляющую), попутно создавая файл с параметрами (props). Контроллер при этом не нужен — можно деплоить по ходу разработки, не внедряя компонент в само веб-приложение.


    Другие фронтенд-разработчики ревьюят компонент, используя локальный или задеплоенный Uibook: можно понажимать на все кнопочки и проверить, что callback вызываются. Так мы экономим до 30 часов каждый месяц на тестировании компонентов.


    Дамир Мельников, фронтенд-разработчик «Амплифера», также отмечает возможность совместной работы с дизайнерами, продактами и редакторами:


    Uibook позволяет мне быстро работать над компонентами — примерять новые стили, следить за мобильной версией, изучать, как ведёт себя компонента при разных вводных. Кроме того, Uibook позволяет быстро поделиться своей работой с дизайнером (живой макет), редактором (для вычитки интерфейсных текстов) и другими фронтенд-разработчиками.


    Контент-лид «Амплифера» Александр Марфицин замечает, как Uibook упростил работу по написанию интерфейсных текстов:


    Когда делаешь тексты для интерфейса, то часто работаешь вслепую и не видишь, как будут выглядеть надписи в «живом» продукте. Uibook решает эту проблему. Можно не только вычитывать старые тексты, но и создавать новые, опираясь на ограничения компонентов и примеряя свои черновики на реальном интерфейсе. Все текстовые элементы редактируемы, это позволяет получать цельный результат — от заголовка до даже самой маленькой надписи.

    И сам процесс работы стал более прозрачным — с Uibook лучше понимаешь устройство продукта и интерфейса изнутри, начинаешь лучше понимать важность хорошего текста для интерфейса.


    ⌘⌘⌘


    Надеюсь, что Uibook найдёт применение в вашем проекте. Если остались вопросы, то посмотрите детальную инструкцию в репозитории на Гитхабе. Или пишите мне в твиттере или на почту.


    Спасибо Александру Марфицину marfitsin за помощь в подготовке статьи.

    Поделиться публикацией

    Комментарии 13

      +2

      На английском статью можно для коллег?

        0
        Скоро переведу :)
        –4
        TL;DR, но кратенькое замечание: при нейминге продукта очень полезно его (name) произносить, а не просто лепить хайповые буковки.
        Представьте — Вы разговариваете с русским клиентом и произносите: «Сейчас я Вам уибук…»
          +2

          Вроде же это читается как "юай-бук"

            –1
            А GUI читается исключительно как «джыюай».
            Блаженны, кто верует.
              0
              Напишите uibook и gui так, чтобы не было смешно русскоговорящим малолеткам и понятно всем остальным. Спасибо.
                0
                Хотя бы UI Book, чтобы было видно, что это точно UI.
                Строчные буквы в слитном слове не сильно вызывают желание спеллинга.
                И зря Вы про малолеток: не знают, как английские буквы читаются, не только они, но и вполне взрослые люди, не знающие английского. Откуда-то же взялись "эс как доллар" и "вэ как галочка".
          0
          а почему решили использовать border для выделения активных элементов? есть же outline с которым вёрстка не будет путешествовать в разные стороны
            0
            Если речь про режим редактирования текста, то там, конечно, используется `outline`. Но есть зелёная рамка вокруг всего рабочего пространства, она сделана через `border`, так как иначе она окажется снаружи. Можно сделать тенями, но зачем?
              0
              Тени не ломают флоу. Меньше беспокойства.
                0

                Чтобы контент внутри не прыгал при появлении границы.
                Тенями делать не обязательно, но место под его отображение зарезервировать нужно.

              +1
              Просто открываем и просматриваем подряд все компоненты

              Вот так делать не надо. Этот момент следует автоматизировать и показывать визуальные дифы, если они есть.

                0
                Да, автоматическое визуальное тестирование — правильная вещь. Но в рамках этой статьи не важно кто именно смотрит изменения. Для тестирования по скриншотам всё равно нужны такие же страницы UiBook со всеми состояниями.

                Но у нас чуть сложнее — мы используем UiBook ещё и для тестирования анимаций. У нас есть страницы, который постоянно крутят анимации:
                amplifr.com/uikit/#MobileLayout:ru

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое