Pull to refresh

Comments 10

Button - кнопка. В данном компоненте будут базовые методы для работы с кнопками.

А описывать методы для кнопок, типа hover, внутри которых использовать коробочный hover - это для красивой отчётности, я правильно понимаю?

Не совсем, тут много причин:

  1. Чтобы динамически обработать и сгенерировать нужный нам локатор и только потом использовать объект локатора в методе

  2. Чтобы уникализировать методы работы с объектами на странице. Я приводил пример выше с .toBeVisible(), .isVisible(), оба метода выполнят задачу, но правильный по сути только один. Да, на hover это не распространяется, тут этот пункт работать не будет

  3. Если вы тестируете продукт, в котором есть специфические компоненты, например для hover на такой компонент, необходимо сначала кликнуть куда-то, ну или в этом духе. Тогда можно делать кастомные компоненты, например MyCustomButton, внутри реализовывать именно тот hover, который будет кликать, а потом делать hover. Ну это чисто пример, на практике разное бывает

  4. Да, нужен читабельный шаг для отчета. По дефолту playwright делает шаги, но они не отражают бизнес логику, которую мы тестируем. + Как показывает практика, manual qa и менеджерам очень сложно читать дефолтные шаги от Playwright, они не информативны

Спасибо за статью, хотелось бы оставить несколько замечаний:

Обратите внимание, что все автотесты будут писаться через async, await, т.к. это единственный возможный способ для playwright. В других фреймворках может быть иначе.

  • Не единственный, ведь можно писать тесты с использованием чепочки промисов(Promise chaining), хоть это и не очень удобно. Или если не нравится использовать async/await можно использовать c++ библиотеки которые изменяют логику работы async/await в синхронный режим. Этим страдал webdriverio ver.6, когда разработчики выпустили синхронный режим через враппер библиотеки fibers.

  • В примере модального окна "SearchModal" - данный класс не наследует ни компонент ни страницу, хотя входные параметры такие же как у страницы. Что по вашему Page а что Component?

  • Не раскрыты понятия что такое Page, PageFactory и Component. Как, зачем и как их использовать и почему, в чем их преимущества и недостатки. Особенно это касается PageFactory которая только вначале присутствует а что это и зачем не понятно.

  • TS позволяет инициализировать поля вне конструктора, что уменьшит кол-во строк, но для этого надо сделать добавить параметру page модификатор доступа

import {Page} from 'playwright'; // или из @playwright/test
import {BasePage} from './base.page';
// остальная пачка импортов
class MyPage extends BasePage {
  readonly myTitle = new Title({page: this.page, locator: '#qwe'});
  constructor(public readonly page: Page){} // конструктор пуст
}
  • зачем у абстрактного класса поле "typeOf" которое всегда переопределяется у других компонентов? может лучше было оставить поле typeOf абстрактным?

  • "typeOfUpper" - используется только для test.step. как по мне - не стоит раздувать кол-во функции и свойств лишний раз, это касается и "сomponentName". Зачем лишняя проверка если вы и так не сможете создать ваш компонент без поля name(таипскрипт об этом позаботится и выкинет ошибку)

  1. Да, можно промисы через then, catch, это ведь тоже самое, что и async/await. Тут вопрос только в том, как мы это используем. Кто понял, тот понял)

  2. Когда фронтенд разработчики пишут приложение, у них есть понятия screen/page, module/component. То есть страница (Page) состоит из компонентов (Component), компонентами могут быть, модальные окна, формы, карточки, лист айтемы, и т.д. Page Factory это больше про то, как мы работаем с локаторами. В Page Factory мы оцениваем локатор, как какой-то конкретный объект или свойство. Ну если привести пример из жизни, то все элементы это конструктор lego, Page - это собранная модель, Component - это отдельные части, рука, нога, голова, Page Factory - это сами детальки lego)

  3. Преимущества описывал выше, в разделе "Page Factory", посмотрите, там достаточно много пунктов и подробно описано. Возможно это не классическое представление Page Factory, но единственное рабочее для моих целей, цели я тоже описал

  4. Да, прикольная фича, возьму на заметку. Я привык писать на python, там такой возможности нет

  5. typeOf переопределяется для отчета, в отчете будет видно с каким объектом мы работали. То есть Click on button(typeOf) with name "Hello", Click on input(typeOf) with name "Some"

  6. typeOfUpper - возможно да, но вам стоит помнить, что эта статья не туториал. Я не пытаюсь рассказать людям как писать супер правильный TS код, мне больше интересно показать, как лучше писать UI авто тесты.

позвольте придраться к ответу. Все еще не понятно что по вашему "SearchModal". т.к. данный класс не наследует ни component ни page. хотя сигнатура конструктора там от page, но по здравой логике это должен быть component

В принципе SearchModal можно наследовать от BasePage, при необходимости. Но как по мне Components не должны наследоваться ни от кого (если только нет родительских компонентов).

Например если мы говорим про модальное окно логина, которое предлагает нам войти в систему, то это Component. Поля ввода, кнопки, иконки в этом модальном окне будут считаться, как Page Factory. Модальное окно логина, может быть использовано на разных страницах, поэтому мы выносим это в отдельный слой - Component. В автотестах мы сможем использовать этот Component на разных страницах, например DasboardPage, FormsPage, ProfilePage и т.д. нам будет достаточно использовать композицию и не дублировать код. Page Factory же поможет нам, удобнее работать с элементами внутри модального окна логина.

Надеюсь, я правильно понял ваш вопрос)

Очень хорошая статья. Расскажите пожалуйста про содержимое BaseFixture

import { BaseFixture } from '../types/playwright';

Вообще было бы интересно по фикстурам статью от вас увидеть.

Спасибо, приятно это слышать!

По сути BaseFixture это просто интерфейс, который описывает встроенные фикстуры в playwright и используется для описания правильной типизации объекта фикстуры. Чтобы typescript правильно воспринял тип Fixturesиз playwright нам необходимо передать в него типы тех фикстур, которые мы используем или от которых наследуемся Fixtures<ContextPagesFixture, BaseFixture> .

В этой фикстуре мы используем page (встроенная фикстура в playwright), если не указать BaseFixture, то typescript выдаст ошибку по типу "Property 'page' does not exist on type 'ContextPagesFixture'.ts(2339)". Чтобы это исправить мы передаем тип BaseFixture, как бы говорим typescript, смотри все ок, это известный нам аргумент

Кстати, тут я допустил ошибку, лучше использовать встроенный в playwright тип, который называется PlaywrightTestArgs внутри него есть все встроенные фикстуры по типу page, context, browser, request и т.д. Тогда бы у нас тип выглядел так Fixtures<ContextPagesFixture, PlaywrightTestArgs> + не пришлось бы писать свой тип

На счет статьи, хорошая идея, обязательно подумаю

А почему у Вас BASE_URL в отдельный конфиг вынесен, у PW же есть такое свойство в конфиге, чем это обусловлено?

Да, тут скорее ошибка, забыл, что у playwright это можно в playwright.config.ts вынести
Спасибо, исправил)

Sign up to leave a comment.

Articles