Каких результатов планируется достичь?

  • Настроены версии python с помощью pyenv

  • Установлен PyCharm

  • Создан репозиторий на GitHub

  • Написан автотест

  • Автоматически сформирована документация для автотеста

  • Автоматически сформирован отчет о результатах прогона автотестов

Используемое оборудование и программное обеспечение

Все дальнейшие инструкции были написаны для MacOS. Для применения их на Windows читателю потребуется иногда заглядывать в документацию используемого программного обеспечения, чтобы подбирать аналогичные команды для Windows.

Для работы с кодом будут использоваться PyCharm и встроенный в MacOS терминал.

Дальнейшие примеры кода были написаны на python 3.11.1. Корректно они будут работать и на более старой версии 3.8.16.

Детального описания двух модулей (фабрика браузеров и интеграция с QASE.io), иcпользуемых в проекте, в инструкции ниже не будет. Это связано с тем, что инструкция рассчитана на начинающих специалистов и разбор некоторых модулей потребует слишком большого количества пояснения. С такими модулями мы будем работать как есть, их код будет доступен в GitHub этой статьи и может быть взят оттуда в исходном виде.

Инструкция

Устанавливаем Python с помощью Pyenv

Возможно, у вас уже установлен python. Если нет, то можно воспользоваться одним из нескольких доступных путей. Мне нравится использовать pyenv (официальный GitHub) для управления версиями python на рабочем компьютере.

  1. Устанавливаем XCode (официальный сайт).

  2. Открываем встроенный в MacOS терминал.

  3. Запускаем в терминале команду по установке Homebrew (официальный сайт)/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

  4. Запускаем в терминале команду brew install pyenv, для установки pyenv (внимательно следим за всеми рекомендациями в течение установки).

  5. Чтобы установить необходимые версии python в терминале запускаем команду pyenv install 3.10.4 -v и дожидаемся установки. Таким же образом могут быть установлены все остальные необходимые вам версии python.

  6. Для наглядности можно в finder открыть папку своего пользователя, затем нажать command + . (точка). Эта команда покажет скрытые файлы. Затем в папке своего пользователя вы увидите скрытую папку .pyenv. Открываем ее, в ней  находим папку versions. Уже в ней видим папку 3.11.1 ( и все остальные папки с названиями скаченных версий python). В ней находим папку bin, которая и содержит наш python. Таким образом теперь вы знаете, что путь до нужной версии python выглядит следующим образом: [user_name]/.pyenv/versions/[version_name]/bin/python. Этот путь мы будем использовать далее.

Если с установкой pyenv возникли сложности, то можно скачать python с официального сайта и установить как обычную программу.

Регистрируемся на GitHub и клонируем пустой репозиторий

Если аккаунта на GitHub у вас еще нет, то на этом шаге вам потребуется зарегистрироваться на GitHub и зайти в свой аккаунт.

Теперь нам необходимо создать новый репозиторий. Для этого нажимаем на кнопку New.

На открывшейся странице указываем наименование репозитория и выбираем его видимость (public/private). В моем случае это будет public.

Нажимаем кнопку Create repository. Откроется страница Quick setup.

Чтобы склонировать репозиторий на рабочий компьютер потребуется создать SSH ключ.

Для этого в верхнем правом углу кликаем на свою аватарку. В открывшемся меню выбираем Settings.

В навигации ищем пункт SSH and CPG keys. Откроется соответствующая страница.

Чтобы увидеть инструкцию по созданию SSH ключа кликаем на ссылку подсказки и там выбираем пункт Generating a new SSH key ...

Далее открываем встроенный в MacOS терминал. В нем будет вводить команды из инструкции GitHub.

