v2-2 Page Object

This commit is contained in:
Александров Александр Владимирович 2025-06-23 23:34:53 +03:00
parent 2829cfe461
commit c9ecb2466a
11 changed files with 383 additions and 120 deletions

3
environment.properties Normal file
View File

@ -0,0 +1,3 @@
browser=chrome
path.to.chrome.driver=src/test/resources/chromedriver.exe
base.url=http://training.appline.ru/user/login

54
pom.xml
View File

@ -1,30 +1,58 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>ru.ibs</groupId> <groupId>ru.ibs</groupId>
<artifactId>sel1</artifactId> <artifactId>appline-test-project</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<name>Archetype - sel1</name>
<url>https://git.goodtester.ru</url> <properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies> <dependencies>
<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --> <!-- Selenium -->
<dependency> <dependency>
<groupId>org.seleniumhq.selenium</groupId> <groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId> <artifactId>selenium-java</artifactId>
<version>4.33.0</version> <version>4.33.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>commons-configuration</groupId>
<artifactId>junit</artifactId> <artifactId>commons-configuration</artifactId>
<version>4.13.1</version> <version>1.10</version>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<systemPropertyVariables>
<env.properties>src/test/resources/environment.properties</env.properties>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project> </project>

View File

@ -0,0 +1,34 @@
package ru.ibs.framework.managers;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class DriverManager {
private static DriverManager instance;
private WebDriver driver;
public DriverManager() {
String chromePath = TestPropManager.getTestPropManager().getProperty("path.to.chrome.driver");
System.setProperty("webdriver.chrome.driver", chromePath);
driver = new ChromeDriver();
driver.manage().window().maximize();
}
public static DriverManager getDriverManager() {
if (instance == null) {
instance = new DriverManager();
}
return instance;
}
public WebDriver getDriver() {
return driver;
}
public void quitDriver() {
if (driver != null) {
driver.quit();
driver = null;
}
}
}

View File

@ -0,0 +1,29 @@
package ru.ibs.framework.managers;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class TestPropManager {
private static final Properties properties = new Properties();
private static TestPropManager instance;
private TestPropManager() {
try (FileInputStream fis = new FileInputStream("environment.properties")) {
properties.load(fis);
} catch (IOException e) {
throw new RuntimeException("Не удалось загрузить environment.properties", e);
}
}
public static TestPropManager getTestPropManager() {
if (instance == null) {
instance = new TestPropManager();
}
return instance;
}
public String getProperty(String key) {
return properties.getProperty(key);
}
}

View File

@ -0,0 +1,45 @@
package ru.ibs.framework.pages;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import ru.ibs.framework.managers.DriverManager;
import java.time.Duration;
public class BasePage {
protected WebDriver driver = DriverManager.getDriverManager().getDriver();
protected WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
public BasePage() {
PageFactory.initElements(driver, this);
}
protected void fillInputField(By locator, String value) {
WebElement el = waitUntilVisible(locator);
scrollToElement(el);
el.clear();
el.sendKeys(value);
}
protected void scrollToElement(WebElement element) {
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
}
protected WebElement waitUntilVisible(By locator) {
return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
}
protected WebElement waitUntilClickable(By locator) {
return wait.until(ExpectedConditions.elementToBeClickable(locator));
}
protected void waitUntilInvisible(By locator) {
wait.until(ExpectedConditions.invisibilityOfElementLocated(locator));
}
}

View File

