Skip to content

Commit 44f64ad

Browse files
committed
Merge remote-tracking branch 'origin/master' into main-graph-v2-backend
2 parents a0507e5 + efe996d commit 44f64ad

23 files changed

Lines changed: 1258 additions & 1334 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ All notable changes to this project will be documented in this file.
66

77
### Added
88

9+
- Allow querying revenue metrics (`total_revenue`, `average_revenue`) with visit dimensions in Stats API v2
910
- Allow querying `views_per_visit` with a time dimension in Stats API
1011
- Add `bounce_rate` to page-filtered Top Stats even when imports are included, but render a metric warning about imported data not included in `bounce_rate` tooltip.
11-
- Add `time_on_page` to page-filtered Top Stats even when imports are included, unless legacy time on page is in view.
12+
- Add `time_on_page` to page-filtered Top Stats even when imports are included, unless legacy time on page is in view.
1213
- Adds team_id to query debug metadata (saved in system.query_log log_comment column)
1314
- Add "Unknown" option to Countries shield, for when the country code is unrecognized
1415
- Add "Last 24 Hours" to dashboard time range picker and Stats API v2
16+
- Always compare against the same time range in comparisons with "Today"
1517

1618
### Removed
1719

assets/js/dashboard/util/goals.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const SPECIAL_GOALS = {
1010
'Outbound Link: Click': { title: 'Outbound Links', prop: 'url' },
1111
'Cloaked Link: Click': { title: 'Cloaked Links', prop: 'url' },
1212
'File Download': { title: 'File Downloads', prop: 'url' },
13+
'Form: Submission': { title: 'Form Actions', prop: 'path' },
1314
'WP Search Queries': {
1415
title: 'WordPress Search Queries',
1516
prop: 'search_query'

e2e/tests/dashboard/behaviours.spec.ts

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { test, expect, Page } from '@playwright/test'
22
import {
33
setupSite,
44
populateStats,
5+
addGoal,
56
addCustomGoal,
67
addPageviewGoal,
78
addScrollDepthGoal,
@@ -23,6 +24,346 @@ import {
2324

2425
const getReport = (page: Page) => page.getByTestId('report-behaviours')
2526

27+
test('special goals', async ({ page, request }) => {
28+
const report = getReport(page)
29+
const { domain } = await setupSite({ page, request })
30+
31+
await populateStats({
32+
request,
33+
domain,
34+
events: [
35+
{
36+
user_id: 123,
37+
name: 'pageview',
38+
pathname: '/page1',
39+
timestamp: { minutesAgo: 60 }
40+
},
41+
{
42+
user_id: 123,
43+
name: 'Form: Submission',
44+
'meta.key': ['path'],
45+
'meta.value': ['/form-action/path'],
46+
timestamp: { minutesAgo: 50 }
47+
},
48+
{
49+
user_id: 123,
50+
name: '404',
51+
'meta.key': ['path'],
52+
'meta.value': ['/wrong-path'],
53+
timestamp: { minutesAgo: 45 }
54+
},
55+
{
56+
user_id: 123,
57+
name: 'Outbound Link: Click',
58+
'meta.key': ['url'],
59+
'meta.value': ['https://example.com/link'],
60+
timestamp: { minutesAgo: 40 }
61+
},
62+
{
63+
user_id: 123,
64+
name: 'Cloaked Link: Click',
65+
'meta.key': ['url'],
66+
'meta.value': ['https://example.com/cloaked-link'],
67+
timestamp: { minutesAgo: 35 }
68+
},
69+
{
70+
user_id: 123,
71+
name: 'File Download',
72+
'meta.key': ['url'],
73+
'meta.value': ['https://example.com/file.zip'],
74+
timestamp: { minutesAgo: 30 }
75+
},
76+
{
77+
user_id: 123,
78+
name: 'WP Search Queries',
79+
'meta.key': ['search_query'],
80+
'meta.value': ['some query'],
81+
timestamp: { minutesAgo: 25 }
82+
},
83+
{
84+
user_id: 123,
85+
name: 'WP Form Completions',
86+
'meta.key': ['path'],
87+
'meta.value': ['/some/path'],
88+
timestamp: { minutesAgo: 20 }
89+
},
90+
{
91+
user_id: 124,
92+
name: 'pageview',
93+
pathname: '/page1',
94+
timestamp: { minutesAgo: 60 }
95+
},
96+
{
97+
user_id: 124,
98+
name: 'Form: Submission',
99+
'meta.key': ['path'],
100+
'meta.value': ['/form-action/another-path'],
101+
timestamp: { minutesAgo: 50 }
102+
},
103+
{
104+
user_id: 124,
105+
name: '404',
106+
'meta.key': ['path'],
107+
'meta.value': ['/another-wrong-path'],
108+
timestamp: { minutesAgo: 45 }
109+
},
110+
{
111+
user_id: 124,
112+
name: 'Outbound Link: Click',
113+
'meta.key': ['url'],
114+
'meta.value': ['https://example.com/another-link'],
115+
timestamp: { minutesAgo: 40 }
116+
},
117+
{
118+
user_id: 124,
119+
name: 'Cloaked Link: Click',
120+
'meta.key': ['url'],
121+
'meta.value': ['https://example.com/another-cloaked-link'],
122+
timestamp: { minutesAgo: 35 }
123+
},
124+
{
125+
user_id: 124,
126+
name: 'File Download',
127+
'meta.key': ['url'],
128+
'meta.value': ['https://example.com/another-file.zip'],
129+
timestamp: { minutesAgo: 30 }
130+
},
131+
{
132+
user_id: 124,
133+
name: 'WP Search Queries',
134+
'meta.key': ['search_query'],
135+
'meta.value': ['another query'],
136+
timestamp: { minutesAgo: 25 }
137+
},
138+
{
139+
user_id: 124,
140+
name: 'WP Form Completions',
141+
'meta.key': ['path'],
142+
'meta.value': ['/another/path'],
143+
timestamp: { minutesAgo: 20 }
144+
}
145+
]
146+
})
147+
148+
await addGoal({ request, domain, params: { event_name: 'Form: Submission' } })
149+
await addGoal({ request, domain, params: { event_name: '404' } })
150+
await addGoal({
151+
request,
152+
domain,
153+
params: { event_name: 'Outbound Link: Click' }
154+
})
155+
await addGoal({
156+
request,
157+
domain,
158+
params: { event_name: 'Cloaked Link: Click' }
159+
})
160+
await addGoal({
161+
request,
162+
domain,
163+
params: { event_name: 'File Download' }
164+
})
165+
await addGoal({
166+
request,
167+
domain,
168+
params: { event_name: 'WP Search Queries' }
169+
})
170+
await addGoal({
171+
request,
172+
domain,
173+
params: { event_name: 'WP Form Completions' }
174+
})
175+
176+
await page.goto('/' + domain, { waitUntil: 'commit' })
177+
178+
const goalsTabButton = tabButton(report, 'Goals')
179+
180+
await goalsTabButton.scrollIntoViewIfNeeded()
181+
await expect(goalsTabButton).toHaveAttribute('data-active', 'true')
182+
183+
await expectHeaders(report, ['Goal', 'Uniques', 'Total', 'CR'])
184+
185+
await expectMetricValues(report, 'Form: Submission', ['2', '2', '100%'])
186+
await expectMetricValues(report, '404', ['2', '2', '100%'])
187+
await expectMetricValues(report, 'Outbound Link: Click', ['2', '2', '100%'])
188+
await expectMetricValues(report, 'Cloaked Link: Click', ['2', '2', '100%'])
189+
await expectMetricValues(report, 'File Download', ['2', '2', '100%'])
190+
await expectMetricValues(report, 'WP Search Queries', ['2', '2', '100%'])
191+
await expectMetricValues(report, 'WP Form Completions', ['2', '2', '100%'])
192+
193+
await test.step('Form: Submission goal is treated as a special goal', async () => {
194+
await rowLink(report, 'Form: Submission').click()
195+
196+
await expect(tabButton(report, 'Form actions')).toHaveAttribute(
197+
'data-active',
198+
'true'
199+
)
200+
201+
await expectHeaders(report, ['path', 'Visitors', 'Events', 'CR'])
202+
203+
await expectMetricValues(report, '/form-action/path', ['1', '1', '50%'])
204+
await expectMetricValues(report, '/form-action/another-path', [
205+
'1',
206+
'1',
207+
'50%'
208+
])
209+
})
210+
211+
await page
212+
.getByRole('button', {
213+
name: 'Remove filter: Goal is Form: Submission'
214+
})
215+
.click()
216+
217+
await goalsTabButton.click()
218+
219+
await test.step('404 goal is treated as a special goal', async () => {
220+
await rowLink(report, '404').click()
221+
222+
await expect(tabButton(report, '404 Pages')).toHaveAttribute(
223+
'data-active',
224+
'true'
225+
)
226+
227+
await expectHeaders(report, ['path', 'Visitors', 'Events', 'CR'])
228+
229+
await expectMetricValues(report, '/wrong-path', ['1', '1', '50%'])
230+
await expectMetricValues(report, '/another-wrong-path', ['1', '1', '50%'])
231+
})
232+
233+
await page
234+
.getByRole('button', {
235+
name: 'Remove filter: Goal is 404'
236+
})
237+
.click()
238+
239+
await goalsTabButton.click()
240+
241+
await test.step('Outbound Link: Click goal is treated as a special goal', async () => {
242+
await rowLink(report, 'Outbound Link: Click').click()
243+
244+
await expect(tabButton(report, 'Outbound Links')).toHaveAttribute(
245+
'data-active',
246+
'true'
247+
)
248+
249+
await expectHeaders(report, ['url', 'Visitors', 'Events', 'CR'])
250+
251+
await expectMetricValues(report, 'https://example.com/link', [
252+
'1',
253+
'1',
254+
'50%'
255+
])
256+
await expectMetricValues(report, 'https://example.com/another-link', [
257+
'1',
258+
'1',
259+
'50%'
260+
])
261+
})
262+
263+
await page
264+
.getByRole('button', {
265+
name: 'Remove filter: Goal is Outbound Link: Click'
266+
})
267+
.click()
268+
269+
await goalsTabButton.click()
270+
271+
await test.step('Cloaked Link: Click goal is treated as a special goal', async () => {
272+
await rowLink(report, 'Cloaked Link: Click').click()
273+
274+
await expect(tabButton(report, 'Cloaked Links')).toHaveAttribute(
275+
'data-active',
276+
'true'
277+
)
278+
279+
await expectHeaders(report, ['url', 'Visitors', 'Events', 'CR'])
280+
281+
await expectMetricValues(report, 'https://example.com/cloaked-link', [
282+
'1',
283+
'1',
284+
'50%'
285+
])
286+
await expectMetricValues(
287+
report,
288+
'https://example.com/another-cloaked-link',
289+
['1', '1', '50%']
290+
)
291+
})
292+
293+
await page
294+
.getByRole('button', {
295+
name: 'Remove filter: Goal is Cloaked Link: Click'
296+
})
297+
.click()
298+
299+
await goalsTabButton.click()
300+
301+
await test.step('File Download goal is treated as a special goal', async () => {
302+
await rowLink(report, 'File Download').click()
303+
304+
await expect(tabButton(report, 'File Downloads')).toHaveAttribute(
305+
'data-active',
306+
'true'
307+
)
308+
309+
await expectHeaders(report, ['url', 'Visitors', 'Events', 'CR'])
310+
311+
await expectMetricValues(report, 'https://example.com/file.zip', [
312+
'1',
313+
'1',
314+
'50%'
315+
])
316+
await expectMetricValues(report, 'https://example.com/another-file.zip', [
317+
'1',
318+
'1',
319+
'50%'
320+
])
321+
})
322+
323+
await page
324+
.getByRole('button', {
325+
name: 'Remove filter: Goal is File Download'
326+
})
327+
.click()
328+
329+
await goalsTabButton.click()
330+
331+
await test.step('WP Search Queries goal is treated as a special goal', async () => {
332+
await rowLink(report, 'WP Search Queries').click()
333+
334+
await expect(tabButton(report, 'WordPress Search Queries')).toHaveAttribute(
335+
'data-active',
336+
'true'
337+
)
338+
339+
await expectHeaders(report, ['search_query', 'Visitors', 'Events', 'CR'])
340+
341+
await expectMetricValues(report, 'some query', ['1', '1', '50%'])
342+
await expectMetricValues(report, 'another query', ['1', '1', '50%'])
343+
})
344+
345+
await page
346+
.getByRole('button', {
347+
name: 'Remove filter: Goal is WP Search Queries'
348+
})
349+
.click()
350+
351+
await goalsTabButton.click()
352+
353+
await test.step('WP Form Completions goal is treated as a special goal', async () => {
354+
await rowLink(report, 'WP Form Completions').click()
355+
356+
await expect(
357+
tabButton(report, 'WordPress Form Completions')
358+
).toHaveAttribute('data-active', 'true')
359+
360+
await expectHeaders(report, ['path', 'Visitors', 'Events', 'CR'])
361+
362+
await expectMetricValues(report, '/some/path', ['1', '1', '50%'])
363+
await expectMetricValues(report, '/another/path', ['1', '1', '50%'])
364+
})
365+
})
366+
26367
test('goals breakdown', async ({ page, request }) => {
27368
const report = getReport(page)
28369
const { domain } = await setupSite({ page, request })

0 commit comments

Comments
 (0)