Создание SSH ключа:

  1. В терминале вводим ssh-keygen -t ed25519 -C "your_email@example.com". Но прежде чем нажать Enter, нужно в кавычках исправить email на свой. Это тот email, на который вы регистрировали аккаунт на GitHub. Потом нажимаем Enter.

  2. Далее нам потребуется еще несколько раз (скорее всего 3 раза) нажать Enter пропуская предложения поставить пароль или изменить название файла. Нажимаем Enter до тех пор, пока не увидим картинку из символов. На этом процедура создания SSH ключа завершена и остается его добавить в GitHub.

  3. Чтобы получить доступ к публичной части SSH ключа, открываем finder MacOS. В нем находим папку Users. А в ней папку своего пользователя. Дальше открываем скрытую папку .ssh. В ней будет как минимум два файла. Первый: id_ed25519. Это приватная часть ключа. Никому этот файл не отдавайте. Второй: id_ed25519.pub. Это публичная часть ключа. Открываем этот файл в любом текстовом редакторе, копируем содержимое полностью и возвращаемся на странице создания SSH ключа в GitHub.

  4. Нажимаем New SSH key. Откроется страница Add new. Вводим title. По сути это наименование устройства, на котором лежит ключ. В моем случае в Title указано MacBook Pro 16 inch. А в поле Key вставляем содержимое файла id_ed25519.pub. Нажимаем кнопку Add SSH key.

  5. Вводим пароль от GitHub и проверяем, что ключ добавлен.

Пример двух добавленных ключей для двух ноутбуков.
Пример двух добавленных ключей для двух ноутбуков.

Теперь можно клонировать репозиторий на рабочий компьютер. В соответствии с распространенным мнением на рабочем компьютере у меня есть папка, где хранятся все клонированные с GitHub проекты. В моем случае она называется Code и лежит прямо в папке пользователя. То есть путь примерно такой: /Users/[user_name]/Code.

Чтобы клонировать репозиторий возвращаемся во встроенный в MacOS терминал и с помощью команды cd переходим в папку Code. В моем случае, чтобы из папки пользователя перейти в папку Code достаточно ввести команду cd Code.

Оказавшись в нужной папке клонируем репозиторий. Нам потребуется ссылка на репозиторий. Берем ее со страницы проекта в GitHub.

Ссылка на репозиторий
Ссылка на репозиторий

В терминале вводим команду git clone [ссылка_на_репозиторий_GitHub] и нажимаем Enter. В моем случае команда выглядит следующим образом: git clone git@github.com:stepushchenko/first_article_about_playwright.git

Процесс перехода к папке Code и клонирования репозитория с GitHub
Процесс перехода к папке Code и клонирования репозитория с GitHub

После завершения клонирования в моей папке Code появилась папка с наименованием репозитория first_article_about_playwright. Пока в этой папке есть только одна скрытая папка .git. Пусть так пока и будет. Созданная в результате клонирования репозитория папка и будет тем самым местом, где будет храниться весь код нашего проекта. Запомним ее, на следующем шаге она нам будет нужна.

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

Устанавливаем PyCharm и настраиваем проект

Если на вашем компьютере отсутствует PyCharm, то начнем с ее установки. Бесплатную версию (Community Edition) можно скачать с официального сайта. После скачивания, устанавливаем. Запускаем.

Для создания нового проекта нажимаем кнопку New Project.

В открывшемся окне потребуется указать директорию, в которой будет храниться код проекта. Эту директорию мы уже создали, когда клонировали репозиторий с GitHub. Теперь нам необходимо эту папку указать в поле Location.

В поле New environment using выбираем Virtualenv.

Поле Location заполнится автоматически, вам лишь нужно проверить, что путь будет такой же, как в поле Location выше, только с добавлением /venv. В этой директории будет храниться все файлы нашего окружения.

В поле Base Interpreter потребуется выбрать установленную нами ранее с помощью pyenv версию python 3.11.1. То есть в поле Base Interpreter должен быть путь вроде такого Users/[user_name]/.pyenv/versions/3.11.1/bin/python.

Галочку с пункта Create a main.py wellcome script предлагаю снять.

Пример заполнения полей при создании нового проекта
Пример заполнения полей при создании нового проекта

На этом настройки окружения мы пока закончим и нажмем кнопку Create. Появится окно, что выбранная директория не является пустой. Так и есть, ведь в ней лежит скрытая папка .git. Поэтому нажимаем кнопку Create from Existing Sources.

Откроется новый, пустой проект.

Пустой проект в PyCharm
Пустой проект в PyCharm

Устанавливаем requirements на проекте

Для того, чтобы внутри проекта использовать возможности сторонних python библиотек (requirements), нам необходимо их установить.

Для установки requirements  будем использовать встроенный в PyCharm терминал (и далее во всей инструкции мы будем использовать встроенный в PyCharm терминал) и файл requrements.txt.

