Compare commits
No commits in common. "main" and "ui-develop" have entirely different histories.
main
...
ui-develop
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/.idea/
|
||||||
|
/out/
|
||||||
|
/target/
|
||||||
|
*.iml
|
||||||
42
pom.xml
Normal file
42
pom.xml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>HelpdeskUITest</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>8</source>
|
||||||
|
<target>8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.seleniumhq.selenium</groupId>
|
||||||
|
<artifactId>selenium-java</artifactId>
|
||||||
|
<version>3.141.59</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testng</groupId>
|
||||||
|
<artifactId>testng</artifactId>
|
||||||
|
<version>6.9.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.qameta.allure</groupId>
|
||||||
|
<artifactId>allure-testng</artifactId>
|
||||||
|
<version>2.13.8</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
66
src/main/java/elements/MainMenu.java
Normal file
66
src/main/java/elements/MainMenu.java
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package elements;
|
||||||
|
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import models.Ticket;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.PageFactory;
|
||||||
|
|
||||||
|
/** Главное меню (блок элементов) */
|
||||||
|
public class MainMenu {
|
||||||
|
|
||||||
|
// Способ объявления элементов страницы, через аннотацию @FindBy (с последующей инициализацией)
|
||||||
|
|
||||||
|
@FindBy(xpath = "//span[contains(text(),'New Ticket')]")
|
||||||
|
private WebElement newTicketButton;
|
||||||
|
|
||||||
|
@FindBy(id = "userDropdown")
|
||||||
|
private WebElement logInButton;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//input[@id='search_query']")
|
||||||
|
private WebElement inputSearch;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//nav//button[@type='submit']")
|
||||||
|
private WebElement goButton;
|
||||||
|
|
||||||
|
public MainMenu(WebDriver driver) {
|
||||||
|
/* Необходимо инициализировать элементы класса, аннотированные @FindBy.
|
||||||
|
Лучше всего это делать в конструкторе. */
|
||||||
|
PageFactory.initElements(driver, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Нажать кнопку создания новго тикета")
|
||||||
|
public void clickOnNewTicketButton() {
|
||||||
|
newTicketButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Нажать кнопку логина")
|
||||||
|
public void clickOnLogInButton() {
|
||||||
|
logInButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Найти тикет с помощью поиска")
|
||||||
|
public void searchTicket(Ticket ticket) {
|
||||||
|
setInputSearch(ticket.getTitle())
|
||||||
|
.clickOnGoButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Если после вызова void метода, может потребоваться вызов другого метода этого же класса,
|
||||||
|
то можно вернуть сам класс и вызвать следующий метод через точку. */
|
||||||
|
@Step("Ввести в поле поиска значение {text}")
|
||||||
|
public MainMenu setInputSearch(String text) {
|
||||||
|
inputSearch.sendKeys(text);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Нажать кнопку поиска")
|
||||||
|
public void clickOnGoButton() {
|
||||||
|
goButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Получить логин пользователя")
|
||||||
|
public String loginedUser() {
|
||||||
|
return logInButton.getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/main/java/models/Dictionaries.java
Normal file
47
src/main/java/models/Dictionaries.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package models;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/** Словари */
|
||||||
|
public class Dictionaries {
|
||||||
|
|
||||||
|
private static final HashMap<Integer, String> priorities = new HashMap<>();
|
||||||
|
private static final HashMap<Integer, String> queues = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
priorities.put(1, "1. Critical");
|
||||||
|
priorities.put(2, "2. High");
|
||||||
|
priorities.put(3, "3. Normal");
|
||||||
|
priorities.put(4, "4. Low");
|
||||||
|
priorities.put(5, "5. Very Low");
|
||||||
|
|
||||||
|
queues.put(1, "Django Helpdesk");
|
||||||
|
queues.put(2, "Some Product");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPriority(int priority) {
|
||||||
|
return priorities.get(priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getQueue(int queue) {
|
||||||
|
return queues.get(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> K getKeyByValue(Map<K, V> map, V value) {
|
||||||
|
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue().equals(value)) {
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getPriorityKey(String name) {
|
||||||
|
return getKeyByValue(priorities, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getQueueKey(String name) {
|
||||||
|
return getKeyByValue(queues, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
179
src/main/java/models/Ticket.java
Normal file
179
src/main/java/models/Ticket.java
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package models;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
public class Ticket {
|
||||||
|
|
||||||
|
/* Класс Ticket пакета models реализуем по аналогии c домашним заданием по тестированию API.
|
||||||
|
Класс должен содержать набор полей, необходимый для заполнения формы создания тикета.
|
||||||
|
Тип данных для каждого поля должен соответствовать документации swagger (см. раздел Models в документации). */
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
private String title;
|
||||||
|
private String due_date;
|
||||||
|
private File file;
|
||||||
|
private String assigned_to;
|
||||||
|
private String created;
|
||||||
|
private String modified;
|
||||||
|
private String submitter_email;
|
||||||
|
private Integer status;
|
||||||
|
private Boolean on_hold;
|
||||||
|
private String description;
|
||||||
|
private String resolution;
|
||||||
|
private Integer priority;
|
||||||
|
private String last_escalation;
|
||||||
|
private String secret_key;
|
||||||
|
private Integer queue;
|
||||||
|
private Integer kbitem;
|
||||||
|
private Integer merged_to;
|
||||||
|
|
||||||
|
public Integer getId(){return id;}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDue_date() {
|
||||||
|
return due_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// обычный сеттер
|
||||||
|
public void setDue_date(String due_date) {
|
||||||
|
this.due_date = due_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// перегруженный сеттер, который принимает дату и форматирует её в строку по шаблону
|
||||||
|
public void setDue_date(LocalDateTime due_date) {
|
||||||
|
this.due_date = due_date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFile(File file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAssigned_to() {
|
||||||
|
return assigned_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssigned_to(String assigned_to) {
|
||||||
|
this.assigned_to = assigned_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(String created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModified() {
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModified(String modified) {
|
||||||
|
this.modified = modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubmitter_email() {
|
||||||
|
return submitter_email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubmitter_email(String submitter_email) {
|
||||||
|
this.submitter_email = submitter_email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(Integer status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getOn_hold() {
|
||||||
|
return on_hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOn_hold(Boolean on_hold) {
|
||||||
|
this.on_hold = on_hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResolution() {
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResolution(String resolution) {
|
||||||
|
this.resolution = resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPriority() {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriority(Integer priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLast_escalation() {
|
||||||
|
return last_escalation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLast_escalation(String last_escalation) {
|
||||||
|
this.last_escalation = last_escalation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSecret_key() {
|
||||||
|
return secret_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecret_key(String secret_key) {
|
||||||
|
this.secret_key = secret_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQueue() {
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQueue(Integer queue) {
|
||||||
|
this.queue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getKbitem() {
|
||||||
|
return kbitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKbitem(Integer kbitem) {
|
||||||
|
this.kbitem = kbitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMerged_to() {
|
||||||
|
return merged_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMerged_to(Integer merged_to) {
|
||||||
|
this.merged_to = merged_to;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/main/java/pages/AbstractPage.java
Normal file
16
src/main/java/pages/AbstractPage.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
/** Элементы общие для всех страниц */
|
||||||
|
public abstract class AbstractPage {
|
||||||
|
|
||||||
|
protected static WebDriver driver;
|
||||||
|
|
||||||
|
public static void setDriver(WebDriver webDriver) {
|
||||||
|
driver = webDriver;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
90
src/main/java/pages/CreateTicketPage.java
Normal file
90
src/main/java/pages/CreateTicketPage.java
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import models.Dictionaries;
|
||||||
|
import models.Ticket;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.PageFactory;
|
||||||
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
|
||||||
|
/** Страница создания тикета */
|
||||||
|
public class CreateTicketPage extends HelpdeskBasePage {
|
||||||
|
|
||||||
|
@FindBy(id = "id_queue")
|
||||||
|
private WebElement selectQueue;
|
||||||
|
|
||||||
|
@FindBy(id = "id_title")
|
||||||
|
private WebElement inputProblem;
|
||||||
|
|
||||||
|
@FindBy(id = "id_body")
|
||||||
|
private WebElement inputDescription;
|
||||||
|
|
||||||
|
@FindBy(id = "id_priority")
|
||||||
|
private WebElement inputPriority;
|
||||||
|
|
||||||
|
@FindBy(id = "id_due_date")
|
||||||
|
private WebElement inputDueOn;
|
||||||
|
|
||||||
|
@FindBy(id = "id_submitter_email")
|
||||||
|
private WebElement inputEmailAddress;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//button[@type='submit']")
|
||||||
|
private WebElement submitTicketButton;
|
||||||
|
|
||||||
|
public CreateTicketPage() {
|
||||||
|
PageFactory.initElements(driver, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Создать тикет")
|
||||||
|
public CreateTicketPage createTicket(Ticket ticket) {
|
||||||
|
selectQueue(ticket.getQueue());
|
||||||
|
setInputProblem(ticket.getTitle());
|
||||||
|
setInputDescription(ticket.getDescription());
|
||||||
|
selectPriority(ticket.getPriority());
|
||||||
|
setDueDate(ticket.getDue_date());
|
||||||
|
setEmailAddress(ticket.getSubmitter_email());
|
||||||
|
|
||||||
|
clickOnSubmitButton();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Ввести имя проблемы: {text}")
|
||||||
|
public void setInputProblem(String text) {
|
||||||
|
inputProblem.sendKeys(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Нажать на кнопку создания тикета")
|
||||||
|
public void clickOnSubmitButton() {
|
||||||
|
submitTicketButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Выбрать очередь: {queue}")
|
||||||
|
public void selectQueue(int queue) {
|
||||||
|
Select select = new Select(selectQueue);
|
||||||
|
select.selectByVisibleText(Dictionaries.getQueue(queue));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Ввести описание проблемы: {text}")
|
||||||
|
public void setInputDescription(String text) {
|
||||||
|
inputDescription.sendKeys(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Выбрать приоритет: {priority}")
|
||||||
|
public void selectPriority(int priority) {
|
||||||
|
Select select = new Select(inputPriority);
|
||||||
|
select.selectByVisibleText(Dictionaries.getPriority(priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Ввести срок выполнения: {date}")
|
||||||
|
public void setDueDate(String date) {
|
||||||
|
inputDueOn.sendKeys(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Ввести email: {email}")
|
||||||
|
public void setEmailAddress(String email) {
|
||||||
|
inputEmailAddress.sendKeys(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
17
src/main/java/pages/HelpdeskBasePage.java
Normal file
17
src/main/java/pages/HelpdeskBasePage.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import elements.MainMenu;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.PageFactory;
|
||||||
|
|
||||||
|
/** Элементы общие для системы Helpdesk */
|
||||||
|
public class HelpdeskBasePage extends AbstractPage {
|
||||||
|
public HelpdeskBasePage() { PageFactory.initElements(driver, this);}
|
||||||
|
|
||||||
|
/** Доступ к элементам главного меню */
|
||||||
|
public MainMenu mainMenu() {
|
||||||
|
return new MainMenu(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
55
src/main/java/pages/LoginPage.java
Normal file
55
src/main/java/pages/LoginPage.java
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.PageFactory;
|
||||||
|
|
||||||
|
/** Страница логина */
|
||||||
|
public class LoginPage extends HelpdeskBasePage {
|
||||||
|
|
||||||
|
// поиск элемента через xpath
|
||||||
|
@FindBy(xpath = "//*[@id='username']")
|
||||||
|
private WebElement user;
|
||||||
|
|
||||||
|
// поиск элемента по id
|
||||||
|
@FindBy(id = "password")
|
||||||
|
private WebElement password;
|
||||||
|
|
||||||
|
// поиск элемента через css
|
||||||
|
@FindBy(css = "[type='submit']")
|
||||||
|
private WebElement loginButton;
|
||||||
|
|
||||||
|
public LoginPage() {
|
||||||
|
PageFactory.initElements(driver, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Авторизация пользователя
|
||||||
|
*
|
||||||
|
* @param user логин пользователя
|
||||||
|
* @param password пароль пользователя
|
||||||
|
*/
|
||||||
|
@Step("Авторизация пользователя")
|
||||||
|
public LoginPage login(String user, String password) {
|
||||||
|
setUser(user);
|
||||||
|
setPassword(password);
|
||||||
|
clickOnLoginButton();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Ввести логин {user}")
|
||||||
|
private void setUser(String user) {
|
||||||
|
this.user.sendKeys(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Ввести пароль")
|
||||||
|
private void setPassword(String password) {
|
||||||
|
this.password.sendKeys(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Нажать кнопку авторизации")
|
||||||
|
private void clickOnLoginButton() {
|
||||||
|
this.loginButton.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/java/pages/MainPage.java
Normal file
32
src/main/java/pages/MainPage.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.PageFactory;
|
||||||
|
|
||||||
|
/** Главная страница */
|
||||||
|
public class MainPage extends HelpdeskBasePage {
|
||||||
|
|
||||||
|
public MainPage() {
|
||||||
|
PageFactory.initElements(driver, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FindBy(xpath = "//span[text()='New Ticket']")
|
||||||
|
private WebElement newTicketButton;
|
||||||
|
|
||||||
|
public void clickOnNewTicket() {
|
||||||
|
if (newTicketButton != null) {
|
||||||
|
newTicketButton.click();
|
||||||
|
}
|
||||||
|
else {throw new RuntimeException();}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FindBy(xpath = "//a[contains(text(),'Log In')]")
|
||||||
|
private WebElement loginButton;
|
||||||
|
|
||||||
|
public void clickOnLogin() {
|
||||||
|
if (loginButton != null) {loginButton.click();}
|
||||||
|
else {throw new RuntimeException();}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/main/java/pages/TicketPage.java
Normal file
69
src/main/java/pages/TicketPage.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import models.Dictionaries;
|
||||||
|
import models.Ticket;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.testng.Assert;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/** Страница отдельного тикета (авторизированный пользователь) */
|
||||||
|
public class TicketPage extends HelpdeskBasePage {
|
||||||
|
|
||||||
|
/* Верстка страницы может измениться, поэтому для таблиц вместо индексов строк и столбцов лучше использовать
|
||||||
|
более универсальные локаторы, например поиск по тексту + parent, following-sibling и другие.
|
||||||
|
|
||||||
|
Текст тоже может измениться, но в этом случае элемент не будет найден и тест упадет,
|
||||||
|
а ошибку можно будет легко локализовать и исправить.
|
||||||
|
В случае изменений ячеек таблицы, локатор будет продолжать работать, но будет указывать на другой элемент,
|
||||||
|
поведение теста при этом изменится непредсказуемым образом и ошибку будет сложно найти. */
|
||||||
|
private final WebElement title = driver.findElement(
|
||||||
|
By.xpath("//th[@colspan='4']/h3"));
|
||||||
|
|
||||||
|
private final WebElement queue = driver.findElement(
|
||||||
|
By.xpath("//th[contains(text(), 'Queue:')]"));
|
||||||
|
|
||||||
|
private final WebElement dueDate = driver.findElement(
|
||||||
|
By.xpath("//th[text()='Due Date']/following-sibling::td[1]"));
|
||||||
|
|
||||||
|
private final WebElement email = driver.findElement(
|
||||||
|
By.xpath("//th[text()='Submitter E-Mail']/following-sibling::td[1]"));
|
||||||
|
|
||||||
|
private final WebElement priority = driver.findElement(
|
||||||
|
By.xpath("//th[text()='Priority']/following-sibling::td[1]"));
|
||||||
|
|
||||||
|
private final WebElement description = driver.findElement(
|
||||||
|
By.xpath("//td[@id='ticket-description']/p"));
|
||||||
|
|
||||||
|
@Step("Проверить значение полей на странице тикета")
|
||||||
|
public void checkTicket(Ticket ticket) {
|
||||||
|
Assert.assertEquals(extractTicketName(title.getText()), ticket.getTitle(), "Название тикета не соответствует");
|
||||||
|
Assert.assertEquals((extractQueue(queue.getText())), ticket.getQueue(), "Очередь тикета не соответствует");
|
||||||
|
Assert.assertEquals((email.getText()), ticket.getSubmitter_email(), "Почта не соответствует");
|
||||||
|
Assert.assertEquals(Dictionaries.getPriorityKey(priority.getText()), ticket.getPriority(), "Приоритетность тикета не соответствует");
|
||||||
|
Assert.assertEquals((description.getText()), ticket.getDescription(), "Описание тикета не соответствует");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer extractQueue(String queue) {
|
||||||
|
if (queue != null && queue.contains(":")) {
|
||||||
|
queue = queue.split(":")[1].trim();
|
||||||
|
|
||||||
|
int toolbarIndex = queue.indexOf("Edit");
|
||||||
|
if (toolbarIndex >= 0) {
|
||||||
|
queue = queue.substring(0, toolbarIndex).trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Dictionaries.getQueueKey(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String extractTicketName(String title){
|
||||||
|
if (title == null || !title.contains(".") || !title.contains("[")) {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
return title.split("\\.")[1].split("\\[")[0].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
src/main/java/pages/TicketsPage.java
Normal file
49
src/main/java/pages/TicketsPage.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import models.Ticket;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.PageFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Страница с таблицей тикетов и фильтрами */
|
||||||
|
public class TicketsPage extends HelpdeskBasePage {
|
||||||
|
public TicketsPage() { PageFactory.initElements(driver, this);}
|
||||||
|
|
||||||
|
@FindBy(xpath = "//div[@class='tickettitle']/a")
|
||||||
|
private List<WebElement> ticketsHref;
|
||||||
|
|
||||||
|
@FindBy(id = "search_query")
|
||||||
|
private WebElement search;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//i[@class='fas fa-search']/parent::button")
|
||||||
|
private WebElement searchButton;
|
||||||
|
|
||||||
|
public TicketsPage clickOnSearch(String title) {
|
||||||
|
if (searchButton != null && search != null) {
|
||||||
|
search.clear();
|
||||||
|
search.sendKeys(title);
|
||||||
|
searchButton.click();
|
||||||
|
}
|
||||||
|
else {throw new RuntimeException();}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ищем строку с и тикетом и нажимаем на нее
|
||||||
|
*
|
||||||
|
* @param ticket
|
||||||
|
*/
|
||||||
|
@Step("Открыть тикет с id {ticket.id}")
|
||||||
|
public void openTicket(Ticket ticket) {
|
||||||
|
String id = String.valueOf(ticket.getId());
|
||||||
|
ticketsHref.stream()
|
||||||
|
.filter(WebElement::isDisplayed)
|
||||||
|
.filter(ticketHref -> ticketHref.getText().startsWith(id))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new AssertionError("Не найден тикет с id " + id))
|
||||||
|
.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
77
src/main/java/pages/ViewPage.java
Normal file
77
src/main/java/pages/ViewPage.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package pages;
|
||||||
|
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import models.Dictionaries;
|
||||||
|
import models.Ticket;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedCondition;
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
|
import org.testng.Assert;
|
||||||
|
|
||||||
|
import static pages.TicketPage.extractQueue;
|
||||||
|
import static pages.TicketPage.extractTicketName;
|
||||||
|
|
||||||
|
/** Страница просмотра карточки тикета (неавторизированный пользователь) */
|
||||||
|
public class ViewPage extends HelpdeskBasePage {
|
||||||
|
|
||||||
|
// Способ объявления и инициализации элементов страницы через driver.findElement(locator)
|
||||||
|
|
||||||
|
/* Инициализация сразу при объявлении элемента.
|
||||||
|
Элемент должен присутствовать на странице браузера в момент создания объекта страницы new ViewPage() */
|
||||||
|
private final WebElement queue = driver.findElement(By.xpath("//th[contains(text(), 'Queue:')]"));
|
||||||
|
private final WebElement email = driver.findElement(By.xpath("//th[text()='Submitter E-Mail']/following-sibling::td[1]"));
|
||||||
|
private final WebElement priority = driver.findElement(By.xpath("//th[text()='Priority']/following-sibling::td[1]"));
|
||||||
|
|
||||||
|
// Пример поиска description, используя промежуточный элемент descriptionLabel
|
||||||
|
private final WebElement descriptionLabel = driver.findElement(By.xpath("//th[text()='Description']"));
|
||||||
|
// Поиск элемента можно выполнять не только относительно driver, но и относительно другого элемента
|
||||||
|
private final WebElement description = descriptionLabel.findElement(By.xpath("./parent::*/following-sibling::tr[1]"));
|
||||||
|
|
||||||
|
/* Поиск элемента по локатору.
|
||||||
|
Используется для элементов, которых нет на странице браузера в момент создания объекта страницы,
|
||||||
|
так как локатор может быть объявлен и проинициализирован до появления элемнета на странице. */
|
||||||
|
private final By captionLocator = By.xpath("//table/caption");
|
||||||
|
private final WebElement caption;
|
||||||
|
|
||||||
|
|
||||||
|
public ViewPage() {
|
||||||
|
// В данном случае инициализация через PageFactory не нужна,
|
||||||
|
// но можем проинициализировать элементы по локаторам (если элементы отображаются)
|
||||||
|
caption = driver.findElement(captionLocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Проверить значение полей на карточке тикета")
|
||||||
|
public ViewPage checkTicket(Ticket ticket) {
|
||||||
|
Assert.assertTrue(getTicketTitle().contains(ticket.getTitle()), "Имя тикета не соответствует");
|
||||||
|
//Assert.assertEquals(extractTicketName(caption.getText()), ticket.getTitle(), "Название тикета не соответствует");
|
||||||
|
Assert.assertEquals((extractQueue(queue.getText())), ticket.getQueue(), "Очередь тикета не соответствует");
|
||||||
|
Assert.assertEquals((email.getText()), ticket.getSubmitter_email(), "Почта не соответствует");
|
||||||
|
Assert.assertEquals(Dictionaries.getPriorityKey(priority.getText()), ticket.getPriority(), "Приоритетность тикета не соответствует");
|
||||||
|
Assert.assertEquals((description.getText()), ticket.getDescription(), "Описание тикета не соответствует");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Получить заголовок тикета")
|
||||||
|
public String getTicketTitle() {
|
||||||
|
// Если элемент появляется не сразу, можно выполнить ожидание по условию
|
||||||
|
|
||||||
|
// условие видимости при поиске по локатору
|
||||||
|
ExpectedCondition<WebElement> condition = ExpectedConditions.visibilityOfElementLocated(captionLocator);
|
||||||
|
|
||||||
|
// поиск с ожиданием по условию
|
||||||
|
WebElement ticketTitle = new WebDriverWait(driver, 5).until(condition);
|
||||||
|
|
||||||
|
return ticketTitle.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Сохранить id тикета в объект")
|
||||||
|
public void saveId(Ticket ticket) {
|
||||||
|
String captionText = caption.getText();
|
||||||
|
String id = captionText.substring(captionText.indexOf("-") + 1, captionText.indexOf("]"));
|
||||||
|
ticket.setId(Integer.parseInt(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
2
src/main/resources/config.properties
Normal file
2
src/main/resources/config.properties
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
site.url=https://at-sandbox.workbench.lanit.ru/
|
||||||
|
webdriver.chrome.driver=/usr/local/bin/chromedriver
|
||||||
2
src/main/resources/user.properties
Normal file
2
src/main/resources/user.properties
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
user=admin
|
||||||
|
password=adminat
|
||||||
124
src/test/java/web/HelpdeskUITest.java
Normal file
124
src/test/java/web/HelpdeskUITest.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package web;
|
||||||
|
|
||||||
|
import io.qameta.allure.Step;
|
||||||
|
import models.Dictionaries;
|
||||||
|
import models.Ticket;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.chrome.ChromeDriver;
|
||||||
|
import org.testng.annotations.AfterTest;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import pages.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class HelpdeskUITest {
|
||||||
|
|
||||||
|
private WebDriver driver;
|
||||||
|
private Ticket ticket;
|
||||||
|
|
||||||
|
private MainPage mainPage;
|
||||||
|
private CreateTicketPage createTicketPage;
|
||||||
|
private TicketsPage ticketsPage;
|
||||||
|
private LoginPage loginPage;
|
||||||
|
private ViewPage viewPage;
|
||||||
|
private TicketPage ticketPage;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public void setup() throws IOException {
|
||||||
|
loadProperties();
|
||||||
|
setupDriver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Загрузить конфигурационные файлы")
|
||||||
|
private void loadProperties() throws IOException {
|
||||||
|
// Читаем конфигурационные файлы в System.properties
|
||||||
|
System.getProperties().load(ClassLoader.getSystemResourceAsStream("config.properties"));
|
||||||
|
System.getProperties().load(ClassLoader.getSystemResourceAsStream("user.properties"));
|
||||||
|
|
||||||
|
username = System.getProperty("user");
|
||||||
|
password = System.getProperty("password");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Создать экземпляр драйвера")
|
||||||
|
private void setupDriver() {
|
||||||
|
// Создание экземпляра драйвера
|
||||||
|
driver = new ChromeDriver();
|
||||||
|
// Устанавливаем размер окна браузера, как максимально возможный
|
||||||
|
driver.manage().window().maximize();
|
||||||
|
// Установим время ожидания для поиска элементов
|
||||||
|
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
|
||||||
|
// Установить созданный драйвер для поиска в веб-страницах
|
||||||
|
AbstractPage.setDriver(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Step("Открыть главную страницу")
|
||||||
|
private void openMainPage() {
|
||||||
|
String siteUrl = System.getProperty("site.url");
|
||||||
|
driver.get(siteUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createTicketTest() throws IOException {
|
||||||
|
loadProperties();
|
||||||
|
|
||||||
|
openMainPage();
|
||||||
|
mainPage = new MainPage();
|
||||||
|
createTicketPage = new CreateTicketPage();
|
||||||
|
loginPage = new LoginPage();
|
||||||
|
ticketsPage = new TicketsPage();
|
||||||
|
|
||||||
|
mainPage.clickOnNewTicket();
|
||||||
|
|
||||||
|
ticket = buildNewTicket();
|
||||||
|
createTicketPage.createTicket(ticket);
|
||||||
|
|
||||||
|
viewPage = new ViewPage();
|
||||||
|
viewPage.checkTicket(ticket);
|
||||||
|
viewPage.saveId(ticket);
|
||||||
|
|
||||||
|
//int id = ticket1.getId();
|
||||||
|
|
||||||
|
mainPage.clickOnLogin();
|
||||||
|
loginPage.login(username, password);
|
||||||
|
|
||||||
|
ticketsPage.clickOnSearch(ticket.getTitle());
|
||||||
|
ticketsPage.openTicket(ticket);
|
||||||
|
|
||||||
|
ticketPage = new TicketPage();
|
||||||
|
ticketPage.checkTicket(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Ticket buildNewTicket() {
|
||||||
|
Ticket ticket = new Ticket();
|
||||||
|
|
||||||
|
String title = "Проверка проблемы "+ System.currentTimeMillis();
|
||||||
|
String description = "Необходимо проверить пользовательский интерфейс";
|
||||||
|
String due_date = "2026-08-17";
|
||||||
|
String email = "helpdesk@example.com";
|
||||||
|
|
||||||
|
ticket.setTitle(title);
|
||||||
|
ticket.setDescription(description);
|
||||||
|
ticket.setQueue(Dictionaries.getQueueKey("Django Helpdesk"));
|
||||||
|
ticket.setPriority(Dictionaries.getPriorityKey("1. Critical"));
|
||||||
|
ticket.setDue_date(due_date);
|
||||||
|
ticket.setSubmitter_email(email);
|
||||||
|
|
||||||
|
return ticket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTest
|
||||||
|
public void close() {
|
||||||
|
if (driver != null) {
|
||||||
|
// Закрываем одно текущее окно браузера
|
||||||
|
driver.close();
|
||||||
|
// Закрываем все открытые окна браузера, завершаем работу браузера, освобождаем ресурсы
|
||||||
|
driver.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user