Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,67 @@ private[scalajslib] object JsEnvConfig {
case class FirefoxOptions(headless: Boolean) extends Capabilities
case class SafariOptions() extends Capabilities
}

final case class Playwright(
capabilities: Playwright.Capabilities
) extends JsEnvConfig
object Playwright {
sealed trait Capabilities
case class ChromeOptions(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
launchOptions: List[String] = List(
"--disable-extensions",
"--disable-web-security",
"--allow-running-insecure-content",
"--disable-site-isolation-trials",
"--allow-file-access-from-files",
"--disable-gpu"
)
) extends Capabilities:

def addLaunchOptions(options: List[String]): ChromeOptions =
copy(launchOptions = (launchOptions ++ options).distinct)

object ChromeOptions:
val default = ChromeOptions()

case class FirefoxOptions(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
firefoxUserPrefs: Map[String, String | Double | Boolean] = Map(
"security.mixed_content.block_active_content" -> false,
"security.mixed_content.upgrade_display_content" -> false,
"security.file_uri.strict_origin_policy" -> false
)
) extends Capabilities:

def addFirefoxUserPrefs(options: Map[String, String | Double | Boolean])
: FirefoxOptions =
copy(firefoxUserPrefs = (firefoxUserPrefs ++ options))

object FirefoxOptions:
val default = FirefoxOptions()

case class WebkitOptions(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
launchOptions: List[String] = List(
"--disable-extensions",
"--disable-web-security",
"--allow-running-insecure-content",
"--disable-site-isolation-trials",
"--allow-file-access-from-files"
)
) extends Capabilities:

def addLaunchOptions(options: List[String]): WebkitOptions =
copy(launchOptions = (launchOptions ++ options).distinct)

object WebkitOptions:
val default = WebkitOptions()
}
}
2 changes: 2 additions & 0 deletions libs/scalajslib/package.mill
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ object `package` extends MillStableScalaModule with BuildInfo {
),
BuildInfo.Value("scalajsEnvPhantomJs", formatDep(Deps.Scalajs_1.scalajsEnvPhantomjs)),
BuildInfo.Value("scalajsEnvSelenium", formatDep(Deps.Scalajs_1.scalajsEnvSelenium)),
BuildInfo.Value("scalajsEnvPlaywright", formatDep(Deps.Scalajs_1.scalajsEnvPlaywright)),
BuildInfo.Value("scalajsImportMap", formatDep(Deps.Scalajs_1.scalajsImportMap))
)
}
Expand All @@ -60,6 +61,7 @@ object `package` extends MillStableScalaModule with BuildInfo {
Deps.Scalajs_1.scalajsEnvExoegoJsdomNodejs,
Deps.Scalajs_1.scalajsEnvPhantomjs,
Deps.Scalajs_1.scalajsEnvSelenium,
Deps.Scalajs_1.scalajsEnvPlaywright,
Deps.Scalajs_1.scalajsImportMap
)
}
Expand Down
2 changes: 2 additions & 0 deletions libs/scalajslib/src/mill/scalajslib/ScalaJSModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ trait ScalaJSModule extends scalalib.ScalaModule with ScalaJSModuleApi { outer =
mvn"${ScalaJSBuildInfo.scalajsEnvPhantomJs}"
case _: JsEnvConfig.Selenium =>
mvn"${ScalaJSBuildInfo.scalajsEnvSelenium}"
case _: JsEnvConfig.Playwright =>
mvn"${ScalaJSBuildInfo.scalajsEnvPlaywright}"
}

Seq(dep)
Expand Down
146 changes: 146 additions & 0 deletions libs/scalajslib/src/mill/scalajslib/api/JsEnvConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ object JsEnvConfig {
implicit def rwExoegoJsDomNodeJs: RW[ExoegoJsDomNodeJs] = macroRW
implicit def rwPhantom: RW[Phantom] = macroRW
implicit def rwSelenium: RW[Selenium] = macroRW
implicit def rwPlaywright: RW[Playwright] = macroRW
implicit def rw: RW[JsEnvConfig] = macroRW

private given Root_JsEnvConfig: Mirrors.Root[JsEnvConfig] =
Expand Down Expand Up @@ -116,4 +117,149 @@ object JsEnvConfig {
new SafariOptions()
}
}