Начнем с создания в корне проекта файла requirements.txt. Для этого правой клавишей кликаем по корневой директории проекта (верхний левый угол, название вашего проекта). Откроется меню. В нем выбираем пункт New. И выбираем File.

В открывшемся окне вводим requirements.txt и нажимаем enter. PyCharm откроет пустой только что созданный файл.

Теперь в нижней части PyCharm открываем вкладку Terminal. Сразу убедимся, что в начале строки в круглых скобках написано venv. Это означает, что виртуальное окружение активировано и все сторонние библиотеки, которые мы будем устанавливать, будут храниться в папке venv. Так мы будем обеспечиваться чистоту и порядок на рабочем компьютере.

В терминале вводим pip3 install pytest. Таким образом мы инициируем скачивание и установку в наш проект pytest. В дальнейшем он позволи нам запускать автотесты.

Команда, процесс установки и результат.
Команда, процесс установки и результат.

Сразу отметим для себя, что была установлена версия pytest 7.2.1. Сохраним эту версию в requirements.txt, чтобы любой другой человек, который в будущем присоединится к работе над нашим проектом имел аналогичное окружение.

Открываем файл requirements.txt. первой строкой пишем pytest==7.2.1. PyCharm сама сохранит изменения.

Теперь дополним файл requirements.txt новыми строками так, чтобы в итоге получить:

pytest==7.2.1
playwright==1.29.1
requests==2.28.2

Чтобы понять, зачем мы внести эти записи в файл requrements.txt попробуем воспользоваться этим файлом по назначению.

В терминале выполним команду pip3 install -r requirements.txt. Выполнение этой команды приведет к тому, что все библиотеки, которые были перечислены в файле requirements.txt будут скачены и установлены в наш проект.

Команда и процесс установки двух дополнительных библиотек.
Команда и процесс установки двух дополнительных библиотек.

Если вы, как и на моих скринах, видите, что для pip имеется более свежая версия, то установите обновление, воспользовавшись командой, которую видите в сообщении pip install --upgrade pip. После ее выполнения pip обновится и сообщение больше не будет показываться.

На этом шаге с requirements.txt мы пока закончим.

Установливем playwright

Playwright является альтернативой Selenium. В этом проекте мы будем использовать именно Playwright, а не Selenium.

Чтобы Playwright корректно работал, нам единоразово надо выполнить в терминале команду playwright install. В процессе выполнения этой команды на ваш компьютер будут скачиваться браузерные движки, на которых в последствии мы будем выполнять прогон автотестов.

Готовим скелет проекта

Чтобы в дальнейшем нам было проще работать над проектом мы создадим несколько файлов и папок.

На данный момент корневая папка проекта называется first_article_about_playwright. В ней мы уже успели создать файл requirements.txt.

Теперь в корневой директории создадим файл conftest.py. И пока оставим пустым.

Добавим в корневую директорию следующие папки:

  1. config

  2. pages

  3. tests

  4. fixtures

В папке config мы будем создавать модули, описывающие настройки нашего проекта.

В папке pages будут хранится модули, описывающие локаторы и шаги для каждой страницы нашего проекта. Постараемся придерживаться правил Page Object Model.

В папке tests мы будем писать автотесты.

В папке fixtures будут хранится модули с фиктурами pytest.

Текущая структура проекта
Текущая структура проекта

Теперь в корневую директорию добавим несколько файлов:

  1. README.md

  2. .gitignore

  3. conftest.py

Файл README.md пригодится для подготки описания проекта.

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

Файл conftest.py потребуется для управления фикстурами pytest.

Пока все созданные файлы будут оставаться пустыми.

Теперь создадим по одному файлу в директориях pages и tests.

В директории pages создадим файл (= модуль, дальше по тексту будут использоваться оба варианта наименования) base_page.py. Пока пусть будет пустым.

В директории tests создадим модуль base_test.py. Его также оставим пустым.

Текущая структура проекта
Текущая структура проекта

Отправляем изменения в GitHub

Как мы видим файлы выделены красным. Ничего страшного в этом нет. Просто они не добавлены в наш GitHub и поэтому PyCharm подсвечивает их красным.

Для того, чтобы добавить созданные файлы в GitHub выполним в терминале PyCharm следующие команды:

git add . 
git commit -m 'creating project structure'
git push

Команда в первой строке добавляет все созданные файлы в индекс для последующего коммита.

Команда из второй строки создает коммит с именем creating project structure.

Третья команда отправляет созданный коммит в GitHub.

Процесс выполнения команд
Процесс выполнения команд

Теперь все изменения, которые мы сделали в проекте, отправлены в GitHub.

Открываем GitHub и смотрим на страницу нашего репозитория. Все созданные нами файлы добавлены в репозиторий.

Текущее состояние репозитория
Текущее состояние репозитория

GitHub даже для начинающих автоматизаторов может оказаться полезен. С одной стороны, там хранится весь ваш код. И если с компьютером будут проблемы, то всегда можно заново склонировать репозиторий из GitHub, не потеряв результаты работы.

С другой стороны, над проектом не всегда работает один человек. А чтобы работать в команде навыки работы с GitHub (или аналогичными решениями вроде GitLab) будут очень полезны.

Вот краткий перечень команд, который пригодится в первые дни работы с GitHub:

  1. git clone (клонируем репозиторий)

  2. git add (добавляем измененные файлы в индекс)

  3. git commit (создаем коммит, сам по себе commit полезен тем, что позволяет как под зонтиком собрать все изменения проекта по одной теме)

  4. git push (отправка изменений на сервер)

  5. git pull (получение изменений с сервера)

Кратко рассматриваем суть проекта

Для того, чтобы написать эту инструкцию, мне надо было выбрать подопытный сайт, на котором мы и будем отрабатывать автотесты.

Хотелось взять какой-то всем известный сайт. И я выбрал google.com. На примере Google Search в рамках этой инструкции мы постараемся написать несколько тестов.

В рамках проекта хочется не только рассмотреть пару примеров создания автотестов, но и коснуться темы документации. В качестве TMS (программы, в которой хранится тестовая документация) будет использоваться QASE.io по причине понятного и бесплатного API.

Создаем аккаунт в QASE.io и начинаем работать с документацией

В рамках этого проекта мы постараемся добиться того, чтобы документация формировалась по большей части автоматически.

Если у вас еще нет аккаунта на QASE.io, то его необходимо будет создать.

После регистрации создадим новый проект. Нажимаем на кнопку Create new project. В появившемся окне заполняем поле Project name. В моем примере это будет Google Search. Оставляем проект приватным. Нажимаем на кнопку Create project.

Заполнение формы создания нового проекта
Заполнение формы создания нового проекта

Перед нами открылась страница проекта. Пока пустого. Проект состоит из Suites и Cases. Suites (далее я буду называть их свиты) - это названия групп (объединения) для кейсов.

Создадим первый свит. Для этого нажимаем на кнопку  + Suite. В поле Suite name внесем Index page. Под Index page я буду подразумевать главную страницу Google с формой поиска и двумя кнопками.

Index page
Index page

Внутри свита Index page создадим наш первый кейс, который будет проверять, что на кнопке Google Search действительно написано 'Google Search'. А то вдруг разработчики Google что-то напутают и случайно выкатят обновления с текстом 'Bing Search'. А наш автотест этот момент отследит и быстро сообщит о проблеме. Кейс я сохранил под именем The main search button must have the text Google Search.

Текущее состояние проекта на QASE.io
Текущее состояние проекта на QASE.io

Как можно увидеть на скрине, созданный кейс имеет свой уникальный номер GS-1. Состоит он из краткого названия проекта и порядкового номера кейса в этом проекте. Пока нам главное запомнить, что у нашего кейса ID = 1.

Далее мы займемся написанием этого автотеста.

Создаем модуль url в config

Сейчас нам надо убедиться в том, что в нашем проекте все настроено корректно и мы можем хотя бы открыть сайт google.com. То есть задача этого модуля - добиться от нашего проекта такого поведения, при котором запущенный автотест может запустить браузер и открыть в нем сайт google.com.

Для этого надо сделать несколько важных изменений в нашем проекте.

В папке config создадим модуль url.py. В модуле url.py мы напишем класс, содержащий в себе только одну переменную - ссылку на сайт google.com.

Для этого в модуле url.py напишем следующий код:

class Url:
    DOMAIN = 'https://google.com'

