diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2b386e9a8..2e145e373 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,7 +16,7 @@ variables:
   # DB Variables for Postgres / Postgis
   POSTGRES_DB: mobilizon_test
   POSTGRES_USER: postgres
-  POSTGRES_PASSWORD: ""
+  POSTGRES_PASSWORD: postgres
   POSTGRES_HOST: postgres
   # DB Variables for Mobilizon
   MOBILIZON_DATABASE_USERNAME: $POSTGRES_USER
@@ -61,7 +61,7 @@ lint-elixir:
     - exit $EXITVALUE
 
 lint-front:
-  image: node:14
+  image: node:16
   stage: check
   before_script:
     - export EXITVALUE=0
@@ -73,7 +73,7 @@ lint-front:
 
 build-frontend:
   stage: build-js
-  image: node:14
+  image: node:16
   before_script:
     - apt update
     - apt install -y --no-install-recommends python build-essential webp imagemagick gifsicle jpegoptim optipng pngquant
@@ -100,10 +100,27 @@ deps:
   needs:
     - install
 
+exunit-1.11:
+  stage: test
+  image: tcitworld/mobilizon-ci:legacy
+  services:
+    - name: postgis/postgis:11-3.0
+      alias: postgres
+  variables:
+    MIX_ENV: test
+  before_script:
+    - mix deps.clean --all
+    - mix deps.get
+    - mix ecto.create
+    - mix ecto.migrate
+  script:
+    - mix coveralls
+  allow_failure: true
+
 exunit:
   stage: test
   services:
-    - name: mdillon/postgis:11
+    - name: postgis/postgis:13-3.1
       alias: postgres
   variables:
     MIX_ENV: test
@@ -140,7 +157,7 @@ jest:
 # cypress:
 #   stage: test
 #   services:
-#     - name: mdillon/postgis:11
+#     - name: postgis/postgis:13.3
 #       alias: postgres
 #   variables:
 #     MIX_ENV=e2e
diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile
index 1f9155a4c..3aaa41b18 100644
--- a/docker/production/Dockerfile
+++ b/docker/production/Dockerfile
@@ -8,7 +8,7 @@ RUN yarn install \
     && yarn run build
 
 # Then, build the application binary
-FROM elixir:1.11-alpine AS builder
+FROM elixir:1.12-alpine AS builder
 
 RUN apk add --no-cache build-base git cmake
 
diff --git a/docker/tests/Dockerfile b/docker/tests/Dockerfile
index 73f0d6c8c..3a6673b1a 100644
--- a/docker/tests/Dockerfile
+++ b/docker/tests/Dockerfile
@@ -1,7 +1,7 @@
 FROM elixir:latest
 LABEL maintainer="Thomas Citharel <tcit@tcit.fr>"
 
-ENV REFRESHED_AT=2021-05-19
+ENV REFRESHED_AT=2021-06-07
 RUN apt-get update -yq && apt-get install -yq build-essential inotify-tools postgresql-client git curl gnupg xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 cmake exiftool
 RUN curl -sL https://deb.nodesource.com/setup_16.x | bash && apt-get install nodejs -yq
 RUN npm install -g yarn wait-on
diff --git a/docker/tests/Dockerfile-legacy b/docker/tests/Dockerfile-legacy
new file mode 100644
index 000000000..a90806409
--- /dev/null
+++ b/docker/tests/Dockerfile-legacy
@@ -0,0 +1,28 @@
+# We build Elixir manually to have the oldest acceptable version of OTP
+FROM erlang:21
+LABEL maintainer="Thomas Citharel <tcit@tcit.fr>"
+
+# elixir expects utf8.
+ENV ELIXIR_VERSION="v1.11.4" \
+    LANG=C.UTF-8
+
+RUN set -xe \
+    && ELIXIR_DOWNLOAD_URL="https://github.com/elixir-lang/elixir/archive/${ELIXIR_VERSION}.tar.gz" \
+    && ELIXIR_DOWNLOAD_SHA256="85c7118a0db6007507313db5bddf370216d9394ed7911fe80f21e2fbf7f54d29" \
+    && curl -fSL -o elixir-src.tar.gz $ELIXIR_DOWNLOAD_URL \
+    && echo "$ELIXIR_DOWNLOAD_SHA256  elixir-src.tar.gz" | sha256sum -c - \
+    && mkdir -p /usr/local/src/elixir \
+    && tar -xzC /usr/local/src/elixir --strip-components=1 -f elixir-src.tar.gz \
+    && rm elixir-src.tar.gz \
+    && cd /usr/local/src/elixir \
+    && make install clean
+
+CMD ["iex"]
+
+ENV REFRESHED_AT=2021-06-07
+RUN apt-get update -yq && apt-get install -yq build-essential inotify-tools postgresql-client git curl gnupg xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 cmake exiftool
+RUN curl -sL https://deb.nodesource.com/setup_12.x | bash && apt-get install nodejs -yq
+RUN npm install -g yarn wait-on
+RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+RUN mix local.hex --force && mix local.rebar --force
+RUN curl https://dbip.mirror.framasoft.org/files/dbip-city-lite-latest.mmdb --output GeoLite2-City.mmdb -s && mkdir -p /usr/share/GeoIP && mv GeoLite2-City.mmdb /usr/share/GeoIP/
diff --git a/lib/federation/activity_pub/transmogrifier.ex b/lib/federation/activity_pub/transmogrifier.ex
index ea0509589..b2430899f 100644
--- a/lib/federation/activity_pub/transmogrifier.ex
+++ b/lib/federation/activity_pub/transmogrifier.ex
@@ -317,9 +317,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
 
       e ->
         Logger.warn(
-          "Unable to process Accept activity #{inspect(id)} for object #{inspect(accepted_object)} only returned #{
-            inspect(e)
-          }"
+          "Unable to process Accept activity #{inspect(id)} for object #{inspect(accepted_object)} only returned #{inspect(e)}"
         )
 
         :error
@@ -347,9 +345,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
 
       e ->
         Logger.warn(
-          "Unable to process Reject activity #{inspect(id)} for object #{inspect(rejected_object)} only returned #{
-            inspect(e)
-          }"
+          "Unable to process Reject activity #{inspect(id)} for object #{inspect(rejected_object)} only returned #{inspect(e)}"
         )
 
         :error
@@ -734,9 +730,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
     else
       {:is_admin, {:ok, %Member{}}} ->
         Logger.warn(
-          "Person #{inspect(actor)} is not an admin from #{inspect(origin)} and can't remove member #{
-            inspect(object)
-          }"
+          "Person #{inspect(actor)} is not an admin from #{inspect(origin)} and can't remove member #{inspect(object)}"
         )
 
         {:error, "Member already removed"}
diff --git a/lib/federation/activity_pub/utils.ex b/lib/federation/activity_pub/utils.ex
index 01ad1abc6..fe5fd4f05 100644
--- a/lib/federation/activity_pub/utils.ex
+++ b/lib/federation/activity_pub/utils.ex
@@ -303,18 +303,14 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
         case role do
           :moderator ->
             Logger.debug(
-              "Checking if activity actor #{actor_url} is a moderator from group from #{
-                object.url
-              }"
+              "Checking if activity actor #{actor_url} is a moderator from group from #{object.url}"
             )
 
             Actors.is_moderator?(actor_id, group_id)
 
           :administrator ->
             Logger.debug(
-              "Checking if activity actor #{actor_url} is an administrator from group from #{
-                object.url
-              }"
+              "Checking if activity actor #{actor_url} is an administrator from group from #{object.url}"
             )
 
             Actors.is_administrator?(actor_id, group_id)
diff --git a/lib/federation/activity_stream/converter/resource.ex b/lib/federation/activity_stream/converter/resource.ex
index 0472ca1b0..a0d8ca6e7 100644
--- a/lib/federation/activity_stream/converter/resource.ex
+++ b/lib/federation/activity_stream/converter/resource.ex
@@ -104,9 +104,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Resource do
   @spec get_parent_id(String.t(), String.t()) :: Resource.t() | map()
   defp get_parent_id(context, resources_url) do
     Logger.debug(
-      "Getting parentID for context #{inspect(context)} and with resources_url #{
-        inspect(resources_url)
-      }"
+      "Getting parentID for context #{inspect(context)} and with resources_url #{inspect(resources_url)}"
     )
 
     case Utils.get_url(context) do
diff --git a/lib/mix/tasks/mobilizon/instance.ex b/lib/mix/tasks/mobilizon/instance.ex
index dcb4e552e..af4d844b1 100644
--- a/lib/mix/tasks/mobilizon/instance.ex
+++ b/lib/mix/tasks/mobilizon/instance.ex
@@ -170,9 +170,7 @@ defmodule Mix.Tasks.Mobilizon.Instance do
             """
             To get started:
             1. Check the contents of the generated files.
-            2. Run `sudo -u postgres psql -f #{escape_sh_path(psql_path)} && rm #{
-              escape_sh_path(psql_path)
-            }`.
+            2. Run `sudo -u postgres psql -f #{escape_sh_path(psql_path)} && rm #{escape_sh_path(psql_path)}`.
             """
         )
       else
diff --git a/lib/mix/tasks/mobilizon/users/clean.ex b/lib/mix/tasks/mobilizon/users/clean.ex
index ff8fe7647..04f6f22dc 100644
--- a/lib/mix/tasks/mobilizon/users/clean.ex
+++ b/lib/mix/tasks/mobilizon/users/clean.ex
@@ -66,9 +66,7 @@ defmodule Mix.Tasks.Mobilizon.Users.Clean do
 
     Enum.each(deleted_users, fn deleted_user ->
       shell_info(
-        "ID: #{deleted_user.id}, Email: #{deleted_user.email}, Profile: @#{
-          hd(deleted_user.actors).preferred_username
-        }"
+        "ID: #{deleted_user.id}, Email: #{deleted_user.email}, Profile: @#{hd(deleted_user.actors).preferred_username}"
       )
     end)
   end
diff --git a/lib/mix/tasks/mobilizon/users/modify.ex b/lib/mix/tasks/mobilizon/users/modify.ex
index e49e8e1e7..e36ad7a4f 100644
--- a/lib/mix/tasks/mobilizon/users/modify.ex
+++ b/lib/mix/tasks/mobilizon/users/modify.ex
@@ -58,11 +58,9 @@ defmodule Mix.Tasks.Mobilizon.Users.Modify do
       An user has been modified with the following information:
         - email: #{user.email}
         - Role: #{user.role}
-        - account status: #{
-        if user.confirmed_at,
-          do: "activated on #{DateTime.to_string(user.confirmed_at)} (UTC)",
-          else: "disabled"
-      }
+        - account status: #{if user.confirmed_at,
+        do: "activated on #{DateTime.to_string(user.confirmed_at)} (UTC)",
+        else: "disabled"}
       """)
     else
       {:makes_changes, false} ->
diff --git a/lib/mix/tasks/mobilizon/users/show.ex b/lib/mix/tasks/mobilizon/users/show.ex
index 6651eb986..60ed9accc 100644
--- a/lib/mix/tasks/mobilizon/users/show.ex
+++ b/lib/mix/tasks/mobilizon/users/show.ex
@@ -19,11 +19,9 @@ defmodule Mix.Tasks.Mobilizon.Users.Show do
          actors <- Users.get_actors_for_user(user) do
       shell_info("""
       Informations for the user #{user.email}:
-        - account status: #{
-        if user.confirmed_at,
-          do: "Activated on #{DateTime.to_string(user.confirmed_at)} (UTC)",
-          else: "disabled"
-      }
+        - account status: #{if user.confirmed_at,
+        do: "Activated on #{DateTime.to_string(user.confirmed_at)} (UTC)",
+        else: "disabled"}
         - Role: #{user.role}
         #{display_actors(actors)}
       """)
diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex
index ad4e454ee..2f78c3dca 100644
--- a/lib/mobilizon/actors/actors.ex
+++ b/lib/mobilizon/actors/actors.ex
@@ -1254,9 +1254,7 @@ defmodule Mobilizon.Actors do
          # Check if followed has blocked follower
          {:already_following, nil} <- {:already_following, is_following(follower, followed)} do
       Logger.info(
-        "Making #{Actor.preferred_username_and_domain(follower)} follow #{
-          Actor.preferred_username_and_domain(followed)
-        } " <>
+        "Making #{Actor.preferred_username_and_domain(follower)} follow #{Actor.preferred_username_and_domain(followed)} " <>
           "(approved: #{approved})"
       )
 
@@ -1269,9 +1267,7 @@ defmodule Mobilizon.Actors do
     else
       {:already_following, %Follower{}} ->
         {:error, :already_following,
-         "Could not follow actor: you are already following #{
-           Actor.preferred_username_and_domain(followed)
-         }"}
+         "Could not follow actor: you are already following #{Actor.preferred_username_and_domain(followed)}"}
 
       {:suspended, _} ->
         {:error, :suspended,
diff --git a/lib/mobilizon/addresses/address.ex b/lib/mobilizon/addresses/address.ex
index 7485ee7a9..2df321757 100644
--- a/lib/mobilizon/addresses/address.ex
+++ b/lib/mobilizon/addresses/address.ex
@@ -85,9 +85,7 @@ defmodule Mobilizon.Addresses.Address do
 
   def representation(%__MODULE__{} = address) do
     String.trim(
-      "#{address.street} #{address.postal_code} #{address.locality} #{address.region} #{
-        address.country
-      }"
+      "#{address.street} #{address.postal_code} #{address.locality} #{address.region} #{address.country}"
     )
   end
 end
diff --git a/lib/service/geospatial/map_quest.ex b/lib/service/geospatial/map_quest.ex
index 77e7f6536..155a53dfc 100644
--- a/lib/service/geospatial/map_quest.ex
+++ b/lib/service/geospatial/map_quest.ex
@@ -35,9 +35,7 @@ defmodule Mobilizon.Service.Geospatial.MapQuest do
 
     with {:ok, %{status: 200, body: body}} <-
            GeospatialClient.get(
-             "https://#{prefix}.mapquestapi.com/geocoding/v1/reverse?key=#{api_key}&location=#{
-               lat
-             },#{lon}&maxResults=#{limit}"
+             "https://#{prefix}.mapquestapi.com/geocoding/v1/reverse?key=#{api_key}&location=#{lat},#{lon}&maxResults=#{limit}"
            ),
          %{"results" => results, "info" => %{"statuscode" => 0}} <- body do
       results |> Enum.map(&process_data/1)
@@ -63,9 +61,7 @@ defmodule Mobilizon.Service.Geospatial.MapQuest do
     if is_nil(api_key), do: raise(ArgumentError, message: @api_key_missing_message)
 
     url =
-      "https://#{prefix}.mapquestapi.com/geocoding/v1/address?key=#{api_key}&location=#{
-        URI.encode(q)
-      }&maxResults=#{limit}"
+      "https://#{prefix}.mapquestapi.com/geocoding/v1/address?key=#{api_key}&location=#{URI.encode(q)}&maxResults=#{limit}"
 
     Logger.debug("Asking MapQuest for addresses with #{url}")
 
diff --git a/lib/service/geospatial/nominatim.ex b/lib/service/geospatial/nominatim.ex
index 92ba1b3fc..9b8754d58 100644
--- a/lib/service/geospatial/nominatim.ex
+++ b/lib/service/geospatial/nominatim.ex
@@ -42,14 +42,10 @@ defmodule Mobilizon.Service.Geospatial.Nominatim do
     url =
       case method do
         :search ->
-          "#{endpoint}/search?format=geocodejson&q=#{URI.encode(args.q)}&limit=#{limit}&accept-language=#{
-            lang
-          }&addressdetails=1&namedetails=1"
+          "#{endpoint}/search?format=geocodejson&q=#{URI.encode(args.q)}&limit=#{limit}&accept-language=#{lang}&addressdetails=1&namedetails=1"
 
         :geocode ->
-          "#{endpoint}/reverse?format=geocodejson&lat=#{args.lat}&lon=#{args.lon}&accept-language=#{
-            lang
-          }&addressdetails=1&namedetails=1"
+          "#{endpoint}/reverse?format=geocodejson&lat=#{args.lat}&lon=#{args.lon}&accept-language=#{lang}&addressdetails=1&namedetails=1"
           |> add_parameter(options, :zoom)
       end
 
diff --git a/lib/service/notifications/scheduler.ex b/lib/service/notifications/scheduler.ex
index 3a37e7e30..0f9356d6e 100644
--- a/lib/service/notifications/scheduler.ex
+++ b/lib/service/notifications/scheduler.ex
@@ -93,9 +93,7 @@ defmodule Mobilizon.Service.Notifications.Scheduler do
         %DateTime{} = begins_on_shifted = shift_zone(begins_on, timezone)
 
         Logger.debug(
-          "Participation event start at #{inspect(begins_on_shifted)} (user timezone is #{
-            timezone
-          })"
+          "Participation event start at #{inspect(begins_on_shifted)} (user timezone is #{timezone})"
         )
 
         notification_date =
diff --git a/lib/web/media_proxy.ex b/lib/web/media_proxy.ex
index 549f0918d..a7c9fe4fb 100644
--- a/lib/web/media_proxy.ex
+++ b/lib/web/media_proxy.ex
@@ -58,7 +58,19 @@ defmodule Mobilizon.Web.MediaProxy do
   end
 
   defp signed_url(url) do
-    :crypto.mac(:hmac, :sha, Config.get([Web.Endpoint, :secret_key_base]), url)
+    sha_hmac(Config.get([Web.Endpoint, :secret_key_base]), url)
+  end
+
+  @compile {:no_warn_undefined, {:crypto, :mac, 4}}
+  @compile {:no_warn_undefined, {:crypto, :hmac, 3}}
+  defp sha_hmac(key, url) do
+    # :crypto.hmac was removed in OTP24, but :crypto.mac was added in OTP 22.1
+    # TODO: Remove me when we don't support OTP 21/22 anymore
+    if function_exported?(:crypto, :mac, 4) do
+      :crypto.mac(:hmac, :sha, key, url)
+    else
+      :crypto.hmac(:sha, key, url)
+    end
   end
 
   def filename(url_or_path) do
diff --git a/mix.exs b/mix.exs
index 250909836..f5af930ce 100644
--- a/mix.exs
+++ b/mix.exs
@@ -160,7 +160,8 @@ defmodule Mobilizon.Mixfile do
       {:sentry, "~> 8.0"},
       {:html_entities, "~> 0.5"},
       {:sweet_xml, "~> 0.6.6"},
-      {:web_push_encryption, "~> 0.3"},
+      {:web_push_encryption,
+       git: "https://github.com/tcitworld/elixir-web-push-encryption", branch: "otp-24"},
       # Dev and test dependencies
       {:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]},
       {:ex_machina, "~> 2.3", only: [:dev, :test]},
diff --git a/mix.lock b/mix.lock
index 75d8b4aa2..d9520581a 100644
--- a/mix.lock
+++ b/mix.lock
@@ -135,6 +135,6 @@
   "ueberauth_twitter": {:hex, :ueberauth_twitter, "0.4.0", "4b98620341bc91bac90459093bba093c650823b6e2df35b70255c493c17e9227", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:oauther, "~> 1.1", [hex: :oauther, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.6", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "fb29c9047ca263038c0c61f5a0ec8597e8564aba3f2b4cb02704b60205fd4468"},
   "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
   "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
-  "web_push_encryption": {:hex, :web_push_encryption, "0.3.0", "598b5135e696fd1404dc8d0d7c0fa2c027244a4e5d5e5a98ba267f14fdeaabc8", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "f10bdd1afe527ede694749fb77a2f22f146a51b054c7fa541c9fd920fba7c875"},
+  "web_push_encryption": {:git, "https://github.com/tcitworld/elixir-web-push-encryption", "4361bd02b0b7f2cb5f8ac302bcd1210b57964a51", [branch: "otp-24"]},
   "xml_builder": {:hex, :xml_builder, "2.1.4", "e60e21c0a39b9dd8dec1db5a2525c713f7fe4e85ed247caedf22a9bcdd2d5069", [:mix], [], "hexpm", "48188a4df8b9168ceb8318d128299bce064d272e18967349b2592347c434e677"},
 }
diff --git a/priv/repo/migrations/20190929170817_rename_postgres_types.exs b/priv/repo/migrations/20190929170817_rename_postgres_types.exs
index b418e6793..ca2057a22 100644
--- a/priv/repo/migrations/20190929170817_rename_postgres_types.exs
+++ b/priv/repo/migrations/20190929170817_rename_postgres_types.exs
@@ -36,9 +36,7 @@ defmodule Mobilizon.Storage.Repo.Migrations.RenamePostgresTypes do
     with %Postgrex.Result{columns: ["exists"], rows: [[true]]} <-
            Ecto.Adapters.SQL.query!(
              Mobilizon.Storage.Repo,
-             "select exists (select 1 from pg_type where typname = '#{
-               old_type_name |> remove_schema
-             }' and typnamespace = (select oid from pg_namespace where nspname = 'public'))"
+             "select exists (select 1 from pg_type where typname = '#{old_type_name |> remove_schema}' and typnamespace = (select oid from pg_namespace where nspname = 'public'))"
            ) do
       Ecto.Migration.execute(
         "ALTER TYPE #{old_type_name |> remove_schema} RENAME TO #{new_type_name |> remove_schema}"
diff --git a/priv/repo/migrations/20210217164549_add_member_since_to_members.exs b/priv/repo/migrations/20210217164549_add_member_since_to_members.exs
index d4eaaf118..87e1ff0a8 100644
--- a/priv/repo/migrations/20210217164549_add_member_since_to_members.exs
+++ b/priv/repo/migrations/20210217164549_add_member_since_to_members.exs
@@ -18,9 +18,7 @@ defmodule Mobilizon.Storage.Repo.Migrations.AddMemberSinceToMembers do
       if role in ["member", "moderator", "administrator", "creator"] do
         Ecto.Adapters.SQL.query!(
           Mobilizon.Storage.Repo,
-          "UPDATE members SET member_since = '#{DateTime.to_iso8601(DateTime.utc_now())}' WHERE id = '#{
-            Ecto.UUID.cast!(id)
-          }'"
+          "UPDATE members SET member_since = '#{DateTime.to_iso8601(DateTime.utc_now())}' WHERE id = '#{Ecto.UUID.cast!(id)}'"
         )
       end
     end)
diff --git a/test/graphql/resolvers/event_test.exs b/test/graphql/resolvers/event_test.exs
index 94db0cd68..ec07b5bd9 100644
--- a/test/graphql/resolvers/event_test.exs
+++ b/test/graphql/resolvers/event_test.exs
@@ -384,9 +384,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
               createEvent(
                   title: "my event is referenced",
                   description: "with tags!",
-                  begins_on: "#{
-        DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
-      }",
+                  begins_on: "#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
                   organizer_actor_id: "#{actor.id}",
                   category: "birthday",
                   tags: ["nicolas", "birthday", "bad tag"]
@@ -428,9 +426,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
               createEvent(
                   title: "my event is referenced",
                   description: "with tags!",
-                  begins_on: "#{
-        DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
-      }",
+                  begins_on: "#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
                   organizer_actor_id: "#{actor.id}",
                   category: "birthday",
                   physical_address: {
@@ -470,9 +466,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
               createEvent(
                   title: "my event is referenced",
                   description: "with tags!",
-                  begins_on: "#{
-        DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
-      }",
+                  begins_on: "#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
                   organizer_actor_id: "#{actor.id}",
                   category: "birthday",
                   physical_address: {
@@ -520,9 +514,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
               createEvent(
                   title: "come to my event",
                   description: "it will be fine",
-                  begins_on: "#{
-        DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
-      }",
+                  begins_on: "#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
                   organizer_actor_id: "#{actor.id}",
                   category: "birthday",
                   picture: {
@@ -609,9 +601,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
               createEvent(
                   title: "come to my event",
                   description: "it will be fine",
-                  begins_on: "#{
-        DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
-      }",
+                  begins_on: "#{DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
                   organizer_actor_id: "#{actor.id}",
                   category: "birthday",
                   picture: {
diff --git a/test/service/formatter/formatter_test.exs b/test/service/formatter/formatter_test.exs
index 3dd7ba167..3a5451354 100644
--- a/test/service/formatter/formatter_test.exs
+++ b/test/service/formatter/formatter_test.exs
@@ -130,11 +130,7 @@ defmodule Mobilizon.Service.FormatterTest do
       assert length(mentions) == 3
 
       expected_text =
-        "<span class=\"h-card mention\" data-user=\"#{gsimg.id}\">@<span>gsimg</span></span> According to <span class=\"h-card mention\" data-user=\"#{
-          archaeme.id
-        }\">@<span>archa_eme_</span></span>, that is @daggsy. Also hello <span class=\"h-card mention\" data-user=\"#{
-          archaeme_remote.id
-        }\">@<span>archaeme</span></span>"
+        "<span class=\"h-card mention\" data-user=\"#{gsimg.id}\">@<span>gsimg</span></span> According to <span class=\"h-card mention\" data-user=\"#{archaeme.id}\">@<span>archa_eme_</span></span>, that is @daggsy. Also hello <span class=\"h-card mention\" data-user=\"#{archaeme_remote.id}\">@<span>archaeme</span></span>"
 
       assert expected_text == text
     end
diff --git a/test/service/metadata/instance_test.exs b/test/service/metadata/instance_test.exs
index 8e7033e80..e39c67e87 100644
--- a/test/service/metadata/instance_test.exs
+++ b/test/service/metadata/instance_test.exs
@@ -10,15 +10,7 @@ defmodule Mobilizon.Service.Metadata.InstanceTest do
       description = Utils.process_description(Config.instance_description())
 
       assert Instance.build_tags() |> Utils.stringify_tags() ==
-               "<title>#{title}</title><meta content=\"#{description}\" name=\"description\"><meta content=\"#{
-                 title
-               }\" property=\"og:title\"><meta content=\"#{Endpoint.url()}\" property=\"og:url\"><meta content=\"#{
-                 description
-               }\" property=\"og:description\"><meta content=\"website\" property=\"og:type\"><script type=\"application/ld+json\">{\n\"@context\": \"http://schema.org\",\n\"@type\": \"WebSite\",\n\"name\": \"#{
-                 title
-               }\",\n\"url\": \"#{Endpoint.url()}\",\n\"potentialAction\": {\n\"@type\": \"SearchAction\",\n\"target\": \"#{
-                 Endpoint.url()
-               }/search?term={search_term}\",\n\"query-input\": \"required name=search_term\"\n}\n}</script>\n"
+               "<title>#{title}</title><meta content=\"#{description}\" name=\"description\"><meta content=\"#{title}\" property=\"og:title\"><meta content=\"#{Endpoint.url()}\" property=\"og:url\"><meta content=\"#{description}\" property=\"og:description\"><meta content=\"website\" property=\"og:type\"><script type=\"application/ld+json\">{\n\"@context\": \"http://schema.org\",\n\"@type\": \"WebSite\",\n\"name\": \"#{title}\",\n\"url\": \"#{Endpoint.url()}\",\n\"potentialAction\": {\n\"@type\": \"SearchAction\",\n\"target\": \"#{Endpoint.url()}/search?term={search_term}\",\n\"query-input\": \"required name=search_term\"\n}\n}</script>\n"
     end
   end
 end
diff --git a/test/service/metadata/metadata_test.exs b/test/service/metadata/metadata_test.exs
index 0a747eab2..290a8a307 100644
--- a/test/service/metadata/metadata_test.exs
+++ b/test/service/metadata/metadata_test.exs
@@ -15,35 +15,17 @@ defmodule Mobilizon.Service.MetadataTest do
       %Actor{} = group = insert(:group, name: "My group")
 
       assert group |> Metadata.build_tags() |> Metadata.Utils.stringify_tags() ==
-               "<meta content=\"#{group.name} (@#{group.preferred_username})\" property=\"og:title\"><meta content=\"#{
-                 group.url
-               }\" property=\"og:url\"><meta content=\"The event organizer didn&#39;t add any description.\" property=\"og:description\"><meta content=\"profile\" property=\"og:type\"><meta content=\"#{
-                 group.preferred_username
-               }\" property=\"profile:username\"><meta content=\"summary\" property=\"twitter:card\"><meta content=\"#{
-                 group.avatar.url
-               }\" property=\"og:image\"><script type=\"application/ld+json\">{\"@context\":\"http://schema.org\",\"@type\":\"Organization\",\"address\":null,\"name\":\"#{
-                 group.name
-               }\",\"url\":\"#{group.url}\"}</script><link href=\"#{
-                 Routes.feed_url(Endpoint, :actor, group.preferred_username, "atom")
-               }\" rel=\"alternate\" title=\"#{group.name}'s feed\" type=\"application/atom+xml\"><link href=\"#{
-                 Routes.feed_url(Endpoint, :actor, group.preferred_username, "ics")
-               }\" rel=\"alternate\" title=\"#{group.name}'s feed\" type=\"text/calendar\">"
+               String.trim("""
+               <meta content="#{group.name} (@#{group.preferred_username})" property="og:title"><meta content="#{group.url}" property="og:url"><meta content="The event organizer didn&#39;t add any description." property="og:description"><meta content="profile" property="og:type"><meta content="#{group.preferred_username}" property="profile:username"><meta content="summary" property="twitter:card"><meta content="#{group.avatar.url}" property="og:image"><script type="application/ld+json">{"@context":"http://schema.org","@type":"Organization","address":null,"name":"#{group.name}","url":"#{group.url}"}</script><link href="#{Routes.feed_url(Endpoint, :actor, group.preferred_username, "atom")}" rel="alternate" title="#{group.name}'s feed" type="application/atom+xml"><link href="#{Routes.feed_url(Endpoint, :actor, group.preferred_username, "ics")}" rel="alternate" title="#{group.name}'s feed" type="text/calendar">
+               """)
 
       assert group
              |> Map.put(:avatar, nil)
              |> Metadata.build_tags()
              |> Metadata.Utils.stringify_tags() ==
-               "<meta content=\"#{group.name} (@#{group.preferred_username})\" property=\"og:title\"><meta content=\"#{
-                 group.url
-               }\" property=\"og:url\"><meta content=\"The event organizer didn&#39;t add any description.\" property=\"og:description\"><meta content=\"profile\" property=\"og:type\"><meta content=\"#{
-                 group.preferred_username
-               }\" property=\"profile:username\"><meta content=\"summary\" property=\"twitter:card\"><script type=\"application/ld+json\">{\"@context\":\"http://schema.org\",\"@type\":\"Organization\",\"address\":null,\"name\":\"#{
-                 group.name
-               }\",\"url\":\"#{group.url}\"}</script><link href=\"#{
-                 Routes.feed_url(Endpoint, :actor, group.preferred_username, "atom")
-               }\" rel=\"alternate\" title=\"#{group.name}'s feed\" type=\"application/atom+xml\"><link href=\"#{
-                 Routes.feed_url(Endpoint, :actor, group.preferred_username, "ics")
-               }\" rel=\"alternate\" title=\"#{group.name}'s feed\" type=\"text/calendar\">"
+               String.trim("""
+               <meta content="#{group.name} (@#{group.preferred_username})" property="og:title"><meta content="#{group.url}" property="og:url"><meta content="The event organizer didn&#39;t add any description." property="og:description"><meta content="profile" property="og:type"><meta content="#{group.preferred_username}" property="profile:username"><meta content="summary" property="twitter:card"><script type="application/ld+json">{"@context":"http://schema.org","@type":"Organization","address":null,"name":"#{group.name}","url":"#{group.url}"}</script><link href="#{Routes.feed_url(Endpoint, :actor, group.preferred_username, "atom")}" rel="alternate" title="#{group.name}'s feed" type="application/atom+xml"><link href="#{Routes.feed_url(Endpoint, :actor, group.preferred_username, "ics")}" rel="alternate" title="#{group.name}'s feed" type="text/calendar">
+               """)
     end
 
     test "that is not a group doesn't give anything" do
@@ -67,45 +49,17 @@ defmodule Mobilizon.Service.MetadataTest do
       assert event
              |> Metadata.build_tags()
              |> Metadata.Utils.stringify_tags() ==
-               "<title>#{event.title} - Mobilizon</title><meta content=\"#{event.description}\" name=\"description\"><meta content=\"#{
-                 event.title
-               }\" property=\"og:title\"><meta content=\"#{event.url}\" property=\"og:url\"><meta content=\"#{
-                 event.description
-               }\" property=\"og:description\"><meta content=\"website\" property=\"og:type\"><link href=\"#{
-                 event.url
-               }\" rel=\"canonical\"><meta content=\"#{event.picture.file.url}\" property=\"og:image\"><meta content=\"summary_large_image\" property=\"twitter:card\"><script type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"Event\",\"description\":\"#{
-                 String.replace(event.description, a, b)
-               }\",\"endDate\":\"#{DateTime.to_iso8601(event.ends_on)}\",\"eventStatus\":\"https://schema.org/EventScheduled\",\"image\":[\"#{
-                 event.picture.file.url
-               }\"],\"location\":{\"@type\":\"Place\",\"address\":{\"@type\":\"PostalAddress\",\"addressCountry\":\"My Country\",\"addressLocality\":\"My Locality\",\"addressRegion\":\"My Region\",\"postalCode\":\"My Postal Code\",\"streetAddress\":\"My Street Address\"},\"name\":\"#{
-                 event.physical_address.description
-               }\"},\"name\":\"#{event.title}\",\"organizer\":{\"@type\":\"Person\",\"name\":\"#{
-                 event.organizer_actor.preferred_username
-               }\"},\"performer\":{\"@type\":\"Person\",\"name\":\"#{
-                 event.organizer_actor.preferred_username
-               }\"},\"startDate\":\"#{DateTime.to_iso8601(event.begins_on)}\"}</script>"
+               String.trim("""
+               <title>#{event.title} - Mobilizon</title><meta content="#{event.description}" name="description"><meta content="#{event.title}" property="og:title"><meta content="#{event.url}" property="og:url"><meta content="#{event.description}" property="og:description"><meta content="website" property="og:type"><link href="#{event.url}" rel="canonical"><meta content="#{event.picture.file.url}" property="og:image"><meta content="summary_large_image" property="twitter:card"><script type="application/ld+json">{"@context":"https://schema.org","@type":"Event","description":"#{String.replace(event.description, a, b)}","endDate":"#{DateTime.to_iso8601(event.ends_on)}","eventStatus":"https://schema.org/EventScheduled","image":["#{event.picture.file.url}"],"location":{"@type":"Place","address":{"@type":"PostalAddress","addressCountry":"My Country","addressLocality":"My Locality","addressRegion":"My Region","postalCode":"My Postal Code","streetAddress":"My Street Address"},"name":"#{event.physical_address.description}"},"name":"#{event.title}","organizer":{"@type":"Person","name":"#{event.organizer_actor.preferred_username}"},"performer":{"@type":"Person","name":"#{event.organizer_actor.preferred_username}"},"startDate":"#{DateTime.to_iso8601(event.begins_on)}"}</script>
+               """)
 
       assert event
              |> Map.put(:picture, nil)
              |> Metadata.build_tags()
              |> Metadata.Utils.stringify_tags() ==
-               "<title>#{event.title} - Mobilizon</title><meta content=\"#{event.description}\" name=\"description\"><meta content=\"#{
-                 event.title
-               }\" property=\"og:title\"><meta content=\"#{event.url}\" property=\"og:url\"><meta content=\"#{
-                 event.description
-               }\" property=\"og:description\"><meta content=\"website\" property=\"og:type\"><link href=\"#{
-                 event.url
-               }\" rel=\"canonical\"><meta content=\"summary_large_image\" property=\"twitter:card\"><script type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"Event\",\"description\":\"#{
-                 String.replace(event.description, a, b)
-               }\",\"endDate\":\"#{DateTime.to_iso8601(event.ends_on)}\",\"eventStatus\":\"https://schema.org/EventScheduled\",\"image\":[\"#{
-                 "#{Endpoint.url()}/img/mobilizon_default_card.png"
-               }\"],\"location\":{\"@type\":\"Place\",\"address\":{\"@type\":\"PostalAddress\",\"addressCountry\":\"My Country\",\"addressLocality\":\"My Locality\",\"addressRegion\":\"My Region\",\"postalCode\":\"My Postal Code\",\"streetAddress\":\"My Street Address\"},\"name\":\"#{
-                 event.physical_address.description
-               }\"},\"name\":\"#{event.title}\",\"organizer\":{\"@type\":\"Person\",\"name\":\"#{
-                 event.organizer_actor.preferred_username
-               }\"},\"performer\":{\"@type\":\"Person\",\"name\":\"#{
-                 event.organizer_actor.preferred_username
-               }\"},\"startDate\":\"#{DateTime.to_iso8601(event.begins_on)}\"}</script>"
+               String.trim("""
+               <title>#{event.title} - Mobilizon</title><meta content="#{event.description}" name="description"><meta content="#{event.title}" property="og:title"><meta content="#{event.url}" property="og:url"><meta content="#{event.description}" property="og:description"><meta content="website" property="og:type"><link href="#{event.url}" rel="canonical"><meta content="summary_large_image" property="twitter:card"><script type="application/ld+json">{"@context":"https://schema.org","@type":"Event","description":"#{String.replace(event.description, a, b)}","endDate":"#{DateTime.to_iso8601(event.ends_on)}","eventStatus":"https://schema.org/EventScheduled","image":["#{"#{Endpoint.url()}/img/mobilizon_default_card.png"}"],"location":{"@type":"Place","address":{"@type":"PostalAddress","addressCountry":"My Country","addressLocality":"My Locality","addressRegion":"My Region","postalCode":"My Postal Code","streetAddress":"My Street Address"},"name":"#{event.physical_address.description}"},"name":"#{event.title}","organizer":{"@type":"Person","name":"#{event.organizer_actor.preferred_username}"},"performer":{"@type":"Person","name":"#{event.organizer_actor.preferred_username}"},"startDate":"#{DateTime.to_iso8601(event.begins_on)}"}</script>
+               """)
     end
   end
 
@@ -116,15 +70,9 @@ defmodule Mobilizon.Service.MetadataTest do
       assert post
              |> Metadata.build_tags()
              |> Metadata.Utils.stringify_tags() ==
-               "<meta content=\"#{post.title}\" property=\"og:title\"><meta content=\"#{post.url}\" property=\"og:url\"><meta content=\"#{
-                 Metadata.Utils.process_description(post.body)
-               }\" property=\"og:description\"><meta content=\"article\" property=\"og:type\"><meta content=\"summary\" property=\"twitter:card\"><link href=\"#{
-                 post.url
-               }\" rel=\"canonical\"><meta content=\"#{post.picture.file.url}\" property=\"og:image\"><meta content=\"summary_large_image\" property=\"twitter:card\"><script type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"Article\",\"author\":{\"@type\":\"Organization\",\"name\":\"#{
-                 post.attributed_to.preferred_username
-               }\"},\"dateModified\":\"#{DateTime.to_iso8601(post.updated_at)}\",\"datePublished\":\"#{
-                 DateTime.to_iso8601(post.publish_at)
-               }\",\"name\":\"My Awesome article\"}</script>"
+               String.trim("""
+               <meta content="#{post.title}" property="og:title"><meta content="#{post.url}" property="og:url"><meta content="#{Metadata.Utils.process_description(post.body)}" property="og:description"><meta content="article" property="og:type"><meta content="summary" property="twitter:card"><link href="#{post.url}" rel="canonical"><meta content="#{post.picture.file.url}" property="og:image"><meta content="summary_large_image" property="twitter:card"><script type="application/ld+json">{"@context":"https://schema.org","@type":"Article","author":{"@type":"Organization","name":"#{post.attributed_to.preferred_username}"},"dateModified":"#{DateTime.to_iso8601(post.updated_at)}","datePublished":"#{DateTime.to_iso8601(post.publish_at)}","name":"My Awesome article"}</script>
+               """)
     end
   end
 
@@ -135,9 +83,9 @@ defmodule Mobilizon.Service.MetadataTest do
       assert comment
              |> Metadata.build_tags()
              |> Metadata.Utils.stringify_tags() ==
-               "<meta content=\"#{comment.actor.preferred_username}\" property=\"og:title\"><meta content=\"#{
-                 comment.url
-               }\" property=\"og:url\"><meta content=\"#{comment.text}\" property=\"og:description\"><meta content=\"website\" property=\"og:type\"><meta content=\"summary\" property=\"twitter:card\">"
+               String.trim("""
+               <meta content="#{comment.actor.preferred_username}" property="og:title"><meta content="#{comment.url}" property="og:url"><meta content="#{comment.text}" property="og:description"><meta content="website" property="og:type"><meta content="summary" property="twitter:card">
+               """)
     end
   end
 
diff --git a/test/tasks/users_test.exs b/test/tasks/users_test.exs
index f263fa6cc..6c0463a39 100644
--- a/test/tasks/users_test.exs
+++ b/test/tasks/users_test.exs
@@ -82,11 +82,7 @@ defmodule Mix.Tasks.Mobilizon.UsersTest do
       actor2 = insert(:actor, user: user)
 
       output =
-        "Informations for the user #{@email}:\n  - account status: Activated on #{confirmed_at} (UTC)\n  - Role: #{
-          role
-        }\n  Identities (2):\n    - @#{actor1.preferred_username} / \n    - @#{
-          actor2.preferred_username
-        } / \n\n\n"
+        "Informations for the user #{@email}:\n  - account status: Activated on #{confirmed_at} (UTC)\n  - Role: #{role}\n  Identities (2):\n    - @#{actor1.preferred_username} / \n    - @#{actor2.preferred_username} / \n\n\n"
 
       Show.run([@email])
       assert_received {:mix_shell, :info, [output_received]}
@@ -136,9 +132,7 @@ defmodule Mix.Tasks.Mobilizon.UsersTest do
       assert_received {:mix_shell, :info, [output_received]}
 
       assert output_received ==
-               "An user has been modified with the following information:\n  - email: #{
-                 user.email
-               }\n  - Role: #{user.role}\n  - account status: disabled\n"
+               "An user has been modified with the following information:\n  - email: #{user.email}\n  - Role: #{user.role}\n  - account status: disabled\n"
 
       assert {:ok, %User{confirmed_at: confirmed_at}} = Users.get_user_by_email(@email)
 
@@ -150,9 +144,7 @@ defmodule Mix.Tasks.Mobilizon.UsersTest do
       assert {:ok, %User{confirmed_at: confirmed_at}} = Users.get_user_by_email(@email)
 
       assert output_received ==
-               "An user has been modified with the following information:\n  - email: #{
-                 user.email
-               }\n  - Role: #{user.role}\n  - account status: activated on #{confirmed_at} (UTC)\n"
+               "An user has been modified with the following information:\n  - email: #{user.email}\n  - Role: #{user.role}\n  - account status: activated on #{confirmed_at} (UTC)\n"
 
       refute is_nil(confirmed_at)
 
@@ -183,9 +175,7 @@ defmodule Mix.Tasks.Mobilizon.UsersTest do
                Users.get_user_by_email(@modified_email)
 
       assert output_received ==
-               "An user has been modified with the following information:\n  - email: #{
-                 @modified_email
-               }\n  - Role: #{user.role}\n  - account status: activated on #{confirmed_at} (UTC)\n"
+               "An user has been modified with the following information:\n  - email: #{@modified_email}\n  - Role: #{user.role}\n  - account status: activated on #{confirmed_at} (UTC)\n"
     end
   end
 end
diff --git a/test/web/controllers/webfinger_controller_test.exs b/test/web/controllers/webfinger_controller_test.exs
index d5dfff832..bfbe7d4c8 100644
--- a/test/web/controllers/webfinger_controller_test.exs
+++ b/test/web/controllers/webfinger_controller_test.exs
@@ -23,9 +23,7 @@ defmodule Mobilizon.Web.WebFingerControllerTest do
     conn = get(conn, "/.well-known/host-meta")
 
     assert response(conn, 200) ==
-             "<?xml version=\"1.0\" encoding=\"UTF-8\"?><XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\" xmlns:hm=\"http://host-meta.net/ns/1.0\"><hm:Host>mobilizon.test</hm:Host><Link rel=\"lrdd\" template=\"#{
-               Endpoint.url()
-             }/.well-known/webfinger?resource={uri}\" type=\"application/jrd+json\" /></XRD>"
+             "<?xml version=\"1.0\" encoding=\"UTF-8\"?><XRD xmlns=\"http://docs.oasis-open.org/ns/xri/xrd-1.0\" xmlns:hm=\"http://host-meta.net/ns/1.0\"><hm:Host>mobilizon.test</hm:Host><Link rel=\"lrdd\" template=\"#{Endpoint.url()}/.well-known/webfinger?resource={uri}\" type=\"application/jrd+json\" /></XRD>"
 
     assert {"content-type", "application/xrd+xml; charset=utf-8"} in conn.resp_headers
   end