final class Playwright private (val capabilities: Playwright.Capabilities) extends JsEnvConfig
object Playwright {
implicit def rwCapabilities: RW[Capabilities] = macroRW

private given Root_Capabilities: Mirrors.Root[Capabilities] =
Mirrors.autoRoot[Capabilities]

def apply(capabilities: Capabilities): Playwright =
new Playwright(capabilities = capabilities)

sealed trait Capabilities

/**
* Default launch options for Chrome, directly derived from the scala-js-env-playwright implementation: https://github.com/ThijsBroersen/scala-js-env-playwright/blob/main/src/main/scala/jsenv/playwright/PlaywrightJSEnv.scala
*/
val defaultChromeLaunchOptions = List(
"--disable-extensions",
"--disable-web-security",
"--allow-running-insecure-content",
"--disable-site-isolation-trials",
"--allow-file-access-from-files",
"--disable-gpu"
)

def chrome(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
launchOptions: List[String] = defaultChromeLaunchOptions
): Playwright =
val options = ChromeOptions(
headless = headless,
showLogs = showLogs,
debug = debug,
launchOptions = launchOptions
)
new Playwright(options)

case class ChromeOptions(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
launchOptions: List[String] = defaultChromeLaunchOptions
) extends Capabilities {
def withHeadless(value: Boolean): ChromeOptions = copy(headless = value)
def withShowLogs(value: Boolean): ChromeOptions = copy(showLogs = value)
def withDebug(value: Boolean): ChromeOptions = copy(debug = value)
def withLaunchOptions(value: List[String]): ChromeOptions = copy(launchOptions = value)
}
object ChromeOptions:
implicit def rw: RW[ChromeOptions] = macroRW

/**
* Default Firefox user prefs, directly derived from the scala-js-env-playwright implementation: https://github.com/ThijsBroersen/scala-js-env-playwright/blob/main/src/main/scala/jsenv/playwright/PlaywrightJSEnv.scala
*/
val defaultFirefoxUserPrefs: Map[String, String | Double | Boolean] =
Map(
"security.mixed_content.block_active_content" -> false,
"security.mixed_content.upgrade_display_content" -> false,
"security.file_uri.strict_origin_policy" -> false
)

def firefox(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
firefoxUserPrefs: Map[String, String | Double | Boolean] = defaultFirefoxUserPrefs
): Playwright =
val options = FirefoxOptions(
headless = headless,
showLogs = showLogs,
debug = debug,
firefoxUserPrefs = firefoxUserPrefs
)
new Playwright(options)
case class FirefoxOptions(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
firefoxUserPrefs: Map[String, String | Double | Boolean] = defaultFirefoxUserPrefs
) extends Capabilities {
def withHeadless(value: Boolean): FirefoxOptions = copy(headless = value)
def withShowLogs(value: Boolean): FirefoxOptions = copy(showLogs = value)
def withDebug(value: Boolean): FirefoxOptions = copy(debug = value)
def withFirefoxUserPrefs(value: Map[String, String | Double | Boolean]): FirefoxOptions =
copy(firefoxUserPrefs = value)
}
object FirefoxOptions:
given upickle.default.ReadWriter[String | Double | Boolean] =
upickle.default.readwriter[ujson.Value].bimap[String | Double | Boolean](
{
case v: Boolean => upickle.default.writeJs(v)
case v: Double => upickle.default.writeJs(v)
case v: String => upickle.default.writeJs(v)
},
json =>
json.boolOpt
.orElse(
json.numOpt
).orElse(
json.strOpt.map(_.toString)
).getOrElse(throw new Exception("Invalid value"))
)
given rw: RW[FirefoxOptions] = macroRW

/**
* Default launch options for Webkit, directly derived from the scala-js-env-playwright implementation: https://github.com/ThijsBroersen/scala-js-env-playwright/blob/main/src/main/scala/jsenv/playwright/PlaywrightJSEnv.scala
*/
val defaultWebkitLaunchOptions = List(
"--disable-extensions",
"--disable-web-security",
"--allow-running-insecure-content",
"--disable-site-isolation-trials",
"--allow-file-access-from-files"
)
Comment on lines +229 to +235
Copy link
Member

Choose a reason for hiding this comment

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

Where do these options come from? Can you link some documentation to ease future maintenence?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are the defaults we currently have in the plugin. Shall I just add some documentation referring to the plugin repo?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, that helps maintaining them.

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 cannot find any docs related to using the jsEnvConfig task. Where shall we add something?

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 added refs to the plugin repo source in code docs.


def webkit(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
launchOptions: List[String] = defaultWebkitLaunchOptions
): Playwright =
val options = WebkitOptions(
headless = headless,
showLogs = showLogs,
debug = debug,
launchOptions = launchOptions
)
new Playwright(options)

case class WebkitOptions(
headless: Boolean = true,
showLogs: Boolean = false,
debug: Boolean = false,
launchOptions: List[String] = defaultWebkitLaunchOptions
) extends Capabilities {
def withHeadless(value: Boolean): WebkitOptions = copy(headless = value)
def withShowLogs(value: Boolean): WebkitOptions = copy(showLogs = value)
def withDebug(value: Boolean): WebkitOptions = copy(debug = value)
def withLaunchOptions(value: List[String]): WebkitOptions = copy(launchOptions = value)
}
object WebkitOptions:
implicit def rw: RW[WebkitOptions] = macroRW
}
}
24 changes: 24 additions & 0 deletions libs/scalajslib/src/mill/scalajslib/worker/ScalaJSWorker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,30 @@ private[scalajslib] class ScalaJSWorker(jobs: Int)
workerApi.JsEnvConfig.Selenium.SafariOptions()
}
)
case config: api.JsEnvConfig.Playwright =>
val options = config.capabilities match
case options: api.JsEnvConfig.Playwright.ChromeOptions =>
workerApi.JsEnvConfig.Playwright.ChromeOptions(
headless = options.headless,
showLogs = options.showLogs,
debug = options.debug,
launchOptions = options.launchOptions
)
case options: api.JsEnvConfig.Playwright.FirefoxOptions =>
workerApi.JsEnvConfig.Playwright.FirefoxOptions(
headless = options.headless,
showLogs = options.showLogs,
debug = options.debug,
firefoxUserPrefs = options.firefoxUserPrefs
)
case options: api.JsEnvConfig.Playwright.WebkitOptions =>
workerApi.JsEnvConfig.Playwright.WebkitOptions(
headless = options.headless,
showLogs = options.showLogs,
debug = options.debug,
launchOptions = options.launchOptions
)
workerApi.JsEnvConfig.Playwright(options)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ class ScalaJSWorkerImpl extends ScalaJSWorkerApi {
Phantom(config)
case config: JsEnvConfig.Selenium =>
Selenium(config)
case config: JsEnvConfig.Playwright =>
Playwright(config)
}