Первая строка означает создание класса.

Вторая строка с соответствующим отступом создает переменную DOMAIN со значением https://google.com.

Чтобы нам было удобно обращаться к config из других модулей в папке config создадим файл '__init__.py'. Перед словом init и после него ставим по два нижних подчеркивания.

В сам файле '__init__.py' добавляем следующий код:

from config.url import Url

url = Url()

Первая строка импортирует класс Url, который мы написали в модуле url.py.

Третья строка создает переменную, значением которой является экземпляр класса Url. Такая конструкция позволит нам из любого другого модуля получить ссылку на сайт google.com обратившись к config.url.DOMAIN.

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

Создаем еще два модуля в config и первую фикстуру

Теперь, когда мы знаем, откуда нам взять адрес сайта google.com требуется научить наши автотесты открывать этот сайт.

Но прежде мы заберем из репозитория этой статьи из директории fixtures модуль page. В нем уже написана фабрика браузеров, которая позволяет запускать автотесты в браузерах Chrome или Firefox.

Забрали этот модуль в своей проект? Если да, то видите, что PyCharm ругается на то, что у вас есть множественные ошибки в модуле page.py. Это нормально. Произошло так по причине того, что в модуле page.py используются конфиги под названиями playwright и expectations.

Давайте создадим их, чтобы исправить эти ошибки.

В папке config создаем два файла:

  1. playwright.py

  2. expectations.py

В них будут храниться настройки ожидания и самого playwright.

В модуль expectations.py добавляем следующий код:

class Expectations:
    DEFAULT_TIMEOUT = 60 * 1000

Первая строка создает класс.

Вторая строка создает переменную DEFAULT_TIMEOUT со значением 60000 миллисекунд (или 60 секунд). Значение этой переменной мы будем использовать в качестве значения таймаута по умолчанию. То есть если наш автотест не успел завершить начатое действие за 60 секунд, то мы его прервем.

В модуль playwright.py добавим следующий код:

import os


class Playwright:
    PAGE_VIEWPORT_SIZE = {'width': 1920, 'height': 1080}
    ENV = os.getenv('ENV') if os.getenv('ENV') is not None else 'stage'
    BROWSER = os.getenv('BROWSER') if os.getenv('BROWSER') is not None else 'chrome'
    IS_HEADLESS = os.getenv('HEADLESS') if os.getenv('HEADLESS') is not None else False
    SLOW_MO = int(os.getenv('SLOW_MO')) if os.getenv('SLOW_MO') is not None else 50
    LOCALE = 'en-US'

Кажется, что тут уже сильно сложно, но в целом разберемся.

Первая строка импортирует встроенную в python библиотеку os, которая дает нам возможность взаимодействовать с операционной системой (например, с ее помощью можно создавать файлы или папки, а потом удалять их). Но будем использовать эту библиотеку для того, чтобы считывать значения переменных из команд в терминале. Об этом подробнее позже.

Четвертая строка создает класс Playwright.

Строки с 5 по 10 задают значения для переменных. Если в команде в терминале была такая переменная, то значение будет взято оттуда. Если переменной в команде в терминале не было, то будет присвоено значение по умолчанию.

Все эти переменные управляют поведением автотестов. Например, переменная из строки 5 задает размеры окна браузера, в переменная из строки 10 задает языковые настройки для браузера, выставляя их на английский язык.

Особенно важна для нас переменная из строки 7. Она отвечает за то, в каком браузере будут выполняться автотесты. По умолчанию там указан Google Chrome.

Кажется, что недостающие файлы мы создали и теперь ошибки должны уйти. Но прежде чем ошибки уйдут, нам необходимо зайти в модуль '__init__.py' в директории config и внести туда добавленные классы.

Модуль __init__.py после внесения необходимых изменений
Модуль __init__.py после внесения необходимых изменений

Если сейчас мы откроем модуль page в директории fixtures, то обнаружим, что ошибки ушли.

Таким образом на данный момент в проекте мы уже имеем:

  • Три модуля в директории config. Каждый модуль несет в себе настройки для автотестов. И все модули указаны в '__init__.py' для быстрого обращения к ним в будущем.

  • Один модуль в директории fixtures. С помощью этой фикстуры осуществляется открытие браузера.

