diff --git a/.gitignore b/.gitignore index 2c86004..ad355bb 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ project/plugins/project/ .idea .metals .lh +.bloop .bsp .vscode .DS_Store diff --git a/src/main/scala/jsenv/playwright/CEComRun.scala b/src/main/scala/jsenv/playwright/CEComRun.scala index 85d6b3f..41e4f05 100644 --- a/src/main/scala/jsenv/playwright/CEComRun.scala +++ b/src/main/scala/jsenv/playwright/CEComRun.scala @@ -16,6 +16,8 @@ class CEComRun( override val pwConfig: Config, override val runConfig: RunConfig, override val input: Seq[Input], + override val launchOptions: List[String], + override val additionalLaunchOptions: List[String], onMessage: String => Unit ) extends JSComRun with Runner { @@ -27,7 +29,7 @@ class CEComRun( override protected def receivedMessage(msg: String): Unit = onMessage(msg) lazy val future: Future[Unit] = - jsRunPrg(browserName, headless, isComEnabled = true, None) + jsRunPrg(browserName, headless, isComEnabled = true, pwLaunchOptions) .use(_ => IO.unit) .unsafeToFuture() diff --git a/src/main/scala/jsenv/playwright/CERun.scala b/src/main/scala/jsenv/playwright/CERun.scala index 8dd50fd..6449e7d 100644 --- a/src/main/scala/jsenv/playwright/CERun.scala +++ b/src/main/scala/jsenv/playwright/CERun.scala @@ -14,12 +14,14 @@ class CERun( override val headless: Boolean, override val pwConfig: Config, override val runConfig: RunConfig, - override val input: Seq[Input] + override val input: Seq[Input], + override val launchOptions: List[String], + override val additionalLaunchOptions: List[String] ) extends JSRun with Runner { scribe.debug(s"Creating CERun for $browserName") lazy val future: Future[Unit] = - jsRunPrg(browserName, headless, isComEnabled = false, None) + jsRunPrg(browserName, headless, isComEnabled = false, pwLaunchOptions) .use(_ => IO.unit) .unsafeToFuture() diff --git a/src/main/scala/jsenv/playwright/PWEnv.scala b/src/main/scala/jsenv/playwright/PWEnv.scala index f099bb3..9c95567 100644 --- a/src/main/scala/jsenv/playwright/PWEnv.scala +++ b/src/main/scala/jsenv/playwright/PWEnv.scala @@ -9,12 +9,32 @@ import java.nio.file.Path import java.nio.file.Paths import scala.util.control.NonFatal +/** + * Playwright JS environment + * + * @param browserName + * browser name, options are "chromium", "chrome", "firefox", "webkit", default is "chromium" + * @param headless + * headless mode, default is true + * @param showLogs + * show logs, default is false + * @param debug + * debug mode, default is false + * @param pwConfig + * Playwright configuration + * @param launchOptions + * override launch options, if not provided default launch options are used + * @param additionalLaunchOptions + * additional launch options (added to (default) launch options) + */ class PWEnv( browserName: String = "chromium", headless: Boolean = true, showLogs: Boolean = false, debug: Boolean = false, - pwConfig: Config = Config() + pwConfig: Config = Config(), + launchOptions: List[String] = Nil, + additionalLaunchOptions: List[String] = Nil ) extends JSEnv { private lazy val validator = { @@ -27,7 +47,14 @@ class PWEnv( override def start(input: Seq[Input], runConfig: RunConfig): JSRun = { try { validator.validate(runConfig) - new CERun(browserName, headless, pwConfig, runConfig, input) + new CERun( + browserName, + headless, + pwConfig, + runConfig, + input, + launchOptions, + additionalLaunchOptions) } catch { case ve: java.lang.IllegalArgumentException => scribe.error(s"CEEnv.startWithCom failed with throw ve $ve") @@ -51,6 +78,8 @@ class PWEnv( pwConfig, runConfig, input, + launchOptions, + additionalLaunchOptions, onMessage ) } catch { @@ -66,13 +95,11 @@ class PWEnv( } object PWEnv { - final class Config private (val materialization: Config.Materialization) { + case class Config( + materialization: Config.Materialization = Config.Materialization.Temp + ) { import Config.Materialization - private def this() = this( - materialization = Config.Materialization.Temp - ) - /** * Materializes purely virtual files into a temp directory. * @@ -131,16 +158,9 @@ object PWEnv { def withMaterialization(materialization: Materialization): Config = copy(materialization = materialization) - - private def copy( - materialization: Config.Materialization = materialization - ): Config = { - new Config(materialization) - } } object Config { - def apply(): Config = new Config() abstract class Materialization private () object Materialization { @@ -153,4 +173,23 @@ object PWEnv { } } } + + val chromeLaunchOptions = List( + "--disable-extensions", + "--disable-web-security", + "--allow-running-insecure-content", + "--disable-site-isolation-trials", + "--allow-file-access-from-files", + "--disable-gpu" + ) + + val firefoxLaunchOptions = List("--disable-web-security") + + val webkitLaunchOptions = List( + "--disable-extensions", + "--disable-web-security", + "--allow-running-insecure-content", + "--disable-site-isolation-trials", + "--allow-file-access-from-files" + ) } diff --git a/src/main/scala/jsenv/playwright/PageFactory.scala b/src/main/scala/jsenv/playwright/PageFactory.scala index a846c64..920306e 100644 --- a/src/main/scala/jsenv/playwright/PageFactory.scala +++ b/src/main/scala/jsenv/playwright/PageFactory.scala @@ -8,7 +8,6 @@ import com.microsoft.playwright.BrowserType.LaunchOptions import com.microsoft.playwright.Page import com.microsoft.playwright.Playwright -import scala.jdk.CollectionConverters.seqAsJavaListConverter object PageFactory { def pageBuilder(browser: Browser): Resource[IO, Page] = { Resource.make(IO { @@ -22,7 +21,7 @@ object PageFactory { playwright: Playwright, browserName: String, headless: Boolean, - launchOptions: Option[LaunchOptions] = None + launchOptions: LaunchOptions ): Resource[IO, Browser] = Resource.make(IO { @@ -35,47 +34,11 @@ object PageFactory { playwright.webkit() case _ => throw new IllegalArgumentException("Invalid browser type") } - launchOptions match { - case Some(launchOptions) => - browserType.launch(launchOptions.setHeadless(headless)) - case None => - val launchOptions = browserName.toLowerCase match { - case "chromium" | "chrome" => - new BrowserType.LaunchOptions().setArgs( - List( - "--disable-extensions", - "--disable-web-security", - "--allow-running-insecure-content", - "--disable-site-isolation-trials", - "--allow-file-access-from-files", - "--disable-gpu" - ).asJava - ) - case "firefox" => - new BrowserType.LaunchOptions().setArgs( - List( - "--disable-web-security" - ).asJava - ) - case "webkit" => - new BrowserType.LaunchOptions().setArgs( - List( - "--disable-extensions", - "--disable-web-security", - "--allow-running-insecure-content", - "--disable-site-isolation-trials", - "--allow-file-access-from-files" - ).asJava - ) - case _ => throw new IllegalArgumentException("Invalid browser type") - } - val browser = browserType.launch(launchOptions.setHeadless(headless)) - scribe.info( - s"Creating browser ${browser.browserType().name()} version ${browser - .version()} with ${browser.hashCode()}" - ) - browser - } + val browser = browserType.launch(launchOptions.setHeadless(headless)) + scribe.info( + s"Creating browser ${browser.browserType().name()} version ${browser.version()} with ${browser.hashCode()}" + ) + browser })(browser => IO { scribe.debug(s"Closing browser with ${browser.hashCode()}") @@ -95,7 +58,7 @@ object PageFactory { def createPage( browserName: String, headless: Boolean, - launchOptions: Option[LaunchOptions] + launchOptions: LaunchOptions ): Resource[IO, Page] = for { playwright <- playWrightBuilder diff --git a/src/main/scala/jsenv/playwright/Runner.scala b/src/main/scala/jsenv/playwright/Runner.scala index f2ee254..6f5abb5 100644 --- a/src/main/scala/jsenv/playwright/Runner.scala +++ b/src/main/scala/jsenv/playwright/Runner.scala @@ -2,6 +2,7 @@ package jsenv.playwright import cats.effect.IO import cats.effect.Resource +import com.microsoft.playwright.BrowserType import com.microsoft.playwright.BrowserType.LaunchOptions import jsenv.playwright.PWEnv.Config import jsenv.playwright.PageFactory._ @@ -12,6 +13,7 @@ import org.scalajs.jsenv.RunConfig import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic.AtomicBoolean import scala.concurrent.duration.DurationInt +import scala.jdk.CollectionConverters.seqAsJavaListConverter trait Runner { val browserName: String = "" // or provide actual values @@ -19,13 +21,15 @@ trait Runner { val pwConfig: Config = Config() // or provide actual values val runConfig: RunConfig = RunConfig() // or provide actual values val input: Seq[Input] = Seq.empty // or provide actual values + val launchOptions: List[String] = Nil + val additionalLaunchOptions: List[String] = Nil // enableCom is false for CERun and true for CEComRun protected val enableCom = false protected val intf = "this.scalajsPlayWrightInternalInterface" protected val sendQueue = new ConcurrentLinkedQueue[String] // receivedMessage is called only from JSComRun. Hence its implementation is empty in CERun - protected def receivedMessage(msg: String): Unit + protected def receivedMessage(msg: String): Unit var wantToClose = new AtomicBoolean(false) // List of programs // 1. isInterfaceUp() @@ -47,7 +51,7 @@ trait Runner { browserName: String, headless: Boolean, isComEnabled: Boolean, - launchOptions: Option[LaunchOptions] + launchOptions: LaunchOptions ): Resource[IO, Unit] = for { _ <- Resource.pure( scribe.info( @@ -123,6 +127,29 @@ trait Runner { } } + protected lazy val pwLaunchOptions = + browserName.toLowerCase() match { + case "chromium" | "chrome" => + new BrowserType.LaunchOptions().setArgs( + if (launchOptions.isEmpty) + (PWEnv.chromeLaunchOptions ++ additionalLaunchOptions).asJava + else (launchOptions ++ additionalLaunchOptions).asJava + ) + case "firefox" => + new BrowserType.LaunchOptions().setArgs( + if (launchOptions.isEmpty) + (PWEnv.firefoxLaunchOptions ++ additionalLaunchOptions).asJava + else (launchOptions ++ additionalLaunchOptions).asJava + ) + case "webkit" => + new BrowserType.LaunchOptions().setArgs( + if (launchOptions.isEmpty) + (PWEnv.webkitLaunchOptions ++ additionalLaunchOptions).asJava + else (launchOptions ++ additionalLaunchOptions).asJava + ) + case _ => throw new IllegalArgumentException("Invalid browser type") + } + } //private class WindowOnErrorException(errs: List[String]) diff --git a/src/test/scala/jsenv/playwright/PWSuiteChrome.scala b/src/test/scala/jsenv/playwright/PWSuiteChrome.scala index 08d1932..978648b 100644 --- a/src/test/scala/jsenv/playwright/PWSuiteChrome.scala +++ b/src/test/scala/jsenv/playwright/PWSuiteChrome.scala @@ -6,5 +6,5 @@ import org.scalajs.jsenv.test._ @RunWith(classOf[JSEnvSuiteRunner]) class PWSuiteChrome extends JSEnvSuite( - JSEnvSuiteConfig(new PWEnv("chrome", debug = true, headless = true)) + JSEnvSuiteConfig(new PWEnv("chrome", debug = false, headless = true)) ) diff --git a/src/test/scala/jsenv/playwright/PWSuiteFirefox.scala b/src/test/scala/jsenv/playwright/PWSuiteFirefox.scala index d929c47..3610b8b 100644 --- a/src/test/scala/jsenv/playwright/PWSuiteFirefox.scala +++ b/src/test/scala/jsenv/playwright/PWSuiteFirefox.scala @@ -6,5 +6,5 @@ import org.scalajs.jsenv.test._ @RunWith(classOf[JSEnvSuiteRunner]) class PWSuiteFirefox extends JSEnvSuite( - JSEnvSuiteConfig(new PWEnv("firefox", debug = true)) + JSEnvSuiteConfig(new PWEnv("firefox", debug = false, headless = true)) ) diff --git a/src/test/scala/jsenv/playwright/PWSuiteWebKit.scala b/src/test/scala/jsenv/playwright/PWSuiteWebKit.scala index 3b53cbf..60c1c30 100644 --- a/src/test/scala/jsenv/playwright/PWSuiteWebKit.scala +++ b/src/test/scala/jsenv/playwright/PWSuiteWebKit.scala @@ -1,9 +1,10 @@ -//package jsenv.playwright -// -//import org.junit.runner.RunWith -//import org.scalajs.jsenv.test._ -// -//@RunWith(classOf[JSEnvSuiteRunner]) -//class PWSuiteWebKit extends JSEnvSuite( -// JSEnvSuiteConfig(new PWEnv("webkit", debug = true)) -//) +// package jsenv.playwright + +// import org.junit.runner.RunWith +// import org.scalajs.jsenv.test._ + +// @RunWith(classOf[JSEnvSuiteRunner]) +// class PWSuiteWebKit +// extends JSEnvSuite( +// JSEnvSuiteConfig(new PWEnv("webkit", debug = false, headless = true)) +// )