Completed Test Task

master
Yevhen Unico 1 year ago
commit 17bd3b7917

16
.gitignore vendored

@ -0,0 +1,16 @@
.idea/workspace.xml
*.xml
!/**/assembly.xml
!/**/pom.xml
!/**/*log4j2*.xml
!/**/extent-config.xml
tests/allure-results
tests/resources/videos
buid/
target/
gradle/
.idea/
path/
out/
*.iml
*.log

@ -0,0 +1,61 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.8.20'
}
def java_version = 17
java {
sourceCompatibility = JavaVersion.toVersion(java_version)
targetCompatibility = JavaVersion.toVersion(java_version)
}
tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
jvmTarget = java_version.toString()
}
}
dependencies {
implementation 'com.microsoft.playwright:playwright:1.34.0'
implementation 'org.testng:testng:7.8.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.8.20'
implementation 'org.jetbrains.kotlin:kotlin-reflect:1.8.20'
implementation 'io.cucumber:cucumber-testng:7.14.0'
implementation 'io.cucumber:cucumber-java:7.14.0'
implementation 'org.slf4j:slf4j-api:1.7.32'
implementation 'ch.qos.logback:logback-classic:1.2.6'
implementation 'org.projectlombok:lombok:1.18.30'
implementation 'org.jsoup:jsoup:1.15.4'
implementation 'org.springframework:spring-context:6.0.9'
implementation 'org.testng:testng:7.8.0'
implementation("io.rest-assured:rest-assured:5.1.1")
}
repositories {
mavenLocal()
mavenCentral()
google()
maven {
url 'https://repo.maven.apache.org/maven2/'
}
maven {
url "https://plugins.gradle.org/m2"
}
maven {
url "https://repo1.maven.org/maven2/"
}
}
test {
systemProperty('encryptionKey', System.getProperty('encryptionKey'))
useTestNG() {
listeners << 'core.listeners.TestNGListener'
suites('src/test/resources/testng.xml')
}
jvmArgs('--add-opens', 'java.base/java.lang=ALL-UNNAMED')
jvmArgs('--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED')
jvmArgs('--add-opens', 'java.base/java.nio=ALL-UNNAMED')
}

@ -0,0 +1,20 @@
package core
import io.restassured.RestAssured
import io.restassured.http.ContentType
import io.restassured.response.Response
class BaseApi {
fun getRequest(url: String): Response {
return RestAssured.given()
.contentType(ContentType.JSON)
.get(url)
}
fun postRequest(url: String, body: Map<String, Any>): Response {
return RestAssured.given()
.contentType(ContentType.JSON)
.body(body)
.post(url)
}
}

@ -0,0 +1,33 @@
package core.listeners
import core.web.browser.InitialBrowser
import org.testng.ISuiteListener
import org.testng.ITestContext
import org.testng.ITestListener
import org.testng.ITestResult
class TestNGListener : ITestListener, ISuiteListener {
override fun onTestStart(result: ITestResult?) {
}
override fun onTestSuccess(result: ITestResult?) {
InitialBrowser.getInstance().destroy()
}
override fun onTestFailure(result: ITestResult?) {
InitialBrowser.getInstance().destroy()
}
override fun onTestSkipped(result: ITestResult?) {
}
override fun onTestFailedButWithinSuccessPercentage(result: ITestResult?) {
}
override fun onStart(context: ITestContext?) {
InitialBrowser.getInstance()
}
override fun onFinish(context: ITestContext?) {
}
}

@ -0,0 +1,30 @@
package core.properties
import java.io.IOException
import java.util.*
class PropertiesReader {
private val urlProperties = URLProperties()
init {
val urlPropertiesFile = "urls.properties"
urlProperties.loadFromProperties(loadProperty(urlPropertiesFile))
}
fun urlsProperties(): URLProperties {
return urlProperties
}
private fun loadProperty(fileName: String?): Properties {
val properties = Properties()
try {
PropertiesReader::class.java.getResourceAsStream("/$fileName").use { inputStream ->
properties.load(inputStream)
}
} catch (e: IOException) {
throw RuntimeException(e)
}
return properties
}
}

@ -0,0 +1,10 @@
package core.properties
import java.util.*
class URLProperties {
lateinit var exampleURL: String
fun loadFromProperties(properties: Properties) {
exampleURL = properties.getProperty("exampleURL")
}
}

@ -0,0 +1,20 @@
package core.utils.api
import io.restassured.response.Response
import org.testng.Assert
class ApiOpertations {
fun assertStatusCode(response: Response, expectedStatusCode: Int) {
Assert.assertEquals(response.statusCode, expectedStatusCode, "Status code should be $expectedStatusCode")
}
fun assertFieldNotNull(response: Response, field: String) {
val value = response.jsonPath().getString(field)
Assert.assertNotNull(value, "$field field should not be null")
}
fun assertIdGreaterThanZero(response: Response) {
val id = response.jsonPath().getInt("id")
Assert.assertTrue(id > 0, "ID should be greater than 0")
}
}

@ -0,0 +1,48 @@
package core.utils.helpers
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import kotlin.reflect.KClass
// Return logger for name
fun <T : Any> T.logger(name: String): Logger {
return LoggerFactory.getLogger(name)
}
// Return logger for Java class, if companion object fix the name
fun <T : Any> logger(forClass: Class<T>): Logger {
return LoggerFactory.getLogger(unwrapCompanionClass(forClass))
}
// unwrap companion class to enclosing class given a Java Class
fun <T : Any> unwrapCompanionClass(ofClass: Class<T>): Class<*> {
return ofClass.enclosingClass?.takeIf {
ofClass.enclosingClass.kotlin.objectInstance?.javaClass == ofClass
} ?: ofClass
}
// unwrap companion class to enclosing class given a Kotlin Class
fun <T : Any> unwrapCompanionClass(ofClass: KClass<T>): KClass<*> {
return unwrapCompanionClass(ofClass.java).kotlin
}
// Return logger for Kotlin class
fun <T : Any> logger(forClass: KClass<T>): Logger {
return logger(forClass.java)
}
// return logger from extended class (or the enclosing class)
fun <T : Any> T.logger(): Logger {
return logger(this.javaClass)
}
// return a lazy logger property delegate for enclosing class
fun <R : Any> R.lazyLogger(): Lazy<Logger> {
return lazy { logger(this.javaClass) }
}
// return a logger property delegate for enclosing class
fun <R : Any> R.injectLogger(): Lazy<Logger> {
return lazyOf(logger(this.javaClass))
}