Чтобы сохранить изменения, отправим все в GitHub с помощью ранее изученных команд.

Проверяем открывается ли браузер

Чтобы убедиться в том, что браузер и правда будет открываться по нашей команде мы создадим очень простой автотест. В директории tests создадим модуль test_index_page.py.

Он будет содержать следующий код:

import pytest


class TestFooter:

    def test_user_should_be_able_to_open_popup_select_subscription_plan(self, page):
        pass
    

Первая строка импортирует pytest. Ранее мы установили его и записали в файл requirements.txt. Теперь начнем его использовать.

Четвертая строка создает класс TestFooter. Важно, чтобы все классы, содержащие автотесты, начинались со слова Test.

Шестая строка создает метод, который и является автотестом. Важно, чтобы метод начинался с test_. Так мы дадим понять pytest, что это именно автотест. Название автотеста один в один повторяет название кейса в QASE.io. Когда автотестов будет очень много, надо будет как-то в них ориентироваться. Поэтому понятные, читаемые названия важны. Еще один важный момент заключается в том, что в параметрах метода написано название созданной нами ранее фикстуры, которая открывает браузер. Как раз ее работу мы сейчас и будем проверять.

Чтобы запустить созданный нами автотест будет достаточно в терминале PyCharm запустить команду pytest . Именно с точкой после пробела. Запускаем.

Выполнение команды pytest .
Выполнение команды pytest .

Выполнение команды завершилось ошибкой. А браузер так и не открылся. если у вас аналогично, то это нормально. Ошибка вызвана тем, что pytest не понимает, где ему искать фикстуру page.

Чтобы дать понять pytest, где ему искать фикстуры у нас есть модуль conftest.py. Мы создали его ранее в корневой директории проекта.

Внесем в файл conftest.py следующий код:

pytest_plugins = [
    'fixtures.page',
]

pytest_plugins - это переменная, которая содержит список модулей, в которых pytest должен искать фикстуры. Так как мы создали фикстуру page в модуле page, который лежит в директории fixtures, то путь получается fixtures.page.

Теперь еще раз попробуем запустить команду pytest . в терминале PyCharm. Для этого нет необходимости опять набирать команду, достаточно нажать клавишу вверх, чтобы повторить ранее введенную команду.

Выполнение команды pytest .
Выполнение команды pytest .

В этот раз выполнение команды прошло успешно. Сначала открылся браузер, практически сразу он закрылся, а затем в терминале мы увидели зеленую точку, сообщающую нам, что тест прошел успешно.

Раз браузер у нас открывается, то можно двигаться дальше.

Создаем первый шаг, который откроет нужную страницу в браузере

Наш автотест будет состоять из нескольких последовательных событий:

  1. Открытие браузера. За это отвечает созданный нами модуль page в директории fixtures.

  2. Открытие в браузере страницы google.com. Это мы будем делать сейчас.

  3. Проверку текста на кнопке. Это мы сделаем чуть чуть позже.

В директории pages создадим модуль index_page.py со следующим кодом:

from playwright.sync_api import Page
import config


class IndexPage:

    def open_index_page(self, page: Page) -> None:
        page.goto(config.url.DOMAIN)

Первая строка импортирует класс Page из playwright.

Вторая строка импортирует созданный нами config.

Пятая строка создает класс IndexPage.

Седьмая строка создает метод, который и является необходимым нам шагом.

Разберем подробнее этот метод:

  • название метода отражает то, что он делает в рамках автотеста. Этот метод должен открыть страницу Index page.

  • так как метод не будет ничего возвращать, то сразу прописываем для него -> None:

  • метод принимает параметр page: Page. Ранее мы об этом не говорили, поэтому чуть ниже будет краткое описание.

  • внутри метода мы вызываем goto, который и отвечает за открытие нужного URL

  • в качестве параметра для goto мы передаем значение переменной DOMAIN, которую ранее прописывали в config.url.

Лирическое отступление про страницы в playwright

Playwright можно рассматривать как многослойную структуру, которая состоит из следующих элементов:

  1. Browser. Это тот самый браузер. Google Chrome, Firefox или Safari.

  2. Browser Context. Это несколько окон одного браузера.

  3. Page. Это табы в окне браузера. То есть открыли вы Chrome, а в нем на одной вкладке открыли google.com, на второй instagram.com, на третьей pornhub.com. Каждая вкладка браузера в терминологии playwright будет называться страницей. К такой терминологии со временем привыкаешь.

