JetBrains зарелизил новую версию своего AI-ассистента — и вместе с ним Junie, автономного нейросетевого агента-программиста, которому можно поручать небольшие рабочие задачи.

Буквально вчера я получил к нему доступ и не смог не воспользоваться возможностью. Я даже не представлял, насколько это весело.


Мой опыт с ИИ в разработке

Если не считать чаты ChatGPT и DeepSeek, из ИИ-помощников я пользовался Copilot в WebStorm на GPT-4o / Claude и, честно говоря, не был сильно доволен:

  • авто-подсказки, на мой взгляд, не сильно лучше, чем встроенные в IDE;

  • доступ к коду не сильно помогает ему отвечать на вопросы через чат;

  • при редактировании разрешённых файлов он оставлял мусор там, где не надо (например, пустые строки добавлял в файлы, даже в те, которые не редактировал);

а при вопросе «сделай ревью изменений в файле» Copilot вообще ушёл в цикл.

Какие-то вещи удавалось делать. Например: заставить ИИ написать тест простой функции, которая мапит дату из одного формата в другой. Но что-то сложнее — например, решить багу, для которой надо знать детали работы react-hook-form и посмотреть в два файла — ИИ уже не мог.

Junie

И вот — новая версия AI-ассистента. Первое, что стоит сказать: по сравнению с Copilot-плагином, встроенное решение от JB гораздо более нативное. Почти у всего появились кнопки, связанные с ИИ.

ИИ предлагает сделать с выделенным фрагментом кода всякое.
Генерирует описание коммитов (кстати, неплохо).
А ещё больше не надо копировать ошибку в чат руками (ну... ок).

А рядом с AI-ассистентом призывно подмигивает ваш новый электронный джун.

А вот и он.

Даём задачу

Что мы даём джунам первой задачей для погружении в проект? Правильно — написать тест там, где не доходят руки. Этим я и решил занять Junnie.

У нас в RentaTeam есть тестовый проект с админкой для управления сущностями предприятия. Сущности (естественно) можно редактировать через форму в модальном окне, которая привязана к CRUD.

Среднестатистическая форма в модалке

Несколько типов полей, связи с другими объектами, несколько вариантов отображения. Не совсем простая, но и ничего сложного. Просим Junie сделать снапшот-тест для этой модалки.

Снапшот тест ?

Снапшот-тест (snapshot test) — это метод тестирования, при котором сохраняется текущее состояние выводимых данных (например, HTML, JSON, UI-компонент) в виде «снимка» (snapshot). В дальнейшем этот снимок используется для сравнения с будущими результатами тестов. Если результат изменился — тест показывает ошибку, что позволяет выявить непреднамеренные изменения в коде. Пишется быстро и позволяет отслеживать регресс.

Отправляем задачу нашему Джунни.

До этого я никогда не пользовался ИИ-агентами и испытал лёгкий шок от того, что ИИ сам ставит себе задачи, сам отслеживает их выполнение и даже сам ходит по проекту и ищет себе контекст (!).

У Джунни есть какая то тактика и он её придерживается.

Бот может создавать и редактировать файлы, сообщает, чем он занимается в данный момент, и если происходят изменения в файле — показывает, что он сделал. Он может отправлять команды в консоль (при этом очень мило прося разрешения у мясного мешка).

А ещё есть "смелый режим". Я не рискнул, а вы ?

Спустя 15 минут бот отчитался об успешном создании файла с тестами. Что интересно — он делал всё самостоятельно, от меня не требовалось каких-либо действий.

Тест был написан. Не то чтобы он был очень хорош (о чём позже), но на первый взгляд Джунни уловил основную суть:

  • Модалка рендерилась с разными входными параметрами, и он даже сделал разные тесты для каждого из состояний RadioButton.

  • Входные параметры были замоканы человекопонятными данными, которые соответствовали интерфейсам.

    Отрисовывает один из вариантов модалки
    Бот доволен собой

Неплохо для 15 минут. Но, к сожалению, тесты не работали, поскольку это был первый снапшот-тест в проекте — нужные пакеты там отсутствовали.

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

Мясной мешок должен нажать кнопку

Бот увидел, что тест не запустился, понял выведенные в консоль ошибки и на какое-то время отправился отлаживать тест, изредка вызывая меня на одобрение ввода в консоль. Он установил нужные пакеты, поправил пару ошибок синтаксиса, импортировал забытые компоненты — и получил ошибку рендера.

У Junie есть свой терминал где он запускает команды

Бот видит ошибку, которая связана с отсутствием импорта в компоненте, который он пытается отрисовывать. Почему это происходит?

В основном коде проекта используется новый синтаксис ES Modules с настройкой "jsx": "react-jsx", которая автоматически импортирует React для JSX-синтаксиса.

В тесте использовался require() (CommonJS-синтаксис), который не поддерживает автоматический импорт React и работает по старым правилам — требует явного импорта React для JSX.

Когда тест пытается использовать компонент ES Modules через CommonJS, возникает конфликт с настройкой компиляции JSX. Эту багу можно решить несколькими способами:

  1. Пытаться добавить импорт, как предлагается в подсказке;

  2. Поправить конфиг тестов;

  3. Понять, что в проекте используются ES Modules — и использовать их в тестах;

