Skip to content

Commit

Permalink
Add full end-to-end Phoenix app test (#797)
Browse files Browse the repository at this point in the history
Co-Authored-By: Andrea Leopardi <an.leopardi@gmail.com>
  • Loading branch information
solnic and whatyouhide authored Oct 21, 2024
1 parent 1993c77 commit 4403f5d
Show file tree
Hide file tree
Showing 50 changed files with 2,755 additions and 30 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,19 @@ jobs:
path: |
_build
deps
test_integrations/phoenix_app/_build
test_integrations/phoenix_app/deps
key: |
${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
restore-keys: |
${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-
- name: Install and compile Mix dependencies
if: steps.mix-deps-cache.outputs.cache-hit != 'true'
run: mix do deps.get --check-locked, deps.compile
run: |
mix do deps.get --check-locked, deps.compile
cd test_integrations/phoenix_app
mix do deps.get --check-locked, deps.compile
- name: Save Mix dependencies cache
uses: actions/cache/save@v4
Expand All @@ -70,6 +75,8 @@ jobs:
path: |
_build
deps
test_integrations/phoenix_app/_build
test_integrations/phoenix_app/deps
key: |
${{ steps.mix-deps-cache.outputs.cache-primary-key }}
Expand All @@ -84,6 +91,9 @@ jobs:
- name: Run tests
run: mix test

- name: Run integration tests
run: mix test.integrations

- name: Retrieve PLT Cache
uses: actions/cache@v4
if: matrix.dialyzer
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ erl_crash.dump

# Generated by "mix sentry.package_source_code"
/priv/sentry.map

test_integrations/phoenix_app/db
65 changes: 63 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule Sentry.Mixfile do
package: package(),
deps: deps(),
elixirc_paths: elixirc_paths(Mix.env()),
test_paths: test_paths(System.get_env("SENTRY_INTEGRATION")),
dialyzer: [
flags: [:unmatched_returns, :error_handling, :extra_return],
plt_file: {:no_warn, "plts/dialyzer.plt"},
Expand All @@ -22,7 +23,8 @@ defmodule Sentry.Mixfile do
],
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
"coveralls.html": :test
"coveralls.html": :test,
"test.integrations": :test
],
name: "Sentry",
docs: [
Expand Down Expand Up @@ -83,6 +85,9 @@ defmodule Sentry.Mixfile do
defp elixirc_paths(:test), do: ["test/support"] ++ elixirc_paths(:dev)
defp elixirc_paths(_other), do: ["lib"]

defp test_paths(nil), do: ["test"]
defp test_paths(integration), do: ["test_integrations/#{integration}/test"]

defp deps do
[
{:nimble_options, "~> 1.0"},
Expand Down Expand Up @@ -123,6 +128,62 @@ defmodule Sentry.Mixfile do
end

defp aliases do
[test: ["sentry.package_source_code", "test"]]
[
test: ["sentry.package_source_code", "test"],
"test.integrations": &run_integration_tests_if_supported/1
]
end

defp run_integration_tests_if_supported(args) do
if Version.match?(System.version(), ">= 1.16.0") do
run_integration_tests("phoenix_app", args)
else
Mix.shell().info("Skipping integration tests for Elixir versions < 1.16")
end
end

defp run_integration_tests(integration, args) do
IO.puts(
IO.ANSI.format([
"\n",
[:bright, :cyan, "==> Running tests for integration: #{integration}"]
])
)

case setup_integration(integration) do
{_, 0} ->
color_arg = if IO.ANSI.enabled?(), do: "--color", else: "--no-color"

{_, status} = run_in_integration(integration, ["test", color_arg | args])

if status > 0 do
IO.puts(
IO.ANSI.format([
:red,
"Integration tests for #{integration} failed"
])
)

System.at_exit(fn _ -> exit({:shutdown, 1}) end)
else
IO.puts(
IO.ANSI.format([
:green,
"Integration tests for #{integration} passed"
])
)
end
end
end

defp setup_integration(integration) do
run_in_integration(integration, ["deps.get"])
end

defp run_in_integration(integration, args) do
System.cmd("mix", args,
into: IO.binstream(:stdio, :line),
cd: Path.join("test_integrations", integration)
)
end
end
54 changes: 27 additions & 27 deletions mix.lock

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions test_integrations/phoenix_app/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
import_deps: [:ecto, :ecto_sql, :phoenix],
subdirectories: ["priv/*/migrations"],
plugins: [Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
]
37 changes: 37 additions & 0 deletions test_integrations/phoenix_app/.gitignore
Original file line number Diff line number Diff line change
@@ -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").
phoenix_app-*.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/

18 changes: 18 additions & 0 deletions test_integrations/phoenix_app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# PhoenixApp

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
5 changes: 5 additions & 0 deletions test_integrations/phoenix_app/assets/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

/* This file is for your main application CSS */
44 changes: 44 additions & 0 deletions test_integrations/phoenix_app/assets/js/app.js
Original file line number Diff line number Diff line change
@@ -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

74 changes: 74 additions & 0 deletions test_integrations/phoenix_app/assets/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// See the Tailwind configuration guide for advanced usage
// https://tailwindcss.com/docs/configuration

const plugin = require("tailwindcss/plugin")
const fs = require("fs")
const path = require("path")

module.exports = {
content: [
"./js/**/*.js",
"../lib/phoenix_app_web.ex",
"../lib/phoenix_app_web/**/*.*ex"
],
theme: {
extend: {
colors: {
brand: "#FD4F00",
}
},
},
plugins: [
require("@tailwindcss/forms"),
// Allows prefixing tailwind classes with LiveView classes to add rules
// only when LiveView classes are applied, for example:
//
// <div class="phx-click-loading:animate-ping">
//
plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])),
plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])),
plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])),

// Embeds Heroicons (https://heroicons.com) into your app.css bundle
// See your `CoreComponents.icon/1` for more information.
//
plugin(function({matchComponents, theme}) {
let iconsDir = path.join(__dirname, "../deps/heroicons/optimized")
let values = {}
let icons = [
["", "/24/outline"],
["-solid", "/24/solid"],
["-mini", "/20/solid"],
["-micro", "/16/solid"]
]
icons.forEach(([suffix, dir]) => {
fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
let name = path.basename(file, ".svg") + suffix
values[name] = {name, fullPath: path.join(iconsDir, dir, file)}
})
})
matchComponents({
"hero": ({name, fullPath}) => {
let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
let size = theme("spacing.6")
if (name.endsWith("-mini")) {
size = theme("spacing.5")
} else if (name.endsWith("-micro")) {
size = theme("spacing.4")
}
return {
[`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
"-webkit-mask": `var(--hero-${name})`,
"mask": `var(--hero-${name})`,
"mask-repeat": "no-repeat",
"background-color": "currentColor",
"vertical-align": "middle",
"display": "inline-block",
"width": size,
"height": size
}
}
}, {values})
})
]
}
Loading

0 comments on commit 4403f5d

Please sign in to comment.