В рамках наших автотестов важно отметить, что первую Page создает фикстура page. И дальше эта Page передается в качестве параметров в каждый шаг автотеста.

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

Добавляем первый шаг в автотест

Чтобы добавить шаг в автотест мы создаем в директории pages модуль '__init__.py' (аналогичный по смыслу такому же модулю в директории config).

В '__init__.py' добавляем следующий код:

from pages.index_page import IndexPage

index_page = IndexPage()

Теперь мы сможем из других модулей быстро получать методы index_page.py.

Сразу так и поступим. Для этого откроем модуль test_index_page.py и добавим в него импорт pages и внутрь автотеста добавим созданный нами шаг, который открывает google.com.

Итоговый код модуля test_index_page.py теперь выглядит так:

import pytest
import pages


class TestFooter:

    def test_user_should_be_able_to_open_popup_select_subscription_plan(self, page):
        pages.index_page.open_index_page(page)

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

Для этого в модуль test_index_page.py импортируем time. А в сам автотест добавляем строку time.sleep(10). Такая строка заставляет автотест 10 секунд просто ждать.

Текущий внешний вид модуля  test_index_page.py
Текущий внешний вид модуля test_index_page.py

Проверяем, как работает наш автотест уже знакомой нам командой pytest .

В процессе выполнения автотеста сначала открылся браузер, затем был осуществлен переход по  адресу https://google.com и дальше 10 браузер ничего не делал. Затем закрылся. Как вы можете заметить, происходящее в браузере соответствует тому, что написано в строчках кода нашего автотеста.

На этом моменте можно залить изменения в GitHub.

Подбираем локатор для кнопки Google Search

Перед тем, как переходить к автоматизации действий в браузере нам важно подготовить локаторы. В нашем первом автотесте будет достаточно одного локатора. Локатор кнопки Google Search.

Чтобы подготовить локатор, открываем в Google Chrome страницу google.com. Теперь кликаем правой кнопкой мышки и в открывшемся меню выбираем пункт Inspect. Откроется панель Chrome Dev Tools.

В Chrome Dev Tools мы выбираем вкладку Elements. Видим HTML страницы.

Теперь наводим мышку на кнопку Google Search и еще раз выбираем Inspect.

Теперь вкладка Elements сконцентрирована именно на HTML коде кнопки Google Search.

HTML код кнопки Google Search
HTML код кнопки Google Search

Теперь нажимаем Command + F, чтобы открыть строку поиска по HTML коду страницы. Для поиска элемента я буду использовать XPATH.

Найти нужный элемент страницы можно самыми разными способами. В рамках данный статьи для поиска кнопки Google Search я буду использовать следующий XPATH:

//div[@class='FPdoLc lJ9FBc']//input[@name='btnK']
//div[@class='FPdoLc lJ9FBc']//input[@name='btnK']

При подборе локаторов таким образом важно обращать внимание, чтобы в правой части строки поиска количество найденных элементов было 1/1. Есть исключения, но сейчас мы на этом не будем останавливаться.

Создаем второй шаг, который проверит текст кнопки

Так как мы уже научились открывать браузер и открывать в нем нужную страницу, то нам остается добавить финальный шаг для нашего первого автотеста. Надо проверить, что кнопка содержит текст Google Search.

Для этого в модуль index_page.py добавим еще один метод под названием get_text_from_google_search_button.

Метод будет содержать следующий код:

return page.locator(self._BUTTON_GOOGLE_SEARCH).get_attribute('value')

return - вернет результат выполнения page.locator(self._BUTTON_GOOGLE_SEARCH).text_content()

page - это наша страница https://google.com

locator(self._BUTTON_GOOGLE_SEARCH) - найдет на странице элемент, который мы определили на предыдущем шаге

.get_attribute('value') - это метод, который найдет в указанном элементе аттрибут value

Таким образом мы будем сначала искать элемент, а потом искать в нем текст.

Текущее содержание модуля index_page.py
Текущее содержание модуля index_page.py

Узнать подробности об используемых в этой статье возможностях playwright (и обо всех других) можно на сайте с документацией playwright.

