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

BrowserWebDriverContainer fails to determine Selenium version for Selenium 4 (alpha) #3607

Open
mkornblum opened this issue Dec 15, 2020 · 3 comments

Comments

@mkornblum
Copy link

This seems like a similar issue to #611, except this time it's Selenium 4.

When using Selenium 4, the manifest in selenium-api-4.0.0-alpha-3.jar looks like this:

Manifest-Version: 1.0
Multi-Release: true
Created-By: mergejars
Target-Label: //java/client/src/org/openqa/selenium:core-base-lib

This means that SeleniumUtils.java ends up returning 2.45 for the Selenium version (ie, the base case).

This also means that we end up with a BrowserWebDriverContainer with Chrome version 40-something in it (I forget the exact version, but it's an old one). I tried passing in an explicit container name when constructing the BrowserWebDriverContainer, like this:

  @Container
  static final BrowserWebDriverContainer BROWSER_CONTAINER = new BrowserWebDriverContainer("selenium/standalone-chrome:4")
      .withCapabilities(getChromeOptions())
      .withRecordingMode(VncRecordingMode.RECORD_FAILING, getFileLocation());

But this always ends up throwing a TimeoutException, for reasons I don't understand.

15:13:51.867 [main] DEBUG 🐳 [selenium/standalone-chrome:4] - Wait strategy threw an exception
org.rnorth.ducttape.TimeoutException: java.util.concurrent.TimeoutException
	at org.rnorth.ducttape.timeouts.Timeouts.callFuture(Timeouts.java:70)
	at org.rnorth.ducttape.timeouts.Timeouts.doWithTimeout(Timeouts.java:60)
	at org.testcontainers.containers.wait.strategy.WaitAllStrategy.waitUntilReady(WaitAllStrategy.java:53)
	at org.testcontainers.containers.GenericContainer.waitUntilContainerStarted(GenericContainer.java:892)
	at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:440)
	at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:325)
	at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
	at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:323)
	at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:311)
	at org.testcontainers.junit.jupiter.TestcontainersExtension$StoreAdapter.start(TestcontainersExtension.java:242)
	at org.testcontainers.junit.jupiter.TestcontainersExtension$StoreAdapter.access$200(TestcontainersExtension.java:229)
	at org.testcontainers.junit.jupiter.TestcontainersExtension.lambda$null$1(TestcontainersExtension.java:59)
	at org.junit.jupiter.engine.execution.ExtensionValuesStore.lambda$getOrComputeIfAbsent$0(ExtensionValuesStore.java:80)
	at org.junit.jupiter.engine.execution.ExtensionValuesStore$MemoizingSupplier.get(ExtensionValuesStore.java:185)
	at org.junit.jupiter.engine.execution.ExtensionValuesStore.getOrComputeIfAbsent(ExtensionValuesStore.java:87)
	at org.junit.jupiter.engine.execution.NamespaceAwareStore.getOrComputeIfAbsent(NamespaceAwareStore.java:53)
	at org.testcontainers.junit.jupiter.TestcontainersExtension.lambda$beforeAll$2(TestcontainersExtension.java:59)
	at java.util.ArrayList.forEach(ArrayList.java:1259)
	at org.testcontainers.junit.jupiter.TestcontainersExtension.beforeAll(TestcontainersExtension.java:59)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$invokeBeforeAllCallbacks$8(ClassTestDescriptor.java:361)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.invokeBeforeAllCallbacks(ClassTestDescriptor.java:361)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.before(ClassTestDescriptor.java:197)
	at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.before(ClassTestDescriptor.java:77)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:120)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:134)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:118)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:117)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
	at java.util.ArrayList.forEach(ArrayList.java:1259)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:134)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:120)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:134)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:118)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:117)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: java.util.concurrent.TimeoutException: null
	at java.util.concurrent.FutureTask.get(FutureTask.java:205)
	at org.rnorth.ducttape.timeouts.Timeouts.callFuture(Timeouts.java:65)
	... 53 common frames omitted
15:13:51.868 [main] DEBUG org.testcontainers.shaded.com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: bd3ae4d99c8bf93752cecc4637189bc93d9e74b678d6473dcc45a25f6e53dfe4,false
15:13:51.868 [main] DEBUG org.testcontainers.shaded.com.github.dockerjava.core.exec.InspectContainerCmdExec - GET: DefaultWebTarget{path=[/containers/bd3ae4d99c8bf93752cecc4637189bc93d9e74b678d6473dcc45a25f6e53dfe4/json], queryParams={}}
15:13:51.873 [main] ERROR 🐳 [selenium/standalone-chrome:4] - Could not start container

Thanks for any assistance and let me know if I can provide further info!

@artemkorsakov
Copy link

artemkorsakov commented Mar 12, 2021

I had the same problem, I have solved it like this (on Scala):

  private val logWaitStrategy: WaitStrategy =
    new LogMessageWaitStrategy()
      .withRegEx(
        ".*(RemoteWebDriver instances should connect to|Selenium Server is up and running|.*Started Selenium standalone.*).*\n"
      )
      .withStartupTimeout(Duration.of(15, SECONDS))

  private val waitStrategy = new WaitAllStrategy()
    .withStrategy(logWaitStrategy)
    .withStrategy(new HostPortWaitStrategy)
    .withStartupTimeout(Duration.of(15, SECONDS))

  container.setWaitStrategy(waitStrategy)