@ -1,17 +1,16 @@
package ru.ibs.tests; package ru.ibs.tests;
import org.junit.*; import org.junit.*;
import org.openqa.selenium.*; import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.*;
import java.time.Duration; import java.time.Duration;
public class ApplineBusinessTripTest { public class ApplineBusinessTripTest {
private WebDriver driver; private WebDriver driver;
private WebDriverWait wait; private LoginPage loginPage;
@Before @Before
public void setUp() { public void setUp() {
@ -20,126 +19,47 @@ public class ApplineBusinessTripTest {
driver = new ChromeDriver(); driver = new ChromeDriver();
driver.manage().window().maximize(); driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.get("http://training.appline.ru/user/login"); driver.get("http://training.appline.ru/user/login");
loginPage = new LoginPage(driver);
} }
@Test @Test
public void applineLoginScenario() { public void applineLoginScenario() {
// Логин DashboardPage dashboardPage = loginPage.login("Irina Filippova", "testing");
fillInputField(By.id("prependedInput"), "Irina Filippova"); Assert.assertTrue("Dashboard not loaded", dashboardPage.isDashboardLoaded());
fillInputField(By.id("prependedInput2"), "testing");
WebElement loginButton = driver.findElement(By.xpath("//button[@type='submit']")); BusinessTripPage businessTripPage = dashboardPage.goToBusinessTrip();
waitUntilClickable(loginButton).click(); Assert.assertTrue("Trips page not loaded", businessTripPage.isTripsPageLoaded());
// Проверка заголовка businessTripPage.openCreateTripForm();
WebElement dashboardTitle = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("//h1[@class='oro-subtitle' and contains(text(), 'Панель быстрого запуска')]")));
Assert.assertTrue("Заголовок 'Панель быстрого запуска' не найден", dashboardTitle.isDisplayed());
// Наведение на меню "Расходы" и клик по "Командировки" businessTripPage.selectDepartment("Отдел внутренней разработки");
Actions actions = new Actions(driver); businessTripPage.selectOrganization("Edge");
WebElement expensesMenu = driver.findElement(By.xpath("//span[text()='Расходы']/ancestor::li")); businessTripPage.setTicketsCheckbox(true);
actions.moveToElement(expensesMenu).perform(); businessTripPage.fillCity("Дмитров");
WebElement businessTrip = wait.until(ExpectedConditions.elementToBeClickable( businessTripPage.fillDate(
By.xpath("//a[@href='/business-trip/']/span[text()='Командировки']"))); By.xpath("//input[@placeholder='Укажите дату' and contains(@id, 'departureDatePlan')]"),
businessTrip.click(); "01.01.2025"
);
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("div.loader-overlay"))); businessTripPage.fillDate(
By.xpath("//input[@placeholder='Укажите дату' and contains(@id, 'returnDatePlan')]"),
"10.01.2025"
);
WebElement tripsHeader = wait.until(ExpectedConditions.visibilityOfElementLocated( businessTripPage.saveAndClose();
By.xpath("//h1[contains(text(), 'Командировки')]")));
Assert.assertTrue(tripsHeader.isDisplayed());
// Клик по "Создать командировку" Assert.assertTrue("Expected validation error not shown",
WebElement containerDiv = wait.until(ExpectedConditions.elementToBeClickable( businessTripPage.isErrorDisplayed("Список командируемых сотрудников не может быть пустым"));
By.cssSelector("div.pull-left.btn-group.icons-holder")
));
containerDiv.click();
// Проверка заголовка "Создать командировку"
WebElement createTripHeader = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("//h1[@class='user-name' and contains(text(), 'Создать командировку')]")));
Assert.assertTrue(createTripHeader.isDisplayed());
// Подразделение
WebElement departmentSelect = driver.findElement(By.xpath("//select[contains(@name,'businessUnit')]"));
new Select(departmentSelect).selectByVisibleText("Отдел внутренней разработки");
// Принимающая организация
driver.findElement(By.id("company-selector-show")).click();
WebElement organizationSpan = wait.until(ExpectedConditions.elementToBeClickable(
By.cssSelector("span.select2-chosen")
));
organizationSpan.click();
WebElement input = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("input.select2-input")
));
input.sendKeys("Edge");
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//span[@class='select2-match' and text()='Edge']"))).click();
// Чекбокс "Заказ билетов"
WebElement ticketsCheckbox = driver.findElement(By.xpath("//label[contains(text(),'Заказ билетов')]/preceding-sibling::input"));
if (!ticketsCheckbox.isSelected()) {
ticketsCheckbox.click();
}
// Заполнить города
fillInputField(By.xpath("//input[contains(@id,'arrivalCity')]"), "Дмитров");
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("div.loader-overlay")));
// Даты
By departureDateLocator = By.xpath("//input[@placeholder='Укажите дату' and contains(@id, 'departureDatePlan')]");
By returnDateLocator = By.xpath("//input[@placeholder='Укажите дату' and contains(@id, 'returnDatePlan')]");
fillDateField(departureDateLocator, "01.01.2025");
fillDateField(returnDateLocator, "10.01.2025");
// Сохранить и закрыть
WebElement saveBtn = driver.findElement(By.xpath("//button[contains(text(),'Сохранить и закрыть')]"));
scrollToElement(saveBtn);
saveBtn.click();
WebElement errorMsg = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("//span[@class='validation-failed' and contains(text(), 'Список командируемых сотрудников не может быть пустым')]")));
Assert.assertTrue("Ожидаемая ошибка не найдена", errorMsg.isDisplayed());
} }
@After @After
public void tearDown() { public void tearDown() {
if (driver != null) if (driver != null) {
driver.quit(); driver.quit();
} }
private WebElement waitUntilClickable(WebElement element) {
return wait.until(ExpectedConditions.elementToBeClickable(element));
}
private void fillInputField(By locator, String value) {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
scrollToElement(element);
element.clear();
element.sendKeys(value);
Assert.assertEquals("Поле заполнено некорректно", value, element.getAttribute("value"));
}
private void fillDateField(By locator, String dateValue) {
WebElement dateInput = wait.until(ExpectedConditions.elementToBeClickable(locator));
scrollToElement(dateInput);
dateInput.clear();
dateInput.sendKeys(dateValue);
dateInput.sendKeys(Keys.TAB);
Assert.assertEquals("Поле даты заполнено некорректно", dateValue, dateInput.getAttribute("value"));
}
private void scrollToElement(WebElement element) {
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
} }
} }

