diff --git a/environment.properties b/environment.properties new file mode 100644 index 0000000..e28884c --- /dev/null +++ b/environment.properties @@ -0,0 +1,3 @@ +browser=chrome +path.to.chrome.driver=src/test/resources/chromedriver.exe +base.url=http://training.appline.ru/user/login \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9adfd42..39b051d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,30 +1,58 @@ - + + 4.0.0 + ru.ibs - sel1 + appline-test-project 1.0-SNAPSHOT - Archetype - sel1 - https://git.goodtester.ru + + + 11 + 11 + UTF-8 + + + + junit + junit + 4.13.2 + - + org.seleniumhq.selenium selenium-java 4.33.0 - - junit - junit - 4.13.1 - test + commons-configuration + commons-configuration + 1.10 - + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + + **/*Test.java + + + src/test/resources/environment.properties + + + + + - diff --git a/src/test/java/ru/ibs/framework/managers/DriverManager.java b/src/test/java/ru/ibs/framework/managers/DriverManager.java new file mode 100644 index 0000000..36f817a --- /dev/null +++ b/src/test/java/ru/ibs/framework/managers/DriverManager.java @@ -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; + } + } +} diff --git a/src/test/java/ru/ibs/framework/managers/TestPropManager.java b/src/test/java/ru/ibs/framework/managers/TestPropManager.java new file mode 100644 index 0000000..bf482c6 --- /dev/null +++ b/src/test/java/ru/ibs/framework/managers/TestPropManager.java @@ -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); + } +} diff --git a/src/test/java/ru/ibs/framework/pages/BasePage.java b/src/test/java/ru/ibs/framework/pages/BasePage.java new file mode 100644 index 0000000..a549d1f --- /dev/null +++ b/src/test/java/ru/ibs/framework/pages/BasePage.java @@ -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)); + } +} diff --git a/src/test/java/ru/ibs/tests/ApplineBusinessTripTest.java b/src/test/java/ru/ibs/tests/ApplineBusinessTripTest.java index 0055dcd..99b2ecb 100644 --- a/src/test/java/ru/ibs/tests/ApplineBusinessTripTest.java +++ b/src/test/java/ru/ibs/tests/ApplineBusinessTripTest.java @@ -1,17 +1,16 @@ package ru.ibs.tests; 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.interactions.Actions; -import org.openqa.selenium.support.ui.*; import java.time.Duration; public class ApplineBusinessTripTest { private WebDriver driver; - private WebDriverWait wait; + private LoginPage loginPage; @Before public void setUp() { @@ -20,126 +19,47 @@ public class ApplineBusinessTripTest { driver = new ChromeDriver(); driver.manage().window().maximize(); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); - wait = new WebDriverWait(driver, Duration.ofSeconds(10)); driver.get("http://training.appline.ru/user/login"); + + loginPage = new LoginPage(driver); } @Test public void applineLoginScenario() { - // Логин - fillInputField(By.id("prependedInput"), "Irina Filippova"); - fillInputField(By.id("prependedInput2"), "testing"); + DashboardPage dashboardPage = loginPage.login("Irina Filippova", "testing"); + Assert.assertTrue("Dashboard not loaded", dashboardPage.isDashboardLoaded()); - WebElement loginButton = driver.findElement(By.xpath("//button[@type='submit']")); - waitUntilClickable(loginButton).click(); + BusinessTripPage businessTripPage = dashboardPage.goToBusinessTrip(); + Assert.assertTrue("Trips page not loaded", businessTripPage.isTripsPageLoaded()); - // Проверка заголовка - WebElement dashboardTitle = wait.until(ExpectedConditions.visibilityOfElementLocated( - By.xpath("//h1[@class='oro-subtitle' and contains(text(), 'Панель быстрого запуска')]"))); - Assert.assertTrue("Заголовок 'Панель быстрого запуска' не найден", dashboardTitle.isDisplayed()); + businessTripPage.openCreateTripForm(); - // Наведение на меню "Расходы" и клик по "Командировки" - Actions actions = new Actions(driver); - WebElement expensesMenu = driver.findElement(By.xpath("//span[text()='Расходы']/ancestor::li")); - actions.moveToElement(expensesMenu).perform(); + businessTripPage.selectDepartment("Отдел внутренней разработки"); + businessTripPage.selectOrganization("Edge"); + businessTripPage.setTicketsCheckbox(true); + businessTripPage.fillCity("Дмитров"); - WebElement businessTrip = wait.until(ExpectedConditions.elementToBeClickable( - By.xpath("//a[@href='/business-trip/']/span[text()='Командировки']"))); - businessTrip.click(); + businessTripPage.fillDate( + By.xpath("//input[@placeholder='Укажите дату' and contains(@id, 'departureDatePlan')]"), + "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( - By.xpath("//h1[contains(text(), 'Командировки')]"))); - Assert.assertTrue(tripsHeader.isDisplayed()); + businessTripPage.saveAndClose(); - // Клик по "Создать командировку" - WebElement containerDiv = wait.until(ExpectedConditions.elementToBeClickable( - 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()); + Assert.assertTrue("Expected validation error not shown", + businessTripPage.isErrorDisplayed("Список командируемых сотрудников не может быть пустым")); } @After public void tearDown() { - if (driver != null) + if (driver != null) { 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); + } } } diff --git a/src/test/java/ru/ibs/tests/BaseTests.java b/src/test/java/ru/ibs/tests/BaseTests.java new file mode 100644 index 0000000..8d37efb --- /dev/null +++ b/src/test/java/ru/ibs/tests/BaseTests.java @@ -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(); + } +} diff --git a/src/test/java/ru/ibs/tests/BusinessTripPage.java b/src/test/java/ru/ibs/tests/BusinessTripPage.java new file mode 100644 index 0000000..892d905 --- /dev/null +++ b/src/test/java/ru/ibs/tests/BusinessTripPage.java @@ -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); + } +} diff --git a/src/test/java/ru/ibs/tests/DashboardPage.java b/src/test/java/ru/ibs/tests/DashboardPage.java new file mode 100644 index 0000000..84be3c1 --- /dev/null +++ b/src/test/java/ru/ibs/tests/DashboardPage.java @@ -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); + } +} diff --git a/src/test/java/ru/ibs/tests/LoginPage.java b/src/test/java/ru/ibs/tests/LoginPage.java new file mode 100644 index 0000000..e5f169a --- /dev/null +++ b/src/test/java/ru/ibs/tests/LoginPage.java @@ -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); + } +} diff --git a/src/test/resources/chromedriver.exe b/src/test/resources/chromedriver.exe new file mode 100644 index 0000000..148462f Binary files /dev/null and b/src/test/resources/chromedriver.exe differ