Problem is here and here

For Selenium 4 LogMessageWaitStrategy must be .withRegEx( ".*(RemoteWebDriver instances should connect to|Selenium Server is up and running|.*Started Selenium standalone.*).*\n"

And I disabled the startup checks: Add checks.disable=true to your $HOME/.testcontainers.properties to completely disable them.
When checks was enabled my tests crashed on mac after reruning - I had to restart docker.

@artemkorsakov
Copy link

artemkorsakov commented Apr 2, 2021

Full example:

import com.dimafeng.testcontainers.SingleContainer
import com.dimafeng.testcontainers.lifecycle.TestLifecycleAware
import com.github.dockerjava.api.model.Bind
import org.openqa.selenium.remote.{ DesiredCapabilities, RemoteWebDriver }
import org.testcontainers.containers.BrowserWebDriverContainer
import org.testcontainers.containers.wait.strategy._
import org.testcontainers.lifecycle.TestDescription
import org.testcontainers.utility.DockerImageName

import java.io.File
import java.time.Duration
import java.time.temporal.ChronoUnit.SECONDS
import java.util.Optional

case class SeleniumContainer(
    cap: DesiredCapabilities,
    recMode: Option[(BrowserWebDriverContainer.VncRecordingMode, File)] = None
) extends SingleContainer[BrowserWebDriverContainer[_]]
    with TestLifecycleAware {
  private val imageTag = "4.0.0-alpha-7-20201119"

  private val dockerImageName: Option[DockerImageName] =
    cap.getBrowserName.capitalize match {
      case "Chrome"  => Some(DockerImageName.parse("selenium/standalone-chrome").withTag(imageTag))
      case "Firefox" => Some(DockerImageName.parse("selenium/standalone-firefox").withTag(imageTag))
      case _         => None
    }

  private val logWaitStrategy: WaitStrategy =
    new LogMessageWaitStrategy()
      .withRegEx(
        ".*(RemoteWebDriver instances should connect to|Selenium Server is up and running|.*Started Selenium standalone.*).*\n"
      )
      .withStartupTimeout(Duration.of(15, SECONDS))

  private val waitStrategy = new WaitAllStrategy()
    .withStrategy(logWaitStrategy)
    .withStrategy(new HostPortWaitStrategy)
    .withStartupTimeout(Duration.of(15, SECONDS))

  override val container: BrowserWebDriverContainer[_] =
    dockerImageName
      .map(new BrowserWebDriverContainer(_))
      .getOrElse(new BrowserWebDriverContainer())

  container.setWaitStrategy(waitStrategy)
  container.withCapabilities(cap)
  recMode.foreach { case (recMode, recDir) => container.withRecordingMode(recMode, recDir) }

  def webDriver: RemoteWebDriver = container.getWebDriver

  override def afterTest(description: TestDescription, throwable: Option[Throwable]): Unit = {
    val javaThrowable: Optional[Throwable] = throwable match {
      case Some(error) => Optional.of(error)
      case None        => Optional.empty()
    }
    container.afterTest(description, javaThrowable)
    container.setBinds(new java.util.ArrayList[Bind]())
  }

}

And Suite:

import com.dimafeng.testcontainers.ForEachTestContainer
import org.openqa.selenium.WebDriver
import org.openqa.selenium.remote.DesiredCapabilities
import org.scalatest.Suite
import org.testcontainers.containers.BrowserWebDriverContainer
import org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode

import java.io.File

trait SeleniumContainerSuite extends ForEachTestContainer { self: Suite =>

  private val desiredCapabilities: DesiredCapabilities = new DesiredCapabilities(new ChromeOptions)

  private val recordingMode: Option[(BrowserWebDriverContainer.VncRecordingMode, File)] = Some((VncRecordingMode.RECORD_FAILING, new File("some dir")))

  val container: SeleniumContainer = SeleniumContainer(desiredCapabilities, recordingMode)

  implicit def webDriver: WebDriver = container.webDriver

}
import org.openqa.selenium.WebDriver
import org.scalatest.flatspec.FixtureAnyFlatSpec
import org.scalatest.matchers.should.Matchers._
import org.scalatestplus.selenium.WebBrowser._

class SeleniumContainerSuiteSpec extends FixtureAnyFlatSpec with SeleniumContainerSuite {

  "Browser" should "show google" in { f =>
    implicit val wd: WebDriver = f.webDriver
    go to "https://www.google.com/"
  }

  it should "reuse webDriver" in { f =>
    implicit val wd: WebDriver = f.webDriver
    go to "https://www.google.com/"
  }

}

@eddumelendez
Copy link
Member

There has been a lot of changes on BrowserWebDriverContainer and AFAICS, the wait strategy implemented is like the one suggested. Also, selenium 4 is GA so there should not be issues around it.

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

No branches or pull requests

3 participants