Filter out empty entries when listing stats for UTM props (#3339)

* Filter out empty entries when listing stats for UTM props

* Update test fixtures removing noref entries in UTM CSV stat exports

* Update external API tests to account for lack of noref records for UTM stats

* Filter out entries with empty UTM props from imported GA stats

* Remove unreachable GA utm_source dim clause in imported stats logic
This commit is contained in:
Adrian Gruntkowski 2023-09-12 09:11:50 +02:00 committed by GitHub
parent 9b029c1558
commit 27a11fc5b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 484 additions and 246 deletions

View File

@ -443,9 +443,10 @@ defmodule Plausible.Stats.Breakdown do
defp do_group_by(q, "visit:utm_medium") do
from(
s in q,
where: fragment("not empty(?)", s.utm_medium),
group_by: s.utm_medium,
select_merge: %{
utm_medium: fragment("if(empty(?), ?, ?)", s.utm_medium, @no_ref, s.utm_medium)
utm_medium: s.utm_medium
}
)
end
@ -453,9 +454,10 @@ defmodule Plausible.Stats.Breakdown do
defp do_group_by(q, "visit:utm_source") do
from(
s in q,
where: fragment("not empty(?)", s.utm_source),
group_by: s.utm_source,
select_merge: %{
utm_source: fragment("if(empty(?), ?, ?)", s.utm_source, @no_ref, s.utm_source)
utm_source: s.utm_source
}
)
end
@ -463,9 +465,10 @@ defmodule Plausible.Stats.Breakdown do
defp do_group_by(q, "visit:utm_campaign") do
from(
s in q,
where: fragment("not empty(?)", s.utm_campaign),
group_by: s.utm_campaign,
select_merge: %{
utm_campaign: fragment("if(empty(?), ?, ?)", s.utm_campaign, @no_ref, s.utm_campaign)
utm_campaign: s.utm_campaign
}
)
end
@ -473,9 +476,10 @@ defmodule Plausible.Stats.Breakdown do
defp do_group_by(q, "visit:utm_content") do
from(
s in q,
where: fragment("not empty(?)", s.utm_content),
group_by: s.utm_content,
select_merge: %{
utm_content: fragment("if(empty(?), ?, ?)", s.utm_content, @no_ref, s.utm_content)
utm_content: s.utm_content
}
)
end
@ -483,9 +487,10 @@ defmodule Plausible.Stats.Breakdown do
defp do_group_by(q, "visit:utm_term") do
from(
s in q,
where: fragment("not empty(?)", s.utm_term),
group_by: s.utm_term,
select_merge: %{
utm_term: fragment("if(empty(?), ?, ?)", s.utm_term, @no_ref, s.utm_term)
utm_term: s.utm_term
}
)
end

View File

@ -142,32 +142,30 @@ defmodule Plausible.Stats.Imported do
:utm_medium ->
imported_q
|> where([i], fragment("not empty(?)", i.utm_medium))
|> select_merge([i], %{
utm_medium: fragment("if(empty(?), ?, ?)", i.utm_medium, @no_ref, i.utm_medium)
})
:utm_source ->
imported_q
|> select_merge([i], %{
utm_source: fragment("if(empty(?), ?, ?)", i.utm_source, @no_ref, i.utm_source)
utm_medium: i.utm_medium
})
:utm_campaign ->
imported_q
|> where([i], fragment("not empty(?)", i.utm_campaign))
|> select_merge([i], %{
utm_campaign: fragment("if(empty(?), ?, ?)", i.utm_campaign, @no_ref, i.utm_campaign)
utm_campaign: i.utm_campaign
})
:utm_term ->
imported_q
|> where([i], fragment("not empty(?)", i.utm_term))
|> select_merge([i], %{
utm_term: fragment("if(empty(?), ?, ?)", i.utm_term, @no_ref, i.utm_term)
utm_term: i.utm_term
})
:utm_content ->
imported_q
|> where([i], fragment("not empty(?)", i.utm_content))
|> select_merge([i], %{
utm_content: fragment("if(empty(?), ?, ?)", i.utm_content, @no_ref, i.utm_content)
utm_content: i.utm_content
})
:page ->

View File

@ -306,12 +306,6 @@ defmodule Plausible.ImportedTest do
"name" => "social",
"visit_duration" => 20,
"visitors" => 3
},
%{
"bounce_rate" => 100.0,
"name" => "Direct / None",
"visit_duration" => 60.0,
"visitors" => 1
}
]
end
@ -395,12 +389,6 @@ defmodule Plausible.ImportedTest do
"visitors" => 2,
"bounce_rate" => 100.0,
"visit_duration" => 50.0
},
%{
"bounce_rate" => 0.0,
"name" => "Direct / None",
"visit_duration" => 100.0,
"visitors" => 1
}
]
end
@ -485,12 +473,6 @@ defmodule Plausible.ImportedTest do
"visitors" => 2,
"bounce_rate" => 100.0,
"visit_duration" => 50.0
},
%{
"bounce_rate" => 0.0,
"name" => "Direct / None",
"visit_duration" => 100.0,
"visitors" => 1
}
]
end
@ -574,12 +556,6 @@ defmodule Plausible.ImportedTest do
"visitors" => 2,
"bounce_rate" => 100.0,
"visit_duration" => 50.0
},
%{
"bounce_rate" => 0.0,
"name" => "Direct / None",
"visit_duration" => 100.0,
"visitors" => 1
}
]
end

