Heroku throwing R14 (memory) errors when running Selenium tests

Viewed 88

I've been trying to get Selenium tests setup on Heroku. However, I've observed that when even a small test runs, Heroku throws R14 errors due to memory consumption.

I started trying to run these tests using free dynos and have upgraded up to the Standard 2X dynos and still see this issue. I can't imagine that these tests require more than 1GB of RAM to run. I suppose it's possible but I was interested in hearing other people's experiences with this and to see if anyone ran into similar issues and had solutions.

Locally the tests are super speedy and run fine. I know on the Heroku side that the buildpacks need to dynamically download chrome and the driver each time the tests are run so a little slowness there is to be expected.

A couple notes about my process:

  1. I'm using the Gradle wrapper to run the test script
  2. I'm running the Selenium test via the jUnit framework
  3. I'm using the heroku/google-chrome and heroku/chromedriver buildpacks

Here's my setup so you can see if I'm doing anything strange...

SeleniumConfig.kt

class SeleniumConfig {
    val driver: WebDriver

    init {
        val options = ChromeOptions()
        val driverFile = System.getenv("CHROME_DRIVER_PATH")
        val binary = System.getenv("GOOGLE_CHROME_BIN")

        options.apply {
            addArguments("--enable-javascript")
            addArguments("--start-maximized")
            addArguments("--incognito")
            addArguments("--headless")
            addArguments("--disable-gpu")
            addArguments("--no-sandbox")
        }

        val service = ChromeDriverService.Builder()
            .usingDriverExecutable(File(driverFile))
            .build()

        binary?.let { options.setBinary(it) }

        driver = ChromeDriver(service, options)
        driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS)
    }
}

BaseSeleniumTest.kt

open class BaseSeleniumTest(private val path: String) {
    companion object {
        const val DEFAULT_WAIT = 5000L
    }

    protected val config = SeleniumConfig()
    protected val driver: WebDriver
        get() = config.driver

    @BeforeEach
    fun setUp() {
        driver.get("https://<mysite>$path")
        implicitWait()
    }

    @AfterEach
    fun tearDown() {
        driver.close()
        driver.quit()
    }

    fun implicitWait() {
        driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT, TimeUnit.MILLISECONDS)
    }
}

SigninTest.kt

class SigninTest : BaseSeleniumTest("/signin") {

    @Test
    fun `Succeed signing in`() {
        val username = driver.findElement(By.name("email"))
        val password = driver.findElement(By.name("password"))
        username.sendKeys("test@test.com")
        password.sendKeys("password")
        username.submit()
        implicitWait()
    }

    @Test
    fun `Fail with invalid username`() {
        val username = driver.findElement(By.name("email"))
        val password = driver.findElement(By.name("password"))
        username.sendKeys("wrong")
        password.sendKeys("password")
        username.submit()
        implicitWait()
        assertEquals("Invalid email or password",
            driver.findElement(By.cssSelector(".form-error")).text)
    }

    @Test
    fun `Fail with invalid password`() {
        val username = driver.findElement(By.name("email"))
        val password = driver.findElement(By.name("password"))
        username.sendKeys("test@test.com")
        password.sendKeys("wrong")
        username.submit()
        implicitWait()
        assertEquals("Invalid email or password",
            driver.findElement(By.cssSelector(".form-error")).text)
    }
}

Any help that anyone could give me would be appreciated!

0 Answers
Related