Setting up Wallaby with Docker Compose, Chrome and Selenium

I cannot remember. I have kind of given up on Wallaby. I get random failures when I do any tests that involve more than 10 interactions (which I really really need - I want to test entire workflows that can include up to 100 interactions in a single test). Here is my setup anyway (I stopped getting that error so maybe it will help you). The sanity tests pass reliably for me (since they do a small number of interactions):

sanity_test.exs

defmodule MyApp.WallabyTest do
  use MyAppWeb.WallabyCase, async: false

  feature "login allows good user", %{session: session} do
    session
    |> auth_user(session, "use@myapp.comr", "wallaby-user-password")
  end

  feature "login denies non-existent user", %{session: session} do
    session
    |> visit("#{@backend_url}session/new")
    |> find(@login_form, fn form ->
      form
      |> fill_in(@login_email_field, with: "a")
      |> fill_in(@login_password_field, with: "a")
      |> click(@login_submit_button)
    end)
    |> assert_has(css(".bg-red-100", text: "Wrong email or password"))
  end

  feature "frontend can be reached", %{session: session} do
    session
    |> visit("#{@frontend_url}")
    |> assert_has(css("#home-wrapper"))
  end
end

wallaby_case.ex

defmodule MyAppWeb.WallabyCase do
  @moduledoc """
  """

  use ExUnit.CaseTemplate

  using do
    quote do
      use Wallaby.Feature
      import Wallaby.{Browser, Query}

      alias MyAppWeb.Router.Helpers, as: Routes

      # absolute urls for backend and frontend
      @backend_url "http://localhost:4002/"
      @frontend_url "http://frontend:3000/"

      # wallaby elements for logging in
      @login_form css("form")
      @login_email_field text_field("Email")
      @login_password_field text_field("Password")
      @login_submit_button button("Sign In")

      defp auth_user(session, user, password) do
        session
        |> visit("#{@backend_url}session/new")
        |> find(@login_form, fn form ->
          form
          |> fill_in(@login_email_field, with: user)
          |> fill_in(@login_password_field, with: password)
          |> click(@login_submit_button)
        end)
        |> assert_has(css("#orders-table"))
      end

    end
  end

  setup tags do
    alias Ecto.Adapters.SQL.Sandbox
    alias MyApp.Accounts.User
    alias MyApp.{Repo, Seeds}

    unless tags[:async] do
      :ok = Sandbox.checkout(MyApp.Repo)
      Sandbox.mode(MyApp.Repo, {:shared, self()})
    end

    Seeds.run()

    %User{}
    |> User.changeset(%{
      email: "user@myapp.com",
      name: "user",
      password: "wallaby-user-password"
    })
    |> Repo.insert!()

    :ok
  end
end

docker-compose.override.yml

version: "3.8"
services:

  db:
    image: postgres:12.3
    env_file:
      - ./my-app-backend/docker/dev.env
    restart: always
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data

  backend:
    image: my-app-backend:local
    build:
      context: ./my-app-backend
      dockerfile: ./docker/Dockerfile.dev
    depends_on:
      - db
      - frontend # so the wallaby tests pass
    env_file:
      - ./my-app-backend/docker/dev.env
    ports:
      - "4000:4000"
    volumes:
      - /opt/my-app/assets/node_modules
      - ./my-app-backend/assets:/opt/my-app/assets:ro
      - ./my-app-backend/config:/opt/my-app/config:ro
      - ./my-app-backend/lib:/opt/my-app/lib:ro
      - ./my-app-backend/priv:/opt/my-app/priv
      - ./my-app-backend/test:/opt/my-app/test:ro
      - ./my-app-backend/seeds:/opt/my-app/seeds:ro
      - ./my-app-backend/mix.exs:/opt/my-app/mix.exs:ro
      - ./my-app-backend/mix.lock:/opt/my-app/mix.lock:ro
      - ./my-app-backend/docker/.iex.exs:/opt/my-app/.iex.exs:ro
      - ./my-app-backend/entrypoint.sh:/opt/my-app/entrypoint.sh:ro
      - ./my-app-backend/dev/support:/opt/my-app/dev/support:ro
      - ./.wallaby_screenshots:/opt/my-app/screenshots
    stdin_open: true
    tty: true

  frontend:
    image: my-app-frontend:local
    build:
      context: ./my-app-frontend
      dockerfile: ./docker/Dockerfile.dev
    env_file:
      - ./my-app-frontend/docker/dev.env
    ports:
      - "3000:3000"
    volumes:
      - ./my-app-frontend:/opt/my-app:ro
      - /opt/my-app/node_modules
    stdin_open: true
    tty: true


volumes:
  db-data:

my-app-backend/docker/Dockerfile.dev

# https://github.com/c0b/docker-elixir/wiki/use-observer
FROM elixir:latest

RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt update
RUN apt install -y git nodejs inotify-tools
RUN apt install -y chromium-driver

RUN mkdir -p /opt/my-app
WORKDIR /opt/my-app

RUN mix local.hex --force && \
  mix local.rebar --force && \
  mix archive.install --force hex phx_new

COPY mix.exs .
COPY mix.lock .

# copy the deps in dev environment for faster builds
COPY deps ./deps
RUN ["mix", "deps.get"]
RUN ["mix", "deps.compile"]

COPY assets ./assets
WORKDIR /opt/my-app/assets
RUN ["npm", "install"]

WORKDIR /opt/my-app

COPY config ./config
COPY lib ./lib
COPY seeds ./seeds
COPY priv ./priv
COPY test ./test
COPY dev/support ./dev/support

RUN ["mix", "compile"]

# compile deps in test environment for faster test runs when built
RUN export MIX_ENV=test && mix deps.compile

COPY ./entrypoint.sh ./entrypoint.sh
COPY docker/.iex.exs .iex.exs
COPY .iex.exs .
CMD ["/bin/bash", "entrypoint.sh"]

Note this is a setup for :dev environment only. I hope it helps you and I hope someone else can spot some problem with it.