diff --git a/core/src/main/scala/chekhov/ChekhovConfig.scala b/core/src/main/scala/chekhov/ChekhovConfig.scala index 3c2fdce..aa8b23e 100644 --- a/core/src/main/scala/chekhov/ChekhovConfig.scala +++ b/core/src/main/scala/chekhov/ChekhovConfig.scala @@ -81,6 +81,13 @@ final case class ChekhovConfig( browserInstallEnv: Map[String, String] = Map.empty, traceCapture: ArtifactCapture = ArtifactCapture.Off, videoCapture: ArtifactCapture = ArtifactCapture.Off, + // Launch a system browser instead of a Playwright-downloaded one: `executablePath` + // points at a browser binary, `channel` selects an installed channel (e.g. "chrome"). + // When either is set the pinned-browser-revision check is skipped. `launchArgs` are + // extra process args (e.g. "--no-sandbox" in sandboxed / NixOS environments). + executablePath: Option[String] = None, + channel: Option[String] = None, + launchArgs: List[String] = Nil, ) object ChekhovConfig: @@ -108,6 +115,19 @@ object ChekhovConfig: .orElse(sys.env.get("CHEKHOV_VIDEO_CAPTURE")) .flatMap(ArtifactCapture.fromString) .getOrElse(ArtifactCapture.Off), + executablePath = sys.props + .get("chekhov.executablePath") + .orElse(sys.env.get("CHEKHOV_EXECUTABLE_PATH")) + .filter(_.nonEmpty), + channel = sys.props + .get("chekhov.channel") + .orElse(sys.env.get("CHEKHOV_CHANNEL")) + .filter(_.nonEmpty), + launchArgs = sys.props + .get("chekhov.launchArgs") + .orElse(sys.env.get("CHEKHOV_LAUNCH_ARGS")) + .map(_.split("[,\\s]+").iterator.map(_.trim).filter(_.nonEmpty).toList) + .getOrElse(Nil), ) def layer(config: ChekhovConfig): ULayer[ChekhovConfig] = diff --git a/driver/src/main/scala/chekhov/driver/PlaywrightDriver.scala b/driver/src/main/scala/chekhov/driver/PlaywrightDriver.scala index 474097e..51002e2 100644 --- a/driver/src/main/scala/chekhov/driver/PlaywrightDriver.scala +++ b/driver/src/main/scala/chekhov/driver/PlaywrightDriver.scala @@ -20,9 +20,12 @@ object PlaywrightDriver: def launch(using Trace): ZIO[Scope & ChekhovConfig, ChekhovError, Browser] = for config <- ZIO.service[ChekhovConfig] - _ <- ZIO + // A system browser (executablePath / channel) needs no downloaded revision. + systemBrowser = config.executablePath.isDefined || config.channel.isDefined + _ <- ZIO .fromEither(PinnedPlaywright.requireBrowser(config.browser)) .mapError(p => ChekhovError.Driver(p.message)) + .unless(systemBrowser) // GitHub Actions / containers: Chromium needs the sandbox disabled. ci = sys.env.get("CI").contains("true") || sys.env.get("GITHUB_ACTIONS").contains("true") result <- conn.send( @@ -31,6 +34,11 @@ object PlaywrightDriver: Commands.BrowserTypeLaunch( headless = Some(config.headless), chromiumSandbox = if ci then Some(false) else None, + executablePath = config.executablePath, + channel = config.channel, + args = + if config.launchArgs.nonEmpty then Some(Json.Arr(config.launchArgs.map(Json.Str(_))*)) + else None, ), ) guid <- guidOf(result, "browser")