defmodule PlausibleWeb.TrackerPlugTest do
  @moduledoc """
  This test module uses auto-generated JavaScript tracker files in priv/tracker/js.

  To speed up running Elixir tests locally, the tracker files are not automatically generated
  with every `mix test` command. That means, you have to manually run the below command
  once before executing `mix test`. This is to make sure all tracker files are in place and up to date.

  ```
  npm run deploy --prefix tracker
  ```

  If you're making changes in the tracker template files (`src/plausible.js`, `compile.js`),
  do regenerate the files before running tests, so they're up to date.
  """
  use PlausibleWeb.ConnCase, async: true
  use Plausible.Teams.Test
  import Plug.Test

  alias PlausibleWeb.Tracker

  describe "plausible-web.js" do
    @example_config %{
      installation_type: :manual,
      track_404_pages: true,
      hash_based_routing: true,
      file_downloads: false,
      outbound_links: false,
      pageview_props: false,
      tagged_events: true,
      revenue_tracking: false,
      form_submissions: true
    }

    test "returns the script for an existing site", %{conn: conn} do
      site = new_site()

      tracker_script_configuration =
        Tracker.update_script_configuration!(
          site,
          Map.put(@example_config, :site_id, site.id),
          :installation
        )

      response = get(conn, "/js/#{tracker_script_configuration.id}.js") |> response(200)

      assert String.contains?(response, "!function(){var")
      assert String.contains?(response, "domain:\"#{site.domain}\"")
      assert String.contains?(response, "formSubmissions:!0")
      refute String.contains?(response, "outboundLinks:!0")
      refute String.contains?(response, "fileDownloads:!0")
    end

    # window.plausible is a substring checked for by the wordpress plugin to avoid 'optimization' by other wordpress plugins
    test "script contains window.plausible", %{conn: conn} do
      site = new_site()

      tracker_script_configuration =
        Tracker.update_script_configuration!(
          site,
          Map.put(@example_config, :site_id, site.id),
          :installation
        )

      response = get(conn, "/js/#{tracker_script_configuration.id}.js") |> response(200)

      assert String.contains?(response, "window.plausible")
    end

    test "returns 404 for unknown site", %{conn: conn} do
      conn
      |> get("/js/pa-a14125a2-000-000-0000-000000000000.js")
      |> response(404)
    end
  end

  describe "legacy variants" do
    test "returns legacy script p.js" do
      assert String.contains?(get_script("p.js"), "; samesite=strict; path=/")
    end

    test "returns plausible script with every alias" do
      plausible_js_response = get_script("plausible.js")

      assert plausible_js_response == get_script("script.js")
      assert plausible_js_response == get_script("analytics.js")
    end

    test "returns the right script extensions no matter the order" do
      response = get_script("plausible.compat.file-downloads.hash.outbound-links.js")

      assert String.contains?(response, "getElementById(\"plausible\")")
      assert String.contains?(response, "file-types")
      assert String.contains?(response, "hashchange")
      assert String.contains?(response, "Outbound Link: Click")

      refute String.contains?(response, "data-exclude")
      # local extension disabled
      assert String.contains?(response, "/^localhost$|^127(\\.[0-9]+)")

      assert response == get_script("plausible.outbound-links.file-downloads.compat.hash.js")
    end

    test "pageleave extension" do
      # Some customers who have participated in the private preview of the
      # scroll depth feature, have updated their tracking scripts to
      # `script.pageleave.js` per our request. With the public release of
      # scroll depth, this functionality is included in the default script,
      # but we must continue to serve `script.pageleave.js` for as long as
      # those customers are still using it.
      assert get_script("script.pageleave.js") == get_script("script.js")
      assert get_script("script.manual.pageleave.js") == get_script("script.manual.js")
    end

    for variant <- [
          "plausible.js",
          "script.manual.pageview-props.tagged-events.pageleave.js",
          "script.compat.local.exclusions.js",
          "script.hash.revenue.file-downloads.pageview-props.js"
        ] do
      test "variant #{variant} is available" do
        script = get_script(unquote(variant))
        assert String.starts_with?(script, "!function(){var")
        assert String.length(script) > 200

        assert String.contains?(script, "window.plausible")
      end
    end
  end

  def get_script(filename) do
    opts = PlausibleWeb.TrackerPlug.init([])

    conn(:get, "/js/#{filename}")
    |> PlausibleWeb.TrackerPlug.call(opts)
    |> response(200)
  end
end