View File

@ -0,0 +1,18 @@
package ru.ibs.tests;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import ru.ibs.framework.managers.DriverManager;
public class BaseTests {
@BeforeClass
public static void beforeAll() {
DriverManager.getDriverManager();
}
@AfterClass
public static void afterAll() {
DriverManager.getDriverManager().quitDriver();
}
}

View File

@ -0,0 +1,105 @@
package ru.ibs.tests;
import org.openqa.selenium.*;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.*;
import java.time.Duration;
public class BusinessTripPage {
private WebDriver driver;
private WebDriverWait wait;
@FindBy(xpath = "//h1[contains(text(), 'Командировки')]")
private WebElement tripsHeader;
@FindBy(css = "div.pull-left.btn-group.icons-holder")
private WebElement createTripButton;
@FindBy(xpath = "//h1[@class='user-name' and contains(text(), 'Создать командировку')]")
private WebElement createTripHeader;
@FindBy(xpath = "//select[contains(@name,'businessUnit')]")
private WebElement departmentSelect;
@FindBy(id = "company-selector-show")
private WebElement companySelectorShow;
@FindBy(css = "span.select2-chosen")
private WebElement organizationSpan;
@FindBy(css = "input.select2-input")
private WebElement organizationInput;
@FindBy(xpath = "//label[contains(text(),'Заказ билетов')]/preceding-sibling::input")
private WebElement ticketsCheckbox;
@FindBy(xpath = "//button[contains(text(),'Сохранить и закрыть')]")
private WebElement saveAndCloseButton;
public BusinessTripPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
PageFactory.initElements(driver, this);
}
public boolean isTripsPageLoaded() {
return wait.until(ExpectedConditions.visibilityOf(tripsHeader)).isDisplayed();
}
public void openCreateTripForm() {
wait.until(ExpectedConditions.elementToBeClickable(createTripButton)).click();
wait.until(ExpectedConditions.visibilityOf(createTripHeader));
}
public void selectDepartment(String departmentName) {
Select select = new Select(departmentSelect);
select.selectByVisibleText(departmentName);
}
public void selectOrganization(String orgName) {
companySelectorShow.click();
wait.until(ExpectedConditions.elementToBeClickable(organizationSpan)).click();
wait.until(ExpectedConditions.visibilityOf(organizationInput)).sendKeys(orgName);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//span[@class='select2-match' and text()='" + orgName + "']"))).click();
}
public void setTicketsCheckbox(boolean checked) {
if (ticketsCheckbox.isSelected() != checked) {
ticketsCheckbox.click();
}
}
public void fillCity(String city) {
By cityInputLocator = By.xpath("//input[contains(@id,'arrivalCity')]");
WebElement cityInput = wait.until(ExpectedConditions.visibilityOfElementLocated(cityInputLocator));
scrollToElement(cityInput);
cityInput.clear();
cityInput.sendKeys(city);
// Optionally assert
}
public void fillDate(By dateLocator, String dateValue) {
WebElement dateInput = wait.until(ExpectedConditions.elementToBeClickable(dateLocator));
scrollToElement(dateInput);
dateInput.clear();
dateInput.sendKeys(dateValue);
dateInput.sendKeys(Keys.TAB);
// Optionally assert
}
public void saveAndClose() {
scrollToElement(saveAndCloseButton);
saveAndCloseButton.click();
}
public boolean isErrorDisplayed(String errorText) {
By errorLocator = By.xpath("//span[@class='validation-failed' and contains(text(), '" + errorText + "')]");
return wait.until(ExpectedConditions.visibilityOfElementLocated(errorLocator)).isDisplayed();
}
private void scrollToElement(WebElement element) {
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element);
}
}

