Если вы уже знакомы с АЕМ-ом, смело пропускайте эту часть. Если же нет - вам стоит понять, что же такое этот АЕМ и почему с его тестированием возникают сложности.
AEM - content management system от Adobe (как выразилась коллега - WordPress на стероидах). Что это значит? Мы не создаем непосредственные веб страницы, а работаем над сложной админкой (AEM-author), которая в будущем позволит контенщикам (Editors) создавать эти страницы, используя набор определенных компонентов. Эти страницы будут видны (после publish действия) конечным юзерам (AEM-publish). Так что наша работа, собственно, и заключается в создании этих компонент.
Стоит сделать еще одну ремарку. Под компонентой, стоит понимать не только user interface, но и его возможную конфигурацию, которая может участвовать в логике на беке. Например, компонентой будет карточка нашего продукта, при нажатии на которую будет выполнен процесс букинга продукта и переход на страницу оплаты оного. При чем, в это же время, будет отправлена информацию в Google аналитику и возможно, что-то еще.
И так, что мы имели — AEM version 6.4.4.0. Процессы тестирования, установленные задолго до нашего привлечения. Вся ответственность была возложена на автотесты:
Screenshots tests — Поскольку AEM — content management system => Значит наши стили, да и вообще весь фронт очень важен, ведь это то с чем сталкивается конечный пользователь (возможно расскажу об этом в другой статье).
Web-component tests — самые обычные UI тесты с использованием Cypress в качестве основы. Только проверялись не страницы, а компоненты.
Web Performance tests — мониторинг производительности наших Web-страниц (с помощью Sitespeed)
Что мы строили — корпоративный сайт со всякими свистелками и перделками для отдела маркетинга для привлечения клиентов и увеличения продаж (с покупкой прям на сайте). Перед нами стояла задача разработать возможность едиторам создавать страницы с различными статьями. Создать компоненты, которые бы отображали созданные нами статьи в определенном порядке, плюс возможность применять фильтрацию, основываясь на подвязанных тегах.
Какая сложность возникает при автоматизации тестировании такого функционала? Зависит, где будет происходить фильтрация. В нашем случае всё происходило на стороне бека. Это осложняет тестирование, поскольку, создает невероятное количество комбинаций статей и соответствующих тегов. Они же, в свою очередь, должны где-то хранится.
С одной стороны, все очевидно — фильтр подразумевает наличие критериев и соответствующих сущностей. А если добавить сюда возможность создания новых критериев и новых сущностей? Задача резко усложняется. Добавляем итеративную разработку — изменения происходят не только в страницах, но и в логике их работы. Всё. Теперь мы не можем полагаться только на статический контент.
Представим, что мы таки оставляем статический контент. Тогда подобные изменения требуют от нас менять существующий контент для соответствия новой имплементации. При 5 страницах в этом нет ничего сложного, вот только становиться затратно по времени, если у вас 10+ страниц.
И так какой же выход?
А что если мы будем создавать страницы на лету?
Создали несколько страниц, пошли проверили нашу функциональность для данной комбинации, создали новые, проверили для них.
Long story short
К сожалению, АЕМ не предоставляет никакой информации о своем API. А если такая информация где-то и есть, я не смог ее найти. Да и тестирование АЕМ-а — минимально описанная головная боль (Тестируете АЕМ? — Делитесь в комментариях как).
Так что последующие выводы целиком и полностью — reverse engineering построенный на запросах отправленных фронтом (AEM-author) на бек.
В моем случае, и я уверен — в подавляющем большинстве случаев, - создание страниц в АЕМ-е сведется к следующим действиям:
Создание страницы с помощью темплейта (page template)
Добавление компонент на страницу
Конфигурация компонент
Паблиш страницы
И, конечно, мы будем:
Удалять страницы
Приступим...
Нам понадобиться dev-tools на вкладке Network.
1. Создание страницы с помощью темплейта
Открываем AEM-author
Sites
Переходим в нужную нам папку
Жмякаем Create
Выбираем нужный нам template
Заполняем интересующие нас поля
Запускаем запись Network запросов в dev-tools
Нажимаем Create
Первый же запрос `${aem-author-URL}/libs/wcm/core/content/sites/createpagewizard/_jcr_content
` будет содержать всю необходимую нам информацию.
Тут мы сталкиваемся с первой сложностью. Это POST запрос с FormData
. Т.е. запрос не содержит привычный многим тестировщикам body в виде JSON/XML
объекта. Вместо этого данные отправляются как Content-Type: application/x-www-form-urlencoded.
Во многих случаях любой JS объект можно легко перевести в данный формат (по-сути, это будет простая url encoded строка key=value
записанная через &
). Правда, тут нужно быть осторожными, поскольку данный формат не подразумевает, что ключ (key
) является уникальным. Т.е. ваша Form Data
может содержать tags=Tag1&tags=Tag2
(несколько тегов у страницы, в моем случае).
Самое важное на что стоит обратить внимание на этих скриншотах:
parentPath
— папка/страницв в AEM-e, в которой будет создана наша страницаtemplate
— путь к теплейту, который будет использован для создания страницы
… Ниже идут поля, применимые к моему проекту …
./jcr:title
— имя/тайтл моей страницы (обязательное поле на UI)./cq:tags
— тег, который я добавил странице (опциональное поле)./articleDate
,./articleTimeToRead
и:cq_csrf_token
Все остальные поля, опциональны и могут быть опущены в запросах.
Теперь, на счет авторизации. Как видно выше, запросы содержат token
. Я использовал cypress.io для написания автотестов, так что для авторизации API запросов просто указывал auth
объект с username
и password
, на ряду с методом, хедером и body. (For more info check Cypress: Request - arguments and http-authentication).
key takeaways: все запросы на создание новых страниц идут на `${aem-author-URL}/libs/wcm/core/content/sites/createpagewizard/_jcr_content
`, parentPath
и template
присутствуют для всех вариантов создания страниц с помощью темплейта.
2. Добавление компонент на страницу
Находим нужную нам страницу в AEM author
Жмякаем Edit
Выбираем нужную позицию (место) для компоненты
Жмякаем
+
Запускаем запись Network запросов в dev-tools
Находим и выбираем нужный нам компонент
Нужный нам запрос `${aem-author-URL}/content/${page-path}/jcr:content/par/${some-url-part}/par/
`.
Из важного тут:
./@CopyFrom
— темплейт (default) конфигурации компоненты (button в моем случае)./sling:resourceType
— название и путь к компоненте, которую я добавлялparentResourceType
— тут я не уверен, судя по всему место, куда добавить компоненту
3. Конфигурация компонент
На нужной нам странице выбираем необходимый компонент
Жмякаем “гаечный ключ”
Модифицируем конфигурацию данной компоненты
Запускаем запись Network запросов в dev-tools
Жмякаем кнопку Done
Наш запрос первый в списке `${aem-author-URL}/content/${page-path}/_jcr_content/par/${component-name}
`.
Из важного тут:
./sling:resourceType
— название и путь к компоненте, которую я добавлял:cq_csrf_token
— токен, значит нужно использовать auth
4. Паблиш страницы
Находим нужную нам страницу
Запускаем запись Network запросов в dev-tools
Жмякаем Quick Publish -> Publish
4.1.
В данном случае нам нужны первые 2 запроса.
4.1.1. Получение связанных ассетов
Запрос reference.json… — `${aem-author-URL}/libs/wcm/core/content/reference.json?${url-params}
` — получаем информацию о ассетах (assets), cвязаных с нашей страницей.
Из важного — тут используются query string params
. В path
указан путь к нашей странице.
В ответе нам придет массив ассетов. Нам понадобятся path`s
тех, чей published
статус false
.
4.1.2. Публикация страницы и ассетов
Запрос replicate — `${aem-author-URL}/bin/replicate
` — запрос на публикацию нашей страницы и связанных с ней сущностей.
Как вы видите, основное на что стоит обратить внимание:
cmd: Activate
— команда для паблиша страницыpath
— пути к нашей странице и к 2м ассетам
4.2.
Поскольку паблишинг страниц — асинхронное действие. Необходимо убедиться, что он состоялся.
Для этого нам понадобиться еще один запрос — GET `${aem-author-URL}/etc/replication/agents.author/publish_publish/jcr:content.queue.json
`. Он вернет нам массив страниц ожидающих паблишинга. Так что придётся сделать, как минимум еще один запрос, проверить есть ли необходимая нам страница в массиве body.queue
. Опять же искать по path
. Если страница все еще присутствует в очереди, придётся повторить проверку один или даже несколько раз (я выставил timeout в 1 секунду, но думаю можно и меньше).
5. Удаление страницы
Находим нужную нам страницу
Выбираем ее
Запускаем запись Network запросов в dev-tools
Жмякаем Delete-> Delete
Наш запрос `${aem-author-URL}/bin/wcmcommand
`.
Из важного тут:
cmd
— deletePagepath
— путь к страницеforce: false
— но я бы рекомендовал ставитьtrue
(дабы при удалении не происходило дополнительных проверок)checkChildren: true
— можно опустить
Итак, подведем итог…
Выше описанным способом можно создавать и конфигурировать страницы в АЕМ-е на лету. Основная проблема возникшая у меня — разобраться с последовательностью действий и структой отправляемых запросов.
В подавляющем большинстве все они содержат FormData
. И тут вам придётся выбрать способ, откуда брать эту информацию (использовать готовые моки или генерировать на лету). Я выбрал второй способ и с помощью билдеров создавал необходимые мне структуры FormData
(но это отдельная история).
Для тех кто дочитал аж сюда, несколько странностей вылезших в процессе создания страниц таким способом:
AEM заменяет пробелы на `
-
`. То есть если вы создали страницу с Тайтлом `Bla 1 2 3 4
` и не указали специфический путь к ней, тогда АЕМ сделает эту страницу доступной по пути…/bla-1-2-3-4
Пути страниц всегда будут в
lowerCase
(см пред. пример)При использовании `
_
` в тайтле начиная с (приблизительно с 18и символов) АЕМ удалит все последующие `_
`. Те если вы создали страницу с тайтломBlaBla123456789123456_blabla
, то доступ к ней будет не по…/blabla123456789123456_blabla
, а по…/blabla123456789123456blabla
Для сетапа некоторых добавленных компонент понадобиться их
id
. Его можно получить в ответе запроса на добавление этой компоненты на страницу.