Изучение Cypress можно начать, имея довольно слабое представление о JavaScript. Первое препятствие, с которым можно столкнуться в начале обучения, – это понимание того, как получить доступ к данным в ответе в формате JSON. Эта статья предназначена для всех, кто находится на ранних этапах пути изучения работы в Cypress.
Содержание:
- Доступ к элементам в объекте
- Доступ к элементам в массиве
- Массив объектов
- Распространенная ошибка №1 – Сравнение массивов
- Распространенная ошибка №2 – Невозможно прочитать свойство ‘x’ из неопределенного массива
Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
Доступ к элементам в объекте
Начнем с простого, прежде чем погрузиться во все тонкости JSON. Допустим, у нас есть объект JSON, содержащий всего пару ключей:
{ "color": "red", "id": 4, "available": false }
Для тестирования такого объекта мы можем написать следующий тест. Конечно, в реальном мире мы, скорее всего, не будем тестировать фикстуру, но для наглядности можно упростить ситуацию. Вместо .fixture()
можно представить .wait()
команду, которая перехватывает сетевой вызов.
cy .fixture('cars') .then( car => { expect(car.color).to.eq("red") expect(car.id).to.eq(4) expect(car.available).to.eq(false) })
Неважно, какое значение имеет атрибут нашего объекта, мы можем получить к нему доступ, используя так называемую точечную нотацию. Это objectname.attribute
нотация, разделенная точкой, отсюда и название. Или мы можем использовать скобочную нотацию, которая делает то же самое, но с несколько иным синтаксисом:
cy .fixture('cars') .then( car => { expect(car['color']).to.eq("red") expect(car['id']).to.eq(4) expect(car['available']).to.eq(false) })
Вы можете спросить, почему кто-то выбрал этот синтаксис, а не точечную нотацию, которая выглядит менее громоздкой, особенно если мы хотим получить доступ к атрибуту, находящемуся на несколько уровней ниже. При использовании скобочной нотации можно фактически передать переменную, в итоге получается что-то вроде этого:
cy .fixture('cars') .then(car => { const attr = 'color' expect(car[attr]).to.eq("red") })
Доступ к элементам в массиве
Теперь добавим еще один элемент в нашу car.json
фикстуру. Это будет список характеристик, отформатированный в виде массива:
{ "color": "red", "id": 4, "available": false, "features": ["speed limiter", "panoramic windshield", "automatic transmission"] }
Допустим, мы хотим написать тест для пары таких элементов. Этот тест будет выглядеть примерно так:
cy .fixture('cars') .then( car => { expect(car.features[0]).to.eq('speed limiter') expect(car.features[1]).to.eq('panoramic windshield') expect(car.features[2]).to.eq('automatic transmission') })
Обратите внимание, что мы используем стиль, аналогичный упомянутой скобочной нотации. Именно так осуществляется доступ к элементам массива. Однако точечной нотации для массивов не существует, поэтому попытка написать что-то вроде features.1
приведет к ошибке.
Массивы широко используются и иногда могут содержать большое количество информации. Если необходимо проверить массив на наличие только одного элемента, можно использовать include
assertion:
cy .fixture('cars') .then(car => { expect(car.features).to.include('speed limiter') })
Интересный факт – строки в JavaScript могут вести себя как массивы. Это означает, что мы можем обращаться к каждой букве, используя скобочную нотацию, и использовать то же include
утверждение, что и в предыдущем примере:
cy .fixture('cars') .then(car => { expect(car.color[0]).to.eq('r') // access first letter in "red" expect(car.color).to.include('ed') })
Существует множество различных утверждений для работы с массивами, ознакомиться с ними можно в документации Cypress.
Массив объектов
Теперь объединим массивы и объекты. Наша фикстура будет иметь внутри себя несколько объектов – обычная ситуация при работе с api, возвращающим список элементов. Наш JSON-файл будет выглядеть примерно так:
[ { "color": "red", "id": 4, "available": false, "features": ["speed limiter", "panoramic windshield", "automatic transmission"] }, { "color": "blue", "id": 7, "available": true, "features": ["speed limiter", "automatic transmission"] } ]
Чтобы проверить, например, цвет второго элемента, нам придется совместить два упомянутых подхода – обращение к массиву элементов и обращение к ключу объекта:
cy .fixture('cars') .then(cars => { expect(cars[1].color).to.eq('blue') })
С помощью cars[1]
мы выбираем второй элемент из нашего массива объектов, а внутри этого объекта используем .color
для выбора нужного значения. Другими словами, мы путешествуем по структуре JSON. Конечно, мы можем также использовать скобочную нотацию и написать то же самое следующим образом:
cy .fixture('cars') .then(cars => { expect(car[1]['color']).to.eq('blue') })
Поначалу эти комбинации могут показаться непривычными, но через некоторое время они становятся естественными. Большую помощь здесь может оказать Chrome DevTools. Щелчок правой кнопкой мыши на объекте JSON может вызвать меню, из которого можно скопировать путь атрибута к заданному значению.
Распространенная ошибка №1 – Cравнение массивов
При попытке разобраться с объектами JSON можно столкнуться с различными ошибками. Например, странное поведение наблюдается при попытке сравнить наш car.features
массив с другим массивом. Допустим, у нас есть утверждение следующего вида:
cy .fixture('cars') .then(cars => { expect(cars[0].features).to.eq(["speed limiter", "panoramic windshield", "automatic transmission"]) })
Несмотря на то, что, казалось бы, все должно пройти успешно, наш тест проваливается. Что еще более странно, так это ошибка в консоли:
Все выглядит одинаково, так почему же тест не работает?
Причина, по которой это происходит, заключается в том, как в JavaScript выполняется сравнение. Это очень похоже на то, почему '1' == 1
будет возвращать true
, а '1' === 1
будет возвращать false
. Разница связана с тем, насколько строгим является это сравнение. При сравнении двух массивов в нашем тесте необходимо использовать deep.eq
а не eq
.
Распространенная ошибка № 2 – Невозможно прочитать свойство ‘x’ из неопределенного ключа
При определении правильного пути к свойству также случаются ошибки. Возможно, вы уже сталкивались с проблемой, подобной той, о которой говорится в подзаголовке.
Чтобы глубже разобраться в проблеме, расширим наш JSON-файл дополнительными атрибутами:
[ { "color": "red", "id": 4, "available": false, "features": ["speed limiter", "panoramic windshield", "automatic transmission"], "engine": { "horsepower": 134, "rpm": 6000, "fueling system": "turbo/GDI" } }, { "color": "blue", "id": 7, "available": true, "features": ["speed limiter", "automatic transmission"], "engine": { "horsepower": 175, "rpm": 6000, "fueling system": "MPI" } } ]
Мы добавили некоторые engine
атрибуты, поэтому давайте проверим их с помощью следующего теста:
cy .fixture('car') .then(cars => { expect(cars[0].engines.horsepower).to.eq(134) })
Этот тест завершится неудачей со следующей ошибкой:
![Cannot read property ‘x’ of undefined](cannot-read-property-x-of-undefined.png” shadow=”shadow-md)
Причина неудачи этого теста заключается в том, что ключ horsepower
не может быть найден. Часть of undefined
указывает нам на причину. Похоже, что ключ, который должен находиться внутри engines
атрибута, не определен.
Обычно в таких случаях вместо всего пути следует вывести родительский атрибут через console.log()
, а затем продолжить работу с каждым родительским атрибутом, пока не найдется что-нибудь, что поможет установить путь.
Если сделать это в данном случае, то обнаружится, что была допущена опечатка, и вместо engines
надо было ввести engine
. В данном примере это кажется очевидной ошибкой. Но в случае с огромными полезными нагрузками, содержащими несколько уровней информации, все может оказаться гораздо сложнее.
Надеемся, эта статья поможет вам разобраться с объектами JSON при работе в Cypress. Делитесь своими мыслями в комментариях.
Перевод статьи «Reading and testing JSON object in Cypress».
Используйте cy-spok. Облегчит жизнь.
Пингбэк: Большой учебник по Cypress