Русский
Русский
English
Статистика
Реклама

Scala Selenium. Самый стремительный взлет в Лиги наций УЕФА?

Какой самый стремительный взлет в Лиги наций УЕФА?

Т.к. цель этой статьи показать, как пишутся 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:

Place

Country

1

Faroe Islands

2

Malta

3

Latvia

4

Andorra

1

Gibraltar

2

Liechtenstein

3

San 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 MainPagego to mainPageval 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.ArrayBuffercase 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)

Самые успешные сборные?

Разделим полученный результат на группы сборных, объединенных по достигнутому прогрессу.

Получим следующий результат:

Суперпрогресс (сборные, совершившие прорыв через два дивизиона) - 2

Country

1st

2nd

3rd

Hungary

C(2)

B(1)

A

Armenia

D(2)

C(1)

B

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

Поднялись и закрепились - 13

Country

1st

2nd

3rd

Denmark

B(1)

A(2)

A

Romania

C(2)

B(3)

B

Scotland

C(1)

B(2)

B

Finland

C(1)

B(2)

B

Israel

C(2)

B(3)

B

Norway

C(1)

B(2)

B

Luxembourg

D(2)

C(2)

C

Azerbaijan

D(2)

C(3)

C

Georgia

D(1)

C(3)

C

Belarus

D(1)

C(2)

C

Kosovo

D(1)

C(3)

C

North Macedonia

D(1)

C(2)

C

и т.д. Полный список результатов тут. А исходный код тут.

Предыдущая статья: Scala + Selenium. Сколько человек в сборной имеют более одного гражданства?

Источник: habr.com
К списку статей
Опубликовано: 01.04.2021 20:04:02
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Scala

Браузеры

Тестирование веб-сервисов

Selenium

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru