Skip to content

Add tests for {node + jsdom, chrome, firefox, webworkers} #540

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

Merged
merged 2 commits into from
Sep 1, 2021
Merged
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
12 changes: 3 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,11 @@ jobs:
- name: Setup Scala
uses: japgolly/[email protected]

- name: Build
run: sbt -DCI=1 "++${{ matrix.scalaversion }}" package

- name: Test generate documentation
run: sbt -DCI=1 "++${{ matrix.scalaversion }}" doc

- name: Build examples
run: sbt -DCI=1 "++${{ matrix.scalaversion }}" example/compile
- name: Build and test
run: sbt -DCI=1 "++${{ matrix.scalaversion }}" test package doc

- name: Validate formatting
run: sbt -DCI=1 "++${{ matrix.scalaversion }}" scalafmtCheck
run: sbt -DCI=1 "++${{ matrix.scalaversion }}" dom/scalafmtCheck

- name: Validate api report
if: matrix.scalaversion != '2.11.12' && matrix.scalaversion != '3.0.1'
Expand Down
18 changes: 13 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ ThisBuild / organization := "org.scala-js"
ThisBuild / shellPrompt := ((s: State) => Project.extract(s).currentRef.project + "> ")
ThisBuild / versionScheme := Some("early-semver")

val root = Build.root
val scalafixRules = Build.scalafixRules
val dom = Build.dom
val example = Build.example
val readme = Build.readme
val root = Build.root
val scalafixRules = Build.scalafixRules
val dom = Build.dom
val testsShared = Build.testsShared
val testsWebworker = Build.testsWebworker
val testsChrome = Build.testsChrome
val testsFirefox = Build.testsFirefox
val testsNodeJsdom = Build.testsNodeJsdom
val example = Build.example
val readme = Build.readme

// TODO: Remove after dom project get it's own directory
Global / onLoad ~= (_.andThen("project root" :: _))
33 changes: 31 additions & 2 deletions prePR.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,43 @@ addCommandAlias("prePR", "+prePR_nonCross")

val prePR_nonCross = taskKey[Unit]("Performs all necessary work required before submitting a PR, for a single version of Scala.")