Завершаем работу над первым автотестом

Чтобы автотест мог получить текст с кнопки Google Search надо добавить этот шаг в автотест.

В модуле test_index_page.py первым делом убираем импорт time. Он нам пока не пригодится. Удаляем мы и вызов метода time.sleep() из автотеста.

Теперь в этом же автотесте надо вызвать наш шаг, который возвращает текст с кнопки.

Получится такой код:

import pytest
import pages


class TestFooter:

    def test_user_should_be_able_to_open_popup_select_subscription_plan(self, page):
        pages.index_page.open_index_page(page)
        pages.index_page.get_text_from_google_search_button(page)

Но проблема этого автотеста в том, что он ничего не проверяет. Он просто возвращает текст с кнопки, но не сравнивает это значение с эталонным.

Сравнение мы можем провести с помощью assert.

Итоговый вид автотеста
Итоговый вид автотеста

Теперь нам остается лишь запустить автотест и убедиться, что все работает корректно.

Но выполнение автотеста завершилось ошибкой.

Как видно из ошибки вместо Google Search мы получаем Google pretraga. Немного внимательности с моей и стороны и разгадка ошибки найдена. Дело в том, что моя текущая локация - Черногория. Поэтому Google подсовывает мне по умолчанию страницу на черногорском языке.

Это хороший повод для того, чтобы немного развить автотест и добавить в него дополнительный шаг - выбор английского языка. Этот выбор предлагается прямо под формой поиска на странице google.com.

Текст на кнопке и ссылка на выбор английского языка
Текст на кнопке и ссылка на выбор английского языка

Дорабатываем первый автотест

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

Корректный XPATH нашелся довольно быстро:

_LINK_ENGLISH_LANG = "//a[contains(text(), 'English')]"

А код шага, который будет кликать на эту ссылку может выглядеть следующим образом:

def press_link_english_lang(self, page: Page):
    page.locator(self._LINK_ENGLISH_LANG).click()

Таким образом полный код модуля index_page.py выглядит следующим образом:

Теперь этот шаг надо добавить в автотест test_user_should_be_able_to_open_popup_select_subscription_plan.

Для этого открываем модуль test_index_page.py и сразу за шагом открытия адреса google.com добавляем подготовленный нами шаг выбора английского языка.

Получится такой код:

import pytest
import pages


class TestFooter:

    def test_user_should_be_able_to_open_popup_select_subscription_plan(self, page):
        pages.index_page.open_index_page(page)
        pages.index_page.press_link_english_lang(page)
        actual_result = pages.index_page.get_text_from_google_search_button(page)
        assert actual_result == 'Google Search', 'Google Search button text is not correct'

Нужный нам шаг появился на строке 9.

Теперь запускаем автотест и проверяем результат. Результат говорит, что автотест корректно переключается на английский язык. А потом проверяет текст на кнопке. И текст совпадает с эталоном.

Результат выполнения автотеста
Результат выполнения автотеста

В рамках этой статьи должны быть рассмотрены еще две темы:

  • автоматическая генерация шагов для кейсов

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

В обоих пунктах будет вестись тесная работа с API QASE.

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

Комментарии (7)


  1. bmwark
    06.02.2023 16:57

    спасибо за статью, надеюсь будет продолжение по настройке CI/CD и запуску в докерах?


    1. Stepushchenko Автор
      06.02.2023 16:57

      В ближайшее время такой статьи не появится скорее всего. Компетенций пока нет сильных в этой задаче.


  1. Altynd
    06.02.2023 17:01
    -1

    Добрый день, по какой причине может не работать команда "pytest ." Также в модуле test/test_index_page.py подсвечивает серым import pytest. Если вручную нажимать run на тестах то все работает


    1. Stepushchenko Автор
      06.02.2023 17:01
      -1

      Какая появляется ошибка в терминале при запуске команды pytest .?


  1. vagon333
    06.02.2023 20:53

    Вопрос от новичка: насколько полезно/уместно использовать code coverage для этой задачи?
    pip install coverage


    1. Stepushchenko Автор
      07.02.2023 17:42

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


    1. SweetLemo
      09.02.2023 10:09

      насколько я знаю code coverage используется для юнит тестов, когда в одном репозитории и код проекта и юнит тесты, тогда рабочий вариант