From cf21bf76807e5e9bf40c1f062718f7260ddcdba4 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Wed, 7 Oct 2026 17:48:13 +0400 Subject: [PATCH] Start Volt's application before the shared test browser The browser a test run shares lives under Volt.Supervisor, which a project depending on Volt with runtime: false has not started, so its browser tests failed unless test_helper.exs started Volt itself. --- CHANGELOG.md | 6 ++++++ guides/features/testing.md | 2 +- lib/volt/test/browser/supervisor.ex | 18 +++++++++++++----- test/volt/test/browser_runner_test.exs | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17e94d0..c69b034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixed + +- Start Volt's application before the browser a test run shares, which lives under its supervisor. A project that depends on Volt with `runtime: false` had to start it in `test_helper.exs`, or browser tests failed with `Volt.Supervisor` not running. + ## 0.22.0 - 2026-10-07 ### Added diff --git a/guides/features/testing.md b/guides/features/testing.md index be5f38e..41fd6b0 100644 --- a/guides/features/testing.md +++ b/guides/features/testing.md @@ -311,7 +311,7 @@ npx playwright install chromium By default Volt uses `node_modules/playwright/cli.js` when present, otherwise `playwright` from `PATH`. Pass PlaywrightEx supervisor options with `playwright: [...]` if your executable lives elsewhere. -A test run shares one browser, launched the first time a test needs it, and every test gets a browser context of its own, so tests do not see each other's storage, cookies or pages. The ExUnit modules Volt generates for browser tests are `async: true`. +A test run shares one browser, launched the first time a test needs it, and every test gets a browser context of its own, so tests do not see each other's storage, cookies or pages. The ExUnit modules Volt generates for browser tests are `async: true`. The browser runs under Volt's application, which the first browser test starts if the project has not, as with a `runtime: false` dependency. ## ExUnit integration diff --git a/lib/volt/test/browser/supervisor.ex b/lib/volt/test/browser/supervisor.ex index 0251e46..0a8a56f 100644 --- a/lib/volt/test/browser/supervisor.ex +++ b/lib/volt/test/browser/supervisor.ex @@ -15,13 +15,21 @@ defmodule Volt.Test.Browser.Supervisor do @playwright Volt.Test.Browser.Playwright - @doc "Start the tree, or find it already running." + @doc """ + Start the tree, or find it already running. + + The tree lives under `Volt.Supervisor`, so Volt's application is started + first: a project that depends on Volt with `runtime: false` has not started + it. + """ @spec start(Config.t()) :: {:ok, pid()} | {:error, term()} def start(%Config{} = config) do - case Supervisor.start_child(Volt.Supervisor, {__MODULE__, config}) do - {:ok, pid} -> {:ok, pid} - {:error, {:already_started, pid}} -> {:ok, pid} - {:error, reason} -> {:error, reason} + with {:ok, _started} <- Application.ensure_all_started(:volt) do + case Supervisor.start_child(Volt.Supervisor, {__MODULE__, config}) do + {:ok, pid} -> {:ok, pid} + {:error, {:already_started, pid}} -> {:ok, pid} + {:error, reason} -> {:error, reason} + end end end diff --git a/test/volt/test/browser_runner_test.exs b/test/volt/test/browser_runner_test.exs index 8d2a6be..f9dcc0c 100644 --- a/test/volt/test/browser_runner_test.exs +++ b/test/volt/test/browser_runner_test.exs @@ -39,6 +39,24 @@ defmodule Volt.Test.BrowserRunnerTest do assert :ok = apply(module, name, [%{}]) end + test "starts Volt's application for a project that does not", %{tmp_dir: tmp_dir} do + file = + write!(tmp_dir, "stopped.browser.test.ts", ~TS""" + import { test, expect } from 'volt:test' + + test('runs', () => { + expect(document.body).toBeTruthy() + }) + """) + + config = Volt.Test.Config.read(browser: true, root: tmp_dir) + :ok = Application.stop(:volt) + on_exit(fn -> Application.ensure_all_started(:volt) end) + + assert {:ok, %Result{status: :passed}} = + Volt.Test.BrowserRunner.run_test(file, 1, config: config) + end + test "browser test modules run concurrently", %{tmp_dir: tmp_dir} do write!(tmp_dir, "async.browser.test.ts", ~TS""" import { test, expect } from 'volt:test'