// Unfortunately we can't just call `root/Test/compile` because it doesn't take aggregation into account :(
ThisBuild / prePR_nonCross := Def.sequential(
root / clean,

Def.task {
(root / clean).value
(scalafixRules / clean).value
(dom / clean).value
(testsShared / clean).value
(testsWebworker / clean).value
(testsChrome / clean).value
(testsFirefox / clean).value
(testsNodeJsdom / clean).value
(example / clean).value
},

dom / Compile / scalafmt,
Def.taskDyn {
if (scalaVersion.value.startsWith("2."))
(dom / Compile / scalafix).toTask("")
else
Def.task[Unit]((dom / Compile / compile).value)
},
root / Compile / compile,

Def.task {
(testsShared / Test / compile).value
(testsWebworker / Test / compile).value
(testsChrome / Test / compile).value
(testsFirefox / Test / compile).value
(testsNodeJsdom / Test / compile).value
(example / Test / compile).value
},

Def.taskDyn {
if (scalaVersion.value.startsWith("2.12."))
Def.task[Unit]((readme / Compile / compile).value)
else
Def.task(())
},

).value
94 changes: 94 additions & 0 deletions project/Build.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import sbt._
import sbt.Keys._
import java.util.concurrent.TimeUnit
import org.openqa.selenium.{Capabilities, WebDriver}
import org.openqa.selenium.chrome.{ChromeDriver, ChromeOptions}
import org.openqa.selenium.firefox.{FirefoxOptions, FirefoxProfile}
import org.openqa.selenium.remote.server.{DriverFactory, DriverProvider}
import org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv
import org.scalajs.jsenv.selenium.SeleniumJSEnv
import org.scalajs.sbtplugin.ScalaJSJUnitPlugin
import org.scalajs.sbtplugin.ScalaJSPlugin
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
import sbtbuildinfo.BuildInfoPlugin
import sbtbuildinfo.BuildInfoPlugin.autoImport._
import scalafix.sbt.ScalafixPlugin
import scalafix.sbt.ScalafixPlugin.autoImport._
import scalatex.ScalatexReadme
Expand All @@ -21,6 +31,11 @@ object Build {
.aggregate(
scalafixRules,
dom,
testsShared,
testsWebworker,
testsChrome,
testsFirefox,
testsNodeJsdom,
example,
// readme, // This is a Scala 2.12 only module
)
Expand All @@ -43,6 +58,85 @@ object Build {
libraryDependencies += Dep.scalafixCore.value,
)

lazy val testsShared = project
.in(file("tests-shared"))
.dependsOn(dom)
.enablePlugins(ScalaJSPlugin, ScalaJSJUnitPlugin)
.configure(commonSettings, crossScala, preventPublication, moveTestLibsToCompile)

lazy val testsWebworker = project
.in(file("tests-webworker"))
.dependsOn(testsShared)
.enablePlugins(ScalaJSPlugin, ScalaJSJUnitPlugin, BuildInfoPlugin)
.configure(commonSettings, crossScala, preventPublication, moveTestLibsToCompile)
.settings(
buildInfoKeys := Seq[BuildInfoKey](
"wwJsPath" -> (Compile / fastOptJS / artifactPath).value.absolutePath,
),
buildInfoPackage := "org.scalajs.dom.tests.webworker",
scalaJSUseMainModuleInitializer := true,
)

def testsWebworkers: Project => Project = _
.dependsOn(testsWebworker)
.settings(
Test / test := {
val _ = (testsWebworker / Compile / fastOptJS).value
(Test / test).value
},
)

lazy val testsChrome = project
.in(file("tests-chrome"))
.dependsOn(testsShared % Test)
.enablePlugins(ScalaJSPlugin, ScalaJSJUnitPlugin)
.configure(commonSettings, crossScala, preventPublication, testsWebworkers)
.settings(
Test / jsEnv := {
System.setProperty("webdriver.chrome.silentOutput", "true")
val o = new ChromeOptions()
o.setHeadless(true)
o.addArguments("--allow-file-access-from-files")
val df = new DriverFactory {
private[this] val default = SeleniumJSEnv.Config().driverFactory
override def newInstance(c: Capabilities): WebDriver = {
val d = default.newInstance(c).asInstanceOf[ChromeDriver]
d.manage.timeouts.pageLoadTimeout(if (inCI) 10 else 1, TimeUnit.MINUTES)
d.manage.timeouts.setScriptTimeout(if (inCI) 10 else 1, TimeUnit.MINUTES)
d
}
override def registerDriverProvider(p: DriverProvider): Unit =
default.registerDriverProvider(p)
}
new SeleniumJSEnv(o, SeleniumJSEnv.Config().withDriverFactory(df))
},
)

lazy val testsFirefox = project
.in(file("tests-firefox"))
.dependsOn(testsShared % Test)
.enablePlugins(ScalaJSPlugin, ScalaJSJUnitPlugin)
.configure(commonSettings, crossScala, preventPublication, testsWebworkers)
.settings(
Test / jsEnv := {
val p = new FirefoxProfile()
p.setPreference("privacy.file_unique_origin", false)
val o = new FirefoxOptions()
o.setProfile(p)
o.setHeadless(true)
new SeleniumJSEnv(o)
},
)

lazy val testsNodeJsdom = project
.in(file("tests-node-jsdom"))
.dependsOn(testsShared % Test)
.enablePlugins(ScalaJSPlugin, ScalaJSJUnitPlugin)
.configure(commonSettings, crossScala, preventPublication)
.settings(
Test / jsEnv := new JSDOMNodeJSEnv,
)

lazy val example = project
.dependsOn(dom)
.enablePlugins(ScalaJSPlugin)
Expand Down
11 changes: 11 additions & 0 deletions project/Lib.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sbt._
import sbt.Keys._
import org.scalajs.sbtplugin.ScalaJSJUnitPlugin
import Dependencies._

object Lib {
Expand All @@ -22,6 +23,7 @@ object Lib {
case Some((2, 13)) => "-Wunused:imports,patvars,locals,implicits" :: Nil
case _ => Nil
}),
testOptions += Tests.Argument(TestFramework("com.novocode.junit.JUnitFramework"), "-v"),
)

