Приложение учителя — тест-кейсы
Ручные тест-кейсы для тестировщика с реальным железом. Опираются только на то, что реально реализовано в mvp/teacher-app/ на момент написания (сверено с PLAN.md, SCENARIOS-COVERAGE.md, кодом экранов src/pages/, серверной частью electron/server/, протоколом protocols/02-student-app--teacher-app.md). Нереализованное помечено «(если реализовано)» или не включено вовсе — список см. в сводке в конце файла.
Стенд тестировщика
Для полного прохождения нужно:
- Ноутбук учителя (macOS или Windows) с установленным приложением учителя.
- Второй ноутбук (или второй профиль/ВМ) с приложением ученика — для интеграционных кейсов веток Г, Д, Е.
- Android-телефон с приложением-мостом + модуль STM32 — только для кейсов, помеченных «(реальный робот)». Если модуля нет, эти кейсы можно проходить частично: до момента запуска на роботе, дальше — пропустить и отметить «нет железа». Виртуальный робот (кнопка «Запустить на виртуальном роботе» на вкладке «Код учеников») не требует ни телефона, ни модуля и покрывает logic запуска программы.
- Роутер или точка доступа (хотспот с телефона подходит) — для веток LAN. Оба ноутбука и роутер — в одной Wi-Fi/Ethernet сети.
- Второй ноутбук/эмулятор учителя — только для раздела «Два учителя в одной сети».
- Опционально: доступ в интернет — для раздела «Синхронизация с порталом» и «Документация».
Сброс к чистому состоянию. Закрыть приложение учителя, удалить его локальную базу (путь и команду уточнить в mvp/BUILD.md/README приложения — файл называется как база student-app, rubrick.db, но в профиле teacher-app). Не удалять базу при запущенном приложении.
Как фиксировать находку: шаг → что сделал → что ожидал → что увидел → скриншот → ОС и версия приложения (вкладка нет отдельного «О программе» в коде на момент письма — версия видна на вкладке «Обновления», «Установлена версия …»).
Термины: «отправлено / подтверждено / недоступен» — три состояния доставки команды (протокол 02 §6.6), см. раздел «Управление классом». «Разрешено» / «эффективное значение» — итоговое значение флага после разрешения приоритета ученик > класс > глобально.
Сводная таблица разделов
| № | Раздел | Кейсов |
|---|---|---|
| 1 | Первый запуск и общая рамка приложения | 4 |
| 2 | Классы и ученики (ростер) | 15 |
| 3 | Подключение — сопряжение и обнаружение учеников в LAN | 12 |
| 4 | Управление классом — живые команды | 8 |
| 5 | Разрешения (feature flags) | 8 |
| 6 | Курсы и уроки — выдача заданий | 13 |
| 7 | Код учеников — приём сдач и просмотр | 6 |
| 8 | Документация / вики | 3 |
| 9 | Синхронизация с порталом | 9 |
| 10 | Обновления приложения | 9 |
| 11 | Офлайн и деградация сети (D-086) | 8 |
| 12 | Два учителя в одной сети | 3 |
| 13 | Кроссплатформенность macOS/Windows | 4 |
| Итого | 99 |
1. Первый запуск и общая рамка приложения
TC-001. Первый запуск создаёт локальный сервер и виден статус-бейдж
Приоритет: P1 Предусловия: Чистая база, приложение учителя не запущено. Шаги:
- Запустить приложение учителя.
- Посмотреть на бейдж состояния сервера в шапке (справа от заголовка «РУБРИК · панель учителя»).
Ожидаемый результат: Сразу после запуска бейдж кратко показывает «Запуск сервера…», затем переходит в «Сервер для учеников доступен» с указанием порта. Приложение не виснет на этапе запуска.
TC-002. Все восемь вкладок открываются без ошибок
Приоритет: P1 Предусловия: Приложение запущено. Шаги:
- По очереди открыть вкладки: «Классы», «Класс», «Курсы и уроки», «Код учеников», «Разрешения», «Портал», «Подключение», «Обновления».
Ожидаемый результат: Каждая вкладка открывается, показывает свой контент или явное пустое состояние («Пока нет классов», «Курсов пока нет» и т.п.), не белый экран и не зависание.
TC-003. Пустые состояния читаемы и не выглядят как баг
Приоритет: P2 Предусловия: Чистая база, ничего ещё не создано. Шаги:
- Открыть «Классы» — ничего не выбирая.
- Открыть «Код учеников», «Разрешения» без выбранного класса/ученика.
Ожидаемый результат: Везде понятные подписи-заглушки («Выберите класс слева…», «Выберите класс выше»), не пустая белая область и не текст ошибки.
TC-004. Повторный запуск не запрашивает ничего заново
Приоритет: P3 Предусловия: После TC-001, база не сброшена. Шаги:
- Закрыть приложение.
- Запустить снова.
Ожидаемый результат: Приложение открывается сразу на вкладке «Классы» с уже созданными данными, сервер поднимается автоматически без участия учителя.
2. Классы и ученики (ростер)
TC-005. Создание класса
Приоритет: P1 Предусловия: Вкладка «Классы». Шаги:
- Ввести название класса, например «7А».
- Нажать «Добавить».
Ожидаемый результат: Класс появляется в списке слева и автоматически выбирается; справа — «Ученики» с пустым списком.
TC-006. Пустое название класса не создаёт класс
Приоритет: P2 Шаги:
- Оставить поле «Название класса» пустым, нажать «Добавить».
Ожидаемый результат: Ошибка «Название класса не может быть пустым», класс не создан.
TC-007. Переименование класса
Приоритет: P2 Предусловия: Есть класс. Шаги:
- Нажать «✎» у класса, ввести новое название, подтвердить.
Ожидаемый результат: Название в списке обновилось.
TC-008. Блокировка/разблокировка класса из списка классов
Приоритет: P2 Предусловия: Есть класс. Шаги:
- В меню класса выбрать «Заблокировать».
- В окне причины ввести «Обед» (или оставить поле пустым) и нажать «Заблокировать».
- Посмотреть на бейдж «заблокирован» у класса.
- В меню класса выбрать «Разблокировать».
Ожидаемый результат: После шага 2 у класса появляется бейдж «заблокирован»; если у кого-то из класса идёт программа, перед блокировкой показывается предупреждение. Ученики видят «Причина: Обед» (при пустом поле строки нет). После шага 4 бейдж пропадает.
TC-009. Удаление пустого класса — без предупреждения о потерях
Приоритет: P2 Предусловия: Есть класс без учеников. Шаги:
- Нажать «✕» у пустого класса.
Ожидаемый результат: Диалог «Удалить класс «...»?» с текстом «Класс пуст — удаление ничего не затронет», кнопка «Удалить». После подтверждения класс исчезает из списка.
TC-010. Удаление класса с учениками — предупреждение называет последствия
Приоритет: P1 Предусловия: Класс с 2+ учениками, у одного есть сохранённая работа (см. раздел 7, или после интеграционного кейса из раздела 3). Шаги:
- Нажать «✕» у класса.
Ожидаемый результат: Диалог называет класс и число учеников с верным склонением: «В классе «7А» 3 ученика. Они будут удалены вместе с классом и всеми их работами. Это нельзя отменить», кнопка «Удалить класс и учеников» (не просто «Удалить»). После подтверждения класс, его ученики и их работы исчезают; на ноутбуках учеников их профили пропадают из выбора профиля после очередной синхронизации (как при удалении ученика по одному). Это НЕ нативный confirm() браузера — окно не блокирует остальной интерфейс модально на уровне ОС.
TC-011. Добавление ученика и разовый показ PIN
Приоритет: P1 Предусловия: Выбран класс. Шаги:
- Ввести имя ученика, выбрать аватар, нажать «Добавить ученика».
- Посмотреть на блок с PIN.
- Переключиться на другую вкладку и вернуться на «Классы».
Ожидаемый результат: После шага 1 ученик появляется в списке; в блоке показан PIN с подписью «Запишите или продиктуйте ученикам сейчас — второй раз PIN не показывается». После шага 3 PIN больше нигде не виден (ни в списке, ни при повторном открытии вкладки) — сохранить его можно было только скриншотом/записью в момент создания.
TC-012. Повторное имя ученика — предупреждение, затем разрешение (тёзки)
Приоритет: P1 Предусловия: В классе уже есть ученик «Иванов Пётр». Шаги:
- Ввести «Иванов Пётр», нажать «Добавить ученика».
- Убедиться, что карточка НЕ создана, есть предупреждение о дубле.
- Нажать «Добавить ученика» ещё раз с тем же именем.
Ожидаемый результат: После шага 1 — предупреждение «...уже есть в этом классе. Если это другой ребёнок с таким же именем — нажмите «Добавить ученика» ещё раз», карточка не создана. После шага 3 — создаётся вторая карточка с тем же именем (тёзки — это ожидаемо, не баг).
TC-013. Список учеников: строкой — добавление нескольких сразу
Приоритет: P2 Предусловия: Выбран класс. Шаги:
- Нажать «Списком…».
- В текстовое поле вставить несколько имён, по одному на строке.
- Нажать «Добавить всех».
Ожидаемый результат: Каждая строка создаёт отдельного ученика; для всех показываются PIN в общем блоке «PIN для «...»: ...». Пустые строки в списке игнорируются.
TC-014. Массовое добавление останавливается на ошибке, не откатывает уже созданных
Приоритет: P3 Предусловия: Выбран класс. Шаги:
- В «Списком…» вставить список из нескольких валидных имён.
- Спровоцировать ошибку на середине списка, если возможно (например, оборвать сервер/базу — опционально, кейс можно пропустить, если не удаётся воспроизвести условие).
Ожидаемый результат: Сообщение об ошибке добавляет «— добавление остановлено, уже созданные ученики остались» и список действительно обновляется, показывая тех, кто успел создаться.
TC-015. Сброс PIN ученику
Приоритет: P1 Предусловия: Есть ученик. Шаги:
- Нажать «Сброс PIN» у ученика.
Ожидаемый результат: Новый PIN показывается один раз в блоке «PIN для «...»»; старый PIN перестаёт подходить (проверяется интеграционно из ветки 3 — старым PIN ученик войти не может, новым — может).
TC-016. Блокировка/разблокировка отдельного ученика
Приоритет: P2 Предусловия: Есть ученик. Шаги:
- В меню ученика выбрать «Заблокировать».
- В окне причины ввести причину (или оставить поле пустым) и нажать «Заблокировать».
- Посмотреть на бейдж «заблокирован».
Ожидаемый результат: Бейдж появляется/пропадает; причина видна только этому ученику, в списке ростера у других её нет. (Реальный эффект на стороне ученика проверяется через command-log — см. TC-039, «Блокировка ученика».)
TC-017. Перевод ученика в другой класс
Приоритет: P2 Предусловия: Есть минимум 2 класса, в одном — ученик. Шаги:
- У ученика выбрать в списке «Перевести в…» другой класс.
Ожидаемый результат: Ученик исчезает из текущего списка (класс не может остаться пустым по ошибке отображения) и появляется в списке учеников целевого класса.
TC-018. Объединение дублирующихся профилей (merge)
Приоритет: P1 Предусловия: В классе два ученика — явные дубли одного ребёнка (например, созданы саморегистрацией и учителем), у одного или обоих есть сохранённые работы. Шаги:
- У одного ученика выбрать в списке «Объединить с…» второго.
- Прочитать диалог подтверждения.
- Подтвердить.
Ожидаемый результат: Диалог называет число переносимых работ и текст «Работы обоих профилей сохранятся — они просто окажутся под одним именем». После подтверждения — уведомление «Профиль «...» объединён с «...»: перенесено работ — N», исходный профиль-источник исчезает из списка, у оставшегося — работы обоих.
TC-019. Переименование и удаление ученика с работами — диалог называет последствия
Приоритет: P1 Предусловия: У ученика есть сохранённые работы (см. раздел 3/7). Шаги:
- Нажать «✎», переименовать ученика.
- Нажать «✕» у ученика с работами.
Ожидаемый результат: Переименование проходит без диалога подтверждения. Удаление показывает диалог с числом работ: «У ученика N сохранённых работ и его прогресс — после удаления они станут недоступны. Отменить удаление будет нельзя», кнопка «Всё равно удалить». Удаление ученика БЕЗ работ показывает нейтральный текст «У ученика нет сохранённых работ» и кнопку «Удалить».
3. Подключение — сопряжение и обнаружение учеников в LAN
Требует второй ноутбук с приложением ученика в одной сети с ноутбуком учителя.
TC-020. Название кабинета вместо личного имени учителя
Приоритет: P2 Предусловия: Вкладка «Подключение». Шаги:
- Прочитать подсказку под заголовком «Название кабинета».
- Ввести название, например «Кабинет 204», сохранить.
Ожидаемый результат: Подсказка явно предупреждает не использовать личное имя («транслируется всем в сети без шифрования»). Значение сохраняется и не сбрасывается при перезапуске приложения.
TC-021. Открытие сопряжения показывает отпечаток сервера
Приоритет: P1 Шаги:
- Нажать «Открыть сопряжение».
Ожидаемый результат: Кнопка меняется на «Закрыть сопряжение» (красная), появляется блок с 6-символьным отпечатком сервера и подсказкой «Ученик увидит тот же отпечаток... Если отпечатки не совпали — подключается не этот компьютер», плюс срок действия («Действует до HH:MM:SS»).
TC-022. Полное сопряжение: ученик находит учителя, PIN совпадает
Приоритет: P1 (интеграционный, с реальным student-app) Предусловия: На ноутбуке учителя создан класс с 1–2 учениками (PIN записаны), сопряжение открыто (TC-021). На втором ноутбуке — приложение ученика с чистой базой, режим «В классе». Шаги:
- На ученическом ноутбуке дождаться автоматического поиска учителя.
- На учительском ноутбуке подтвердить устройство в разделе «Запросы на подключение» → «Разрешить».
- На ученическом экране сверить показанный отпечаток с отпечатком на учительском экране (TC-021).
- У ученика продолжить — должен появиться экран выбора карточки (не главный экран).
- Выбрать созданного учителем ученика, ввести записанный PIN.
Ожидаемый результат: Устройство переходит из «Запросы на подключение» в «Подключённые устройства». Отпечатки на обоих экранах совпадают побайтово (все 6 символов). У ученика на экране выбора карточки нет кнопки «Добавить ученика» (ростер — учителя). Вход по PIN, выданному учителем, успешен.
TC-023. Отклонение устройства
Приоритет: P1 Предусловия: Продолжение TC-022, но на шаге подтверждения выбрать «Отклонить». Шаги:
- В «Запросы на подключение» нажать «Отклонить».
Ожидаемый результат: Устройство переходит в «Неактивные устройства» со статусом «отклонено» и кнопкой «Вернуть в очередь». Ученик на своей стороне не получает доступ к классу.
TC-024. Возврат отклонённого устройства в очередь
Приоритет: P2 Предусловия: После TC-023. Шаги:
- В «Неактивные устройства» нажать «Вернуть в очередь» у отклонённого устройства.
- На ученическом ноутбуке инициировать повторную попытку подключения.
Ожидаемый результат: Устройство снова появляется в «Запросы на подключение» после следующей попытки подключения ученика.
TC-025. Отзыв доступа у подключённого устройства
Приоритет: P1 Предусловия: Устройство в «Подключённые устройства» (после TC-022). Шаги:
- Нажать «Отозвать доступ», прочитать диалог, подтвердить.
- Проверить состояние на ученическом ноутбуке.
Ожидаемый результат: Диалог предупреждает «Устройство отключится сразу — чтобы вернуть его, откройте сопряжение и подтвердите заново». После подтверждения устройство переходит в «Неактивные устройства» со статусом «доступ отозван». На ученическом ноутбуке связь рвётся (см. также TC-070 в разделе про офлайн).
TC-026. Закрытие сопряжения — новые устройства подключиться не могут
Приоритет: P2 Шаги:
- Нажать «Закрыть сопряжение».
- С третьего/нового ученического устройства попытаться найти учителя.
Ожидаемый результат: После закрытия — текст «Сопряжение закрыто — новые устройства не могут подключиться». Новое устройство не может завершить сопряжение (детали поведения на стороне ученика — см. mvp/testcases/student-app.md, если есть, или TESTER-GUIDE ветка D).
TC-027. Автозакрытие сопряжения по таймауту (60 минут)
Приоритет: P3 Предусловия: Сопряжение открыто. Шаги:
- Открыть сопряжение, зафиксировать «Действует до …».
- Дождаться указанного времени (или ускорить часы/подождать реальные 60 минут — по возможности тестировщика; иначе кейс можно пометить «не проверено, долгий таймер»).
Ожидаемый результат: По истечении срока кнопка возвращается в состояние «Открыть сопряжение» без участия учителя.
TC-028. Ученик без роли в классе (pending) — приём в ростер
Приоритет: P1 (интеграционный) Предусловия: На ученическом ноутбуке создан локальный профиль ДО подключения к учителю (в самостоятельном режиме) и есть хотя бы одна сохранённая программа, затем устройство переключается в режим «В классе» и подключается к этому учителю; в классе учителя пока нет соответствующего ученика. Шаги:
- Дождаться синхронизации на учительском ноутбуке.
- Открыть «Подключение» → раздел «Ученики, которых нет в списке».
- Проверить предложенное имя (или ввести своё), выбрать класс, нажать «Добавить в класс».
Ожидаемый результат: В разделе виден профиль с (возможно) предложенным именем и числом ожидающих работ («Ждут N работ»). После добавления — уведомление с новым PIN и подсказкой «продиктуйте этот код ученику — он заменяет тот, который ребёнок мог придумать себе сам». Ученик появляется в списке класса на вкладке «Классы»; его прежние работы становятся видны на вкладке «Код учеников» после следующей синхронизации.
TC-029. Отклонение «не мой ученик»
Приоритет: P2 Предусловия: Продолжение TC-028 или отдельный pending-профиль. Шаги:
- В «Ученики, которых нет в списке» нажать «Не мой ученик».
Ожидаемый результат: Профиль пропадает из списка ожидающих, в класс не добавляется.
TC-030. Несовпадение отпечатка сервера — предупреждение, не блокировка
Приоритет: P2 Предусловия: Требует смоделировать переустановку/подмену сервера — например, сбросить локальную базу учителя (сервер получит новый sid/fp) при уже подключённых/ожидающих устройствах со старым отпечатком. Если условие сложно воспроизвести физически, кейс можно провести как код-ревью факта — пометить соответственно. Шаги:
- Открыть «Подключение», посмотреть на баннер сводки отпечатков (появляется, когда есть устройства, хоть раз обращавшиеся к серверу).
Ожидаемый результат: Если есть несовпадения — баннер «N из M устройств... видят другой отпечаток сервера» с пояснением «не блокирует подключение». Разрешение конкретного устройства в списке «Запросы на подключение» остаётся возможным (кнопка «Разрешить» активна) — предупреждение не мешает действию.
TC-031. Предупреждение о клонированном образе диска (дублирующаяся установка)
Приоритет: P3 Предусловия: Два ученических устройства, развёрнутых из одного образа (или недостижимо в стенде — тогда пометить «не проверено, нужен клон образа»). Шаги:
- Подключить оба клонированных устройства к серверу.
- Открыть «Подключение», посмотреть на баннер о дублирующейся установке.
Ожидаемый результат: Баннер «N устройств(о) отвечают с разных адресов под одним идентификатором» с пояснением про клонированный диск и текстом «Ничего не блокируется». Подключение работать не перестаёт, только одно из двух устройств фактически сможет удерживать сессию за раз.
4. Управление классом — живые команды
Требует активное подключение ученика (после раздела 3).
Три команды учителя — что каждая делает у ученика
Ответ на вопрос тестировщика (12.09.2026). Ярлыки похожи, последствия разные.
| Команда | Что происходит у ученика | Срок | Переживает перезапуск |
|---|---|---|---|
| Заблокировать класс / ученика | Карточку нельзя выбрать; если ученик уже в ней — через 2 секунды его возвращает на выбор карточки с текстом «Твой профиль/группа заблокирован(а) учителем» | до «Разблокировать», но не дольше 30 минут без связи с учителем | да |
| Заморозить класс / ученика | Идущая программа останавливается, весь экран закрыт панелью «Учитель приостановил работу» с причиной и таймером; работать нельзя | до «Разморозить» или 30 минут | да, пока срок не истёк |
| Остановить всех | Останавливает идущую программу у всех подключённых, класс не важен. Ничего не блокирует, панели нет | разовая; при переподключении воспроизводится, только если ей меньше 30 секунд | нет |
Заморозка, срок которой истёк, при следующем входе ученика не применяется — ни живьём, ни воспроизведением. Если после «Остановить всех» у ученика появилась панель «Учитель приостановил работу» — это ошибка, а не поведение команды (так выглядел BUG-08 до 12.09.2026).
TC-032. Заморозка и снятие заморозки класса
Приоритет: P1 (интеграционный) Предусловия: Ученик подключён и на связи, вкладка «Класс» → выбран класс. Шаги:
- Ввести причину (необязательно), нажать «Заморозить класс».
- Посмотреть на карточку команды в разделе «Команды» — состояние должно смениться с «отправлено» на «подтверждено».
- Проверить на ученическом ноутбуке, что рабочее пространство действительно заблокировано.
- Нажать «Разморозить класс».
Ожидаемый результат: Сразу после отправки карточка показывает «отправлено» — учительское приложение никогда само не помечает команду подтверждённой. В течение нескольких секунд после получения командой ученик присылает подтверждение, состояние переходит в «подтверждено», в разделе «Ученики на связи» появляется «сообщает: заморожен». После разморозки — обратный переход.
TC-033. Аварийная остановка всех
Приоритет: P1 (интеграционный, желательно с реальным роботом) Предусловия: Ученик выполняет программу на роботе или в виртуальном роботе. Шаги:
- Нажать «Остановить всех».
- У ученика выйти из карточки и войти снова; затем перезапустить приложение ученика.
Ожидаемый результат: Команда рассылается всем подключённым ученикам независимо от выбранного класса; исполнение программы у ученика прерывается; карточка команды показывает подтверждение от затронутых учеников. После повторного входа и перезапуска работа продолжается: никакой панели «Учитель приостановил работу» быть не должно — «Остановить всех» ничего не блокирует.
TC-034. Блокировка/разблокировка класса командным каналом
Приоритет: P1 Шаги:
- Нажать «Заблокировать класс», подтвердить получение на ученическом ноутбуке.
- Нажать «Разблокировать класс».
Ожидаемый результат: Аналогично TC-032 — три состояния доставки видны корректно; блокировка класса — это отдельная команда от «заморозки» (разные ярлыки в списке команд: «Блокировка класса» / «Заморозка»).
TC-035. Команды одному ученику: заморозка, блокировка
Приоритет: P1 Предусловия: Раздел «Команды одному ученику», выбран конкретный ученик. Шаги:
- Заморозить ученика, дождаться подтверждения.
- Заблокировать ученика, дождаться подтверждения.
- Снять оба состояния.
Ожидаемый результат: Команды влияют только на выбранного ученика, не на весь класс (проверить на двух подключённых учениках сразу — второй продолжает работать).
TC-036. Состояние «недоступен» для команды, если ученик пропал со связи
Приоритет: P1 Предусловия: Ученик подключён. Шаги:
- Отправить команду (например, «Заморозить ученика»).
- Сразу же закрыть приложение ученика или отключить его от сети (Wi-Fi выкл.).
Ожидаемый результат: Карточка команды переходит в состояние «недоступен» (после ~15 с отсутствия presence или разрыва сокета), не остаётся навсегда в «отправлено» и не помечается ложно «подтверждено».
TC-037. Отправка прав вручную («Отправить права»)
Приоритет: P2 Шаги:
- На вкладке «Класс» нажать «Отправить права» для класса, затем — для отдельного ученика.
Ожидаемый результат: Команда flags_push появляется в списке команд, подтверждается так же, как остальные. Полезно для повторной отправки без изменения значения (например, после переподключения устройства).
TC-038. Устаревание ограничения через 30 минут без связи
Приоритет: P3 (долгий кейс — можно пометить «не проверено по времени» при нехватке времени) Предусловия: Заморозка/блокировка активна, ученик теряет связь с учителем на 30+ минут. Шаги:
- Заморозить ученика/класс.
- Разорвать связь ученика с учителем (закрыть учительское приложение или выключить сеть) более чем на 30 минут.
- У ученика посмотреть на состояние рабочего пространства.
- На учительской стороне (после восстановления связи с приложением, если оно было закрыто) открыть карточку соответствующей команды.
Ожидаемый результат: У ученика ограничение автоматически снимается с объяснением «связь с учителем потеряна, ограничение снято» — работа не остаётся замороженной навечно. На учительской стороне карточка команды рендерится как «истекло — ограничение больше не действует», отдельно от активного состояния (другой бейдж/цвет).
TC-039. Журнал команд не путает конвергентные и разовые команды при переподключении
Приоритет: P3 Предусловия: Несколько разных команд отправлены за сессию (заморозка, stop_all, флаги). Шаги:
- Отправить
stop_all. - Отключить и снова подключить ученика спустя >30 секунд.
Ожидаемый результат: Повторно подключившийся ученик НЕ получает повторную аварийную остановку — поздний stop_all не должен «выстрелить» задним числом (в отличие от «заморозки»/«блокировки», которые сходятся к последнему состоянию при переподключении в любое время).
5. Разрешения (feature flags)
TC-040. Значения по умолчанию на глобальном уровне
Приоритет: P2 Предусловия: Чистая база, вкладка «Разрешения», область «Глобально». Шаги:
- Посмотреть на состояние каждого флага.
Ожидаемый результат: Все флаги, кроме «Обязательный PIN при саморегистрации», показаны как «не задано» (наследуют встроенный дефолт «включено»). «Обязательный PIN» — тоже «не задано», но встроенный дефолт для него «выключено» (единственный флаг, где так).
TC-041. Изменение глобального флага доходит до подключённого ученика
Приоритет: P1 (интеграционный) Предусловия: Ученик подключён, у него доступны оба режима редактора. Шаги:
- На «Разрешения» → «Глобально» выключить «Режим «Блоки»».
- Проверить на ученическом ноутбуке.
Ожидаемый результат: Изменение отправляется автоматически подключённым ученикам сразу (без отдельного нажатия «Отправить права» — согласно подсказке «Изменение сразу отправляется подключённым ученикам, кого оно затрагивает»); у ученика режим «Блоки» перестаёт быть доступен, Python остаётся.
TC-042. Оба режима редактора нельзя выключить одновременно
Приоритет: P1 Предусловия: «Режим «Блоки»» уже выключен глобально (после TC-041). Шаги:
- Попытаться выключить «Режим Python» глобально.
Ожидаемый результат: Операция отклоняется с понятной ошибкой — эффективное значение не может оставить ученика без единого редактора. (Проверить формулировку ошибки — она должна объяснять, что именно произошло, а не быть кодом/стектрейсом.)
TC-043. Разрешение конфликта через переопределение на уровне ученика
Приоритет: P2 Предусловия: Продолжение TC-042 (Python и Блоки оба на «включено» глобально). Шаги:
- Область «Ученик» → выбрать ученика → выключить «Режим «Блоки»» только для него.
- Проверить предпросмотр «Действует сейчас: выключено (источник: Ученик)».
Ожидаемый результат: Переопределение на уровне ученика применяется, для остальных учеников ничего не меняется. Попытка также выключить у этого ученика Python должна быть отклонена той же проверкой (нельзя оставить конкретного ученика без обоих режимов).
TC-044. Сброс переопределения — наследование
Приоритет: P2 Предусловия: Есть переопределение на уровне класса или ученика (после TC-043). Шаги:
- Нажать «Сбросить (наследовать)» у переопределённого флага.
Ожидаемый результат: Строка переходит в состояние «не задано — наследуется»; эффективное значение для затронутых учеников возвращается к значению более высокого уровня (класс или глобально).
TC-045. Приоритет разрешения: ученик > класс > глобально
Приоритет: P1 Предусловия: Задать три разных значения одного флага на трёх уровнях (например, «Виртуальный робот»: глобально — включено, класс ученика — выключено, лично ученику — включено). Шаги:
- Настроить как описано выше.
- Открыть «Ученик» → выбрать этого ученика, прочитать предпросмотр.
Ожидаемый результат: «Действует сейчас: включено (источник: Ученик)» — переопределение ученика побеждает переопределение класса, которое в свою очередь побеждало бы глобальное.
TC-046. allow_add_student — только глобальный уровень
Приоритет: P2 Шаги:
- Открыть область «Класс» или «Ученик» и посмотреть на строку «Добавление учеников на устройстве».
Ожидаемый результат: Строка показана, но без контролов переключения — только текст «Эта настройка задаётся только на уровне «Глобально»».
TC-046a. Строка каждого разрешения называет своё значение по умолчанию
Приоритет: P2 Шаги:
- Открыть «Разрешения», область «Глобально», просмотреть все строки.
Ожидаемый результат: Под названием каждой из восьми строк одной и той же жирной строкой написано «По умолчанию: включено» либо «По умолчанию: выключено». Выключено по умолчанию только «Добавление учеников на устройстве» и «Обязательный PIN при саморегистрации», остальные включены. У «Добавление учеников на устройстве» дополнительно: «состав класса ведёт учитель. Пока ноутбук ни разу не подключался к приложению учителя, кнопка «Добавить ученика» доступна.» (D-132, протокол 04 §3.3).
- Выключить глобально «Режим Python», перейти в область «Класс» (нужен хотя бы один класс).
Ожидаемый результат (шаг 2): у «Режим Python» написано «Наследуется: выключено (Глобально)», а не «включено»; у строк без глобальной настройки — «Наследуется: включено (по умолчанию)». В области «Ученик» строка показывает значение класса, если оно задано, иначе глобальное.
TC-047. pin_required включён — только creation-time политика
Приоритет: P2 (интеграционный) Предусловия: Ученический ноутбук в режиме «В классе», подключён к этому учителю. Шаги:
- Включить «Обязательный PIN при саморегистрации» глобально (или для класса).
- На ученической стороне попробовать саморегистрацию нового профиля без PIN.
- Проверить, что уже существующий профиль без PIN продолжает входить как раньше.
Ожидаемый результат: Новая саморегистрация без PIN отклоняется/требует PIN; уже созданные профили без PIN не блокируются задним числом (ретроактивная блокировка недопустима по описанию флага).
6. Курсы и уроки — выдача заданий
TC-048. Создание курса
Приоритет: P1 Шаги:
- На «Курсы и уроки» ввести название и описание, нажать «Добавить курс».
Ожидаемый результат: Курс появляется в списке слева и выбирается автоматически; справа — «Уроки» с пустым списком.
TC-049. Пустое название не создаёт курс
Приоритет: P3 Шаги:
- Оставить «Название курса» пустым, нажать «Добавить курс».
Ожидаемый результат: Ничего не создаётся (кнопка неактивна/нет эффекта — форма отбрасывает пустое значение без ошибки).
TC-050. Добавление урока с заданием, сборкой и подсказками
Приоритет: P1 Предусловия: Выбран курс. Шаги:
- Нажать «+ Новый урок».
- Заполнить название, длительность, «Задание», «Сборка», подсказки по одной на строку.
- Сохранить.
Ожидаемый результат: Урок появляется в списке последним (новые уроки добавляются в конец порядка); в подписи под названием видно «N мин · [первая строка задания]».
TC-051. Автопроверка — JSON-схема грейдера
Приоритет: P2 Предусловия: Открыт редактор урока. Шаги:
- Раскрыть «Автопроверка (JSON-схема грейдера, для продвинутых)».
- Ввести валидный JSON вида
{"id": "...", "checks": [...]}(пример в подсказке редактора). - Сохранить.
- Открыть урок на редактирование снова.
Ожидаемый результат: JSON сохраняется и при повторном открытии показывается заново (с форматированием через отступы); в подписи урока появляется «автопроверка настроена».
TC-100. Автопроверка по расстоянию снова доступна в редакторе (D-143)
Приоритет: P2 Предусловия: Открыт редактор урока, раздел «Автопроверка». Шаги:
- Раскрыть подсказку по типам проверок.
- Вставить пример
distance_traveledиз подсказки, сохранить.
Ожидаемый результат: в списке три типа: время, расстояние, датчик; у расстояния пометка «сейчас работает на виртуальном роботе» и «направление пока не проверяется»; урок с этим JSON сохраняется без ошибки.
TC-052. Невалидный JSON автопроверки не даёт сохранить урок
Приоритет: P2 Шаги:
- В поле автопроверки ввести заведомо битый JSON («{невалидно»).
- Нажать «Сохранить урок».
Ожидаемый результат: Сохранение блокируется, показывается понятная ошибка про формат JSON — остальные поля урока при этом не теряются (форма не закрывается и не очищается).
TC-053. Изменение порядка уроков
Приоритет: P2 Предусловия: В курсе 3+ урока. Шаги:
- Нажать «↓» у первого урока, затем «↑» у последнего.
Ожидаемый результат: Порядок в списке меняется соответственно и сохраняется после обновления страницы/переключения курса и обратно.
TC-054. Удаление урока
Приоритет: P2 Шаги:
- Нажать «✕» у урока, прочитать диалог, подтвердить.
Ожидаемый результат: Диалог «Урок пропадёт из курса и у учеников. Отменить удаление будет нельзя», после подтверждения урок исчезает из списка.
TC-055. Удаление курса с уроками
Приоритет: P1 Предусловия: Курс с 2+ уроками. Шаги:
- Нажать «✕» у курса.
Ожидаемый результат: Диалог называет число уроков: «Вместе с курсом будут удалены все его уроки (N шт.). У учеников, проходивших курс, он пропадёт из библиотеки. Отменить удаление будет нельзя», кнопка «Всё равно удалить».
TC-056. Выдача курса ученику — курс появляется на его стороне
Приоритет: P1 (интеграционный) Предусловия: Курс с уроками создан, ученик подключён к этому учителю. Шаги:
- Дождаться синхронизации (или запустить её вручную, если в интерфейсе ученика есть такая кнопка).
- На ученической стороне открыть «Курсы».
Ожидаемый результат: Курс и его уроки видны ученику в том порядке, что задал учитель; содержимое задания/сборки/подсказок совпадает.
TC-057. Экспорт курса в файл
Приоритет: P2 Предусловия: Есть курс. Шаги:
- Нажать «⇩» («Экспорт курса в файл») у курса.
- Дождаться подтверждения с путём файла.
Ожидаемый результат: Уведомление «Курс сохранён: [путь]», файл действительно создан по этому пути и может быть скопирован на флешку.
TC-058. Импорт курса из файла — новый курс
Приоритет: P1 Предусловия: Есть валидный файл-пакет курса (например, экспортированный в TC-057), титул курса уникален для этой базы. Шаги:
- Нажать «Импорт курса из файла…», выбрать файл.
Ожидаемый результат: Уведомление «Импортирован курс «...» (N уроков)», курс появляется в списке и автоматически выбирается.
TC-059. Импорт курса с уже установленным названием — копия, не перезапись
Приоритет: P1 Предусловия: Курс с тем же названием уже есть в базе (например, повторно импортировать файл из TC-058). Шаги:
- Повторно импортировать тот же файл.
- Прочитать диалог «Курс «...» уже установлен».
- Подтвердить «Импортировать копию».
Ожидаемый результат: Диалог явно говорит «Установленный курс и прогресс учеников не изменятся» — импорт создаёт ОТДЕЛЬНУЮ копию, не перезаписывает существующий курс и не трогает прогресс учеников по нему. Уведомление после импорта помечает результат «— как отдельная копия».
TC-060. Импорт битого файла курса
Приоритет: P2 Предусловия: Подготовить файл, не являющийся валидным пакетом курса (переименовать любой другой файл в ожидаемое расширение, или испортить валидный экспорт). Шаги:
- Импортировать этот файл.
Ожидаемый результат: Понятная ошибка («Пакет не читается» или аналогичная), приложение не падает, список курсов не меняется.
7. Код учеников — приём сдач и просмотр
TC-061. Программа ученика доезжает и видна учителю
Приоритет: P1 (интеграционный) Предусловия: Ученик подключён, написал и сохранил программу (Python или блоки) на своей стороне. Шаги:
- На «Код учеников» выбрать класс, затем ученика.
- Выбрать программу в списке «Программы».
Ожидаемый результат: Программа появляется в списке с меткой режима («Python» / «Блоки») и временем синхронизации; при выборе показывается исходный код (для Python — обычный текст, для блоков — JSON блочной структуры), подпись «Просмотр только для чтения — редактировать код ученика из панели учителя нельзя».
TC-062. Открытие кода ученика уведомляет его
Приоритет: P2 (интеграционный) Предусловия: Продолжение TC-061, ученический ноутбук на экране, где видно такое уведомление (если реализовано на ученической стороне — иначе кейс пропустить и пометить как непроверяемый с этой стороны). Шаги:
- Открыть программу ученика в «Код учеников».
- Проверить на ученическом ноутбуке.
Ожидаемый результат: Ученик получает пассивное уведомление вида «учитель смотрит твою программу».
TC-063. Запуск Python-программы ученика на виртуальном роботе
Приоритет: P1 Предусловия: Выбрана программа в режиме Python. Шаги:
- Нажать «Запустить на виртуальном роботе».
- Наблюдать за консольной панелью.
- Нажать «Остановить» до завершения.
Ожидаемый результат: Кнопка «Запустить» блокируется на время выполнения, в панели появляются строки лога/телеметрии; «Остановить» прерывает выполнение немедленно, в консоли появляется «Остановлено.».
TC-064. Запуск недоступен для программ на блоках
Приоритет: P2 Предусловия: Выбрана программа в режиме «Блоки». Шаги:
- Посмотреть на кнопку «Запустить на виртуальном роботе».
Ожидаемый результат: Кнопка неактивна, под ней текст «Запуск на виртуальном роботе в этой версии доступен только для программ на Python».
TC-065. У ученика без синхронизированных программ — пустое состояние
Приоритет: P3 Предусловия: Выбран ученик, ни разу не сохранявший программу. Шаги:
- Открыть «Код учеников» → выбрать этого ученика.
Ожидаемый результат: «У этого ученика пока нет синхронизированных программ», без ошибки.
TC-066. Учитель не может редактировать код ученика
Приоритет: P1 Предусловия: Открыта программа ученика. Шаги:
- Попробовать найти любой элемент редактирования/сохранения на странице (поле ввода поверх кода, кнопку «Сохранить» и т.п.).
Ожидаемый результат: Такого элемента нет — код показан в <pre>, только для чтения, как и заявлено (сверено с кодом — экран не имеет write-канала в принципе).
8. Документация / вики
Живёт на публичном портале (/docs), не внутри самого приложения учителя — учитель открывает её в обычном браузере. Не требует входа.
TC-067. Раздел документации открывается без входа
Приоритет: P2 Предусловия: Есть доступ в интернет и адрес развёрнутого портала (или локальный стенд портала). Шаги:
- Открыть в браузере
<адрес портала>/docsбез авторизации.
Ожидаемый результат: Список документов открывается, сгруппированный по разделам (например, «Тестировщику», «Устройство продукта», «Состояние работ», «Протоколы обмена»), доступен без входа в аккаунт.
TC-068. Открытие конкретного документа
Приоритет: P2 Шаги:
- Открыть, например, «Руководство тестировщика» из списка.
Ожидаемый результат: Документ отображается читаемым текстом с настоящими абзацами (не «лесенкой» из фрагментов по одной строке в каждом <p>), таблицы и списки не разваливаются на отдельные пункты без структуры.
TC-069. Диаграммы в документах не выглядят сломанными
Приоритет: P3 Предусловия: Открыт документ, содержащий mermaid-диаграмму (например, «Обзор MVP»). Шаги:
- Найти в тексте документа блок с диаграммой.
Ожидаемый результат: Диаграмма показана как читаемый текст-исходник с подписью о том, что это исходник диаграммы, а не рендерится как визуальная картинка. Это ожидаемое поведение (не баг) — но подпись должна присутствовать, иначе выглядит как поломка.
9. Синхронизация с порталом
Требует интернет и, по возможности, реальный или тестовый портал (см. mvp/portal/PLAN.md). Согласно D-086/OVERVIEW §1 — эта секция никогда не должна мешать LAN-серверу учителя (см. также раздел 11).
TC-070. Портал не настроен — понятное состояние
Приоритет: P2 Предусловия: Чистая база, вкладка «Портал». Шаги:
- Открыть «Портал».
Ожидаемый результат: Раздел «Аккаунт» показывает «Сначала укажите адрес и ключ портала выше», кнопки входа/регистрации неактивны, пока не сохранён базовый URL/ключ.
TC-071. Регистрация нового аккаунта учителя
Приоритет: P1 Предусловия: Введены и сохранены адрес портала и ключ. Шаги:
- Ввести email и пароль, нажать «Зарегистрироваться».
Ожидаемый результат: Если требуется подтверждение почты — уведомление «Аккаунт создан. Подтвердите email — до подтверждения синхронизация недоступна»; иначе — «Аккаунт создан и вход выполнен» и раздел переключается в состояние «вошли как …».
TC-072. Вход существующим аккаунтом
Приоритет: P1 Шаги:
- Ввести email/пароль зарегистрированного аккаунта, нажать «Войти».
Ожидаемый результат: «Вход выполнен», появляются разделы «Мои курсы» и «Публичные курсы».
TC-073. Выход из аккаунта не рвёт связь с учениками
Приоритет: P1 Предусловия: Учитель вошёл, ученик подключён по LAN. Шаги:
- Нажать «Выйти».
- Проверить, что подключённый ученик по-прежнему на связи (вкладка «Класс»).
Ожидаемый результат: Уведомление «Выход не влияет на подключённых учеников — синхронизация с портала просто выключается»; ученик остаётся подключён, живые команды продолжают работать.
TC-074. Публикация локального курса на портал (push)
Приоритет: P1 Предусловия: Есть локально созданный курс (раздел 6), учитель вошёл в портал. Шаги:
- В «Мои курсы» нажать «Отправить на портал» у курса.
Ожидаемый результат: «Отправлено на портал», у курса появляется пометка «связан с порталом». Повторное нажатие без изменений даёт «Уже отправлено (повтор запроса)», не создаёт дубль.
TC-075. Загрузка курсов с портала (pull)
Приоритет: P1 Предусловия: На портале есть курс, привязанный к аккаунту (например, из другого сеанса/машины). Шаги:
- Нажать «Загрузить с портала».
Ожидаемый результат: Уведомление «Обновлено: N[, пропущено (есть локальные правки): M]», список локальных курсов обновляется. Курс с несохранёнными локальными правками не перезаписывается молча — он в числе «пропущено».
TC-076. Конфликт версий при отправке — три явных варианта разрешения
Приоритет: P1 Предусловия: Тот же курс изменён и на портале (с другой машины/сессии), и локально. Шаги:
- Нажать «Отправить на портал» у изменённого курса.
- Прочитать блок «Конфликт версий».
- Опробовать по очереди (на разных копиях конфликта, если можно повторить): «Сохранить как копию», «Оставить версию с портала», «Оставить мою версию».
Ожидаемый результат: Диалог прямо говорит «Слияние текста не выполняется» — выбор один из трёх, без попытки автоматически смержить содержимое. Каждый вариант даёт свою пометку успеха и ни один не происходит молча/без явного действия учителя.
TC-077. Просмотр и импорт публичных курсов
Приоритет: P2 Шаги:
- Нажать «Показать публичные курсы».
- Импортировать один из них.
Ожидаемый результат: Список публичных курсов появляется без необходимости быть автором; импорт доступен только вошедшему в аккаунт учителю (кнопка «Импортировать» неактивна для незалогиненного — если получится проверить без входа, см. TC-070).
TC-078. Портал недоступен (нет интернета) — не считается ошибкой приложения
Приоритет: P1 Предусловия: Учитель вошёл ранее, теперь интернет отключён. Шаги:
- Отключить интернет (Wi-Fi/Ethernet до внешней сети, локальная сеть с учеником может при этом работать).
- Нажать «Загрузить с портала» или «Отправить на портал».
Ожидаемый результат: Явная, но не пугающая ошибка о недоступности сети; приложение не падает, локальная работа с классом (вкладки «Класс», «Классы», «Разрешения») продолжает работать без сбоев. После восстановления интернета повторное действие проходит успешно без перезапуска приложения.
10. Обновления приложения
TC-079. Проверка обновлений своего приложения
Приоритет: P1 Предусловия: Вкладка «Обновления», есть интернет. Шаги:
- Нажать «Проверить обновления».
Ожидаемый результат: Один из трёх исходов: «Версия актуальна»; блок «Доступна версия X» с кнопкой «Скачать»; либо (без интернета) «Проверить обновления не удалось: [причина]. Приложение работает дальше — это нормально, если в школе нет интернета» — и это НЕ считается багом.
Во всех трёх исходах: на время работы кнопка подписана «Проверяем…», а под сообщением стоит строка «проверено в ЧЧ:ММ» с текущим временем.
TC-079a. Видно, что проверка была, даже когда ответ не изменился
Приоритет: P1 Предусловия: Вкладка «Обновления». Годится любое состояние — в том числе ненастроенный портал. Шаги:
- Запомнить время в строке «проверено в …» (если её ещё нет — нажать «Проверить обновления» один раз, чтобы появилась).
- Подождать не меньше минуты.
- Нажать «Проверить обновления» ещё раз.
Ожидаемый результат: время в строке «проверено в …» изменилось. Сообщение выше при этом может остаться прежним — это нормально, вопрос кейса именно в том, видно ли, что проверка состоялась.
Была ошибка (до D-125): отметки времени не было, подписи на кнопке не было, и повторная проверка не меняла на экране ничего. QA завела это как неработающую кнопку — и была права: способа отличить сработавшую проверку от несработавшей не существовало.
TC-079b. Ненастроенный портал назван настройкой, а не молчащей сетью
Приоритет: P1 Предусловия: Вкладка «Портал», адрес портала НЕ заполнен (чистая установка). Шаги:
- Убедиться, что на вкладке «Портал» адрес пуст.
- Вкладка «Обновления» → «Проверить обновления».
- Прочитать сообщение целиком.
Ожидаемый результат: «Проверить обновления не удалось: адрес портала не настроен — укажите его на вкладке «Портал»». Фразы «ни один источник обновлений не ответил» нет. Фразы «это нормально, если в школе нет интернета» тоже нет — интернет тут ни при чём, и подсказка про него уводила бы от единственного нужного действия. Ниже, в «Раздаче классу», причина названа так же — экран не должен рассказывать две разные истории про одну пустую настройку.
TC-080. Скачивание и отложенная установка обновления
Приоритет: P1 Предусловия: Доступно обновление (TC-079). Шаги:
- Нажать «Скачать», дождаться прогресса.
- После завершения — прочитать подсказку про установку.
Ожидаемый результат: Пока скачивается — «Скачивание… N%»; после — состояние «готово» с текстом «Обновление скачано и проверено. Установка закроет приложение — лучше не посреди урока» и отдельная кнопка «Установить сейчас» — то есть скачивание и установка разделены, установка не начинается сама.
TC-081. Установка обновления
Приоритет: P2 Предусловия: Обновление скачано (TC-080). Осторожно: закрывает приложение. Шаги:
- Нажать «Установить сейчас».
Ожидаемый результат: Приложение закрывается для установки; после перезапуска — новая версия видна в «Установлена версия ...».
TC-082. Раздача обновлений классу по локальной сети
Приоритет: P1 Предусловия: В школе/на стенде нет интернета у учеников, но учительский ноутбук предварительно пополнил «запас» (нажатие «Обновить запас», сделанное заранее там, где есть интернет). Шаги:
- На «Обновления» → «Раздача классу» посмотреть таблицу «Кому / Система / Версия».
- Со стороны ученического ноутбука инициировать обновление приложения ученика по локальной сети (если такая функция доступна на стороне ученика — иначе кейс сверить только по наличию раздачи).
Ожидаемый результат: Таблица показывает готовые к раздаче пакеты для учеников/учителя с указанием ОС и версии; подсказка «Интернет им при этом не нужен». Ученический ноутбук без интернета получает обновление именно с учительского компьютера по локальной сети.
TC-083. Раздача не поднялась — видимая ошибка, не тишина
Приоритет: P1 Предусловия: Спровоцировать конфликт порта раздачи (например, занять указанный порт другим процессом) или иное препятствие запуску relay-сервера. Шаги:
- Открыть «Обновления» → «Раздача классу».
Ожидаемый результат: Баннер «Раздача не работает: [причина]» с пояснением «Ученики не получат обновления от этого компьютера» — учитель узнаёт о проблеме сразу на этом экране, а не по тому, что тридцать учеников остались на старой версии (комментарий из кода экрана прямо формулирует эту цель).
TC-084. Обновление запаса
Приоритет: P2 Предусловия: есть интернет. Адрес портала настраивать НЕ надо — он зашит в сборку по умолчанию (меняют его только школы со своим порталом, на вкладке «Портал»). Шаги:
- Нажать «Обновить запас».
- Дождаться окончания. Это долго: обход тянет настоящие установщики (APK ~170 МБ, exe ~100 МБ), на школьном канале — минуты. Кнопка всё это время подписана «Обновляем запас…».
- Прочитать строку под таблицей.
Ожидаемый результат: пока идёт — кнопка «Обновляем запас…» и заблокирована от повторного нажатия. После — строка «проверено в ЧЧ:ММ» с текущим временем, и один из исходов названный словами:
- таблица «Кому / Система / Версия» с готовыми пакетами;
- «На портале пока нет ни одной сборки для раздачи (спросили N)» — штатное состояние пилота, пока выпуск не опубликован, а не поломка;
- «Ни одну сборку получить не удалось — портал недоступен или отвечает ошибкой»;
- «Часть сборок получить не удалось: не вышло N из M».
Была ошибка (до D-126): портал отвечал 404 на каждую позицию — на пилоте это норма, сборок ещё не выпускали, — и обход завершался, не оставив на экране ни следа: список пуст, ошибки нет, текст тот же, что до нажатия. Отличить «сходили, на портале пусто» от «кнопка не работает» было нечем; QA так и записала — «ничего не происходит».
TC-084a. Ненастроенный портал больше не мешает раздаче на свежей установке
Приоритет: P1 Предусловия: чистый профиль учителя, адрес портала на вкладке «Портал» не заполнен Шаги:
- Открыть «Обновления» → «Раздача классу».
Ожидаемый результат: баннера «Раздача не работает: адрес портала не настроен» НЕТ. Раздача пользуется адресом по умолчанию, зашитым в сборку.
Была ошибка: свежая установка объявляла раздачу неработающей и отправляла учителя настраивать портал на вкладке, которую никто не открывает. Тест-кейс при этом про настройку портала не упоминал — и был прав: настраивать её не должно быть нужно.
11. Офлайн и деградация сети (D-086: LAN — только удобство учителя, урок работает без сети)
Ключевой принцип продукта: путь ученик↔робот не завязан на IP-сеть вообще (Bluetooth + USB), LAN нужна только для того, чтобы УЧИТЕЛЬ видел класс. Раздел проверяет именно это: пропажа сети не должна ломать урок, а данные не должны теряться.
TC-085. Класс без роутера вообще — учитель просто не видит учеников
Приоритет: P1 Предусловия: Ученические ноутбуки НЕ подключены ни к какой сети (Wi-Fi выключен), учительский ноутбук — тоже. Шаги:
- Запустить приложение учителя без сети.
- На ученических ноутбуках писать и запускать программы на реальном роботе по Bluetooth (без какого-либо участия сети).
Ожидаемый результат: Учительское приложение запускается штатно (локальный сервер поднимается на loopback/локальном интерфейсе даже без внешней сети), вкладка «Класс» показывает «Никто ещё не подключился» — не ошибку. Ученики при этом полноценно работают: пишут код, подключаются к роботу по Bluetooth, запускают программы, видят результат — без единого сбоя, связанного с отсутствием LAN.
TC-086. Хотспот с телефона вместо роутера — работает как обычная сеть
Приоритет: P1 (интеграционный) Предусловия: Точка доступа — обычный мобильный хотспот (не роутер класса). Шаги:
- Подключить учительский и ученический ноутбуки к хотспоту.
- Пройти сокращённый вариант TC-022 (сопряжение) и TC-032 (заморозка/подтверждение).
Ожидаемый результат: Обнаружение, сопряжение и командный канал работают так же, как с обычным роутером — хотспот с телефона официально поддерживается как равноценная замена роутеру (OVERVIEW §1: «это обычный хотспот для ноутбуков... несёт класс без проблем»).
TC-087. Ученик отваливается от сети посреди урока — урок не прерывается
Приоритет: P1 (интеграционный) Предусловия: Ученик подключён, работает над программой (пишет код локально, не завязан на связь с учителем для самого написания/запуска). Шаги:
- Выключить Wi-Fi на ученическом ноутбуке.
- Продолжить писать код, запускать программу на роботе (Bluetooth не зависит от Wi-Fi).
- На учительской стороне посмотреть на «Ученики на связи».
- Включить Wi-Fi обратно.
Ожидаемый результат: На шаге 2 у ученика ничего не ломается — редактирование, запуск на роботе продолжают работать. На шаге 3 учитель видит ученика как «недоступен» (не «на связи», не тихо пропавшим без индикации). После шага 4 статус возвращается на «на связи» без ручных действий учителя, без потери данных (продолжение см. TC-088).
TC-088. Работы ученика синхронизируются с опозданием, а не теряются
Приоритет: P1 (интеграционный) Предусловия: Продолжение TC-087 — ученик сохранил/изменил программу, пока был отключён от сети. Шаги:
- После восстановления связи (TC-087, шаг 4) подождать автоматическую синхронизацию.
- На «Код учеников» проверить, что последняя версия программы, написанная во время разрыва связи, доехала до учителя.
Ожидаемый результат: Программа, сохранённая офлайн, появляется у учителя после восстановления сети с корректным временем синхронизации — ничего не потеряно, досинхронизация происходит сама, без ручного «отправить ещё раз» со стороны ученика.
TC-089. Незакрытая заморозка не остаётся навечно при пропаже учителя
Приоритет: P1 Предусловия: См. TC-038 — комбинация с реальным отключением учителя. Шаги:
- Заморозить ученика/класс.
- Полностью закрыть приложение учителя (не просто разрыв сети) более чем на 30 минут.
- Проверить состояние рабочего пространства ученика.
Ожидаемый результат: Тот же результат, что в TC-038: ограничение автоматически снимается через 30 минут без контакта, ученик не остаётся заблокированным до бесконечности из-за того, что учитель закрыл ноутбук в конце урока.
TC-090. Сервер учителя падает посреди урока — видимое состояние, не тихая смерть
Приоритет: P1 Предусловия: Ученики подключены и работают. Шаги:
- Спровоцировать сбой сервера (например, занять его порт другим процессом до перезапуска, если тестовая среда это позволяет; либо просто закрыть и понаблюдать за индикатором при следующем запуске).
- Посмотреть на бейдж состояния сервера в шапке приложения учителя.
Ожидаемый результат: Бейдж переходит в «Сервер для учеников недоступен» или «Порт занят» (не остаётся в «Сервер для учеников доступен», пока сервер реально не отвечает). Реклама mDNS-сервиса снимается сразу — подключённые/ищущие ученики видят честное «не найдено», а не зависшее соединение.
TC-091. Восстановление сервера после конфликта порта
Приоритет: P2 Предусловия: Продолжение TC-090, состояние «Порт занят». Шаги:
- В бейдже ввести другой порт в поле рядом с кнопкой «Повторить» (или освободить прежний порт).
- Нажать «Повторить».
Ожидаемый результат: При успехе — бейдж переходит в «Сервер для учеников доступен» с новым портом; ученики, повторно ищущие учителя, находят его на новом порте (mDNS/UDP объявление обновляется).
TC-092. Урок без интернета целиком — портал недоступен, класс работает
Приоритет: P1 Предусловия: Локальная сеть (роутер/хотспот) есть, интернета нет вовсе. Шаги:
- Пройти сокращённый вариант TC-022, TC-032 (сопряжение, заморозка) без интернета.
- Открыть вкладку «Портал» — убедиться, что попытка синхронизации не блокирует остальной интерфейс.
Ожидаемый результат: Всё, что не требует интернета (ростер, LAN-подключение учеников, живые команды, курсы/уроки, разрешения), работает штатно. Раздел «Портал» либо неактивен, либо честно сообщает о недоступности сети — не подвешивает вкладку и не мешает остальным вкладкам.
12. Два учителя в одной сети
Не описано как отдельная спроектированная фича в PLAN.md/протоколе — раздел проверяет фактическое поведение (эксплораторно), а не заранее заданный сценарий. Расхождение с ожиданием всё равно стоит зафиксировать как находку.
TC-093. Два запущенных приложения учителя не конфликтуют по порту на одном компьютере
Приоритет: P2 Предусловия: Два экземпляра приложения учителя на одном ноутбуке (если это вообще возможно запустить одновременно — иначе кейс неприменим, пометить «неприменимо»). Шаги:
- Запустить второй экземпляр приложения учителя.
Ожидаемый результат: Либо второй экземпряр честно сообщает о занятом порте (см. TC-090/091), либо подбирает свободный порт сам — в любом случае не падает молча и не создаёт впечатление рабочего сервера, который на деле не слушает.
TC-094. Два разных учителя на разных ноутбуках в одной физической сети
Приоритет: P1 (эксплораторный) Предусловия: Два ноутбука с приложением учителя, каждый со своим классом, оба в одной Wi-Fi сети/хотспоте. Шаги:
- Запустить оба приложения учителя, у каждого — своё уникальное «Название кабинета», сопряжение открыто у обоих.
- С ученического ноутбука в режиме «В классе» инициировать поиск.
Ожидаемый результат: Задокументировать фактическое поведение: находит ли ученик обоих учителей и даёт выбрать нужного, подключается ли к первому найденному, или к «неправильному». Если UI никак не различает двух найденных учителей одинаково видимо для ребёнка (например, по названию кабинета) — это находка для отчёта, а не ожидаемая функция с гарантированным исходом.
TC-095. Ученик по ошибке подключился не к тому учителю (сопряжение чужого класса)
Приоритет: P2 (эксплораторный) Предусловия: Условия TC-094, ученик сопрягается со «своим» учителем через отпечаток по TC-022. Шаги:
- Сверить отпечаток на экране ученика с отпечатком своего учителя (а не соседнего).
- Убедиться, что подтверждение устройства произошло именно на «правильном» учительском ноутбуке (в «Запросы на подключение» этого учителя, а не соседнего).
Ожидаемый результат: Сверка по 6-символьному отпечатку — единственный способ отличить нужного учителя от соседнего в этой версии (нет pairing-кода, см. protocols/02 §5). Если отпечатки на экранах различаются между двумя учительскими приложениями (что и должно быть), ручная сверка предотвращает случайное присоединение не к тому классу.
13. Кроссплатформенность macOS/Windows
TC-096. Первый запуск на Windows запрашивает сетевое разрешение — обе галочки
Приоритет: P1 Предусловия: Чистая установка на Windows, первый запуск. Шаги:
- Запустить приложение учителя первый раз.
- В диалоге брандмауэра Windows разрешить и «частные», и «общественные» сети.
Ожидаемый результат: Диалог появляется (ожидаемое поведение, не баг — так помечено в TESTER-GUIDE). Если разрешить только «частные» сети — школьный Wi-Fi часто определяется как «общественная», и ученики не смогут подключиться, при этом сам учитель будет видеть зелёный индикатор сервера («слушает»), что маскирует проблему. Кейс TC-021/TC-022 стоит повторить именно после разрешения обеих галочек.
TC-097. Неизвестный издатель при установке на Windows — ожидаемо
Приоритет: P3 Предусловия: Установщик .exe, не имеющий пока купленной подписи. Шаги:
- Запустить установщик.
Ожидаемый результат: SmartScreen показывает «Неизвестный издатель»; «Подробнее» → «Выполнить в любом случае» продолжает установку. Это НЕ баг (см. TESTER-GUIDE.md, часть 6, «Что НЕ является багом»).
TC-098. Установка и первый запуск на macOS
Приоритет: P2 Шаги:
- Перетащить
.dmgв «Программы», запустить.
Ожидаемый результат: Приложение запускается без дополнительных диалогов о сети (специфично для Windows), сервер поднимается так же, как описано в TC-001.
TC-099. Раздача обновлений между разными ОС в одном классе
Приоритет: P2 Предусловия: В классе есть и Windows-, и macOS-ноутбуки учеников, учительский «запас» на вкладке «Обновления» пополнен для обеих платформ. Шаги:
- На «Обновления» → «Раздача классу» проверить таблицу — есть строки и для Windows, и для macOS.
Ожидаемый результат: Таблица показывает платформу для каждого пакета («Windows» / «macOS, Apple Silicon» / «macOS, Intel»); ученик получает пакет именно под свою ОС, а не универсальный/не тот.
Что не покрыто и почему
- Реальные моторы/датчики/телеметрия модуля — детально не расписаны в терминах "какое движение ожидать" в этом файле, только факт «программа запускается и выполняется на роботе» (см. TC-033, TC-086, TC-087) — как и оговорено в
TESTER-GUIDE.mdчасть 7, физическая механика вне рамок этого этапа тестирования; интеграционные кейсы указывают на реальный робот там, где применимо, но не проверяют конкретную кинематику. - Bluetooth к настоящему телефону на Windows — согласно
OVERVIEW.md§7.1 это самый большой непроверенный риск проекта и не относится к приложению учителя напрямую (это связка ученик↔телефон); тест-кейсы этого файла используют интеграцию «ученик работает на роботе» как данность. - Личный режим устройства ученика (П3.2/D-119) и media в уроках (П3.1/D-120) — в коде на момент письма отсутствуют (спеки написаны, реализации нет), поэтому не включены. Если появятся — добавить в раздел 6.
- QR-код для сопряжения — отклонено решением продукта (D-114): pairing-код на экране телефона не нужен для этой связки (это про ученик↔робот, не про учитель↔ученик), сюда не относится.
- Прямое (не через discovery) подключение как fallback у ученика к роботу — вне зоны этого файла (протокол 01, не 02).
- Экспорт/печать оценок, ведомости — в изученном коде (
src/pages/*) такого раздела не найдено; явного упоминания вPLAN.mdтоже нет. Не включено, чтобы не выдумывать несуществующий функционал. - Кейсы П2.9 (создание ученика учителем без PIN / «убрать PIN») — по
SCENARIOS-COVERAGE.mdявно помечено «не делалось: требует подтверждения продукта» — не включено. - Traceability конкретных сообщений об ошибках сети портала (§7 протокола 03) — не расписаны построчно, покрыты одним обобщённым TC-078; при необходимости детализировать по кодам ошибок можно отдельным заходом с чтением
electron/portal/errors.ts.