# Сквозные тесты с Cypress GlarusBI использует Cypress для «сквозного тестирования», то есть тестов, которые выполняются для приложения в целом, включая внешний интерфейс, серверную часть и базу данных приложения. Эти тесты, по сути, представляют собой сценарии, написанные на JavaScript, которые запускаются в веб-браузере: посещайте разные URL-адреса, щелкайте различные элементы пользовательского интерфейса, вводите текст и подтверждайте, что все происходит так, как ожидалось (например, элемент появляется на экране или выполняется сетевой запрос). ## Начало работы Тесты Cypress в GlarusBI расположены в `e2e/test/scenarios` в структуре, которая примерно отражает структуру URL-адресов GlarusBI. Например, тесты для административных страниц «модели данных» расположены в `frontend/test/metabase/scenarios/admin/datamodel`. Наш пользовательский Cypress создает свой собственный бэкэнд и создает временную базу данных приложения H2. Оба уничтожаются при завершении этого процесса. Зарезервированный порт по умолчанию - `4000` на локальном хосте. Ничто не мешает вам одновременно запустить локальный экземпляр Metabase на `localhost:3000`. Это может быть даже полезно для отладки. ### Стандартный поток разработки 1. Постоянно делайте фронтенд a. Если вам нужен только фронтенд, запускайте `yarn build-hot` b. Если вам нужна локальная среда Glarus BI с Cypress, самый легкий способ это получить используя `yarn dev` или `yarn dev-ee` (оба основаны на горячем обновлении фронтенда под капотом) 2. В отдельной сессии терминала (без убивания предыдущей) запускайте `yarn test-cypress-open`. Это откроет интерфейс Cypress который позволит вам выбрать какие тест запускать. Либо посмотрите на большей опций запуска. Чтобы запустить все тесты Cypress программно в терминале: ``` yarn run test-cypress-run ``` Вы можете запустить определенный набор сценариев, используя флаг `--folder`, который подберет выбранные сценарии в `e2e/test/scenarios/`. ``` yarn run test-cypress-run --folder sharing ``` Вы можете быстро протестировать один файл только с помощью флага `--spec`. ``` yarn test-cypress-run --spec e2e/test/scenarios/question/new.cy.spec.js ``` Вы можете указать браузер для исполнения тестов Cypress используя флаг `--browser`. Для большей информации просьба обратиться к [официальной документации](https://docs.cypress.io/guides/guides/launching-browsers). Указание браузера имеет наибольший смысл при запуске Cypress в режиме _run_. С другой стороны, режим _open_ (GUI) Cypress позволяет легко переключаться между всеми доступными браузерами в системе. Однако некоторые люди предпочитают указывать браузер даже в этом сценарии. Если вы это сделаете, имейте в виду, что вы просто предварительно выбираете начальный браузер для Cypress, но у вас все еще есть возможность выбрать другой. ## Анатомия теста Тестовые файлы Cypress структурированы как тесты Mocha, где блоки описания используются для группировки связанных тестов, а блоки `it` представляют собой сами тесты. ```js describe("homepage",() => { it('should load the homepage and...', () => { cy.visit("/metabase/url"); // ... }) }) ``` Мы настоятельно рекомендуем использовать такие селекторы, как `cy.findByText()` и `cy.findByLabelText()` из [`@testing-library/cypress`](https://github.com/testing-library/cypress-testing-library ), так как они поощряют написание тестов, которые не зависят от деталей реализации, таких как имена классов CSS. Старайтесь избегать случайного повторного тестирования частей приложения. Например, если вы хотите протестировать что-то в конструкторе запросов, перейдите прямо туда, используя помощник, такой как `openOrdersTable()`, вместо того, чтобы начинать с домашней страницы, нажимая «Создать», затем «Вопрос» и т. д. ## Документация Cypress * Введение: https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html * Команды: https://docs.cypress.io/api/api/table-of-contents.html * Утверждения: https://docs.cypress.io/guides/references/assertions.html ## Советы/Нюансы ### `contains` vs `find` vs `get` В Cypress есть набор похожих команд для выбора элементов. Вот несколько советов по их использованию: * `contains` чувствителен к регистру текста *в DOM*. Если это не соответствует ожидаемому тексту, убедитесь, что CSS не обновил регистр. * `contains` соответствует подстрокам, поэтому, если вы видите «filter by» и «Add a filter», `contains («filter»)` будет соответствовать обоим. Чтобы избежать этих проблем, вы можете либо передать регулярное выражение, закрепляющее начало/конец строки, либо передать селектор в дополнение к строке: `.contains(selector, content)`. * `find` позволит вам искать в пределах вашего предыдущего выбора. `get` будет искать всю страницу, даже если она связана. ### Увеличьте размер области просмотра, чтобы избежать прокрутки Иногда представления Metabase немного велики для области просмотра Cypress по умолчанию 1280x800. Это может потребовать прокрутки для работы тестов. Например, виртуализированные таблицы даже не будут отображать содержимое за пределами области просмотра. Чтобы избежать этих проблем, увеличьте размер области просмотра для определенного теста. Если вы специально не тестируете, как приложение ведет себя при изменении размера окна, пожалуйста, избегайте использования `cy.viewport(width, height);` в середине теста. Вместо этого задайте ширину/высоту области просмотра с помощью дополнительной конфигурации теста Cypress. Эта конфигурация работает как с блоками `describe`, так и с `it`. ```js describe("foo", { viewportWidth: 1400 }, () => {}); it("bar", { viewportWidth: 1600, viewportHeight: 1200 }, () => {}) ``` ### Перезагрузка кода и тестовая перезагрузка Когда вы редактируете тестовый файл Cypress, тесты обновляются и запускаются снова. Однако, когда вы редактируете файл кода, Cypress не обнаружит это изменение. Если вы используете `yarn build-hot`, код будет пересобран и обновлен внутри Cypress. Вам придется вручную щелкнуть повторно после загрузки нового кода. ### Проверка, когда "contains helper" открыт Одной из замечательных особенностей Cypress является то, что вы можете использовать инспектор Chrome после каждого шага теста. Cypress также предоставляет помощника, который может тестировать вызовы `contains` и `get`. Этот помощник создает новый пользовательский интерфейс, который не позволяет проверке нацеливаться на правильные элементы. Если вы хотите проверить DOM в Chrome, вы должны закрыть этот помощник. ### Помещение неправильного HTML-шаблона в Uberjar `yarn build` и `yarn build-hot` перезаписывают шаблон HTML, чтобы ссылаться на правильные файлы Javascript. Если вы запустите `yarn build` перед сборкой тестов Uberjar для Cypress, вы не увидите изменений в вашем Javascript, даже если вы затем запустите `yarn build-hot`. ### Запуск Cypress на машинах M1 Вы можете столкнуться с проблемами при запуске Cypress на машине M1. Это вызвано `@bahmutov/cypress-esbuild-preprocessor`, который использует `esbuild` в качестве зависимости. Ошибка может выглядеть [так](https://github.com/evanw/esbuild/issues/1819#issuecomment-1018771557). [Решение](https://github.com/evanw/esbuild/issues/1819#issuecomment-1080720203) состоит в том, чтобы установить NodeJS с помощью одного из менеджеров версионности Node, таких как [nvm](https://github.com/nvm -sh/nvm) или [n](https://github.com/tj/n). ### Запуск тестов, зависящих от образов Docker Подмножество наших тестов зависит от внешних сервисов, доступных через образы Docker. На момент написания этой статьи это три поддерживаемые внешние базы данных QA, веб-почта и сервер LDAP. Утомительно иметь пять контейнеров Docker, работающих локально. Следующий способ предусмотрен для людей, которые не заботятся об этих тестах, но все же нуждаются в локальном запуске спецификаций, содержащих их. Запустите эту команду: ```sh yarn test-cypress-run --env grepTags="-@external" --spec path/to/spec/foo.cy.spec.js ``` Обратите внимание на знак минус перед тегом `@external`. Для получения более подробной информации обратитесь к [официальной документации](https://github.com/cypress-io/cypress-grep#filter-with-tags). Если вы хотите или вам необходимо провести эти тесты, есть удобная опция, которая сделает всю тяжелую работу за вас: ```sh yarn test-cypress-open-qa ``` ### Проведение испытаний с использованием снегоочистителя Тесты, которые зависят от Снегоочистителя ожидают запуск сервера. Чтобы запустить их вам надо: - запустить локально Снегочиститель: `docker-compose -f ./snowplow/docker-compose.yml up -d` - передать переменные окружения: `MB_SNOWPLOW_AVAILABLE=true MB_SNOWPLOW_URL=http://localhost:9090 yarn test-cypress-open` ### Запуск тестов требует сервер SMTP Некоторые из наших тестов, которые зависят от настраиваемой электронной почты, требуют локального SMTP-сервера. Для этой цели мы используем образ Docker `maildev`. На момент написания этой статьи мы использовали образ `maildev/maildev:2.1.0`. Всегда безопасно использовать образ `:latest` в локальной разработке. Выполните эту команду: ```sh docker run -d -p 1080:1080 -p 1025:1025 maildev/maildev:latest ``` ### Cypress идет с `Lodash` бесплатно Нам не нужно иметь [Lodash](https://lodash.com/) в наших прямых взаимосвязях чтобы [использовать с Cypress](https://docs.cypress.io/api/utilities/_). Он имеет псевдоним с подчеркиванием, и его методы могут быть доступны с помощью `Cypress._.method()`. Мы можем использовать метод `_.times` для локального стресс-тестирования определенного теста (или набора тестов) ```js // Run the test N times Cypress._.times(N, ()=> { it("should foo", ()=> { // ... }); }); ``` ## Снимки БД В начале каждого набора тестов мы стираем базу данных бэкэнда и кеш настроек. Это гарантирует, что набор тестов запустится в предсказуемом состоянии. Как правило, мы используем моментальный снимок по умолчанию, добавляя `before(restore)` внутри первого блока `describe` для восстановления перед запуском всего набора тестов. Если вы хотите использовать снимок помимо стандартного, укажите имя в качестве аргумента для `restore` следующим образом: `before(() => restore("blank"))`. Вы также можете вызвать `restore()` внутри `beforeEach()` для сброса перед каждым тестом или внутри определенных тестов. Снапшоты создаются с помощью отдельного набора тестов Cypress. Эти тесты начинаются с пустой базы данных и выполняют определенные действия, чтобы привести базу данных в предсказуемое состояние. Например: зарегистрируйтесь как bob@metabase.com, добавьте вопрос, включите настройку ABC. Эти тесты, создающие снимки, имеют расширение `.cy.snap.js`. Когда эти тесты запускаются, они создают дампы БД в `frontend/tests/snapshots/*.sql`. Они запускаются до начала тестов и не фиксируются в git. ## Запуск в CI Cypress записывает видео каждого запуска теста, что может быть полезно при отладке. Кроме того, в неудачных тестах сохраняются изображения более высокого качества. Эти файлы можно найти в разделе "Артефакты" в результатах каждого запуска в GitHub Actions. Пример артефактов неудачного теста в каталоге "Onboarding":![GitHub Actions artifacts section](https://user-images.githubusercontent.com/31325167/241774190-f19da1d5-8fca-4c48-9342-ead18066bd12.png) ## Запуск тестов Cypress для версии GlarusBI EE Перед запуском Cypress для версии GlarusBI EE установите переменную окружения `MB_EDITION=ee`. У нас есть специальный блок `описания` под названием `describeEE`, который будет пропускать или запускать тесты в зависимости от версии. **Enterprise запустится без премиум-токена!** Если вы хотите протестировать премиум-функции (флаги функций), то действительные токены должны быть доступны для всех тестов Cypress. Мы достигаем этого, добавляя к переменным среды префикс `CYPRESS_`. Вы должны предоставить два токена, которые соответствуют планам GlarusBI EE/PRO с самостоятельным размещением (все функции включены) и облачным планом STARTER (функции не включены). - `CYPRESS_ALL_FEATURES_TOKEN` - `CYPRESS_NO_FEATURES_TOKEN` ``` MB_EDITION=ee CYPRESS_ALL_FEATURES_TOKEN=xxxxxx CYPRESS_NO_FEATURES_TOKEN=xxxxxx yarn test-cypress-open ``` Если вы перейдете на страницу `/admin/settings/license`, поле ввода лицензии должно показывать активный токен. Будьте осторожны, делясь скриншотами! - Если тесты в блоке `describeEE` выделены серым цветом и не выполняются, убедитесь, что вы запустили версию GlarusBI EE. - Если тесты запускаются, но корпоративные функции отсутствуют: убедитесь, что для используемого вами токена включены соответствующие флаги функций. - Если с токеном все в порядке, остановите все процессы Java: запустите `killall java` и перезапустите Cypress. ## Теги Cypress позволяет нам [тегировать](https://github.com/cypress-io/cypress/tree/develop/npm/grep#tags-in-the-test-config-object) тесты, чтобы легко находить определенные категории тегов. Например, мы можем пометить все тесты, которые требуют внешней базы данных, как `@external`, а затем запустить только эти тесты с помощью `yarn test-cypress-open --env grepTags="@external"`. Теги должны начинаться с `@`, чтобы было легче отличать их от других строк в поиске. Вот теги, которые мы используем: - `@external` - тесты, которые требуют внешнего контейнера Docker для запуска - `@actions` - тесты с использованием действий и изменяющие данные в источнике данных ## Как провести стресс-тестирование ненадежного теста? Локальное исправление ненадежного теста *(flaky test)* не означает, что исправление будет работать в среде CI GitHub. Единственный способ убедиться, что исправление работает — провести его стресс-тестирование в CI. Вот для чего создан `.github/workflows/e2e-stress-test-flake-fix.yml`. Он позволит вам быстро протестировать исправление в вашей ветке, не дожидаясь завершения полной сборки. Для этого выполните следующие действия: ### Подготовка - Создайте новую ветку с предложенным вами исправлением и отправьте ее на удаленный компьютер. - Пропустите открытие PR, либо откройте **черновой** запрос на включение. ### Запуск рабочего процесса стресс-тестирования вручную - Перейдите по ссылке `https://github.com/metabase/metabase/actions/workflows/e2e-stress-test-flake-fix.yml`. - Кликните на триггере *Запустить рабочий процесс*, находящемся рядом с надписью "Этот рабочий процесс имеет триггер события workflow_dispatch". 1. Выберите свою собственную ветку в первом поле "Использовать рабочий процесс из" (эта часть имеет решающее значение!). 2. Скопируйте и вставьте относительный путь спецификации, которую вы хотите протестировать (например, `e2e/test/scenarios/onboarding/urls.cy.spec.js`), не заключая его в кавычки. 3. Установите желаемое количество запусков теста. 4. Optionally provide a grep filter, according to [the documentation](https://github.com/cypress-io/cypress/tree/develop/npm/grep) 5. Нажмите зеленую кнопку "Запустить рабочий процесс" и ждите результатов. ### Things to keep in mind when using this workflow - It will automatically try to find and download the previously built Metabase uberjar stored as an artifact from one of the past commits / CI runs. - It was intended to be used for pure E2E fixes that don't require new Metabase uberjar. - If the fix required a source-code change (either backend of frontend), please open a regular PR instead and let the CI run all tests first. After this, you can trigger the stress-test workflow manually, as explained above, and it will automatically download newly built artifact from this CI run. Please, keep in mind that CI needs to fully finish running first. The workflow uses GitHub REST API which doesn't see artifacts otherwise.