def jsEnvInput(report: Report): Seq[Input] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package mill.scalajslib.worker.jsenv

import mill.scalajslib.worker.api._

object Playwright {
def apply(config: JsEnvConfig.Playwright) = config.capabilities match
case options: JsEnvConfig.Playwright.ChromeOptions =>
io.github.thijsbroersen.jsenv.playwright.PlaywrightJSEnv.chrome(
headless = options.headless,
showLogs = options.showLogs,
debug = options.debug,
launchOptions = options.launchOptions
)
case options: JsEnvConfig.Playwright.FirefoxOptions =>
io.github.thijsbroersen.jsenv.playwright.PlaywrightJSEnv.firefox(
headless = options.headless,
showLogs = options.showLogs,
debug = options.debug,
firefoxUserPrefs = options.firefoxUserPrefs
)
case options: JsEnvConfig.Playwright.WebkitOptions =>
io.github.thijsbroersen.jsenv.playwright.PlaywrightJSEnv.webkit(
headless = options.headless,
showLogs = options.showLogs,
debug = options.debug,
launchOptions = options.launchOptions
)
}
2 changes: 2 additions & 0 deletions mill-build/src/millbuild/Deps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ object Deps {
mvn"org.scala-js::scalajs-env-phantomjs:1.0.0".withDottyCompat(scalaVersion)
val scalajsEnvSelenium =
mvn"org.scala-js::scalajs-env-selenium:1.1.1".withDottyCompat(scalaVersion)
val scalajsEnvPlaywright =
mvn"io.github.thijsbroersen::scala-js-env-playwright:0.2.3"
val scalajsSbtTestAdapter =
mvn"org.scala-js::scalajs-sbt-test-adapter:${scalaJsVersion}".withDottyCompat(scalaVersion)
val scalajsLinker =
Expand Down
Loading