[Scala, Браузеры, Тестирование веб-сервисов] Scala + Selenium. Самый стремительный взлет в Лиги наций УЕФА?
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Какой самый стремительный взлет в Лиги наций УЕФА?Т.к. цель этой статьи показать, как пишутся Selenium-автотесты на Scala, а не поставить интригующий вопрос, продержать читателя в неведении, а в конце статьи дать неожиданный ответ, то дальше будут спойлеры.С момента запуска Лиги наций УЕФА прошло целых два розыгрыша и уже можно подвести промежуточные результаты:
- России два раза подряд занимала второе место в группе дивизиона B (оба раза блестяще начиная и столь же блестяще-позорно заканчивая) и в третьем розыгрыше предсказуемо выступит в том же дивизионе B - вот это стабильность (со слезами на глазах)
- Сборная Турции два раза подряд занимала последнее место в своей группе (оба раза в той же самой, где была и сборная России), но в третьем розыгрыше выступит всего лишь одним дивизионом ниже - в дивизионе С
- А вот и обещанный спойлер: сборная Венгрии в первом розыгрыше заняла второе место в третьем по силе дивизионе С, но в третьем розыгрыше выступит в самом сильном дивизионе А вместе с топ-сборными - вот это феерический взлет. Жаль что он произошел в той же самой группе, где была и сборная России.
А как же выступили остальные сборные? После того, как интрига была напрочь уничтожена, можно заняться автоматизацией. За основу возьмем данные с сайта transfermarkt.com: результаты сборных в Лиге нацийОпределимся с понятиямиВ лиге наций УЕФА 4 по силе дивизиона: A (самый сильный), B, C, D. Победитель дивизиона поднимается в более сильный дивизион, занявший последнее место - опускается дивизионом ниже. В первом розыгрыше в сильных дивизионах было только по 3 команды, но после этого УЕФА решила, что топ-матчей должно быть больше и во втором розыгрыше во всех дивизионах, кроме самого слабого (D), стало выступать по 4 команды. Именно по причине необходимой доукомплектации более сильных дивизионов после первого розыгрыша Турция, занявшая последнее место, не вылетела, а Венгрия, занявшая второе - поднялась выше. Считаем результаты первых двух розыгрышей, определим с помощью спортивного принципа состав групп третьего розыгрыша и сформируем статистику выступлений каждой сборной в следующем виде: Россия (B-B-B). Страница дивизиона Лиги Наций УЕФАДля того, чтобы перейти на страницу группы X необходимо выполнить следующее:
- Перейти на главную страницу сайта transfermarkt.com
- В верхнем меню нажать на пункт Competitions
- Во всплывающем меню выбрать пункт UEFA Nations League X
Xpath локаторы для ссылок меню Competitions и UEFA Nations League X будут следующие:
val competitionsLink: Query = xpath("//a[normalize-space(.)='Competitions']")
def groupLink(group: String): Query = xpath(s"//a[normalize-space(.)='UEFA Nations League $group']")
Мы вынуждены использовать функцию normalize-space, потому что ссылка меню Competitions содержит не только слово Competitions, но ещё и кучу пробелов с одним переносом строки:
Именно поэтому в локаторе //a[normalize-space(.)='Competitions'] мы ищем элемент с тэгом a, текстовое содержимое которого после нормализации пробелов равно Competitions.Ожидание появления элемента query можно реализовать так:
new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(ExpectedConditions.visibilityOfElementLocated(query.by))
в результате вернется видимый элемент WebElement, на который затем можно кликнуть и получится:
competitionsLink.waitVisible().click()
groupLink(group).waitVisible().click()
Конечно, после перехода на страницу группы Лиги Наций нужно подождать, когда эта страница загрузится. Для этого возьмем элемент заглавия страницы с css-локатором div.dataName > h1:
и подождем, когда в нём отобразится название группы:
val header: Query = cssSelector("div.dataName > h1")
new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(ExpectedConditions.textToBe(header.by, s"UEFA Nations League $group"))
Результаты в дивизионеВ правом нижнем углу страницы дивизиона есть результаты выступлений сборных:
Строка с результатами сборной будет иметь xpath-локатор //table//tr[td[@class='rechts']]. Всего у нас будет до 16 строк и каждую строку нужно обработать - выудить из строки место сборной (оно необходимо, чтобы определить состав дивизионов в третьем розыгрыше) и, конечно, название страны. К сожалению, Scala библиотека для Selenium довольно бедная и не позволяет искать подэлементы относительно заданного, поэтому воспользуемся Java-библиотекой:
val resultRow: Query = xpath("//table//tr[td[@class='rechts']]")
import scala.jdk.CollectionConverters._
import org.openqa.selenium._
val webDriver: WebDriver = ???
def results: mutable.Buffer[(Int, String)] =
webDriver.findElements(resultRow.by).asScala.map { el =>
{
val place = el.findElement(By.xpath(".//td[@class='rechts']")).getText
val name = el.findElement(By.xpath(".//td[contains(@class, 'hauptlink')]")).getText
(place.toInt, name)
}
}
Здесь происходит следующее:
- находим все элементы с xpath-локатором //table//tr[td[@class='rechts']]
- конвертируем java.util.List в scala.collection.mutable.Buffer
- для каждого элемента из первого пункта находим два его дочерних подэлемента: .//td[@class='rechts'] - место в таблице, .//td[contains(@class, 'hauptlink')] - название страны
- считываем текст из дочерних элементов
Получим следующую картину, например, для дивизиона D:PlaceCountry1Faroe Islands2Malta 3Latvia 4Andorra 1Gibraltar 2Liechtenstein 3San Marino Previous resultsДля того, чтобы получить результаты предыдущего сезона, необходимо в фильтре Filter by season: выбрать значение 18/19 и нажать на кнопку Show:
Здесь будет больше действий и проверок:
- В первую очередь нужно раскрыть список доступных сезонов (нажать на кнопку с css-локатором a.chzn-single > div > b)
- Затем кликнуть на предыдущий сезон (нажать на ссылку с xpath-локатором //li[.='18/19'])
- После этого необходимо дождаться, когда скроется список доступных сезонов
- Затем необходимо нажать на кнопку Show (css-локатор input[value='Show'])
- И подождать, когда произойдет переход на страницу предыдущего сезона (для этого будем ждать, когда url текущей страницы станет оканчиваться на saison_id=2018 (url на немецком))
val selectSeason: Query = cssSelector("a.chzn-single > div > b")
val previousSeason: Query = xpath("//li[.='18/19']")
val show: Query = cssSelector("input[value='Show']")
def selectPreviousSeason: Boolean = {
selectSeason.waitVisible().click()
previousSeason.waitVisible().click()
new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(invisibilityOfElementLocated(previousSeason.by))
clickOn(show)
new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(wd => wd.getCurrentUrl.endsWith("saison_id=2018"))
}
Теперь можно собрать все воедино и получим следующее:
- Переходим на главную страницу сайта
- Для каждой из групп 'A', 'B', 'C', 'D' выполняем:
- Переходим в заданную группу
- Считываем результаты второго розыгрыша
- Сохраняем их
- Переходим в предыдущий сезон
- Считываем результаты первого розыгрыша
- Сохраняем их
P.S. Забегая вперед, скажу, что за это время Macedonia сменила имя на North Macedonia - это пришлось учесть.
case class Result(number: Int, group: Char, place: Int, country: String)
val mainPage = new MainPage
go to mainPage
val results: ArrayBuffer[Result] = ArrayBuffer.empty[Result]
Seq('A', 'B', 'C', 'D').foreach(group => {
val leagueGroupPage = mainPage.goToGroup(group.toString)
val groupResult = leagueGroupPage.results
groupResult.foreach { case (place, country) => results += Result(2, group, place, country) }
leagueGroupPage.selectPreviousSeason
leagueGroupPage.waitLoad(group.toString)
val previousSeasonResult = leagueGroupPage.results
previousSeasonResult.foreach {
case (place, country) =>
results += Result(1, group, place, country.replace("Macedonia", "North Macedonia"))
}
})
Теперь осталось только обработать результаты.Результаты у нас в виде коллекции case class Result(number: Int, group: Char, place: Int, country: String), приведем эту коллекцию к коллекции case class ParsedResult(country: String, firstSeason: (Char, Int), secondSeason: (Char, Int), thirdSeason: Char, progress: (Int, Int)), где сезон представлен в виде tuple (дивизион, итоговое место), а прогресс - из двух цифр, обозначающих прогресс по итогам розыгрыша: 1 (повышение в классе) | 0 | -1 (понижение)
import scala.collection.mutable.ArrayBuffer
case class Result(number: Int = 0, group: Char = 'E', place: Int = 0, country: String = "")
case class ParsedResult(country: String,
firstSeason: (Char, Int),
secondSeason: (Char, Int),
thirdSeason: Char,
progress: (Int, Int))
val results: ArrayBuffer[Result] = ???
val parsedResults = results
.groupBy(_.country)
.view
.mapValues(seq => {
val country: String = seq.head.country
val firstRes = seq.find(_.number == 1).getOrElse(Result())
val firstSeason: (Char, Int) = (firstRes.group, firstRes.place)
val secondRes = seq.find(_.number == 2).getOrElse(Result())
val secondSeason: (Char, Int) = (secondRes.group, secondRes.place)
val thirdSeason: Char =
if (secondSeason._2 == 1 && secondSeason._1 != 'A') (secondSeason._1 - 1).toChar
else if (secondSeason._2 == 4 && secondSeason._1 != 'D') (secondSeason._1 + 1).toChar
else secondSeason._1
val progress: (Int, Int) = (firstSeason._1 - secondSeason._1, secondSeason._1 - thirdSeason)
ParsedResult(country, firstSeason, secondSeason, thirdSeason, progress)
})
.values
.groupBy(_.progress)
Самые успешные сборные?Разделим полученный результат на группы сборных, объединенных по достигнутому прогрессу.Получим следующий результат: Суперпрогресс (сборные, совершившие прорыв через два дивизиона) - 2Country 1st 2nd3rd Hungary C(2)B(1)AArmenia D(2)C(1)BПоистине феерическое выступление показывают Венгрия и Армения: и вот уже сборная из самого низшего дивизиона будет выступать в той же лиге, что и Россия.Поднялись и закрепились - 13Country 1st 2nd3rd Denmark B(1)A(2)ARomania C(2)B(3)BScotland C(1)B(2)BFinland C(1)B(2)BIsrael C(2)B(3)BNorway C(1)B(2)BLuxembourg D(2)C(2)CAzerbaijan D(2)C(3)CGeorgia D(1)C(3)CBelarus D(1)C(2)CKosovo D(1)C(3)CNorth MacedoniaD(1)C(2)Cи т.д. Полный список результатов тут. А исходный код тут.Предыдущая статья: Scala + Selenium. Сколько человек в сборной имеют более одного гражданства?
===========
Источник:
habr.com
===========
Похожие новости:
- [Тестирование веб-сервисов, Управление проектами, Софт] Минцифры запустило тестирование новой версии портала госуслуг
- [Информационная безопасность, Google Chrome, Браузеры, Разработка под Linux] DNS-over-HTTPS заработает в Google Chrome для Linux
- [Тестирование IT-систем, Тестирование веб-сервисов, Тестирование мобильных приложений, Тестирование игр] Паттерны и Методологии Автоматизации UI: Примеры из жизни (перевод)
- [Разработка веб-сайтов, Тестирование IT-систем, PHP, Тестирование веб-сервисов] Юнит-тестирование на PHP в примерах (перевод)
- [PostgreSQL, Java, Тестирование веб-сервисов] История о PostgreSQL 13, Testcontainers и багах
- [Программирование, Scala] Неявный вывод в Scala
- [Тестирование IT-систем, Я пиарюсь, Тестирование веб-сервисов, Тестирование мобильных приложений, Тестирование игр] Лучшие сайты для практики автоматизации тестирования (перевод)
- [Scala, Браузеры, Тестирование веб-сервисов] Scala + Selenium. Сколько человек в сборной имеют более одного гражданства?
- [Децентрализованные сети, Браузеры, Медийная реклама, Криптовалюты, Будущее здесь] BAT Roadmap 2.0 (перевод)
- [Браузеры, Разработка под Windows, Софт] Windows 10 при установке с диска иногда не устанавливает Edge
Теги для поиска: #_scala, #_brauzery (Браузеры), #_testirovanie_vebservisov (Тестирование веб-сервисов), #_scala, #_selenium, #_scala, #_brauzery (
Браузеры
), #_testirovanie_vebservisov (
Тестирование веб-сервисов
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 23:22
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Какой самый стремительный взлет в Лиги наций УЕФА?Т.к. цель этой статьи показать, как пишутся Selenium-автотесты на Scala, а не поставить интригующий вопрос, продержать читателя в неведении, а в конце статьи дать неожиданный ответ, то дальше будут спойлеры.С момента запуска Лиги наций УЕФА прошло целых два розыгрыша и уже можно подвести промежуточные результаты:
Xpath локаторы для ссылок меню Competitions и UEFA Nations League X будут следующие: val competitionsLink: Query = xpath("//a[normalize-space(.)='Competitions']")
def groupLink(group: String): Query = xpath(s"//a[normalize-space(.)='UEFA Nations League $group']") Именно поэтому в локаторе //a[normalize-space(.)='Competitions'] мы ищем элемент с тэгом a, текстовое содержимое которого после нормализации пробелов равно Competitions.Ожидание появления элемента query можно реализовать так: new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(ExpectedConditions.visibilityOfElementLocated(query.by))
competitionsLink.waitVisible().click()
groupLink(group).waitVisible().click() и подождем, когда в нём отобразится название группы: val header: Query = cssSelector("div.dataName > h1")
new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(ExpectedConditions.textToBe(header.by, s"UEFA Nations League $group")) Строка с результатами сборной будет иметь xpath-локатор //table//tr[td[@class='rechts']]. Всего у нас будет до 16 строк и каждую строку нужно обработать - выудить из строки место сборной (оно необходимо, чтобы определить состав дивизионов в третьем розыгрыше) и, конечно, название страны. К сожалению, Scala библиотека для Selenium довольно бедная и не позволяет искать подэлементы относительно заданного, поэтому воспользуемся Java-библиотекой: val resultRow: Query = xpath("//table//tr[td[@class='rechts']]")
import scala.jdk.CollectionConverters._ import org.openqa.selenium._ val webDriver: WebDriver = ??? def results: mutable.Buffer[(Int, String)] = webDriver.findElements(resultRow.by).asScala.map { el => { val place = el.findElement(By.xpath(".//td[@class='rechts']")).getText val name = el.findElement(By.xpath(".//td[contains(@class, 'hauptlink')]")).getText (place.toInt, name) } }
Здесь будет больше действий и проверок:
val selectSeason: Query = cssSelector("a.chzn-single > div > b")
val previousSeason: Query = xpath("//li[.='18/19']") val show: Query = cssSelector("input[value='Show']") def selectPreviousSeason: Boolean = { selectSeason.waitVisible().click() previousSeason.waitVisible().click() new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(invisibilityOfElementLocated(previousSeason.by)) clickOn(show) new WebDriverWait(driver, Duration.ofSeconds(timeout)).until(wd => wd.getCurrentUrl.endsWith("saison_id=2018")) }
case class Result(number: Int, group: Char, place: Int, country: String)
val mainPage = new MainPage go to mainPage val results: ArrayBuffer[Result] = ArrayBuffer.empty[Result] Seq('A', 'B', 'C', 'D').foreach(group => { val leagueGroupPage = mainPage.goToGroup(group.toString) val groupResult = leagueGroupPage.results groupResult.foreach { case (place, country) => results += Result(2, group, place, country) } leagueGroupPage.selectPreviousSeason leagueGroupPage.waitLoad(group.toString) val previousSeasonResult = leagueGroupPage.results previousSeasonResult.foreach { case (place, country) => results += Result(1, group, place, country.replace("Macedonia", "North Macedonia")) } }) import scala.collection.mutable.ArrayBuffer
case class Result(number: Int = 0, group: Char = 'E', place: Int = 0, country: String = "") case class ParsedResult(country: String, firstSeason: (Char, Int), secondSeason: (Char, Int), thirdSeason: Char, progress: (Int, Int)) val results: ArrayBuffer[Result] = ??? val parsedResults = results .groupBy(_.country) .view .mapValues(seq => { val country: String = seq.head.country val firstRes = seq.find(_.number == 1).getOrElse(Result()) val firstSeason: (Char, Int) = (firstRes.group, firstRes.place) val secondRes = seq.find(_.number == 2).getOrElse(Result()) val secondSeason: (Char, Int) = (secondRes.group, secondRes.place) val thirdSeason: Char = if (secondSeason._2 == 1 && secondSeason._1 != 'A') (secondSeason._1 - 1).toChar else if (secondSeason._2 == 4 && secondSeason._1 != 'D') (secondSeason._1 + 1).toChar else secondSeason._1 val progress: (Int, Int) = (firstSeason._1 - secondSeason._1, secondSeason._1 - thirdSeason) ParsedResult(country, firstSeason, secondSeason, thirdSeason, progress) }) .values .groupBy(_.progress) =========== Источник: habr.com =========== Похожие новости:
Браузеры ), #_testirovanie_vebservisov ( Тестирование веб-сервисов ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 23:22
Часовой пояс: UTC + 5