defmodule AiDebug.BrowserWorkerMoxTest do use ExUnit.Case, async: true import Mox alias AiDebug.BrowserWorker # Make sure mocks are verified on exit setup :verify_on_exit! describe "BrowserWorker with Mox" do test "start_link/1 initializes browser worker with mocked browser" do # This test demonstrates how to use Mox with GenServer processes # In a real implementation, BrowserWorker would accept a browser module option # For demonstration, we'll test the browser interaction pattern browser_ref = make_ref() page_ref = make_ref() # Set up expectations AiDebug.BrowserMock |> expect(:launch, fn opts -> assert opts[:headless] == true assert opts[:browser] in [:chromium, :firefox, :webkit] {:ok, browser_ref} end) |> expect(:new_page, fn ^browser_ref -> {:ok, page_ref} end) # Simulate what BrowserWorker would do on initialization assert {:ok, ^browser_ref} = AiDebug.BrowserMock.launch(headless: true, browser: :chromium) assert {:ok, ^page_ref} = AiDebug.BrowserMock.new_page(browser_ref) end test "navigate/2 uses mocked browser to navigate to URL" do page_ref = make_ref() AiDebug.BrowserMock |> expect(:goto, fn ^page_ref, url, opts -> assert url == "https://example.com" assert opts[:wait_until] == "networkidle" {:ok, %{status: 200, url: url}} end) |> expect(:wait_for_selector, fn ^page_ref, "body", _opts -> :ok end) # Act assert {:ok, response} = AiDebug.BrowserMock.goto(page_ref, "https://example.com", wait_until: "networkidle") assert response.status == 200 assert :ok = AiDebug.BrowserMock.wait_for_selector(page_ref, "body", []) end test "screenshot/2 captures page screenshot" do page_ref = make_ref() screenshot_data = <<137, 80, 78, 71, 13, 10, 26, 10>> # PNG header AiDebug.BrowserMock |> expect(:screenshot, fn ^page_ref, opts -> assert opts[:full_page] == true assert opts[:type] == "png" {:ok, screenshot_data} end) # Act assert {:ok, data} = AiDebug.BrowserMock.screenshot(page_ref, full_page: true, type: "png" ) # Assert - verify it's a PNG assert data == screenshot_data assert byte_size(data) >= 8 end test "execute_script/2 runs JavaScript in page context" do page_ref = make_ref() AiDebug.BrowserMock |> expect(:evaluate, fn ^page_ref, script -> assert script == "document.title" {:ok, "Test Page Title"} end) |> expect(:evaluate, fn ^page_ref, script -> assert script == "window.location.href" {:ok, "https://example.com"} end) # Act - get page info assert {:ok, title} = AiDebug.BrowserMock.evaluate(page_ref, "document.title") assert {:ok, url} = AiDebug.BrowserMock.evaluate(page_ref, "window.location.href") # Assert assert title == "Test Page Title" assert url == "https://example.com" end test "complex user interaction flow" do page_ref = make_ref() # Set up a complex interaction flow AiDebug.BrowserMock |> expect(:wait_for_selector, fn ^page_ref, "#login-form", _opts -> :ok end) |> expect(:type, fn ^page_ref, "#username", "testuser", _opts -> :ok end) |> expect(:type, fn ^page_ref, "#password", "secret123", _opts -> :ok end) |> expect(:click, fn ^page_ref, "#submit-button", _opts -> :ok end) |> expect(:wait_for_selector, fn ^page_ref, ".dashboard", opts -> assert opts[:timeout] == 5000 :ok end) |> expect(:evaluate, fn ^page_ref, "document.querySelector('.welcome').textContent" -> {:ok, "Welcome, testuser!"} end) # Act - simulate login flow assert :ok = AiDebug.BrowserMock.wait_for_selector(page_ref, "#login-form", []) assert :ok = AiDebug.BrowserMock.type(page_ref, "#username", "testuser", []) assert :ok = AiDebug.BrowserMock.type(page_ref, "#password", "secret123", []) assert :ok = AiDebug.BrowserMock.click(page_ref, "#submit-button", []) assert :ok = AiDebug.BrowserMock.wait_for_selector(page_ref, ".dashboard", timeout: 5000) assert {:ok, welcome_text} = AiDebug.BrowserMock.evaluate(page_ref, "document.querySelector('.welcome').textContent") assert welcome_text == "Welcome, testuser!" end test "error handling with mocked browser" do page_ref = make_ref() AiDebug.BrowserMock |> expect(:goto, fn ^page_ref, "http://invalid.localhost", _opts -> {:error, :net_err_name_not_resolved} end) |> expect(:click, fn ^page_ref, "#non-existent", _opts -> {:error, :element_not_found} end) # Act & Assert assert {:error, :net_err_name_not_resolved} = AiDebug.BrowserMock.goto(page_ref, "http://invalid.localhost", []) assert {:error, :element_not_found} = AiDebug.BrowserMock.click(page_ref, "#non-existent", []) end end describe "Pattern for migrating from Mock to Mox" do test "demonstrates injection pattern for real implementation" do # In real code, you would modify BrowserWorker to accept a browser module: # # defmodule BrowserWorker do # def start_link(opts) do # browser_module = opts[:browser_module] || AiDebug.Browser # GenServer.start_link(__MODULE__, {browser_module, opts}) # end # end # # Then in tests: # {:ok, worker} = BrowserWorker.start_link(browser_module: AiDebug.BrowserMock) # This allows dependency injection for testing assert true end end end