View File

@ -1,2 +1 @@
name,conversions,conversion_rate
Direct / None,1,33.3

1 name conversions conversion_rate
Direct / None 1 33.3

View File

@ -1,2 +1 @@
name,conversions,conversion_rate
Direct / None,1,33.3

1 name conversions conversion_rate
Direct / None 1 33.3

View File

@ -1,2 +1 @@
name,conversions,conversion_rate
Direct / None,1,33.3

1 name conversions conversion_rate
Direct / None 1 33.3

View File

@ -1,2 +1 @@
name,conversions,conversion_rate
Direct / None,1,33.3

1 name conversions conversion_rate
Direct / None 1 33.3

View File

@ -1,2 +1 @@
name,conversions,conversion_rate
Direct / None,1,33.3

1 name conversions conversion_rate
Direct / None 1 33.3

View File

@ -1,2 +1 @@
name,visitors,bounce_rate,visit_duration
Direct / None,1,0,60

1 name visitors bounce_rate visit_duration
Direct / None 1 0 60

View File

@ -1,2 +1 @@
name,visitors,bounce_rate,visit_duration
Direct / None,1,0,60

1 name visitors bounce_rate visit_duration
Direct / None 1 0 60

View File

@ -1,2 +1 @@
name,visitors,bounce_rate,visit_duration
Direct / None,1,0,60

1 name visitors bounce_rate visit_duration
Direct / None 1 0 60

View File

@ -1,2 +1 @@
name,visitors,bounce_rate,visit_duration
Direct / None,1,0,60

1 name visitors bounce_rate visit_duration
Direct / None 1 0 60

View File

@ -1,2 +1 @@
name,visitors,bounce_rate,visit_duration
Direct / None,1,0,60

1 name visitors bounce_rate visit_duration
Direct / None 1 0 60

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,3,67,20
ads,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 3 67 20
2 ads 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,3,67,20
content,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 3 67 20
2 content 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,3,67,20
search,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 3 67 20
2 search 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,3,67,20
google,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 3 67 20
2 google 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,3,67,20
term,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 3 67 20
2 term 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,3,67,20
ads,2,100,0

1 name visitors bounce_rate visit_duration
Direct / None 3 67 20
2 ads 2 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,4,75,15
content,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 4 75 15
2 content 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,4,75,15
search,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 4 75 15
2 search 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,4,75,15
google,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 4 75 15
2 google 1 100 0

View File

@ -1,3 +1,2 @@
name,visitors,bounce_rate,visit_duration
Direct / None,4,75,15
term,1,100,0

1 name visitors bounce_rate visit_duration
Direct / None 4 75 15
2 term 1 100 0

View File

@ -243,8 +243,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
assert json_response(conn, 200) == %{
"results" => [
%{"utm_medium" => "Search", "visitors" => 2},
%{"utm_medium" => "Direct / None", "visitors" => 1}
%{"utm_medium" => "Search", "visitors" => 2}
]
}
end
@ -275,8 +274,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
assert json_response(conn, 200) == %{
"results" => [
%{"utm_source" => "Google", "visitors" => 2},
%{"utm_source" => "Direct / None", "visitors" => 1}
%{"utm_source" => "Google", "visitors" => 2}
]
}
end
@ -307,8 +305,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
assert json_response(conn, 200) == %{
"results" => [
%{"utm_campaign" => "ads", "visitors" => 2},
%{"utm_campaign" => "Direct / None", "visitors" => 1}
%{"utm_campaign" => "ads", "visitors" => 2}
]
}
end
@ -339,8 +336,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
assert json_response(conn, 200) == %{
"results" => [
%{"utm_content" => "Content1", "visitors" => 2},
%{"utm_content" => "Direct / None", "visitors" => 1}
%{"utm_content" => "Content1", "visitors" => 2}
]
}
end
@ -371,8 +367,7 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
assert json_response(conn, 200) == %{
"results" => [
%{"utm_term" => "Term1", "visitors" => 2},
%{"utm_term" => "Direct / None", "visitors" => 1}
%{"utm_term" => "Term1", "visitors" => 2}
]
}
end

View File

