Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analytics event: BACK_TO_SEARCH #1118

Merged
merged 8 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions frontend/src/components/VBackToSearchResultsLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<VLink
class="time inline-flex flex-row items-center gap-2 rounded-sm p-2 pe-3 text-xs font-semibold text-dark-charcoal-70 hover:text-dark-charcoal"
v-bind="$attrs"
@mousedown="handleClick"
>
<VIcon name="chevron-left" :rtl-flip="true" />
{{ $t("single-result.back") }}
Expand All @@ -12,6 +13,9 @@
<script lang="ts">
import { defineComponent } from "vue"

import { useAnalytics } from "~/composables/use-analytics"
import { useSearchStore } from "~/stores/search"

import VIcon from "~/components/VIcon/VIcon.vue"
import VLink from "~/components/VLink.vue"

Expand All @@ -25,5 +29,29 @@ export default defineComponent({
VLink,
},
inheritAttrs: false,
props: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These must be added below the inheritAttrs field to match the recommended option order.

Also, if you add new required props to a component, you will need to update the usage of that component. This particular component VBackToSearchResultsLink.vue is used in the following locations, which need to be updated:

  • frontend/src/pages/audio/_id/index.vue
  • frontend/src/pages/image/_id/index.vue
  • frontend/src/components/meta/VBackToSearchResultsLink.stories.mdx

/**
* The unique ID of the media
*/
id: {
type: String,
required: true,
},
},
setup(props) {
const { sendCustomEvent } = useAnalytics()
const searchStore = useSearchStore()

const handleClick = () => {
sendCustomEvent("BACK_TO_SEARCH", {
id: props.id,
searchType: searchStore.searchType,
})
}

return {
handleClick,
}
},
})
</script>
1 change: 1 addition & 0 deletions frontend/src/components/VLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
:class="{ 'inline-flex flex-row items-center gap-2': showExternalIcon }"
:to="linkTo"
v-on="$listeners"
@mousedown.native="$emit('mousedown', $event)"
@click.native="$emit('click', $event)"
>
<slot />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import VBackToSearchResultsLink from "~/components/VBackToSearchResultsLink.vue"
/>

export const Template = (args) => ({
template: `<VBackToSearchResultsLink v-bind="args"/>`,
template: `<VBackToSearchResultsLink v-bind="args" :id="id" />`,
components: { VBackToSearchResultsLink },
setup() {
return { args }
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/audio/_id/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<VSkipToContentContainer as="main">
<div v-if="backToSearchPath" class="w-full px-2 py-2 md:px-6">
<VBackToSearchResultsLink :href="backToSearchPath" />
<VBackToSearchResultsLink :id="audio.id" :href="backToSearchPath" />
</div>

<VAudioTrack layout="full" :audio="audio" class="main-track" />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/image/_id/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<VSkipToContentContainer as="main">
<div v-if="backToSearchPath" class="w-full px-2 py-2 md:px-6">
<VBackToSearchResultsLink :href="backToSearchPath" />
<VBackToSearchResultsLink :id="image.id" :href="backToSearchPath" />
</div>

<figure class="relative mb-4 border-b border-dark-charcoal-20 px-6">
Expand Down
13 changes: 12 additions & 1 deletion frontend/src/types/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { MediaType } from "~/constants/media"
import type { MediaType, SearchType } from "~/constants/media"
import type { ReportReason } from "~/constants/content-report"

/**
Expand Down Expand Up @@ -26,6 +26,17 @@ export type Events = {
/** the identifier of the image */
identifier: string
}
/**
* Click on the 'back to search' link on a single result
*
* - Are these links used much? Are they necessary?
*/
BACK_TO_SEARCH: {
/** The unique ID of the media */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small grammar nit.

Suggested change
/** The unique ID of the media */
/** the unique ID of the media */

id: string
/** The content type being searched (can include All content) */
searchType: SearchType
}
/**
* Description: The user clicks the CTA button to the external source to use the image
* Questions:
Expand Down
4 changes: 4 additions & 0 deletions frontend/test/playwright/e2e/attribution.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { test, expect } from "@playwright/test"

import { turnOnAnalytics } from "~~/test/playwright/utils/navigation"

test.describe.configure({ mode: "parallel" })

test.beforeEach(async ({ context }) => {
Expand Down Expand Up @@ -63,6 +65,8 @@ test("sends analytics event on copy", async ({ page }) => {
const id = "e9d97a98-621b-4ec2-bf70-f47a74380452"
const format = "rich"

await turnOnAnalytics(page)

await page.goto(`${mediaType}/${id}?ff_analytics=on`)
await page.click(`[id="copyattr-${format}"]`)

Expand Down
5 changes: 5 additions & 0 deletions frontend/test/playwright/utils/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,8 @@ export const closeFiltersUsingCookies = async (page: Page) => {
export const setBreakpointCookie = async (page: Page, breakpoint: string) => {
await setCookies(page.context(), { uiBreakpoint: breakpoint })
}

export const turnOnAnalytics = async (page: Page) => {
await page.goto("/preferences")
await page.getByLabel("Record custom events and page views.").click()
}
11 changes: 10 additions & 1 deletion frontend/test/unit/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@ Vue.use(VueI18n)
*/
config.stubs["nuxt-link"] = Vue.component("NuxtLink", {
props: ["to"],
template: '<a :href="to" v-on="$listeners"><slot /></a>',
methods: {
handleClick() {
// This is an adaptation to mimic NuxtLink's behavior,
// see https://github.com/WordPress/openverse/pull/1118
// We should try to remove it after migrating to Nuxt 3.
this.$emit("mousedown")
this.$emit("click", new MouseEvent("click"))
},
},
template: '<a :href="to" v-on="$listeners" @click="handleClick"><slot /></a>',
})

config.stubs["svg-icon"] = Vue.component("SvgIcon", {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createLocalVue } from "@vue/test-utils"
import { fireEvent, render } from "@testing-library/vue"

import { PiniaVuePlugin, createPinia } from "~~/test/unit/test-utils/pinia"

import { useAnalytics } from "~/composables/use-analytics"

import VBackToSearchResultsLink from "~/components/VBackToSearchResultsLink.vue"

jest.mock("~/composables/use-analytics", () => ({
useAnalytics: jest.fn(),
}))

const localVue = createLocalVue()
localVue.use(PiniaVuePlugin)
describe("VBackToSearchResultsLink", () => {
it("should send analytics event when clicked", async () => {
const sendCustomEventMock = jest.fn()

useAnalytics.mockImplementation(() => ({
sendCustomEvent: sendCustomEventMock,
}))
obulat marked this conversation as resolved.
Show resolved Hide resolved

const propsData = {
id: "123",
href: "/search",
}

const screen = render(VBackToSearchResultsLink, {
localVue,
pinia: createPinia(),
propsData,
})
const link = screen.getByText("single-result.back")

await fireEvent.click(link)

expect(sendCustomEventMock).toHaveBeenCalledWith("BACK_TO_SEARCH", {
id: propsData.id,
searchType: "all",
})
})
})