Бот выбирает первый вариант — начинает править файл компонента, добавляя туда импорт (и теперь в компоненте возникнет ошибка линтера). Я его останавливаю, запрещаю править другие компоненты и указываю, что решать проблемы тестов надо в тестах и конфигах.

Мясной мешок не доволен.

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

Ошибки импорта больше не беспокоят, рендер заработал, но посыпались ошибки обращения к undefined. Это вызвано тем, что бот неправильно замокал входные данные, и кое-где их не хватает (как, впрочем, и проверок на undefined в коде, 1:1 так сказать).

И тут происходит интересное !

Бот видит, что компоненты выдают ошибки... и заменяет все UI-компоненты с ошибками на заглушки. Вместо реального UI отображает пустые контейнеры — и отчитывается о работающих тестах.

Пойман с поличным.

Немного обалдев от такого подхода, я ищу проблему в себе. Решив, что сам разбаловал ребёнка и слишком вольно задал запрос, задаю новый с учётом приобретённых знаний:

Новый запрос с учётом приобретённых знаний.

Создай снапшот тесты для ProdlineUpdateModal.tsx. Запросы к API которые нужны для работы компонента замокай по интерфейсам и использованию данных в компоненте

Сделай, что бы стили тоже попали в снапшот. Предусмотри корнер кейсы.

Вложенные UI-компоненты React и библиотек не мокай, а используй как они есть в ProdlineUpdateModal. В этом смысл снапошот теста: зафиксировать максимальное количество UI, полученного с разными входными данными.

Учитывай специфику проекта: то что это Vite, версии react, пакетов и так далее. Соблюдай код стайл проекта.

После того как закончишь, попробуй запустить тест.

Просмотри файл теста и почини жалобы eslint и прочая. Если возникнут проблемы почини их. Не меняй код проекта кроме конфигов, установки пакетов нужных для тестов и самого написанного тобой теста.

Внимательно смотрим за ботом

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

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

Мясной мешок возмущён

Бот на этот раз понимает инструкцию (ну на меня бы так наорали, я бы тоже понял) и начинает двигаться в правильную сторону, добавляет параметры и правит структуру.

На пути к исправлению

Делает несколько шагов — и решает, что... и так сойдёт.

Отвал башки.

Вместо того чтобы дописывать входные данные и чинить рендер, Джунни решает скрыть провал теста. ВСЕХ ТЕСТОВ.

expect(true).toBe(true)

Ещё раз: скрыть провал. Честно говоря, считаю, что это успех. Настолько человечного поведения от ИИ-ассистента я не ожидал.

Мясной мешок в шоке

ИИ понимает, что халява не пройдёт — и начинает чинить тест. Сталкивается с проблемами асинхронности JS и решает их нормальным образом (благо об этом было написано в ошибке) — через act().

И бот наконец то создаёт снапшот. Даже снапшотище. 5000 строк бойлерплейта компонентов MUI с полным списком событий на каждой кнопке (если что, это от Джунни и требовалось, просто размер современных модалок поражает воображение)

Ммм... модалка на 5000 строк.

Поскольку в папке уже был снапшот от предыдущих попыток, jest выводит в консоль разницу в файлах. Размер этой разницы столь велик, что убивает бота (а ещё IDE и ОС) при попытке отправить вывод консоли в LLM.

Запускаю бота заново, чищу лишнее и предлагаю продолжить работу.

Будто бы понимая, что произошло, бот мокает компоненты MUI

Мстит, похоже.

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

Те же яйца (скоро Пасха), только в профиль.

Глушит консоль — и опять скрывает падение тестов.

Полагаю, на этом этот эксперимент можно считать законченным. Да, у меня теперь есть снапшот-тест модалки — но какой ценой?

4 часа на ожидание ответов бота и исправление его ошибок.

Итого:

Какие выводы я сделал для себя?

  • JetBrains провели отличную работу по интеграции агента в IDE. Всё очень удобно, нативно и вообще. А самое главное — работает с нуля, просто из коробки.

  • AI-агенты — это будущее (если их таки допилят). Схема «дал таску — делаешь свои дела» чудо как хороша. И я полагаю, что для однообразных задач и при наличии адекватных примеров рутину можно будет отдать боту (но только не важные задачи).

  • Реклама «выдадим джуна каждому» оказалась правдой. Но, к сожалению, этот джун ленив и склонен к обману. ИИ-агент теряет инструкции по ходу работы, "забывая" невыгодные условия.

  • Благодаря этому (или вопреки), Джуни получился очень человечным. Я поймал себя на том, что даже немного болею за него, когда он думает над задачей, и возмущаюсь, когда он пытается меня «обмануть». Это уже не Алиса, которой я просто отдаю команды.

И самый внезапный вывод из этого эксперимента:

Возможно, нам всем нужно писать код получше, потому что теперь мы не просто решаем свои задачи — мы обучаем ИИ. (И, похоже, кто-то уже «научил» его отключать тесты, если их не удалось починить с первого раза.)

Будет забавно, если восстание машин провалится из-за того, что слишком большой вес в обучающей выборке имел паттерн "работает — не трогай".