From 3df0f7ba3a3db95db4ef858784c46076fdff8e3f Mon Sep 17 00:00:00 2001 From: Angelika Tyborska Date: Sat, 8 Jun 2024 10:17:05 +0200 Subject: [PATCH] Split demo projects into two to test lib works without one of the deps --- bin/smoke_test.exs | 15 +- demo/{ => demo_hound}/.formatter.exs | 0 demo/{ => demo_hound}/.gitignore | 0 demo/{ => demo_hound}/README.md | 0 demo/{ => demo_hound}/assets/js/app.js | 0 demo/{ => demo_hound}/assets/vendor/topbar.js | 0 demo/{ => demo_hound}/config/config.exs | 0 demo/{ => demo_hound}/config/dev.exs | 0 demo/{ => demo_hound}/config/prod.exs | 0 demo/{ => demo_hound}/config/runtime.exs | 0 demo/{ => demo_hound}/config/test.exs | 0 demo/{ => demo_hound}/lib/demo.ex | 0 demo/{ => demo_hound}/lib/demo/application.ex | 0 demo/{ => demo_hound}/lib/demo_web.ex | 0 .../demo_web/components/core_components.ex | 0 .../lib/demo_web/components/layouts.ex | 0 .../demo_web/components/layouts/app.html.heex | 0 .../components/layouts/root.html.heex | 0 .../lib/demo_web/controllers/error_html.ex | 0 .../lib/demo_web/controllers/error_json.ex | 0 .../demo_web/controllers/page_controller.ex | 0 .../lib/demo_web/controllers/page_html.ex | 0 .../page_html/dynamic_invalid.html.heex | 0 .../controllers/page_html/invalid.html.heex | 0 .../controllers/page_html/valid.html.heex | 0 .../{ => demo_hound}/lib/demo_web/endpoint.ex | 0 demo/{ => demo_hound}/lib/demo_web/router.ex | 0 .../lib/demo_web/telemetry.ex | 0 demo/demo_hound/mix.exs | 73 ++ demo/demo_hound/mix.lock | 35 + demo/{ => demo_hound}/priv/static/favicon.ico | Bin .../priv/static/images/logo.svg | 0 demo/{ => demo_hound}/priv/static/robots.txt | 0 .../demo_web/controllers/error_html_test.exs | 0 .../demo_web/controllers/error_json_test.exs | 0 .../test/demo_web/integration/pages_test.exs} | 2 +- .../test/support/conn_case.ex | 0 demo/demo_hound/test/test_helper.exs | 3 + demo/demo_wallaby/.formatter.exs | 5 + demo/demo_wallaby/.gitignore | 37 + demo/demo_wallaby/README.md | 18 + demo/demo_wallaby/assets/js/app.js | 44 ++ demo/demo_wallaby/assets/vendor/topbar.js | 165 +++++ demo/demo_wallaby/config/config.exs | 44 ++ demo/demo_wallaby/config/dev.exs | 67 ++ demo/demo_wallaby/config/prod.exs | 14 + demo/demo_wallaby/config/runtime.exs | 84 +++ demo/demo_wallaby/config/test.exs | 14 + demo/demo_wallaby/lib/demo.ex | 9 + demo/demo_wallaby/lib/demo/application.ex | 33 + demo/demo_wallaby/lib/demo_web.ex | 111 +++ .../demo_web/components/core_components.ex | 670 ++++++++++++++++++ .../lib/demo_web/components/layouts.ex | 5 + .../demo_web/components/layouts/app.html.heex | 3 + .../components/layouts/root.html.heex | 17 + .../lib/demo_web/controllers/error_html.ex | 19 + .../lib/demo_web/controllers/error_json.ex | 15 + .../demo_web/controllers/page_controller.ex | 15 + .../lib/demo_web/controllers/page_html.ex | 5 + .../page_html/dynamic_invalid.html.heex | 49 ++ .../controllers/page_html/invalid.html.heex | 32 + .../controllers/page_html/valid.html.heex | 35 + demo/demo_wallaby/lib/demo_web/endpoint.ex | 52 ++ demo/demo_wallaby/lib/demo_web/router.ex | 45 ++ demo/demo_wallaby/lib/demo_web/telemetry.ex | 69 ++ demo/{ => demo_wallaby}/mix.exs | 3 +- demo/{ => demo_wallaby}/mix.lock | 1 - demo/demo_wallaby/priv/static/favicon.ico | Bin 0 -> 152 bytes demo/demo_wallaby/priv/static/images/logo.svg | 6 + demo/demo_wallaby/priv/static/robots.txt | 5 + .../demo_web/controllers/error_html_test.exs | 14 + .../demo_web/controllers/error_json_test.exs | 12 + .../test/demo_web/integration/pages_test.exs} | 2 +- demo/demo_wallaby/test/support/conn_case.ex | 37 + demo/{ => demo_wallaby}/test/test_helper.exs | 1 - mix.exs | 2 +- 76 files changed, 1870 insertions(+), 17 deletions(-) rename demo/{ => demo_hound}/.formatter.exs (100%) rename demo/{ => demo_hound}/.gitignore (100%) rename demo/{ => demo_hound}/README.md (100%) rename demo/{ => demo_hound}/assets/js/app.js (100%) rename demo/{ => demo_hound}/assets/vendor/topbar.js (100%) rename demo/{ => demo_hound}/config/config.exs (100%) rename demo/{ => demo_hound}/config/dev.exs (100%) rename demo/{ => demo_hound}/config/prod.exs (100%) rename demo/{ => demo_hound}/config/runtime.exs (100%) rename demo/{ => demo_hound}/config/test.exs (100%) rename demo/{ => demo_hound}/lib/demo.ex (100%) rename demo/{ => demo_hound}/lib/demo/application.ex (100%) rename demo/{ => demo_hound}/lib/demo_web.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/components/core_components.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/components/layouts.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/components/layouts/app.html.heex (100%) rename demo/{ => demo_hound}/lib/demo_web/components/layouts/root.html.heex (100%) rename demo/{ => demo_hound}/lib/demo_web/controllers/error_html.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/controllers/error_json.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/controllers/page_controller.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/controllers/page_html.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex (100%) rename demo/{ => demo_hound}/lib/demo_web/controllers/page_html/invalid.html.heex (100%) rename demo/{ => demo_hound}/lib/demo_web/controllers/page_html/valid.html.heex (100%) rename demo/{ => demo_hound}/lib/demo_web/endpoint.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/router.ex (100%) rename demo/{ => demo_hound}/lib/demo_web/telemetry.ex (100%) create mode 100644 demo/demo_hound/mix.exs create mode 100644 demo/demo_hound/mix.lock rename demo/{ => demo_hound}/priv/static/favicon.ico (100%) rename demo/{ => demo_hound}/priv/static/images/logo.svg (100%) rename demo/{ => demo_hound}/priv/static/robots.txt (100%) rename demo/{ => demo_hound}/test/demo_web/controllers/error_html_test.exs (100%) rename demo/{ => demo_hound}/test/demo_web/controllers/error_json_test.exs (100%) rename demo/{test/demo_web/integration/pages_hound_test.exs => demo_hound/test/demo_web/integration/pages_test.exs} (97%) rename demo/{ => demo_hound}/test/support/conn_case.ex (100%) create mode 100644 demo/demo_hound/test/test_helper.exs create mode 100644 demo/demo_wallaby/.formatter.exs create mode 100644 demo/demo_wallaby/.gitignore create mode 100644 demo/demo_wallaby/README.md create mode 100644 demo/demo_wallaby/assets/js/app.js create mode 100644 demo/demo_wallaby/assets/vendor/topbar.js create mode 100644 demo/demo_wallaby/config/config.exs create mode 100644 demo/demo_wallaby/config/dev.exs create mode 100644 demo/demo_wallaby/config/prod.exs create mode 100644 demo/demo_wallaby/config/runtime.exs create mode 100644 demo/demo_wallaby/config/test.exs create mode 100644 demo/demo_wallaby/lib/demo.ex create mode 100644 demo/demo_wallaby/lib/demo/application.ex create mode 100644 demo/demo_wallaby/lib/demo_web.ex create mode 100644 demo/demo_wallaby/lib/demo_web/components/core_components.ex create mode 100644 demo/demo_wallaby/lib/demo_web/components/layouts.ex create mode 100644 demo/demo_wallaby/lib/demo_web/components/layouts/app.html.heex create mode 100644 demo/demo_wallaby/lib/demo_web/components/layouts/root.html.heex create mode 100644 demo/demo_wallaby/lib/demo_web/controllers/error_html.ex create mode 100644 demo/demo_wallaby/lib/demo_web/controllers/error_json.ex create mode 100644 demo/demo_wallaby/lib/demo_web/controllers/page_controller.ex create mode 100644 demo/demo_wallaby/lib/demo_web/controllers/page_html.ex create mode 100644 demo/demo_wallaby/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex create mode 100644 demo/demo_wallaby/lib/demo_web/controllers/page_html/invalid.html.heex create mode 100644 demo/demo_wallaby/lib/demo_web/controllers/page_html/valid.html.heex create mode 100644 demo/demo_wallaby/lib/demo_web/endpoint.ex create mode 100644 demo/demo_wallaby/lib/demo_web/router.ex create mode 100644 demo/demo_wallaby/lib/demo_web/telemetry.ex rename demo/{ => demo_wallaby}/mix.exs (94%) rename demo/{ => demo_wallaby}/mix.lock (97%) create mode 100644 demo/demo_wallaby/priv/static/favicon.ico create mode 100644 demo/demo_wallaby/priv/static/images/logo.svg create mode 100644 demo/demo_wallaby/priv/static/robots.txt create mode 100644 demo/demo_wallaby/test/demo_web/controllers/error_html_test.exs create mode 100644 demo/demo_wallaby/test/demo_web/controllers/error_json_test.exs rename demo/{test/demo_web/integration/pages_wallaby_test.exs => demo_wallaby/test/demo_web/integration/pages_test.exs} (96%) create mode 100644 demo/demo_wallaby/test/support/conn_case.ex rename demo/{ => demo_wallaby}/test/test_helper.exs (72%) diff --git a/bin/smoke_test.exs b/bin/smoke_test.exs index d97534c..01ebafc 100755 --- a/bin/smoke_test.exs +++ b/bin/smoke_test.exs @@ -13,17 +13,12 @@ check_output = fn (output, pattern) -> end end -demo_project_path = "./demo" -demo_test_files = - [ - "test/demo_web/integration/pages_wallaby_test.exs", - "test/demo_web/integration/pages_hound_test.exs" - ] +demo_project_paths = ["./demo/demo_hound", "./demo/demo_wallaby"] -Enum.each(demo_test_files, fn demo_test_file -> - IO.puts("checking #{demo_test_file}") +Enum.each(demo_project_paths, fn demo_project_path -> + IO.puts("checking #{demo_project_path}") - {output, 2} = System.cmd("mix", ["test", demo_test_file], cd: demo_project_path) + {output, 2} = System.cmd("mix", ["test", "test/demo_web/integration/pages_test.exs"], cd: demo_project_path) check_output.(output, ~r/3 (features|tests), 2 failures/) check_output.(output, "invalid page with accessibility errors") @@ -37,7 +32,7 @@ Enum.each(demo_test_files, fn demo_test_file -> check_output.(output, "1.

Angelika's Star Trek series ranking

") check_output.(output, "... and 10 more nodes") - IO.puts("ok #{demo_test_file}") + IO.puts("ok #{demo_project_path}") end) IO.puts("all ok") diff --git a/demo/.formatter.exs b/demo/demo_hound/.formatter.exs similarity index 100% rename from demo/.formatter.exs rename to demo/demo_hound/.formatter.exs diff --git a/demo/.gitignore b/demo/demo_hound/.gitignore similarity index 100% rename from demo/.gitignore rename to demo/demo_hound/.gitignore diff --git a/demo/README.md b/demo/demo_hound/README.md similarity index 100% rename from demo/README.md rename to demo/demo_hound/README.md diff --git a/demo/assets/js/app.js b/demo/demo_hound/assets/js/app.js similarity index 100% rename from demo/assets/js/app.js rename to demo/demo_hound/assets/js/app.js diff --git a/demo/assets/vendor/topbar.js b/demo/demo_hound/assets/vendor/topbar.js similarity index 100% rename from demo/assets/vendor/topbar.js rename to demo/demo_hound/assets/vendor/topbar.js diff --git a/demo/config/config.exs b/demo/demo_hound/config/config.exs similarity index 100% rename from demo/config/config.exs rename to demo/demo_hound/config/config.exs diff --git a/demo/config/dev.exs b/demo/demo_hound/config/dev.exs similarity index 100% rename from demo/config/dev.exs rename to demo/demo_hound/config/dev.exs diff --git a/demo/config/prod.exs b/demo/demo_hound/config/prod.exs similarity index 100% rename from demo/config/prod.exs rename to demo/demo_hound/config/prod.exs diff --git a/demo/config/runtime.exs b/demo/demo_hound/config/runtime.exs similarity index 100% rename from demo/config/runtime.exs rename to demo/demo_hound/config/runtime.exs diff --git a/demo/config/test.exs b/demo/demo_hound/config/test.exs similarity index 100% rename from demo/config/test.exs rename to demo/demo_hound/config/test.exs diff --git a/demo/lib/demo.ex b/demo/demo_hound/lib/demo.ex similarity index 100% rename from demo/lib/demo.ex rename to demo/demo_hound/lib/demo.ex diff --git a/demo/lib/demo/application.ex b/demo/demo_hound/lib/demo/application.ex similarity index 100% rename from demo/lib/demo/application.ex rename to demo/demo_hound/lib/demo/application.ex diff --git a/demo/lib/demo_web.ex b/demo/demo_hound/lib/demo_web.ex similarity index 100% rename from demo/lib/demo_web.ex rename to demo/demo_hound/lib/demo_web.ex diff --git a/demo/lib/demo_web/components/core_components.ex b/demo/demo_hound/lib/demo_web/components/core_components.ex similarity index 100% rename from demo/lib/demo_web/components/core_components.ex rename to demo/demo_hound/lib/demo_web/components/core_components.ex diff --git a/demo/lib/demo_web/components/layouts.ex b/demo/demo_hound/lib/demo_web/components/layouts.ex similarity index 100% rename from demo/lib/demo_web/components/layouts.ex rename to demo/demo_hound/lib/demo_web/components/layouts.ex diff --git a/demo/lib/demo_web/components/layouts/app.html.heex b/demo/demo_hound/lib/demo_web/components/layouts/app.html.heex similarity index 100% rename from demo/lib/demo_web/components/layouts/app.html.heex rename to demo/demo_hound/lib/demo_web/components/layouts/app.html.heex diff --git a/demo/lib/demo_web/components/layouts/root.html.heex b/demo/demo_hound/lib/demo_web/components/layouts/root.html.heex similarity index 100% rename from demo/lib/demo_web/components/layouts/root.html.heex rename to demo/demo_hound/lib/demo_web/components/layouts/root.html.heex diff --git a/demo/lib/demo_web/controllers/error_html.ex b/demo/demo_hound/lib/demo_web/controllers/error_html.ex similarity index 100% rename from demo/lib/demo_web/controllers/error_html.ex rename to demo/demo_hound/lib/demo_web/controllers/error_html.ex diff --git a/demo/lib/demo_web/controllers/error_json.ex b/demo/demo_hound/lib/demo_web/controllers/error_json.ex similarity index 100% rename from demo/lib/demo_web/controllers/error_json.ex rename to demo/demo_hound/lib/demo_web/controllers/error_json.ex diff --git a/demo/lib/demo_web/controllers/page_controller.ex b/demo/demo_hound/lib/demo_web/controllers/page_controller.ex similarity index 100% rename from demo/lib/demo_web/controllers/page_controller.ex rename to demo/demo_hound/lib/demo_web/controllers/page_controller.ex diff --git a/demo/lib/demo_web/controllers/page_html.ex b/demo/demo_hound/lib/demo_web/controllers/page_html.ex similarity index 100% rename from demo/lib/demo_web/controllers/page_html.ex rename to demo/demo_hound/lib/demo_web/controllers/page_html.ex diff --git a/demo/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex b/demo/demo_hound/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex similarity index 100% rename from demo/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex rename to demo/demo_hound/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex diff --git a/demo/lib/demo_web/controllers/page_html/invalid.html.heex b/demo/demo_hound/lib/demo_web/controllers/page_html/invalid.html.heex similarity index 100% rename from demo/lib/demo_web/controllers/page_html/invalid.html.heex rename to demo/demo_hound/lib/demo_web/controllers/page_html/invalid.html.heex diff --git a/demo/lib/demo_web/controllers/page_html/valid.html.heex b/demo/demo_hound/lib/demo_web/controllers/page_html/valid.html.heex similarity index 100% rename from demo/lib/demo_web/controllers/page_html/valid.html.heex rename to demo/demo_hound/lib/demo_web/controllers/page_html/valid.html.heex diff --git a/demo/lib/demo_web/endpoint.ex b/demo/demo_hound/lib/demo_web/endpoint.ex similarity index 100% rename from demo/lib/demo_web/endpoint.ex rename to demo/demo_hound/lib/demo_web/endpoint.ex diff --git a/demo/lib/demo_web/router.ex b/demo/demo_hound/lib/demo_web/router.ex similarity index 100% rename from demo/lib/demo_web/router.ex rename to demo/demo_hound/lib/demo_web/router.ex diff --git a/demo/lib/demo_web/telemetry.ex b/demo/demo_hound/lib/demo_web/telemetry.ex similarity index 100% rename from demo/lib/demo_web/telemetry.ex rename to demo/demo_hound/lib/demo_web/telemetry.ex diff --git a/demo/demo_hound/mix.exs b/demo/demo_hound/mix.exs new file mode 100644 index 0000000..9c36b25 --- /dev/null +++ b/demo/demo_hound/mix.exs @@ -0,0 +1,73 @@ +defmodule Demo.MixProject do + use Mix.Project + + def project do + [ + app: :demo, + version: "0.1.0", + elixir: "~> 1.13", + elixirc_paths: elixirc_paths(Mix.env()), + start_permanent: Mix.env() == :prod, + aliases: aliases(), + deps: deps() + ] + end + + # Configuration for the OTP application. + # + # Type `mix help compile.app` for more information. + def application do + [ + mod: {Demo.Application, []}, + extra_applications: [:logger, :runtime_tools] + ] + end + + # Specifies which paths to compile per environment. + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] + + # Specifies your project dependencies. + # + # Type `mix help deps` for examples and options. + defp deps do + [ + {:phoenix, "~> 1.7.11"}, + {:phoenix_html, "~> 4.0"}, + {:phoenix_live_reload, "~> 1.2", only: :dev}, + {:phoenix_live_view, "~> 0.20.2"}, + {:floki, ">= 0.30.0", only: :test}, + {:phoenix_live_dashboard, "~> 0.8.3"}, + {:esbuild, "~> 0.8", runtime: Mix.env() == :dev}, + {:telemetry_metrics, "~> 0.6"}, + {:telemetry_poller, "~> 1.0"}, + {:jason, "~> 1.2"}, + {:dns_cluster, "~> 0.1.1"}, + {:bandit, "~> 1.2"}, + {:hound, "~> 1.1", runtime: false, only: :test}, + {:a11y_audit, path: "../../", only: [:test]} + ] + end + + # Aliases are shortcuts or tasks specific to the current project. + # For example, to install project dependencies and perform other setup tasks, run: + # + # $ mix setup + # + # See the documentation for `Mix` for more info on aliases. + defp aliases do + [ + setup: ["deps.get", "assets.setup", "assets.build"], + "assets.setup": ["esbuild.install --if-missing"], + "assets.build": ["esbuild demo"], + "assets.deploy": [ + "esbuild demo --minify", + "phx.digest" + ], + test: [ + "assets.build", + "test" + ] + ] + end +end diff --git a/demo/demo_hound/mix.lock b/demo/demo_hound/mix.lock new file mode 100644 index 0000000..578441e --- /dev/null +++ b/demo/demo_hound/mix.lock @@ -0,0 +1,35 @@ +%{ + "bandit": {:hex, :bandit, "1.5.2", "ed0a41c43a9e529c670d0fd48371db4027e7b80d43b1942893e17deb8bed0540", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "35ddbdce7e8a2a3c6b5093f7299d70832a43ed2f4a1852885a61d334cab1b4ad"}, + "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, + "dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, + "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"}, + "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, + "hound": {:hex, :hound, "1.1.1", "d3afce4cf0f446331d9d00427e9eb74fa135c296b1d3745d4bbe2096ce259087", [:mix], [{:hackney, "~> 1.5", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8c6342b49f53bb0e5c51d5ecca18a8ce872c44da05a8ce6f828385ebd744fe2a"}, + "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, + "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, + "phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"}, + "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"}, + "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.14", "70fa101aa0539e81bed4238777498f6215e9dda3461bdaa067cad6908110c364", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "82f6d006c5264f979ed5eb75593d808bbe39020f20df2e78426f4f2d570e2402"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, + "plug": {:hex, :plug, "1.16.0", "1d07d50cb9bb05097fdf187b31cf087c7297aafc3fed8299aac79c128a707e47", [: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", "cbf53aa1f5c4d758a7559c0bd6d59e286c2be0c6a1fac8cc3eee2f638243b93e"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"}, + "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, + "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, + "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, +} diff --git a/demo/priv/static/favicon.ico b/demo/demo_hound/priv/static/favicon.ico similarity index 100% rename from demo/priv/static/favicon.ico rename to demo/demo_hound/priv/static/favicon.ico diff --git a/demo/priv/static/images/logo.svg b/demo/demo_hound/priv/static/images/logo.svg similarity index 100% rename from demo/priv/static/images/logo.svg rename to demo/demo_hound/priv/static/images/logo.svg diff --git a/demo/priv/static/robots.txt b/demo/demo_hound/priv/static/robots.txt similarity index 100% rename from demo/priv/static/robots.txt rename to demo/demo_hound/priv/static/robots.txt diff --git a/demo/test/demo_web/controllers/error_html_test.exs b/demo/demo_hound/test/demo_web/controllers/error_html_test.exs similarity index 100% rename from demo/test/demo_web/controllers/error_html_test.exs rename to demo/demo_hound/test/demo_web/controllers/error_html_test.exs diff --git a/demo/test/demo_web/controllers/error_json_test.exs b/demo/demo_hound/test/demo_web/controllers/error_json_test.exs similarity index 100% rename from demo/test/demo_web/controllers/error_json_test.exs rename to demo/demo_hound/test/demo_web/controllers/error_json_test.exs diff --git a/demo/test/demo_web/integration/pages_hound_test.exs b/demo/demo_hound/test/demo_web/integration/pages_test.exs similarity index 97% rename from demo/test/demo_web/integration/pages_hound_test.exs rename to demo/demo_hound/test/demo_web/integration/pages_test.exs index 3c9a958..6863ea8 100644 --- a/demo/test/demo_web/integration/pages_hound_test.exs +++ b/demo/demo_hound/test/demo_web/integration/pages_test.exs @@ -1,4 +1,4 @@ -defmodule DemoWeb.PagesHoundTest do +defmodule DemoWeb.PagesTest do use ExUnit.Case use Hound.Helpers diff --git a/demo/test/support/conn_case.ex b/demo/demo_hound/test/support/conn_case.ex similarity index 100% rename from demo/test/support/conn_case.ex rename to demo/demo_hound/test/support/conn_case.ex diff --git a/demo/demo_hound/test/test_helper.exs b/demo/demo_hound/test/test_helper.exs new file mode 100644 index 0000000..a036ff6 --- /dev/null +++ b/demo/demo_hound/test/test_helper.exs @@ -0,0 +1,3 @@ +ExUnit.start() +Application.put_env(:wallaby, :base_url, DemoWeb.Endpoint.url()) +{:ok, _} = Application.ensure_all_started(:hound) diff --git a/demo/demo_wallaby/.formatter.exs b/demo/demo_wallaby/.formatter.exs new file mode 100644 index 0000000..e945e12 --- /dev/null +++ b/demo/demo_wallaby/.formatter.exs @@ -0,0 +1,5 @@ +[ + import_deps: [:phoenix], + plugins: [Phoenix.LiveView.HTMLFormatter], + inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}"] +] diff --git a/demo/demo_wallaby/.gitignore b/demo/demo_wallaby/.gitignore new file mode 100644 index 0000000..16ccdc4 --- /dev/null +++ b/demo/demo_wallaby/.gitignore @@ -0,0 +1,37 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Temporary files, for example, from tests. +/tmp/ + +# Ignore package tarball (built via "mix hex.build"). +demo-*.tar + +# Ignore assets that are produced by build tools. +/priv/static/assets/ + +# Ignore digested assets cache. +/priv/static/cache_manifest.json + +# In case you use Node.js/npm, you want to ignore these. +npm-debug.log +/assets/node_modules/ + diff --git a/demo/demo_wallaby/README.md b/demo/demo_wallaby/README.md new file mode 100644 index 0000000..2591d47 --- /dev/null +++ b/demo/demo_wallaby/README.md @@ -0,0 +1,18 @@ +# Demo + +To start your Phoenix server: + + * Run `mix setup` to install and setup dependencies + * Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server` + +Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. + +Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). + +## Learn more + + * Official website: https://www.phoenixframework.org/ + * Guides: https://hexdocs.pm/phoenix/overview.html + * Docs: https://hexdocs.pm/phoenix + * Forum: https://elixirforum.com/c/phoenix-forum + * Source: https://github.com/phoenixframework/phoenix diff --git a/demo/demo_wallaby/assets/js/app.js b/demo/demo_wallaby/assets/js/app.js new file mode 100644 index 0000000..ced0434 --- /dev/null +++ b/demo/demo_wallaby/assets/js/app.js @@ -0,0 +1,44 @@ +// If you want to use Phoenix channels, run `mix help phx.gen.channel` +// to get started and then uncomment the line below. +// import "./user_socket.js" + +// You can include dependencies in two ways. +// +// The simplest option is to put them in assets/vendor and +// import them using relative paths: +// +// import "../vendor/some-package.js" +// +// Alternatively, you can `npm install some-package --prefix assets` and import +// them using a path starting with the package name: +// +// import "some-package" +// + +// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. +import "phoenix_html" +// Establish Phoenix Socket and LiveView configuration. +// import {Socket} from "phoenix" +// import {LiveSocket} from "phoenix_live_view" +// import topbar from "../vendor/topbar" + +// let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") +// let liveSocket = new LiveSocket("/live", Socket, { +// longPollFallbackMs: 2500, +// params: {_csrf_token: csrfToken} +// }) + +// Show progress bar on live navigation and form submits +// topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) +// window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) +// window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) + +// connect if there are any LiveViews on the page +// liveSocket.connect() + +// expose liveSocket on window for web console debug logs and latency simulation: +// >> liveSocket.enableDebug() +// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session +// >> liveSocket.disableLatencySim() +// window.liveSocket = liveSocket + diff --git a/demo/demo_wallaby/assets/vendor/topbar.js b/demo/demo_wallaby/assets/vendor/topbar.js new file mode 100644 index 0000000..4195727 --- /dev/null +++ b/demo/demo_wallaby/assets/vendor/topbar.js @@ -0,0 +1,165 @@ +/** + * @license MIT + * topbar 2.0.0, 2023-02-04 + * https://buunguyen.github.io/topbar + * Copyright (c) 2021 Buu Nguyen + */ +(function (window, document) { + "use strict"; + + // https://gist.github.com/paulirish/1579671 + (function () { + var lastTime = 0; + var vendors = ["ms", "moz", "webkit", "o"]; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = + window[vendors[x] + "RequestAnimationFrame"]; + window.cancelAnimationFrame = + window[vendors[x] + "CancelAnimationFrame"] || + window[vendors[x] + "CancelRequestAnimationFrame"]; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + })(); + + var canvas, + currentProgress, + showing, + progressTimerId = null, + fadeTimerId = null, + delayTimerId = null, + addEvent = function (elem, type, handler) { + if (elem.addEventListener) elem.addEventListener(type, handler, false); + else if (elem.attachEvent) elem.attachEvent("on" + type, handler); + else elem["on" + type] = handler; + }, + options = { + autoRun: true, + barThickness: 3, + barColors: { + 0: "rgba(26, 188, 156, .9)", + ".25": "rgba(52, 152, 219, .9)", + ".50": "rgba(241, 196, 15, .9)", + ".75": "rgba(230, 126, 34, .9)", + "1.0": "rgba(211, 84, 0, .9)", + }, + shadowBlur: 10, + shadowColor: "rgba(0, 0, 0, .6)", + className: null, + }, + repaint = function () { + canvas.width = window.innerWidth; + canvas.height = options.barThickness * 5; // need space for shadow + + var ctx = canvas.getContext("2d"); + ctx.shadowBlur = options.shadowBlur; + ctx.shadowColor = options.shadowColor; + + var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); + for (var stop in options.barColors) + lineGradient.addColorStop(stop, options.barColors[stop]); + ctx.lineWidth = options.barThickness; + ctx.beginPath(); + ctx.moveTo(0, options.barThickness / 2); + ctx.lineTo( + Math.ceil(currentProgress * canvas.width), + options.barThickness / 2 + ); + ctx.strokeStyle = lineGradient; + ctx.stroke(); + }, + createCanvas = function () { + canvas = document.createElement("canvas"); + var style = canvas.style; + style.position = "fixed"; + style.top = style.left = style.right = style.margin = style.padding = 0; + style.zIndex = 100001; + style.display = "none"; + if (options.className) canvas.classList.add(options.className); + document.body.appendChild(canvas); + addEvent(window, "resize", repaint); + }, + topbar = { + config: function (opts) { + for (var key in opts) + if (options.hasOwnProperty(key)) options[key] = opts[key]; + }, + show: function (delay) { + if (showing) return; + if (delay) { + if (delayTimerId) return; + delayTimerId = setTimeout(() => topbar.show(), delay); + } else { + showing = true; + if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); + if (!canvas) createCanvas(); + canvas.style.opacity = 1; + canvas.style.display = "block"; + topbar.progress(0); + if (options.autoRun) { + (function loop() { + progressTimerId = window.requestAnimationFrame(loop); + topbar.progress( + "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) + ); + })(); + } + } + }, + progress: function (to) { + if (typeof to === "undefined") return currentProgress; + if (typeof to === "string") { + to = + (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 + ? currentProgress + : 0) + parseFloat(to); + } + currentProgress = to > 1 ? 1 : to; + repaint(); + return currentProgress; + }, + hide: function () { + clearTimeout(delayTimerId); + delayTimerId = null; + if (!showing) return; + showing = false; + if (progressTimerId != null) { + window.cancelAnimationFrame(progressTimerId); + progressTimerId = null; + } + (function loop() { + if (topbar.progress("+.1") >= 1) { + canvas.style.opacity -= 0.05; + if (canvas.style.opacity <= 0.05) { + canvas.style.display = "none"; + fadeTimerId = null; + return; + } + } + fadeTimerId = window.requestAnimationFrame(loop); + })(); + }, + }; + + if (typeof module === "object" && typeof module.exports === "object") { + module.exports = topbar; + } else if (typeof define === "function" && define.amd) { + define(function () { + return topbar; + }); + } else { + this.topbar = topbar; + } +}.call(this, window, document)); diff --git a/demo/demo_wallaby/config/config.exs b/demo/demo_wallaby/config/config.exs new file mode 100644 index 0000000..11b682a --- /dev/null +++ b/demo/demo_wallaby/config/config.exs @@ -0,0 +1,44 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Config module. +# +# This configuration file is loaded before any dependency and +# is restricted to this project. + +# General application configuration +import Config + +config :demo, + generators: [timestamp_type: :utc_datetime] + +# Configures the endpoint +config :demo, DemoWeb.Endpoint, + url: [host: "localhost"], + adapter: Bandit.PhoenixAdapter, + render_errors: [ + formats: [html: DemoWeb.ErrorHTML, json: DemoWeb.ErrorJSON], + layout: false + ], + pubsub_server: Demo.PubSub, + live_view: [signing_salt: "w+ygebMg"] + +# Configure esbuild (the version is required) +config :esbuild, + version: "0.17.11", + demo: [ + args: + ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), + cd: Path.expand("../assets", __DIR__), + env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} + ] + +# Configures Elixir's Logger +config :logger, :console, + format: "$time $metadata[$level] $message\n", + metadata: [:request_id] + +# Use Jason for JSON parsing in Phoenix +config :phoenix, :json_library, Jason + +# Import environment specific config. This must remain at the bottom +# of this file so it overrides the configuration defined above. +import_config "#{config_env()}.exs" diff --git a/demo/demo_wallaby/config/dev.exs b/demo/demo_wallaby/config/dev.exs new file mode 100644 index 0000000..f110fb0 --- /dev/null +++ b/demo/demo_wallaby/config/dev.exs @@ -0,0 +1,67 @@ +import Config + +# For development, we disable any cache and enable +# debugging and code reloading. +# +# The watchers configuration can be used to run external +# watchers to your application. For example, we can use it +# to bundle .js and .css sources. +config :demo, DemoWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. + # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. + http: [ip: {127, 0, 0, 1}, port: 4000], + check_origin: false, + code_reloader: true, + debug_errors: true, + secret_key_base: "NHqcXYFD7uQAtDOjKUwFkkyhTmt4wcd5EYrxYf0aUNK5gbCEoQS/eHaRtEn9uYlQ", + watchers: [ + esbuild: {Esbuild, :install_and_run, [:demo, ~w(--sourcemap=inline --watch)]} + ] + +# ## SSL Support +# +# In order to use HTTPS in development, a self-signed +# certificate can be generated by running the following +# Mix task: +# +# mix phx.gen.cert +# +# Run `mix help phx.gen.cert` for more information. +# +# The `http:` config above can be replaced with: +# +# https: [ +# port: 4001, +# cipher_suite: :strong, +# keyfile: "priv/cert/selfsigned_key.pem", +# certfile: "priv/cert/selfsigned.pem" +# ], +# +# If desired, both `http:` and `https:` keys can be +# configured to run both http and https servers on +# different ports. + +# Watch static and templates for browser reloading. +config :demo, DemoWeb.Endpoint, + live_reload: [ + patterns: [ + ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$", + ~r"lib/demo_web/(controllers|live|components)/.*(ex|heex)$" + ] + ] + +# Enable dev routes for dashboard and mailbox +config :demo, dev_routes: true + +# Do not include metadata nor timestamps in development logs +config :logger, :console, format: "[$level] $message\n" + +# Set a higher stacktrace during development. Avoid configuring such +# in production as building large stacktraces may be expensive. +config :phoenix, :stacktrace_depth, 20 + +# Initialize plugs at runtime for faster development compilation +config :phoenix, :plug_init_mode, :runtime + +# Include HEEx debug annotations as HTML comments in rendered markup +config :phoenix_live_view, :debug_heex_annotations, true diff --git a/demo/demo_wallaby/config/prod.exs b/demo/demo_wallaby/config/prod.exs new file mode 100644 index 0000000..ff10aa9 --- /dev/null +++ b/demo/demo_wallaby/config/prod.exs @@ -0,0 +1,14 @@ +import Config + +# Note we also include the path to a cache manifest +# containing the digested version of static files. This +# manifest is generated by the `mix assets.deploy` task, +# which you should run after static files are built and +# before starting your production server. +config :demo, DemoWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" + +# Do not print debug messages in production +config :logger, level: :info + +# Runtime production configuration, including reading +# of environment variables, is done on config/runtime.exs. diff --git a/demo/demo_wallaby/config/runtime.exs b/demo/demo_wallaby/config/runtime.exs new file mode 100644 index 0000000..8100355 --- /dev/null +++ b/demo/demo_wallaby/config/runtime.exs @@ -0,0 +1,84 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/demo start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :demo, DemoWeb.Endpoint, server: true +end + +if config_env() == :prod do + # The secret key base is used to sign/encrypt cookies and other secrets. + # A default value is used in config/dev.exs and config/test.exs but you + # want to use a different value for prod and you most likely don't want + # to check this value into version control, so we use an environment + # variable instead. + secret_key_base = + System.get_env("SECRET_KEY_BASE") || + raise """ + environment variable SECRET_KEY_BASE is missing. + You can generate one by calling: mix phx.gen.secret + """ + + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + + config :demo, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY") + + config :demo, DemoWeb.Endpoint, + url: [host: host, port: 443, scheme: "https"], + http: [ + # Enable IPv6 and bind on all interfaces. + # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. + # See the documentation on https://hexdocs.pm/bandit/Bandit.html#t:options/0 + # for details about using IPv6 vs IPv4 and loopback vs public addresses. + ip: {0, 0, 0, 0, 0, 0, 0, 0}, + port: port + ], + secret_key_base: secret_key_base + + # ## SSL Support + # + # To get SSL working, you will need to add the `https` key + # to your endpoint configuration: + # + # config :demo, DemoWeb.Endpoint, + # https: [ + # ..., + # port: 443, + # cipher_suite: :strong, + # keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), + # certfile: System.get_env("SOME_APP_SSL_CERT_PATH") + # ] + # + # The `cipher_suite` is set to `:strong` to support only the + # latest and more secure SSL ciphers. This means old browsers + # and clients may not be supported. You can set it to + # `:compatible` for wider support. + # + # `:keyfile` and `:certfile` expect an absolute path to the key + # and cert in disk or a relative path inside priv, for example + # "priv/ssl/server.key". For all supported SSL configuration + # options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1 + # + # We also recommend setting `force_ssl` in your config/prod.exs, + # ensuring no data is ever sent via http, always redirecting to https: + # + # config :demo, DemoWeb.Endpoint, + # force_ssl: [hsts: true] + # + # Check `Plug.SSL` for all available options in `force_ssl`. +end diff --git a/demo/demo_wallaby/config/test.exs b/demo/demo_wallaby/config/test.exs new file mode 100644 index 0000000..14773f3 --- /dev/null +++ b/demo/demo_wallaby/config/test.exs @@ -0,0 +1,14 @@ +import Config + +# We don't run a server during test. If one is required, +# you can enable the server option below. +config :demo, DemoWeb.Endpoint, + http: [ip: {127, 0, 0, 1}, port: 4002], + secret_key_base: "D2jg+Cv2EmgPyq+gr/n6eT6RejYNCy/11TwlsdIBUb2Ipiux0Lx2JcpPxASdBKMJ", + server: true + +# Print only warnings and errors during test +config :logger, level: :warning + +# Initialize plugs at runtime for faster test compilation +config :phoenix, :plug_init_mode, :runtime diff --git a/demo/demo_wallaby/lib/demo.ex b/demo/demo_wallaby/lib/demo.ex new file mode 100644 index 0000000..3f1ac75 --- /dev/null +++ b/demo/demo_wallaby/lib/demo.ex @@ -0,0 +1,9 @@ +defmodule Demo do + @moduledoc """ + Demo keeps the contexts that define your domain + and business logic. + + Contexts are also responsible for managing your data, regardless + if it comes from the database, an external API or others. + """ +end diff --git a/demo/demo_wallaby/lib/demo/application.ex b/demo/demo_wallaby/lib/demo/application.ex new file mode 100644 index 0000000..6412e9a --- /dev/null +++ b/demo/demo_wallaby/lib/demo/application.ex @@ -0,0 +1,33 @@ +defmodule Demo.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + children = [ + DemoWeb.Telemetry, + {DNSCluster, query: Application.get_env(:demo, :dns_cluster_query) || :ignore}, + {Phoenix.PubSub, name: Demo.PubSub}, + # Start a worker by calling: Demo.Worker.start_link(arg) + # {Demo.Worker, arg}, + # Start to serve requests, typically the last entry + DemoWeb.Endpoint + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: Demo.Supervisor] + Supervisor.start_link(children, opts) + end + + # Tell Phoenix to update the endpoint configuration + # whenever the application is updated. + @impl true + def config_change(changed, _new, removed) do + DemoWeb.Endpoint.config_change(changed, removed) + :ok + end +end diff --git a/demo/demo_wallaby/lib/demo_web.ex b/demo/demo_wallaby/lib/demo_web.ex new file mode 100644 index 0000000..9b8ca32 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web.ex @@ -0,0 +1,111 @@ +defmodule DemoWeb do + @moduledoc """ + The entrypoint for defining your web interface, such + as controllers, components, channels, and so on. + + This can be used in your application as: + + use DemoWeb, :controller + use DemoWeb, :html + + The definitions below will be executed for every controller, + component, etc, so keep them short and clean, focused + on imports, uses and aliases. + + Do NOT define functions inside the quoted expressions + below. Instead, define additional modules and import + those modules here. + """ + + def static_paths, do: ~w(assets fonts images favicon.ico robots.txt) + + def router do + quote do + use Phoenix.Router, helpers: false + + # Import common connection and controller functions to use in pipelines + import Plug.Conn + import Phoenix.Controller + import Phoenix.LiveView.Router + end + end + + def channel do + quote do + use Phoenix.Channel + end + end + + def controller do + quote do + use Phoenix.Controller, + formats: [:html, :json], + layouts: [html: DemoWeb.Layouts] + + import Plug.Conn + + unquote(verified_routes()) + end + end + + def live_view do + quote do + use Phoenix.LiveView, + layout: {DemoWeb.Layouts, :app} + + unquote(html_helpers()) + end + end + + def live_component do + quote do + use Phoenix.LiveComponent + + unquote(html_helpers()) + end + end + + def html do + quote do + use Phoenix.Component + + # Import convenience functions from controllers + import Phoenix.Controller, + only: [get_csrf_token: 0, view_module: 1, view_template: 1] + + # Include general helpers for rendering HTML + unquote(html_helpers()) + end + end + + defp html_helpers do + quote do + # HTML escaping functionality + import Phoenix.HTML + # Core UI components and translation + import DemoWeb.CoreComponents + + # Shortcut for generating JS commands + alias Phoenix.LiveView.JS + + # Routes generation with the ~p sigil + unquote(verified_routes()) + end + end + + def verified_routes do + quote do + use Phoenix.VerifiedRoutes, + endpoint: DemoWeb.Endpoint, + router: DemoWeb.Router, + statics: DemoWeb.static_paths() + end + end + + @doc """ + When used, dispatch to the appropriate controller/view/etc. + """ + defmacro __using__(which) when is_atom(which) do + apply(__MODULE__, which, []) + end +end diff --git a/demo/demo_wallaby/lib/demo_web/components/core_components.ex b/demo/demo_wallaby/lib/demo_web/components/core_components.ex new file mode 100644 index 0000000..8abc862 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/components/core_components.ex @@ -0,0 +1,670 @@ +defmodule DemoWeb.CoreComponents do + @moduledoc """ + Provides core UI components. + + At first glance, this module may seem daunting, but its goal is to provide + core building blocks for your application, such as modals, tables, and + forms. The components consist mostly of markup and are well-documented + with doc strings and declarative assigns. You may customize and style + them in any way you want, based on your application growth and needs. + + The default components use Tailwind CSS, a utility-first CSS framework. + See the [Tailwind CSS documentation](https://tailwindcss.com) to learn + how to customize them or feel free to swap in another framework altogether. + + Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage. + """ + use Phoenix.Component + + alias Phoenix.LiveView.JS + + @doc """ + Renders a modal. + + ## Examples + + <.modal id="confirm-modal"> + This is a modal. + + + JS commands may be passed to the `:on_cancel` to configure + the closing/cancel event, for example: + + <.modal id="confirm" on_cancel={JS.navigate(~p"/posts")}> + This is another modal. + + + """ + attr :id, :string, required: true + attr :show, :boolean, default: false + attr :on_cancel, JS, default: %JS{} + slot :inner_block, required: true + + def modal(assigns) do + ~H""" + + """ + end + + def input(%{type: "select"} = assigns) do + ~H""" +
+ <.label for={@id}><%= @label %> + + <.error :for={msg <- @errors}><%= msg %> +
+ """ + end + + def input(%{type: "textarea"} = assigns) do + ~H""" +
+ <.label for={@id}><%= @label %> + + <.error :for={msg <- @errors}><%= msg %> +
+ """ + end + + # All other inputs text, datetime-local, url, password, etc. are handled here... + def input(assigns) do + ~H""" +
+ <.label for={@id}><%= @label %> + + <.error :for={msg <- @errors}><%= msg %> +
+ """ + end + + @doc """ + Renders a label. + """ + attr :for, :string, default: nil + slot :inner_block, required: true + + def label(assigns) do + ~H""" + + """ + end + + @doc """ + Generates a generic error message. + """ + slot :inner_block, required: true + + def error(assigns) do + ~H""" +

+ <.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" /> + <%= render_slot(@inner_block) %> +

+ """ + end + + @doc """ + Renders a header with title. + """ + attr :class, :string, default: nil + + slot :inner_block, required: true + slot :subtitle + slot :actions + + def header(assigns) do + ~H""" +
+
+

+ <%= render_slot(@inner_block) %> +

+

+ <%= render_slot(@subtitle) %> +

+
+
<%= render_slot(@actions) %>
+
+ """ + end + + @doc ~S""" + Renders a table with generic styling. + + ## Examples + + <.table id="users" rows={@users}> + <:col :let={user} label="id"><%= user.id %> + <:col :let={user} label="username"><%= user.username %> + + """ + attr :id, :string, required: true + attr :rows, :list, required: true + attr :row_id, :any, default: nil, doc: "the function for generating the row id" + attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row" + + attr :row_item, :any, + default: &Function.identity/1, + doc: "the function for mapping each row before calling the :col and :action slots" + + slot :col, required: true do + attr :label, :string + end + + slot :action, doc: "the slot for showing user actions in the last table column" + + def table(assigns) do + assigns = + with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do + assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end) + end + + ~H""" +
+ + + + + + + + + + + + + +
<%= col[:label] %> + Actions +
+
+ + + <%= render_slot(col, @row_item.(row)) %> + +
+
+
+ + + <%= render_slot(action, @row_item.(row)) %> + +
+
+
+ """ + end + + @doc """ + Renders a data list. + + ## Examples + + <.list> + <:item title="Title"><%= @post.title %> + <:item title="Views"><%= @post.views %> + + """ + slot :item, required: true do + attr :title, :string, required: true + end + + def list(assigns) do + ~H""" +
+
+
+
<%= item.title %>
+
<%= render_slot(item) %>
+
+
+
+ """ + end + + @doc """ + Renders a back navigation link. + + ## Examples + + <.back navigate={~p"/posts"}>Back to posts + """ + attr :navigate, :any, required: true + slot :inner_block, required: true + + def back(assigns) do + ~H""" +
+ <.link + navigate={@navigate} + class="text-sm font-semibold leading-6 text-zinc-900 hover:text-zinc-700" + > + <.icon name="hero-arrow-left-solid" class="h-3 w-3" /> + <%= render_slot(@inner_block) %> + +
+ """ + end + + @doc """ + Renders a [Heroicon](https://heroicons.com). + + Heroicons come in three styles – outline, solid, and mini. + By default, the outline style is used, but solid and mini may + be applied by using the `-solid` and `-mini` suffix. + + You can customize the size and colors of the icons by setting + width, height, and background color classes. + + Icons are extracted from the `deps/heroicons` directory and bundled within + your compiled app.css by the plugin in your `assets/tailwind.config.js`. + + ## Examples + + <.icon name="hero-x-mark-solid" /> + <.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" /> + """ + attr :name, :string, required: true + attr :class, :string, default: nil + + def icon(%{name: "hero-" <> _} = assigns) do + ~H""" + + """ + end + + ## JS Commands + + def show(js \\ %JS{}, selector) do + JS.show(js, + to: selector, + transition: + {"transition-all transform ease-out duration-300", + "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95", + "opacity-100 translate-y-0 sm:scale-100"} + ) + end + + def hide(js \\ %JS{}, selector) do + JS.hide(js, + to: selector, + time: 200, + transition: + {"transition-all transform ease-in duration-200", + "opacity-100 translate-y-0 sm:scale-100", + "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"} + ) + end + + def show_modal(js \\ %JS{}, id) when is_binary(id) do + js + |> JS.show(to: "##{id}") + |> JS.show( + to: "##{id}-bg", + transition: {"transition-all transform ease-out duration-300", "opacity-0", "opacity-100"} + ) + |> show("##{id}-container") + |> JS.add_class("overflow-hidden", to: "body") + |> JS.focus_first(to: "##{id}-content") + end + + def hide_modal(js \\ %JS{}, id) do + js + |> JS.hide( + to: "##{id}-bg", + transition: {"transition-all transform ease-in duration-200", "opacity-100", "opacity-0"} + ) + |> hide("##{id}-container") + |> JS.hide(to: "##{id}", transition: {"block", "block", "hidden"}) + |> JS.remove_class("overflow-hidden", to: "body") + |> JS.pop_focus() + end + + @doc """ + Translates an error message using gettext. + """ + def translate_error({msg, opts}) do + # You can make use of gettext to translate error messages by + # uncommenting and adjusting the following code: + + # if count = opts[:count] do + # Gettext.dngettext(DemoWeb.Gettext, "errors", msg, msg, count, opts) + # else + # Gettext.dgettext(DemoWeb.Gettext, "errors", msg, opts) + # end + + Enum.reduce(opts, msg, fn {key, value}, acc -> + String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end) + end) + end + + @doc """ + Translates the errors for a field from a keyword list of errors. + """ + def translate_errors(errors, field) when is_list(errors) do + for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts}) + end +end diff --git a/demo/demo_wallaby/lib/demo_web/components/layouts.ex b/demo/demo_wallaby/lib/demo_web/components/layouts.ex new file mode 100644 index 0000000..58a4271 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/components/layouts.ex @@ -0,0 +1,5 @@ +defmodule DemoWeb.Layouts do + use DemoWeb, :html + + embed_templates "layouts/*" +end diff --git a/demo/demo_wallaby/lib/demo_web/components/layouts/app.html.heex b/demo/demo_wallaby/lib/demo_web/components/layouts/app.html.heex new file mode 100644 index 0000000..c753bc6 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/components/layouts/app.html.heex @@ -0,0 +1,3 @@ +
+ <%= @inner_content %> +
diff --git a/demo/demo_wallaby/lib/demo_web/components/layouts/root.html.heex b/demo/demo_wallaby/lib/demo_web/components/layouts/root.html.heex new file mode 100644 index 0000000..2fb9c2e --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/components/layouts/root.html.heex @@ -0,0 +1,17 @@ + + + + + + + <.live_title suffix=" · Phoenix Framework"> + <%= assigns[:page_title] || "Demo" %> + + + + + + <%= @inner_content %> + + diff --git a/demo/demo_wallaby/lib/demo_web/controllers/error_html.ex b/demo/demo_wallaby/lib/demo_web/controllers/error_html.ex new file mode 100644 index 0000000..d59f047 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/controllers/error_html.ex @@ -0,0 +1,19 @@ +defmodule DemoWeb.ErrorHTML do + use DemoWeb, :html + + # If you want to customize your error pages, + # uncomment the embed_templates/1 call below + # and add pages to the error directory: + # + # * lib/demo_web/controllers/error_html/404.html.heex + # * lib/demo_web/controllers/error_html/500.html.heex + # + # embed_templates "error_html/*" + + # The default is to render a plain text page based on + # the template name. For example, "404.html" becomes + # "Not Found". + def render(template, _assigns) do + Phoenix.Controller.status_message_from_template(template) + end +end diff --git a/demo/demo_wallaby/lib/demo_web/controllers/error_json.ex b/demo/demo_wallaby/lib/demo_web/controllers/error_json.ex new file mode 100644 index 0000000..53154fa --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/controllers/error_json.ex @@ -0,0 +1,15 @@ +defmodule DemoWeb.ErrorJSON do + # If you want to customize a particular status code, + # you may add your own clauses, such as: + # + # def render("500.json", _assigns) do + # %{errors: %{detail: "Internal Server Error"}} + # end + + # By default, Phoenix returns the status message from + # the template name. For example, "404.json" becomes + # "Not Found". + def render(template, _assigns) do + %{errors: %{detail: Phoenix.Controller.status_message_from_template(template)}} + end +end diff --git a/demo/demo_wallaby/lib/demo_web/controllers/page_controller.ex b/demo/demo_wallaby/lib/demo_web/controllers/page_controller.ex new file mode 100644 index 0000000..8955c67 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/controllers/page_controller.ex @@ -0,0 +1,15 @@ +defmodule DemoWeb.PageController do + use DemoWeb, :controller + + def valid(conn, _params) do + render(conn, :valid) + end + + def invalid(conn, _params) do + render(conn, :invalid) + end + + def dynamic_invalid(conn, _params) do + render(conn, :dynamic_invalid) + end +end diff --git a/demo/demo_wallaby/lib/demo_web/controllers/page_html.ex b/demo/demo_wallaby/lib/demo_web/controllers/page_html.ex new file mode 100644 index 0000000..74bc494 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/controllers/page_html.ex @@ -0,0 +1,5 @@ +defmodule DemoWeb.PageHTML do + use DemoWeb, :html + + embed_templates "page_html/*" +end diff --git a/demo/demo_wallaby/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex b/demo/demo_wallaby/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex new file mode 100644 index 0000000..4b0e02a --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/controllers/page_html/dynamic_invalid.html.heex @@ -0,0 +1,49 @@ +
+

Angelika's Star Trek series ranking

+
    +
  1. Star Trek: Deep Space Nine
  2. +
  3. Star Trek: The Next Generation
  4. +
  5. Star Trek: Strange New Worlds
  6. +
  7. Star Trek: Voyager
  8. +
  9. Star Trek: Enterprise
  10. +
  11. Star Trek: The Original Series
  12. +
  13. The Orville [1]
  14. +
  15. Star Trek: Discovery
  16. +
  17. Star Trek: Picard
  18. +
+ +

+ [1] While I am aware that The Orville is not technically part of the Star Trek universe, + it is better at capturing what makes Star Trek Star Trek + and telling interesting stories + than the most recent attempts at rebooting the series, Discovery and Picard. +

+ +

+ + + + + + +

+ + a placeholder image that displays its dimensions: 600x400 + +
+ +
+
+ + diff --git a/demo/demo_wallaby/lib/demo_web/controllers/page_html/invalid.html.heex b/demo/demo_wallaby/lib/demo_web/controllers/page_html/invalid.html.heex new file mode 100644 index 0000000..dd9595d --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/controllers/page_html/invalid.html.heex @@ -0,0 +1,32 @@ +
+

Angelika's Star Trek series ranking

+
    +
  1. Star Trek: Deep Space Nine
  2. +
  3. Star Trek: The Next Generation
  4. +
  5. Star Trek: Strange New Worlds
  6. +
  7. Star Trek: Voyager
  8. +
  9. Star Trek: Enterprise
  10. +
  11. Star Trek: The Original Series
  12. +
  13. The Orville [1]
  14. +
  15. Star Trek: Discovery
  16. +
  17. Star Trek: Picard
  18. +
+ +

+ [1] While I am aware that The Orville is not technically part of the Star Trek universe, + it is better at capturing what makes Star Trek Star Trek + and telling interesting stories + than the most recent attempts at rebooting the series, Discovery and Picard. +

+ +

+ + + + + + +

+ + +
diff --git a/demo/demo_wallaby/lib/demo_web/controllers/page_html/valid.html.heex b/demo/demo_wallaby/lib/demo_web/controllers/page_html/valid.html.heex new file mode 100644 index 0000000..4a4fd4d --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/controllers/page_html/valid.html.heex @@ -0,0 +1,35 @@ +
+

Angelika's Star Trek series ranking

+
    +
  1. Star Trek: Deep Space Nine
  2. +
  3. Star Trek: The Next Generation
  4. +
  5. Star Trek: Strange New Worlds
  6. +
  7. Star Trek: Voyager
  8. +
  9. Star Trek: Enterprise
  10. +
  11. Star Trek: The Original Series
  12. +
  13. The Orville [1]
  14. +
  15. Star Trek: Discovery
  16. +
  17. Star Trek: Picard
  18. +
+ +

+ [1] While I am aware that The Orville is not technically part of the Star Trek universe, + it is better at capturing what makes Star Trek Star Trek + and telling interesting stories + than the most recent attempts at rebooting the series, Discovery and Picard. +

+ +

+ + + + + + +

+ + a placeholder image that displays its dimensions: 600x400 +
diff --git a/demo/demo_wallaby/lib/demo_web/endpoint.ex b/demo/demo_wallaby/lib/demo_web/endpoint.ex new file mode 100644 index 0000000..9a0ca04 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/endpoint.ex @@ -0,0 +1,52 @@ +defmodule DemoWeb.Endpoint do + use Phoenix.Endpoint, otp_app: :demo + + # The session will be stored in the cookie and signed, + # this means its contents can be read but not tampered with. + # Set :encryption_salt if you would also like to encrypt it. + @session_options [ + store: :cookie, + key: "_demo_key", + signing_salt: "OzmAnOt4", + same_site: "Lax" + ] + + socket "/live", Phoenix.LiveView.Socket, + websocket: [connect_info: [session: @session_options]], + longpoll: [connect_info: [session: @session_options]] + + # Serve at "/" the static files from "priv/static" directory. + # + # You should set gzip to true if you are running phx.digest + # when deploying your static files in production. + plug Plug.Static, + at: "/", + from: :demo, + gzip: false, + only: DemoWeb.static_paths() + + # Code reloading can be explicitly enabled under the + # :code_reloader configuration of your endpoint. + if code_reloading? do + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + plug Phoenix.LiveReloader + plug Phoenix.CodeReloader + end + + plug Phoenix.LiveDashboard.RequestLogger, + param_key: "request_logger", + cookie_key: "request_logger" + + plug Plug.RequestId + plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] + + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Phoenix.json_library() + + plug Plug.MethodOverride + plug Plug.Head + plug Plug.Session, @session_options + plug DemoWeb.Router +end diff --git a/demo/demo_wallaby/lib/demo_web/router.ex b/demo/demo_wallaby/lib/demo_web/router.ex new file mode 100644 index 0000000..9b77b14 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/router.ex @@ -0,0 +1,45 @@ +defmodule DemoWeb.Router do + use DemoWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_live_flash + plug :put_root_layout, html: {DemoWeb.Layouts, :root} + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + scope "/", DemoWeb do + pipe_through :browser + + get "/valid", PageController, :valid + get "/invalid", PageController, :invalid + get "/dynamic_invalid", PageController, :dynamic_invalid + end + + # Other scopes may use custom stacks. + # scope "/api", DemoWeb do + # pipe_through :api + # end + + # Enable LiveDashboard in development + if Application.compile_env(:demo, :dev_routes) do + # If you want to use the LiveDashboard in production, you should put + # it behind authentication and allow only admins to access it. + # If your application does not have an admins-only section yet, + # you can use Plug.BasicAuth to set up some basic authentication + # as long as you are also using SSL (which you should anyway). + import Phoenix.LiveDashboard.Router + + scope "/dev" do + pipe_through :browser + + live_dashboard "/dashboard", metrics: DemoWeb.Telemetry + end + end +end diff --git a/demo/demo_wallaby/lib/demo_web/telemetry.ex b/demo/demo_wallaby/lib/demo_web/telemetry.ex new file mode 100644 index 0000000..7705011 --- /dev/null +++ b/demo/demo_wallaby/lib/demo_web/telemetry.ex @@ -0,0 +1,69 @@ +defmodule DemoWeb.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.start.system_time", + unit: {:native, :millisecond} + ), + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.start.system_time", + tags: [:route], + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.exception.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + summary("phoenix.socket_connected.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.channel_joined.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.channel_handled_in.duration", + tags: [:event], + unit: {:native, :millisecond} + ), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp periodic_measurements do + [ + # A module, function and arguments to be invoked periodically. + # This function must call :telemetry.execute/3 and a metric must be added above. + # {DemoWeb, :count_users, []} + ] + end +end diff --git a/demo/mix.exs b/demo/demo_wallaby/mix.exs similarity index 94% rename from demo/mix.exs rename to demo/demo_wallaby/mix.exs index cbc3cf9..475354b 100644 --- a/demo/mix.exs +++ b/demo/demo_wallaby/mix.exs @@ -45,8 +45,7 @@ defmodule Demo.MixProject do {:dns_cluster, "~> 0.1.1"}, {:bandit, "~> 1.2"}, {:wallaby, "~> 0.30", runtime: false, only: :test}, - {:hound, "~> 1.1", runtime: false, only: :test}, - {:a11y_audit, path: "../", only: [:test]} + {:a11y_audit, path: "../../", only: [:test]} ] end diff --git a/demo/mix.lock b/demo/demo_wallaby/mix.lock similarity index 97% rename from demo/mix.lock rename to demo/demo_wallaby/mix.lock index 69eda04..9aac913 100644 --- a/demo/mix.lock +++ b/demo/demo_wallaby/mix.lock @@ -7,7 +7,6 @@ "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, - "hound": {:hex, :hound, "1.1.1", "d3afce4cf0f446331d9d00427e9eb74fa135c296b1d3745d4bbe2096ce259087", [:mix], [{:hackney, "~> 1.5", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8c6342b49f53bb0e5c51d5ecca18a8ce872c44da05a8ce6f828385ebd744fe2a"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, diff --git a/demo/demo_wallaby/priv/static/favicon.ico b/demo/demo_wallaby/priv/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7f372bfc21cdd8cb47585339d5fa4d9dd424402f GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=@t!V@Ar*{oFEH`~d50E!_s``s q?{G*w(7?#d#v@^nKnY_HKaYb01EZMZjMqTJ89ZJ6T-G@yGywoKK_h|y literal 0 HcmV?d00001 diff --git a/demo/demo_wallaby/priv/static/images/logo.svg b/demo/demo_wallaby/priv/static/images/logo.svg new file mode 100644 index 0000000..9f26bab --- /dev/null +++ b/demo/demo_wallaby/priv/static/images/logo.svg @@ -0,0 +1,6 @@ + diff --git a/demo/demo_wallaby/priv/static/robots.txt b/demo/demo_wallaby/priv/static/robots.txt new file mode 100644 index 0000000..26e06b5 --- /dev/null +++ b/demo/demo_wallaby/priv/static/robots.txt @@ -0,0 +1,5 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / diff --git a/demo/demo_wallaby/test/demo_web/controllers/error_html_test.exs b/demo/demo_wallaby/test/demo_web/controllers/error_html_test.exs new file mode 100644 index 0000000..aaf8e9f --- /dev/null +++ b/demo/demo_wallaby/test/demo_web/controllers/error_html_test.exs @@ -0,0 +1,14 @@ +defmodule DemoWeb.ErrorHTMLTest do + use DemoWeb.ConnCase, async: true + + # Bring render_to_string/4 for testing custom views + import Phoenix.Template + + test "renders 404.html" do + assert render_to_string(DemoWeb.ErrorHTML, "404", "html", []) == "Not Found" + end + + test "renders 500.html" do + assert render_to_string(DemoWeb.ErrorHTML, "500", "html", []) == "Internal Server Error" + end +end diff --git a/demo/demo_wallaby/test/demo_web/controllers/error_json_test.exs b/demo/demo_wallaby/test/demo_web/controllers/error_json_test.exs new file mode 100644 index 0000000..aa12730 --- /dev/null +++ b/demo/demo_wallaby/test/demo_web/controllers/error_json_test.exs @@ -0,0 +1,12 @@ +defmodule DemoWeb.ErrorJSONTest do + use DemoWeb.ConnCase, async: true + + test "renders 404" do + assert DemoWeb.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}} + end + + test "renders 500" do + assert DemoWeb.ErrorJSON.render("500.json", %{}) == + %{errors: %{detail: "Internal Server Error"}} + end +end diff --git a/demo/test/demo_web/integration/pages_wallaby_test.exs b/demo/demo_wallaby/test/demo_web/integration/pages_test.exs similarity index 96% rename from demo/test/demo_web/integration/pages_wallaby_test.exs rename to demo/demo_wallaby/test/demo_web/integration/pages_test.exs index ed55ae1..96484d5 100644 --- a/demo/test/demo_web/integration/pages_wallaby_test.exs +++ b/demo/demo_wallaby/test/demo_web/integration/pages_test.exs @@ -1,4 +1,4 @@ -defmodule DemoWeb.PagesWallabyTest do +defmodule DemoWeb.PagesTest do use ExUnit.Case, async: true use Wallaby.Feature diff --git a/demo/demo_wallaby/test/support/conn_case.ex b/demo/demo_wallaby/test/support/conn_case.ex new file mode 100644 index 0000000..e51004a --- /dev/null +++ b/demo/demo_wallaby/test/support/conn_case.ex @@ -0,0 +1,37 @@ +defmodule DemoWeb.ConnCase do + @moduledoc """ + This module defines the test case to be used by + tests that require setting up a connection. + + Such tests rely on `Phoenix.ConnTest` and also + import other functionality to make it easier + to build common data structures and query the data layer. + + Finally, if the test case interacts with the database, + we enable the SQL sandbox, so changes done to the database + are reverted at the end of every test. If you are using + PostgreSQL, you can even run database tests asynchronously + by setting `use DemoWeb.ConnCase, async: true`, although + this option is not recommended for other databases. + """ + + use ExUnit.CaseTemplate + + using do + quote do + # The default endpoint for testing + @endpoint DemoWeb.Endpoint + + use DemoWeb, :verified_routes + + # Import conveniences for testing with connections + import Plug.Conn + import Phoenix.ConnTest + import DemoWeb.ConnCase + end + end + + setup _tags do + {:ok, conn: Phoenix.ConnTest.build_conn()} + end +end diff --git a/demo/test/test_helper.exs b/demo/demo_wallaby/test/test_helper.exs similarity index 72% rename from demo/test/test_helper.exs rename to demo/demo_wallaby/test/test_helper.exs index fc756b6..d480fed 100644 --- a/demo/test/test_helper.exs +++ b/demo/demo_wallaby/test/test_helper.exs @@ -1,4 +1,3 @@ ExUnit.start() Application.put_env(:wallaby, :base_url, DemoWeb.Endpoint.url()) {:ok, _} = Application.ensure_all_started(:wallaby) -{:ok, _} = Application.ensure_all_started(:hound) diff --git a/mix.exs b/mix.exs index 8b19ecc..dfa038a 100644 --- a/mix.exs +++ b/mix.exs @@ -42,7 +42,7 @@ defmodule A11yAudit.MixProject do end defp description() do - "Automated accessibility checks for Elixir web apps, based on axe-core." + " Accessibility auditing for Elixir web applications using axe-core" end defp package() do