@ -568,6 +568,74 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
}
]
end
test "filters out entries without utm_medium present", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_medium: "social",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_medium: "social",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_medium: "",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_medium: "social",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_medium: "",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 100
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_mediums?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "social",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_mediums?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "social",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
end
describe "GET /api/stats/:domain/utm_campaigns" do
@ -656,10 +724,82 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
}
]
end
test "filters out entries without utm_campaign present", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_campaign: "profile",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_campaign: "profile",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_campaign: "",
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_campaign: "",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_campaign: "profile",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_campaign: "",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 900
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_campaigns?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "profile",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_campaigns?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "profile",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
end
describe "GET /api/stats/:domain/utm_sources" do
setup [:create_user, :log_in, :create_new_site]
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
test "returns top utm_sources by unique user ids", %{conn: conn, site: site} do
populate_stats(site, [
@ -706,6 +846,326 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
end
end
describe "GET /api/stats/:domain/utm_terms" do
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
test "returns top utm_terms by unique user ids", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_term: "oat milk",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_term: "oat milk",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_term: "Sweden",
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_term: "Sweden",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_term: "oat milk",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_term: "Sweden",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 900
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "Sweden",
"visitors" => 2,
"bounce_rate" => 100,
"visit_duration" => 0
},
%{
"name" => "oat milk",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "Sweden",
"visitors" => 3,
"bounce_rate" => 67,
"visit_duration" => 300
},
%{
"name" => "oat milk",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
test "filters out entries without utm_term present", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_term: "oat milk",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_term: "oat milk",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_term: "",
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_term: "",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_term: "oat milk",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_term: "",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 900
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "oat milk",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "oat milk",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
end
describe "GET /api/stats/:domain/utm_contents" do
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
test "returns top utm_contents by unique user ids", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_content: "ad",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_content: "ad",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_content: "blog",
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_content: "blog",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_content: "ad",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_content: "blog",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 900
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "blog",
"visitors" => 2,
"bounce_rate" => 100,
"visit_duration" => 0
},
%{
"name" => "ad",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "blog",
"visitors" => 3,
"bounce_rate" => 67,
"visit_duration" => 300
},
%{
"name" => "ad",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
test "filters out entries without utm_content present", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_content: "ad",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_content: "ad",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_content: "",
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_content: "",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_content: "ad",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_content: "",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 900
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "ad",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "ad",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
end
describe "GET /api/stats/:domain/sources - with goal filter" do
setup [:create_user, :log_in, :create_new_site]
@ -1074,180 +1534,4 @@ defmodule PlausibleWeb.Api.StatsController.SourcesTest do
]
end
end
describe "GET /api/stats/:domain/utm_terms" do
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
test "returns top utm_terms by unique user ids", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_term: "oat milk",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_term: "oat milk",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_term: "Sweden",
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_term: "Sweden",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_term: "oat milk",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_term: "Sweden",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 900
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "Sweden",
"visitors" => 2,
"bounce_rate" => 100,
"visit_duration" => 0
},
%{
"name" => "oat milk",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_terms?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "Sweden",
"visitors" => 3,
"bounce_rate" => 67,
"visit_duration" => 300
},
%{
"name" => "oat milk",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
end
describe "GET /api/stats/:domain/utm_contents" do
setup [:create_user, :log_in, :create_new_site, :add_imported_data]
test "returns top utm_contents by unique user ids", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
utm_content: "ad",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_content: "ad",
user_id: @user_id,
timestamp: ~N[2021-01-01 00:15:00]
),
build(:pageview,
utm_content: "blog",
timestamp: ~N[2021-01-01 00:00:00]
),
build(:pageview,
utm_content: "blog",
timestamp: ~N[2021-01-01 00:00:00]
)
])
populate_stats(site, [
build(:imported_sources,
utm_content: "ad",
date: ~D[2021-01-01],
visit_duration: 700,
bounces: 1,
visits: 1,
visitors: 1
),
build(:imported_sources,
utm_content: "blog",
date: ~D[2021-01-01],
bounces: 0,
visits: 1,
visitors: 1,
visit_duration: 900
)
])
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01"
)
assert json_response(conn, 200) == [
%{
"name" => "blog",
"visitors" => 2,
"bounce_rate" => 100,
"visit_duration" => 0
},
%{
"name" => "ad",
"visitors" => 1,
"bounce_rate" => 0,
"visit_duration" => 900
}
]
conn =
get(
conn,
"/api/stats/#{site.domain}/utm_contents?period=day&date=2021-01-01&with_imported=true"
)
assert json_response(conn, 200) == [
%{
"name" => "blog",
"visitors" => 3,
"bounce_rate" => 67,
"visit_duration" => 300
},
%{
"name" => "ad",
"visitors" => 2,
"bounce_rate" => 50,
"visit_duration" => 800.0
}
]
end
end
end