Skip to content

Dropdown test #1234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,7 @@ internal class BrowserControllerDockerTest{
browser.goBack()
assertEquals(aPage, browser.getCurrentUrl())
}

//TODO @IVa add test for Select

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package org.evomaster.core.problem.webfrontend

import org.evomaster.core.search.gene.numeric.IntegerGene
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.openqa.selenium.By
import org.openqa.selenium.remote.RemoteWebDriver
import org.openqa.selenium.support.ui.Select
import java.net.URI
import java.net.URISyntaxException
import java.net.URL
import kotlin.math.min

object BrowserActionBuilder {


fun computePossibleUserInteractions(html: String) : List<WebUserInteraction>{
/**
*/
fun computePossibleUserInteractions(driver: RemoteWebDriver) : List<WebUserInteraction>{


val document = try{
Jsoup.parse(html)
Jsoup.parse(driver.pageSource)
}catch (e: Exception){
//TODO double-check
return listOf()
Expand All @@ -22,10 +29,42 @@ object BrowserActionBuilder {

//TODO all cases

handleALinks(document, driver, list)
handleDropDowns(document, driver, list)

return list
}

private fun handleDropDowns(
document: Document,
driver: RemoteWebDriver,
list: MutableList<WebUserInteraction>
) {

document.getElementsByTag("select")
.forEach { jsoup ->
val dropdown = Select(driver.findElement(By.cssSelector(jsoup.cssSelector())))
val type = if(dropdown.isMultiple) {
UserActionType.SELECT_MULTI
} else {
UserActionType.SELECT_SINGLE
}
val options = dropdown.options
.filter{it.isEnabled}
.map{it.text}
list.add(WebUserInteraction(jsoup.cssSelector(), type, options))
}
}

private fun handleALinks(
document: Document,
driver: RemoteWebDriver,
list: MutableList<WebUserInteraction>
) {
document.getElementsByTag("a")
.forEach {
val href = it.attr("href")
val canClick = if(!href.isNullOrBlank()) {
val canClick = if (!href.isNullOrBlank()) {
val uri = try {
URI(href)
} catch (e: URISyntaxException) {
Expand All @@ -38,25 +77,36 @@ object BrowserActionBuilder {
val onclick = it.attr("onclick")
!onclick.isNullOrBlank()
}
if(canClick){
if (canClick) {
list.add(WebUserInteraction(it.cssSelector(), UserActionType.CLICK))
}
}

return list
}


fun createPossibleActions(html: String) : List<WebAction>{
fun createPossibleActions(driver: RemoteWebDriver) : List<WebAction>{

val interactions = computePossibleUserInteractions(html)
val interactions = computePossibleUserInteractions(driver)

val inputs = interactions.filter { it.userActionType == UserActionType.FILL_TEXT }
val others = interactions.filter { it.userActionType != UserActionType.FILL_TEXT }

//TODO genes for inputs

return others.map { WebAction(mutableListOf(it)) }
return others.map {
when(it.userActionType) {
UserActionType.CLICK -> WebAction(mutableListOf(it))
UserActionType.SELECT_SINGLE -> {
val selection = IntegerGene(it.cssSelector, min=0, max=it.inputs.size)
WebAction(mutableListOf(it), singleSelection = mutableMapOf(it.cssSelector to selection))
}
//TODO multi
else -> {
//TODO log warn
WebAction(mutableListOf(it))
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,28 @@ enum class UserActionType {

CLICK,

FILL_TEXT
FILL_TEXT,

/**
* Select only a single element in a dropdown <select> element
*/
SELECT_SINGLE,

/**
* Some dropdown <select> elements might allow to select more than one element
*/
SELECT_MULTI,

DOUBLE_CLICK,
RIGHT_CLICK,
HOVER_OVER_ELEMENT,
VERTICAL_SCROLLING,
HORIZONTAL_SCROLLING,
DRAG_AND_DROP,

CHECK_CHECKBOX,
UNCHECK_CHECKBOX,
CHOOSE_RADIO_BUTTON,
SELECT,
UPLOAD_FILE,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package org.evomaster.core.problem.webfrontend

import org.evomaster.core.problem.gui.GuiAction
import org.evomaster.core.search.StructuralElement
import org.evomaster.core.search.gene.BooleanGene
import org.evomaster.core.search.gene.Gene
import org.evomaster.core.search.gene.collection.ArrayGene
import org.evomaster.core.search.gene.numeric.IntegerGene
import org.evomaster.core.search.gene.string.StringGene
import org.jsoup.Jsoup

Expand All @@ -15,8 +18,20 @@ class WebAction(
/**
* Map from cssLocator (coming from [userInteractions]) for text input to StringGene representing its value
*/
val textData : MutableMap<String, StringGene> = mutableMapOf()
) : GuiAction(textData.values.map { it }) {
val textData : MutableMap<String, StringGene> = mutableMapOf(),
/**
* TODO explanation
*/
val singleSelection: MutableMap<String, IntegerGene> = mutableMapOf(),
/**
* TODO explanation
*/
val multiSelection: MutableMap<String, ArrayGene<BooleanGene>> = mutableMapOf(),
) : GuiAction(
textData.values.map { it }
.plus(singleSelection.values.map { it })
.plus(multiSelection.values.map { it })
) {

init {
val nFillText = userInteractions.count { it.userActionType == UserActionType.FILL_TEXT }
Expand All @@ -28,6 +43,7 @@ class WebAction(
throw IllegalArgumentException("Missing info for input: $key")
}
}
//TODO constraint checks on singleSelection and multiSelection
}

override fun isDefined() : Boolean {
Expand Down Expand Up @@ -65,7 +81,9 @@ class WebAction(
override fun copyContent(): StructuralElement {
return WebAction(
userInteractions.map { it.copy() }.toMutableList(),
textData.entries.associate { it.key to it.value.copy() as StringGene }.toMutableMap()
textData.entries.associate { it.key to it.value.copy() as StringGene }.toMutableMap(),
singleSelection.entries.associate { it.key to it.value.copy() as IntegerGene }.toMutableMap(),
multiSelection.entries.associate { it.key to it.value.copy() as ArrayGene<BooleanGene> }.toMutableMap(),
)
}

Expand All @@ -74,6 +92,7 @@ class WebAction(
userInteractions.addAll(other.userInteractions) //immutable elements
textData.clear()
textData.putAll(other.textData.entries.associate { it.key to it.value.copy() as StringGene })
//TODO singleSelection multiSelection
}

fun getIdentifier() : String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package org.evomaster.core.problem.webfrontend

data class WebUserInteraction(
val cssSelector : String,
val userActionType : UserActionType
val userActionType : UserActionType,
val inputs : List<String> = listOf()
)
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class BrowserController {
}

fun computePossibleUserInteractions() : List<WebUserInteraction>{
return BrowserActionBuilder.computePossibleUserInteractions(getCurrentPageSource())
return BrowserActionBuilder.computePossibleUserInteractions(driver)
}

fun getCurrentPageSource(): String {
Expand All @@ -78,10 +78,18 @@ class BrowserController {
return driver.currentUrl
}

fun getDriver(): RemoteWebDriver{
return driver
}

fun clickAndWaitPageLoad(cssSelector: String){
SeleniumEMUtils.clickAndWaitPageLoad(driver, cssSelector)
}

fun selectAndWaitPageLoad(cssSelector: String, values: List<String>){
//TODO
}

fun goBack(){
driver.navigate().back()
SeleniumEMUtils.waitForPageToLoad(driver,2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class WebFitness : EnterpriseFitness<WebIndividual>() {

val pageBeforeExecutingAction = browserController.getCurrentPageSource()
val urlBeforeExecutingAction = browserController.getCurrentUrl()
val possibilities = BrowserActionBuilder.createPossibleActions(pageBeforeExecutingAction)
val possibilities = BrowserActionBuilder.createPossibleActions(browserController.getDriver())

var blocking = false

Expand Down Expand Up @@ -140,6 +140,13 @@ class WebFitness : EnterpriseFitness<WebIndividual>() {
browserController.clickAndWaitPageLoad(it.cssSelector)
//TODO better wait
}
UserActionType.SELECT_SINGLE, UserActionType.SELECT_MULTI -> {
//TODO
/*
not just clicking, but deciding which options to select.
this is based on values in the genes
*/
}
else -> {
log.error("Not handled action type ${it.userActionType}")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.web.bind.annotation.GetMapping;

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class DropDownWebApplication {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.foo.web.examples.spring.dropdownselector;

import com.foo.web.examples.spring.SpringController;
import com.foo.web.examples.spring.base.BaseWebApplication;

public class DropDownController extends SpringController {
public DropDownController() {
super(BaseWebApplication.class, "/dropdown/index.html");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.evomaster.e2etests.spring.web.dropdownselector;

import com.foo.web.examples.spring.dropdownselector.DropDownController;
import org.evomaster.core.problem.webfrontend.WebIndividual;
import org.evomaster.core.search.Solution;
import org.evomaster.e2etests.spring.web.SpringTestBase;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class DropDownEMTest extends SpringTestBase {
@BeforeAll
public static void initClass() throws Exception {
SpringTestBase.initClass(new DropDownController());
}

@Disabled
@Test
public void testRunEM() throws Throwable {

runTestHandlingFlakyAndCompilation(
"DropDownEM",
"org.DropDownEM",
50,
(args) -> {

Solution<WebIndividual> solution = initAndRun(args);

assertTrue(solution.getIndividuals().size() > 0);

assertHasVisitedUrlPath(solution, "/dropdown/index.html", "/dropdown/page1.html", "/dropdown/page2.html", "/dropdown/page3.html");
assertNoHtmlErrors(solution); // statement ok - gives no errors
}
);
}

}