Skip to content
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

Selenium tests #212

Merged
merged 19 commits into from
Sep 25, 2018
Merged

Selenium tests #212

merged 19 commits into from
Sep 25, 2018

Conversation

Starzu
Copy link
Contributor

@Starzu Starzu commented Jul 30, 2018

Copy-paste from guide + configuration

@Starzu Starzu added this to the 0.8.0 milestone Jul 30, 2018
@Starzu Starzu requested a review from ddworak July 30, 2018 11:31
@Starzu Starzu changed the title Selenium tests WIP: Selenium tests Jul 30, 2018
@Starzu
Copy link
Contributor Author

Starzu commented Jul 30, 2018

The tests seem to be flaky on travis. I want to investigate it before merge.

@Starzu Starzu force-pushed the selenium branch 3 times, most recently from e3d0e2c to bebcc84 Compare July 31, 2018 09:00
@Starzu Starzu changed the title WIP: Selenium tests Selenium tests Jul 31, 2018
@Starzu
Copy link
Contributor Author

Starzu commented Jul 31, 2018

It seems that Selenium with Chrome miss the button clicks sometimes. Firefox is much more stable.

@ddworak ddworak requested a review from g-skiba August 9, 2018 11:53
Copy link
Member

@ddworak ddworak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments to the build setup itself and found you the best reviewer for the rest, good luck! 🤣

.travis.yml Outdated
addons:
firefox: latest
chrome: stable

before_script:
- "export DISPLAY=:99.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be possible to simplify this with xvfb-run wrapper: https://docs.travis-ci.com/user/gui-and-headless-browsers/#using-the-xvfb-run-wrapper

- wget http://chromedriver.storage.googleapis.com/2.36/chromedriver_linux64.zip
- unzip chromedriver_linux64.zip -d selenium-bin
- export PATH=$PWD/selenium-bin:$PATH
# Instal google-chrome-driver
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With dist: trusty it should be possible to just:

before_install:
 - sudo apt-get update
 - sudo apt-get install chromium-chromedriver

@@ -350,3 +350,110 @@ lazy val `benchmarks-frontend` = project.in(file("benchmarks/frontend"))
libraryDependencies ++= Dependencies.benchmarksFrontendDeps.value,
Compile / scalaJSUseMainModuleInitializer := true,
)

lazy val `selenium-shared` = project.in(file("selenium/shared"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd much rather we setup the selenium project in a separate build.sbt file, no need to make this one more complex.

Copy link

@g-skiba g-skiba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions and suggestions, pls let me know what you think

def translations(): RemoteTranslationRPC
def exceptions(): ExceptionsRPC

def call(): CallServerRPC
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is unused, I think you're missing some demo.

pongListeners.foreach(l => l(id))
}

def registerPongListener(listener: Int => Any) = pongListeners += listener
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you want to expose the pongListeners in these methods but rather make them return Unit

li(a(href := FrontendRoutingDemosState(None).url)("Frontend Routing")),
li(a(href := RpcDemosState.url)("RPC")),
li(a(href := RestDemosState.url)("REST")),
li(a(href := I18nDemosState.url)("i18n"))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be missing two links: to /activity which I think is the missing demo and to /jquery


import scala.collection.mutable.ListBuffer

object UrlLoggingDemo {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This demo does not seem to be effectively used (presented) anywhere, is it intentional?

div(BootstrapStyles.Grid.colMd4)(
UdashInputGroup()(
UdashInputGroup.input(
NumberInput(age.transform(_.toString, Integer.parseInt))(maxlength := "6").render
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maxlength attribute does not work this way for number input. min and max attributes might be used instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy-paste things...

}
}

for (_ <- 1 to 3) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This takes at least 24s (3 iterations * 4 names * 2s interval between changes) - are we OK with this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had no choice in case of human-friendly demos in the guide. Now we can reduce these intervals.


override protected def afterAll(): Unit = {
server.stop()
driver.close()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think driver.quit() should be called instead (or maybe additionally?) in order to get rid of the driver process although from what I know it does not always work.

val checkbox = checkboxes.findElement(new ByClassName(s"checkbox-demo-$propertyName"))
checkbox.click()
eventually {
checkboxes.findElements(new ByCssSelector(s"[data-bind=$propertyName]")).asScala.forall(el => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to consider replacing forall with foreach with assertion inside so that you get any more information than just that the you got false instead of true

linkChanger.clear()
linkChanger.sendKeys(s)
eventually {
val escaped = s"/frontend/routing/${s.replaceAll(" ", "%20").replaceAll("#", "%23")}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use URLEncoder


val eventualResponse2 =
inexistentServerConnector.send("/non/existing/path", RESTConnector.HttpMethod.POST, Map.empty, Map.empty, "lol")
intercept[ConnectException](await(eventualResponse2))
intercept[ConnectException](Await.result(eventualResponse2, 10 seconds))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use a global (or even scaled) implicit timeout with the ScalaFutures syntax here:

eventualResponse2.failed.futureValue shouldBe a [ConnectException]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want the global timeout, in this test I want to use this specific value.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can introduce an implicit in the local scope. This specific value occurs at least twice here ;)

checkButtons.findElements(new ByClassName("check-buttons-demo-fruits")).asScala
.foreach { el =>
val contains = el.getText.contains(propertyName)
assert(if (checkbox.getAttribute("selected") != null) contains else !contains)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and in 85-86 I would change it to assert(checkbox.getAttribute("selected") != null) == el.getText.contains(propertyName)). But also (this applies to the whole file) using assertResult or should be assertions instead of assert together with == would still give you more information in case of test failure.

PatienceConfig(scaled(Span(10, Seconds)), scaled(Span(5, Millis)))

// val driver: RemoteWebDriver = new ChromeDriver(new ChromeOptions().setHeadless(false))
val driver: RemoteWebDriver = new FirefoxDriver(new FirefoxOptions().setHeadless(true))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The driver and the server should be started in beforeAll() because if the constructor fails, afterAll() can't be called. So for example if the server fails to start (e.g. some port is already used) then the browser and driver are not closed.

@Starzu Starzu merged commit ba12af7 into master Sep 25, 2018
@Starzu Starzu deleted the selenium branch September 25, 2018 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants