-
Notifications
You must be signed in to change notification settings - Fork 36
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
Selenium tests #212
Conversation
The tests seem to be flaky on travis. I want to investigate it before merge. |
e3d0e2c
to
bebcc84
Compare
It seems that Selenium with Chrome miss the button clicks sometimes. Firefox is much more stable. |
There was a problem hiding this 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" |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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")) |
There was a problem hiding this comment.
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.
There was a problem hiding this 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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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")) |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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 => { |
There was a problem hiding this comment.
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")}" |
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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]
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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.
Copy-paste from guide + configuration