Skip to content

Commit

Permalink
proof of concept: playwright e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
SteffenDE committed Jan 10, 2024
1 parent 76859f6 commit 54baa74
Show file tree
Hide file tree
Showing 11 changed files with 447 additions and 4 deletions.
72 changes: 70 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ jobs:

npm_test:
name: npm test

strategy:
matrix:
include:
- elixir: 1.13.2
otp: 24.2

runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -85,8 +92,8 @@ jobs:
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: 1.13.2
otp-version: 24.2
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}

- name: Restore deps and _build cache
uses: actions/cache@v2
Expand Down Expand Up @@ -119,3 +126,64 @@ jobs:
cd assets
npm install
npm test
e2e_test:
name: e2e test

strategy:
matrix:
include:
- elixir: 1.16.0
otp: 26.2

runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.40.1-jammy
env:
ImageOS: ubuntu22
HOME: /root
steps:
- name: Checkout
uses: actions/checkout@v2

- name: install unzip
run: apt update && apt -y install unzip

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}

- name: Restore deps and _build cache
uses: actions/cache@v2
with:
path: |
deps
_build
key: deps-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
deps-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}
- name: Install dependencies
run: mix deps.get --only e2e

- name: Restore npm cache
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: npm install and test
run: |
npm install
npm run e2e:test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ phoenix_live_view-*.tar

node_modules

/test/e2e/test-results/
/playwright-report/
4 changes: 3 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ defmodule Phoenix.LiveView.MixProject do
]
end

defp elixirc_paths(:e2e), do: ["lib", "test/support"]
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]

Expand All @@ -49,7 +50,8 @@ defmodule Phoenix.LiveView.MixProject do
{:makeup_eex, ">= 0.1.1", only: :docs},
{:makeup_diff, "~> 0.1", only: :docs},
{:html_entities, ">= 0.0.0", only: :test},
{:phoenix_live_reload, "~> 1.4.1", only: :test}
{:phoenix_live_reload, "~> 1.4.1", only: :test},
{:plug_cowboy, "~> 2.6", only: :e2e}
]
end

Expand Down
5 changes: 5 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
%{
"castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"},
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
"earmark_parser": {:hex, :earmark_parser, "1.4.37", "2ad73550e27c8946648b06905a57e4d454e4d7229c2dafa72a0348c99d8be5f7", [:mix], [], "hexpm", "6b19783f2802f039806f375610faa22da130b8edc21209d0bff47918bb48360e"},
"esbuild": {:hex, :esbuild, "0.7.1", "fa0947e8c3c3c2f86c9bf7e791a0a385007ccd42b86885e8e893bdb6631f5169", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "66661cdf70b1378ee4dc16573fcee67750b59761b2605a0207c267ab9d19f13c"},
"ex_doc": {:hex, :ex_doc, "0.30.9", "d691453495c47434c0f2052b08dd91cc32bc4e1a218f86884563448ee2502dd2", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d7aaaf21e95dc5cddabf89063327e96867d00013963eadf2c6ad135506a8bc10"},
Expand All @@ -22,6 +25,8 @@
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
"phoenix_view": {:hex, :phoenix_view, "2.0.1", "a653e3d9d944aace0a064e4a13ad473ffa68f7bc4ca42dbf83cc1d464f1fb295", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "6c358e2cefc5f341c728914b867c556bbfd239fed9e881bac257d70cb2b8a6f6"},
"plug": {:hex, :plug, "1.15.1", "b7efd81c1a1286f13efb3f769de343236bd8b7d23b4a9f40d3002fc39ad8f74c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "459497bd94d041d98d948054ec6c0b76feacd28eec38b219ca04c0de13c79d30"},
"plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
}
75 changes: 75 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,12 @@
"package.json",
"priv/static/*",
"assets/js/phoenix_live_view/*"
]
],
"devDependencies": {
"@playwright/test": "^1.40.1"
},
"scripts": {
"e2e:server": "MIX_ENV=e2e iex -S mix run test/e2e/test_helper.exs",
"e2e:test": "cd test/e2e && npx playwright test"
}
}
40 changes: 40 additions & 0 deletions test/e2e/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// playwright.config.js
// @ts-check
const { devices } = require("@playwright/test");

/** @type {import("@playwright/test").PlaywrightTestConfig} */
const config = {
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? [["github"], ["html"]] : "list",
use: {
trace: "retain-on-failure",
screenshot: "only-on-failure",
baseURL: "http://localhost:4000/",
ignoreHTTPSErrors: true,
},
webServer: {
command: "npm run e2e:server",
url: "http://127.0.0.1:4000/health",
reuseExistingServer: !process.env.CI,
stdout: "pipe",
stderr: "pipe",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
}
],
outputDir: "test-results"
};

module.exports = config;
79 changes: 79 additions & 0 deletions test/e2e/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
Application.put_env(:phoenix_live_view, Phoenix.LiveViewTest.E2E.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 4000],
# TODO: switch to bandit when Phoenix 1.7 is used
# adapter: Bandit.PhoenixAdapter,
server: true,
live_view: [signing_salt: "aaaaaaaa"],
secret_key_base: String.duplicate("a", 64),
render_errors: [
# TODO: uncomment when LV Phoenix 1.7 is used
# formats: [
# html: Phoenix.LiveViewTest.E2E.ErrorHTML,
# ],
view: Phoenix.LiveViewTest.E2E.ErrorHTML,
layout: false
],
debug_errors: true
)

defmodule Phoenix.LiveViewTest.E2E.ErrorHTML do
def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end

defmodule Phoenix.LiveViewTest.E2E.Layout do
use Phoenix.Component

def render("live.html", assigns) do
~H"""
<script src="/assets/phoenix/phoenix.min.js"></script>
<script src="/assets/phoenix_live_view/phoenix_live_view.js"></script>
<script>
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
liveSocket.connect()
</script>
<style>
* { font-size: 1.1em; }
</style>
<%= @inner_content %>
"""
end
end

defmodule Phoenix.LiveViewTest.E2E.Router do
use Phoenix.Router
import Phoenix.LiveView.Router

pipeline :browser do
plug(:accepts, ["html"])
end

live_session :default, layout: {Phoenix.LiveViewTest.E2E.Layout, :live} do
scope "/" do
pipe_through(:browser)

live("/stream", Phoenix.LiveViewTest.StreamLive, :index)
end
end
end

defmodule Phoenix.LiveViewTest.E2E.Endpoint do
use Phoenix.Endpoint, otp_app: :phoenix_live_view

socket("/live", Phoenix.LiveView.Socket)

plug Plug.Static, from: {:phoenix, "priv/static"}, at: "/assets/phoenix"
plug Plug.Static, from: {:phoenix_live_view, "priv/static"}, at: "/assets/phoenix_live_view"

plug :health_check

plug Phoenix.LiveViewTest.E2E.Router

defp health_check(%{request_path: "/health"} = conn, _opts) do
conn |> Plug.Conn.send_resp(200, "OK") |> Plug.Conn.halt()
end

defp health_check(conn, _opts), do: conn
end

{:ok, _} = Supervisor.start_link([Phoenix.LiveViewTest.E2E.Endpoint], strategy: :one_for_one)
Process.sleep(:infinity)
Loading

0 comments on commit 54baa74

Please sign in to comment.