View File

@ -0,0 +1,42 @@
package ru.ibs.tests;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
public class DashboardPage {
private final WebDriver driver;
private final WebDriverWait wait;
@FindBy(xpath = "//h1[@class='oro-subtitle' and contains(text(), 'Панель быстрого запуска')]")
private WebElement dashboardTitle;
@FindBy(xpath = "//span[text()='Расходы']/ancestor::li")
private WebElement expensesMenu;
@FindBy(xpath = "//a[@href='/business-trip/']/span[text()='Командировки']")
private WebElement businessTripLink;
public DashboardPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
PageFactory.initElements(driver, this);
}
public boolean isDashboardLoaded() {
return wait.until(ExpectedConditions.visibilityOf(dashboardTitle)).isDisplayed();
}
public BusinessTripPage goToBusinessTrip() {
Actions actions = new Actions(driver);
actions.moveToElement(expensesMenu).perform();
wait.until(ExpectedConditions.elementToBeClickable(businessTripLink)).click();
return new BusinessTripPage(driver);
}
}

View File

@ -0,0 +1,39 @@
package ru.ibs.tests;
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.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
public class LoginPage {
private final WebDriver driver;
private final WebDriverWait wait;
@FindBy(id = "prependedInput")
private WebElement usernameInput;
@FindBy(id = "prependedInput2")
private WebElement passwordInput;
@FindBy(xpath = "//button[@type='submit']")
private WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
PageFactory.initElements(driver, this);
}
public DashboardPage login(String username, String password) {
wait.until(ExpectedConditions.visibilityOf(usernameInput)).clear();
usernameInput.sendKeys(username);
wait.until(ExpectedConditions.visibilityOf(passwordInput)).clear();
passwordInput.sendKeys(password);
wait.until(ExpectedConditions.elementToBeClickable(loginButton)).click();
return new DashboardPage(driver);
}
}

Binary file not shown.