@ -0,0 +1,95 @@
package core.web.browser
import com.microsoft.playwright.Page
import com.microsoft.playwright.Playwright
import core.exeptions.BrowserException
import core.utils.helpers.logger
import java.nio.file.Paths
object InitialBrowser {
private const val browserName = "CHROME"
private val browserThread = ThreadLocal<InitialBrowser>()
fun getInstance(): InitialBrowser = browserThread.get() ?: synchronized(this) {
browserThread.get() ?: InitialBrowser.also { browserThread.set(it) }
}
private var page: Page? = null
fun getPage(): Page {
if (page == null) {
page = initialBrowser()
page?.context()?.pages()?.get(0)?.close()
if (logger().isDebugEnabled) {
logger().debug("Browser: " + page?.context()?.browser()?.browserType()?.name())
}
}
return page ?: throw IllegalStateException("Page is null")
}
fun setPage(page: Page) {
this.page = page
}
private fun initialBrowser(): Page {
if (logger().isDebugEnabled) {
logger().debug("Initializing browser...")
}
return when (browserName) {
"CHROME" -> {
if (logger().isDebugEnabled) {
logger().debug("Creating driver instance: Chrome local")
}
val playwright = Playwright.create()
val context = playwright.chromium().launchPersistentContext(
Paths.get(""),
Options().browserOptions()
)
val page = context.newPage()
setPage(page)
page
}
else -> throw BrowserException("Browser was not set")
}
}
fun destroy() {
page?.let {
try {
if (logger().isDebugEnabled) {
logger().debug("Closing page...")
}
it.close()
if (logger().isDebugEnabled) {
logger().debug("Closing all context pages...")
}
it.context().pages().forEach { page -> page.close() }
val browser = it.context().browser()
if (browser != null) {
if (logger().isDebugEnabled) {
logger().debug("Closing browser...")
}
browser.close()
} else {
if (logger().isWarnEnabled) {
logger().warn("Browser is null, cannot close it.")
}
}
if (logger().isDebugEnabled) {
logger().debug("Driver destroyed successfully.")
}
} catch (e: Exception) {
if (logger().isErrorEnabled) {
logger().error("Error during driver destruction", e)
}
} finally {
page = null
}
} ?: run {
if (logger().isDebugEnabled) {
logger().debug("Driver destroy called with no driver present.")
}
}
}
}

@ -0,0 +1,20 @@
package core.web.browser
import com.microsoft.playwright.BrowserType
class Options {
fun browserOptions(): BrowserType.LaunchPersistentContextOptions {
val type = BrowserType.LaunchPersistentContextOptions()
val launchOptions: MutableList<String> = ArrayList()
launchOptions.add("--start-maximized")
launchOptions.add("--disable-gpu")
type.setHeadless(false)
.setArgs(launchOptions)
.setTimeout(30000.0)
.setDevtools(false)
.setChromiumSandbox(false)
.setViewportSize(null)
.setAcceptDownloads(true)
return type
}
}

@ -0,0 +1,16 @@
package core.web.elements
import com.microsoft.playwright.Locator
import com.microsoft.playwright.Page
import core.utils.helpers.logger
import core.web.browser.InitialBrowser
import kotlinx.coroutines.runBlocking
class Window : Element() {
fun navigateTo(url: String) {
logger().info("Url: $url")
page.navigate(url)
}
}

@ -0,0 +1,14 @@
package projects.example
import core.properties.PropertiesReader
import core.web.elements.Window
import io.cucumber.java.en.Given
class ExamplePageStepDefs {
private val window: Window = Window()
@Given("^user is on example URL$")
fun openExampleURL() {
window.navigateTo(PropertiesReader().urlsProperties().exampleURL)
}
}

@ -0,0 +1 @@
exampleURL=https://example.com

@ -0,0 +1,29 @@
import core.BaseApi
import core.utils.api.ApiOpertations
import org.testng.annotations.Test
class ApiTestTask {
private val baseApi = BaseApi()
private val validator = ApiOpertations()
@Test
fun assertGetRequestSuccessfulAndContainsTitleField() {
val response = baseApi.getRequest("https://jsonplaceholder.typicode.com/posts/1")
validator.assertStatusCode(response, 200)
validator.assertFieldNotNull(response, "title")
println("GET request successful. Title: ${response.jsonPath().getString("title")}")
}
@Test
fun assertPostRequestCreatesNewResource() {
val payload = mapOf("title" to "foo", "body" to "bar", "userId" to 1)
val response = baseApi.postRequest("https://jsonplaceholder.typicode.com/posts", payload)
validator.assertStatusCode(response, 201)
validator.assertIdGreaterThanZero(response)
println("POST request successful. Created resource ID: ${response.jsonPath().getInt("id")}")
}
}

@ -0,0 +1,9 @@
import org.testng.annotations.Test
import projects.example.ExamplePageStepDefs
class UITestTask {
@Test
fun openExampleUrl() {
ExamplePageStepDefs().openExampleURL()
}
}
Loading…
Cancel
Save