Skip to content

Commit

Permalink
#1022 - Apply Automation test for Yas project
Browse files Browse the repository at this point in the history
- add automation-ui/backoffice
  • Loading branch information
Duy Le Van committed Sep 17, 2024
1 parent 5d8aaf9 commit 6a93c3a
Show file tree
Hide file tree
Showing 27 changed files with 635 additions and 1 deletion.
21 changes: 21 additions & 0 deletions automation-ui/backoffice/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?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>
<parent>
<groupId>com.yas</groupId>
<artifactId>automation-ui</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>

<artifactId>backoffice</artifactId>
<packaging>pom</packaging>

<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.yas.automation.ui;

import com.yas.automation.ui.configuration.BackOfficeConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties(BackOfficeConfiguration.class)
public class AutomationUiApplication {

public static void main(String[] args) {
SpringApplication.run(AutomationUiApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.yas.automation.ui.configuration;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "backoffice")
public record BackOfficeConfiguration(String url, String username, String password) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.yas.automation.ui.form;

import lombok.Getter;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

@Getter
public abstract class BaseForm {

private WebDriver driver;

private BaseForm() {}

public BaseForm(WebDriver driver) {
this.driver = driver;
}

public void submitForm() {
getSubmitBtn().click();
}

public abstract WebElement getSubmitBtn();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.yas.automation.ui.form;

import lombok.Getter;

@Getter
public enum InputType {

TEXT("textService"),
DROPDOWN("dropdownService");

private final String serviceName;

InputType(String serviceName) {
this.serviceName = serviceName;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.yas.automation.ui.service;

import com.yas.automation.ui.form.InputType;
import org.openqa.selenium.WebElement;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class InputDelegateService {

private final Map<String, InputService> inputServiceMap;

public InputDelegateService(Map<String, InputService> inputServiceMap) {
this.inputServiceMap = inputServiceMap;
}

public void setInputValue(InputType inputType, WebElement webElement, Object value) {
if (inputServiceMap.containsKey(inputType.getServiceName())) {
inputServiceMap.get(inputType.getServiceName()).setValue(webElement, value);
} else {
// TODO: define exception to throw
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.yas.automation.ui.service;

import org.openqa.selenium.WebElement;

public interface InputService {

<T> void setValue(WebElement webElement, T value);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.yas.automation.ui.service.impl;

import com.yas.automation.ui.annotation.InputTypeQualifier;
import com.yas.automation.ui.form.InputType;
import com.yas.automation.ui.service.InputService;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Select;
import org.springframework.stereotype.Component;

@Component
@InputTypeQualifier(InputType.DROPDOWN)
public class DropdownService implements InputService {

@Override
public void setValue(WebElement webElement, Object value) {
Select selectBrand = new Select(webElement);
selectBrand.selectByVisibleText((String) value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.yas.automation.ui.service.impl;

import com.yas.automation.ui.annotation.InputTypeQualifier;
import com.yas.automation.ui.form.InputType;
import com.yas.automation.ui.service.InputService;
import org.openqa.selenium.WebElement;
import org.springframework.stereotype.Component;

@Component
@InputTypeQualifier(InputType.TEXT)
public class TextService implements InputService {

@Override
public void setValue(WebElement webElement, Object value) {
webElement.sendKeys((CharSequence) value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.yas.automation.ui.util;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public final class WebElementUtil {

private WebElementUtil() {}

public static WebElement getWebElementBy(WebDriver driver, How how, String identity) {
return getWebElementBy(driver, how, identity, 30);
}

public static WebElement getWebElementBy(WebDriver driver, How how, String identity, long waitTime) {
By locator = how.buildBy(identity);
WebDriverWait waitForEle = new WebDriverWait(driver, Duration.ofSeconds(waitTime));
waitForEle.until(ExpectedConditions.presenceOfElementLocated(locator));
return driver.findElement(locator);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
spring.application.name=automation-ui
app.url=http://storefront/
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.yas.automation.ui;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class AutomationUiApplicationTests {

@Test
void contextLoads() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.yas.automation.ui;

import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;

@CucumberOptions(
features = "src/test/resources/features",
glue = "com.yas.automation.ui",
plugin = {"pretty", "html:target/cucumber-reports"}
)
public class TestNGRunner extends AbstractTestNGCucumberTests {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.yas.automation.ui.configuration;

import com.yas.automation.ui.AutomationUiApplication;
import io.cucumber.spring.CucumberContextConfiguration;
import org.springframework.boot.test.context.SpringBootTest;

@CucumberContextConfiguration
@SpringBootTest(classes = AutomationUiApplication.class)
public class CucumberSpringConfiguration {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.yas.automation.ui.form;

import lombok.Getter;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;

@Getter
public class ProductForm extends BaseForm {

@FindBy(how = How.ID, using = "name")
private WebElement name;

@FindBy(how = How.ID, using = "price")
private WebElement price;

@FindBy(how = How.ID, using = "sku")
private WebElement sku;

@FindBy(how = How.ID, using = "select-option-brandId")
private WebElement brand;

@FindBy(how = How.ID, using = "select-option-taxClassId")
private WebElement tax;

@FindBy(xpath = "//button[@type='submit' and contains(text(),'Create')]")
WebElement createBtn;

public ProductForm(WebDriver webDriver) {
super(webDriver);
PageFactory.initElements(webDriver, this);
}

@Override
public WebElement getSubmitBtn() {
return createBtn;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.yas.automation.ui.hook;

import io.cucumber.java.After;
import io.cucumber.java.Before;
import org.springframework.beans.factory.annotation.Autowired;

/**
* Cucumber hook managing cucumber test scenarios
*/
public class Hooks {
@Autowired
private WebDriverFactory webDriverFactory;

@Before
public void setUp() {
webDriverFactory.getChromeDriver();
}

@After
public void tearDown() {
webDriverFactory.getChromeDriver().close();
webDriverFactory.destroyDriver();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.yas.automation.ui.hook;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.stereotype.Component;

/**
* WebDriverFactory provides utility methods to manage the lifecycle of WebDriver instances.
* <p>
* A new {@link WebDriver} instance is created for each test scenario and is destroyed after the test is completed.
* Since Selenium interacts with and modifies the {@link WebDriver} during the test
* (e.g., invoking {@link WebDriver#quit()} after scenario completion),
* the WebDriver cannot be defined as a Spring bean to prevent unintended side effects on other tests.
* </p>
* <p>
* This class is used by {@link Hooks} to initialize the WebDriver before each scenario and ensure it is destroyed afterward.
* </p>
*/
@Component
public class WebDriverFactory {

private final ThreadLocal<WebDriver> webDriver = new ThreadLocal<>();

/**
* Initializes and returns a new Chrome WebDriver instance if not already created for the current thread.
*
* @return a {@link WebDriver} instance specific to the current thread.
*/
public synchronized WebDriver getChromeDriver() {
if (webDriver.get() == null) {
WebDriver webDriver = new ChromeDriver();
webDriver.manage().window().maximize();
this.webDriver.set(webDriver);
}
return webDriver.get();
}

/**
* Destroys the WebDriver instance for the current thread.
*/
synchronized void destroyDriver() {
WebDriver driver = webDriver.get();
if (driver != null) {
driver.quit();
webDriver.remove();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.yas.automation.ui.pages;

import com.yas.automation.ui.hook.WebDriverFactory;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.How;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import static com.yas.automation.ui.util.WebElementUtil.getWebElementBy;

@Component
public class HomePage {

@Autowired
private final WebDriverFactory webDriverFactory;

@Autowired
public HomePage(WebDriverFactory webDriverFactory) {
this.webDriverFactory = webDriverFactory;
}

/**
* Click event to click to item on side menu
* @param item it should correspond to value on fronted, usually entity name with (s)
* for example: products, brands, etc.
*/
public void clickToCatalogItem(String item) {
WebElement productLink = getWebElementBy(
webDriverFactory.getChromeDriver(),
How.XPATH,
String.format("//li/a[@href='/catalog/%s']", item)
);
productLink.click();
}

}
Loading

0 comments on commit 6a93c3a

Please sign in to comment.