def crossScala: Project => Project = _
Expand Down Expand Up @@ -100,4 +102,13 @@ object Lib {
else
sourceDir / "scala-old-collections"

def moveTestLibsToCompile: Project => Project =
_.settings(
libraryDependencies ~= { _.map(m =>
if (m.configurations.contains(Test.name))
m.withConfigurations(Some(Compile.name))
else
m
)},
)
}
4 changes: 4 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
libraryDependencies += "org.scala-js" %% "scalajs-env-jsdom-nodejs" % "1.1.0"
libraryDependencies += "org.scala-js" %% "scalajs-env-selenium" % "1.1.1"

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.30")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0")
addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.7")
addSbtPlugin("com.lihaoyi" % "scalatex-sbt-plugin" % "0.3.11")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.5.1")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.scalajs.dom.tests.chrome

import org.scalajs.dom.tests.shared._
import org.scalajs.dom.tests.webworker._

class ChromeTests extends SharedTests with WebWorkerTests
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.scalajs.dom.tests.firefox

import org.scalajs.dom.tests.shared._
import org.scalajs.dom.tests.webworker._

class FirefoxTests extends SharedTests with WebWorkerTests
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.scalajs.dom.tests.node.jsdom

import org.scalajs.dom.tests.shared._

class NodeJsdomTests extends SharedTests
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.scalajs.dom.tests.shared

import org.junit.Assert
import scala.concurrent._
import scala.util._
import scala.scalajs.js.timers._

object AsyncTesting {

type AsyncResult = Future[Try[Unit]]

implicit def global: ExecutionContext =
ExecutionContext.global

def async(run: => Future[Any]): AsyncResult = {
val p = Promise[Try[Unit]]()
val timeout = setTimeout(1200) {
p.tryComplete(Failure(new RuntimeException("Test timed out.")))
}
setTimeout(1) {
run.onComplete { ta =>
clearTimeout(timeout)
p.complete(Success(ta.map(_ => ())))
}
}
p.future
}

implicit final class AsyncFutureOps[A](private val self: Future[A]) extends AnyVal {
def tap(f: A => Any): Future[A] =
self.map { a => f(a); a }

def assertEquals(expect: A): Future[A] =
tap(Assert.assertEquals(expect, _))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.scalajs.dom.tests.shared

import java.util.UUID
import org.junit.Test
import org.scalajs.dom._
import org.scalajs.dom.raw._

trait SharedTests {
import SharedTests._

// https://github.com/scala-js/scala-js-dom/issues/411 - console doesn't work in web workers
@Test final def ConsoleLogTest(): Unit =
console.log("Testing console.log")

// https://github.com/scala-js/scala-js-dom/pull/432 - Avoid forcing evaluation of crypto
@Test final def CryptoNonStrictTest(): Unit = {
val _ = crypto.HashAlgorithm
}

@Test final def WindowIdbTest(): Unit =
window.indexedDB.foreach(testIdb)

}

object SharedTests {
def testIdb(idb: IDBFactory): Unit = {
val open = idb.open(UUID.randomUUID().toString())
open.onerror = (e: Event) => sys.error("idb open failed: " + e)
// TODO: Test properly in a different PR
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.scalajs.dom.tests.webworker

import org.scalajs.dom.raw._
import scala.concurrent._
import scala.scalajs.js
import scala.util.Success

final class Client(worker: Worker) {
import Protocol._

private var preInit = new js.Array[Message]
private var promises = new js.Array[Promise[String]]

worker.onmessage = (e: MessageEvent) => {
val m = e.data.asInstanceOf[Message]
if (m._1 == ServerStarted) {
preInit.foreach(worker.postMessage(_))
preInit = null
} else
promises(m._1).complete(Success(m._2))
}

def send(cmd: WebWorkerCmd): Future[String] = {
val id = promises.length
val p = Promise[String]()
val m = Message(id, cmd.id)
promises.push(p)
if (preInit eq null)
worker.postMessage(m)
else
preInit.push(m)
p.future
}
}

object Client {

def workerUrl: String =
"file://" + BuildInfo.wwJsPath

lazy val global =
new Client(new Worker(workerUrl))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.scalajs.dom.tests.webworker

import scala.scalajs.js

object Protocol {

type MsgId = Int
type Message = js.Tuple2[MsgId, String]

def Message(id: MsgId, data: String): Message =
js.Tuple2(id, data)

final val ServerStarted: MsgId = -1
}
Loading